Skip to content
This repository has been archived by the owner on Sep 26, 2021. It is now read-only.

Commit

Permalink
feat: pre-request script parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewBastin committed Sep 24, 2021
1 parent 0e3563b commit b88fe7a
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 8 deletions.
20 changes: 16 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
"license": "MIT",
"dependencies": {
"fp-ts": "^2.11.3",
"lodash": "^4.17.21",
"quickjs-emscripten": "^0.13.0"
},
"devDependencies": {
"@digitak/esrun": "^1.2.4",
"@relmify/jest-fp-ts": "^1.1.1",
"@types/jest": "^26.0.23",
"@types/lodash": "^4.14.173",
"@types/node": "^15.12.5",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
Expand All @@ -46,6 +48,8 @@
"typescript": "^4.3.5"
},
"jest": {
"setupFilesAfterEnv": ["@relmify/jest-fp-ts"]
"setupFilesAfterEnv": [
"@relmify/jest-fp-ts"
]
}
}
64 changes: 64 additions & 0 deletions src/__tests__/preRequest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { execPreRequestScript } from "../preRequest"
import "@relmify/jest-fp-ts"

describe("execPreRequestScript", () => {
test("returns the updated envirionment properly", () => {
return expect(
execPreRequestScript(
`
pw.env.set("bob", "newbob")
`,
[{ key: "bob", value: "oldbob" }, { key: "foo", value: "bar" }]
)()
).resolves.toEqualRight([
{ key: "bob", value: "newbob" },
{ key: "foo", value: "bar" }
])
})

test("fails if the key is not a string", () => {
return expect(
execPreRequestScript(
`
pw.env.set(10, "newbob")
`,
[{ key: "bob", value: "oldbob" }, { key: "foo", value: "bar" }]
)()
).resolves.toBeLeft()
})

test("fails if the value is not a string", () => {
return expect(
execPreRequestScript(
`
pw.env.set("bob", 10)
`,
[{ key: "bob", value: "oldbob" }, { key: "foo", value: "bar" }]
)()
).resolves.toBeLeft()
})

test("fails for invalid syntax", () => {
return expect(
execPreRequestScript(
`
pw.env.set("bob",
`,
[{ key: "bob", value: "oldbob" }, { key: "foo", value: "bar" }]
)()
).resolves.toBeLeft()
})

test("creates new env variable if doesn't exist", () => {
return expect(
execPreRequestScript(
`
pw.env.set("foo", "bar")
`,
[]
)()
).resolves.toEqualRight(
[{ key: "foo", value: "bar" }]
)
})
})
11 changes: 10 additions & 1 deletion src/demo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { runTestScript } from "./index"
import { TestResponse } from "./test-runner"


const dummyResponse: TestResponse = {
status: 200,
body: "hoi",
headers: []
};

// eslint-disable-next-line prettier/prettier
(async () => {
Expand Down Expand Up @@ -37,7 +45,8 @@ import { runTestScript } from "./index"
pw.expect(arr).toHaveLength(3);
pw.expect(arr).not.toHaveLength(4);
});
`
`,
dummyResponse
),
{
depth: 100,
Expand Down
11 changes: 10 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { pipe } from "fp-ts/lib/function"
import { chain, right } from "fp-ts/lib/TaskEither"
import { execPreRequestScript } from "./preRequest"
import { execTestScript, TestResponse } from "./test-runner"

/**
Expand All @@ -13,4 +14,12 @@ export const runTestScript = (
) => pipe(
execTestScript(testScript, response),
chain((results) => right(results[0])) // execTestScript returns an array of descriptors with a single element (extract that)
)
)

/**
* Executes a given pre-request script on the sandbox
* @param preRequestScript The script to run
* @param env The envirionment variables active
* @returns A TaskEither with an error message or an array of the final environments with the all the script values applied
*/
export const runPreRequestScript = execPreRequestScript
77 changes: 77 additions & 0 deletions src/preRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { pipe } from "fp-ts/lib/function";
import { chain, TaskEither, tryCatch, right, left } from "fp-ts/lib/TaskEither";
import * as qjs from "quickjs-emscripten";
import clone from "lodash/clone";

type EnvEntry = {
key: string;
value: string;
};

export const execPreRequestScript = (
preRequestScript: string,
env: EnvEntry[]
): TaskEither<string, EnvEntry[]> => pipe(
tryCatch(
async () => await qjs.getQuickJS(),
(reason) => `QuickJS initialization failed: ${reason}`
),
chain(
(QuickJS) => {
const finalEnv = clone(env)

const vm = QuickJS.createVm()

const pwHandle = vm.newObject()

const envHandle = vm.newObject()

const envSetFuncHandle = vm.newFunction("set", (keyHandle, valueHandle) => {
const key = vm.dump(keyHandle)
const value = vm.dump(valueHandle)

if (typeof key !== "string") return {
error: vm.newString("Expected key to be a string")
}

if (typeof value !== "string") return {
error: vm.newString("Expected value to be a string")
}

const keyIndex = finalEnv.findIndex((env) => env.key === key)

if (keyIndex === -1) {
finalEnv.push({ key, value })
} else {
finalEnv[keyIndex] = { key, value }
}

return {
value: vm.undefined
}
})

vm.setProp(envHandle, "set", envSetFuncHandle)
envSetFuncHandle.dispose()

vm.setProp(pwHandle, "env", envHandle)
envHandle.dispose()

vm.setProp(vm.global, "pw", pwHandle)
pwHandle.dispose()

const evalRes = vm.evalCode(preRequestScript)

if (evalRes.error) {
const errorData = vm.dump(evalRes.error)
evalRes.error.dispose()

return left(`Script evaluation failed: ${errorData}`)
}

vm.dispose()

return right(finalEnv)
}
)
)
2 changes: 1 addition & 1 deletion src/test-runner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isLeft } from "fp-ts/lib/Either"
import { pipe } from "fp-ts/lib/function"
import { bindTo, bind, TaskEither, tryCatch, chain, right, left } from "fp-ts/lib/TaskEither"
import { TaskEither, tryCatch, chain, right, left } from "fp-ts/lib/TaskEither"
import * as qjs from "quickjs-emscripten"
import { marshalObjectToVM } from "./utils"

Expand Down

0 comments on commit b88fe7a

Please sign in to comment.