diff --git a/README.md b/README.md index ff354fc..6a5c26b 100644 --- a/README.md +++ b/README.md @@ -330,7 +330,7 @@ Write functions `lib.js` ```js // Make random color e.g. #34FFFF -function randColor() { +exports.makeColor = function () { const letters = '0123456789ABCDEF'; let color = '#'; for (let i = 0; i < 6; i++) { @@ -340,7 +340,7 @@ function randColor() { } // Detect date in ISO8601(e.g. 2021-06-02:00:00.000Z) format -function isDate(date) { +exports.isDate = function (date) { return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(date) } ``` @@ -354,7 +354,7 @@ Use functions test1: { req: { body: { - // call the `randColor` function to generate random colors + // call the `makeColor` function to generate random colors color:'makeColor()', @eval } }, diff --git a/README.zh-CN.md b/README.zh-CN.md index 096b969..6305bc9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -327,9 +327,9 @@ Apitest 使用JSONA格式描述测试用例。 JSON描述数据,注解描述 ```js // 创建随机颜色 -function randColor() { - const letters = '0123456789ABCDEF'; - let color = '#'; +exports.makeColor = function () { + const letters = "0123456789ABCDEF"; + let color = "#"; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } @@ -337,7 +337,7 @@ function randColor() { } // 判断是否是ISO8601(2021-06-02:00:00.000Z)风格的时间字符串 -function isDate(date) { +exports.isDate = function (date) { return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(date) } ``` @@ -350,7 +350,7 @@ function isDate(date) { test1: { req: { body: { - color: 'makeColor()', @eval // 调用 `randColor` 函数生成随机颜色 + color: 'makeColor()', @eval // 调用 `makeColor` 函数生成随机颜色 } }, res: { diff --git a/src/Loader.ts b/src/Loader.ts index 180ecd4..bfa61e3 100644 --- a/src/Loader.ts +++ b/src/Loader.ts @@ -13,10 +13,13 @@ export interface Module { describe: string; } +export interface JSLib { +} + export default class Loader { private workDir: string; private cases: Cases; - private jslibs: string[] = []; + private jslib: JSLib = {}; private clients: Clients = new Clients(); private modules: Module[] = []; private mixin: JsonaObject; @@ -58,7 +61,7 @@ export default class Loader { mainFile, cases: this.cases, clients: this.clients, - jslibs: this.jslibs, + jslibs: this.jslib, }; } @@ -128,18 +131,11 @@ export default class Loader { const libFile = path.resolve(this.workDir, libFileName); let jslib; try { - jslib = await fs.readFile(libFile, "utf8"); - } catch (err) { - throw new Error(`main@jslib(${libName}): load ${libFileName} failed`); - } - try { - const context = {}; - const script = new vm.Script(jslib); - script.runInNewContext(context); + jslib = require(libFile); } catch (err) { throw new Error(`main@jslib(${libName}): load ${libFileName} throw ${err.message}${toPosString(anno.position)}`); } - this.jslibs.push(jslib); + _.merge(this.jslib, jslib); } else { throw new Error(`[main@jslib] should have string value${toPosString(anno.position)}`); } diff --git a/src/Session.ts b/src/Session.ts index c98fa65..4854886 100644 --- a/src/Session.ts +++ b/src/Session.ts @@ -4,6 +4,7 @@ import * as fs from "fs/promises"; import * as crypto from "crypto"; import * as _ from "lodash"; import { Case, Unit } from "./Cases"; +import { JSLib } from "./Loader"; export const EMPTY_CACHE = { cursor: "", tests: {} }; @@ -11,16 +12,16 @@ export default class Session { private cacheFile: string; private cache: Cache; private unitIds: string[]; - private jslibs: string[] = []; + private jslib: JSLib; - public constructor(cacheFile: string, unitIds: string[], cache: Cache, jslibs: string[]) { + public constructor(cacheFile: string, unitIds: string[], cache: Cache, jslib: JSLib) { this.cacheFile = cacheFile; this.unitIds = unitIds; this.cache = cache; - this.jslibs = jslibs; + this.jslib = jslib; } - public static async create(mainFile: string, unitIds: string[], jslibs: string[]) { + public static async create(mainFile: string, unitIds: string[], jslibs: any) { const cacheFileName = "apitest" + md5(mainFile) + ".json"; const cacheFile = path.resolve(os.tmpdir(), cacheFileName); const cache = await loadCache(cacheFile); @@ -59,7 +60,7 @@ export default class Session { _.set(state, ["req"], req); _.set(this.cache.tests, testcase.paths.concat(["req"]), req); } - return { state, jslibs: this.jslibs }; + return { state, jslib: this.jslib }; } public async saveValue(testcase: Case, key: string, value: any, persist = true) { @@ -89,7 +90,7 @@ export default class Session { } export interface VmContext { - jslibs: string[], + jslib: JSLib, state: any; } diff --git a/src/utils.ts b/src/utils.ts index 625e452..30f22a3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -89,12 +89,13 @@ export function evalValue(paths: string[], ctx: VmContext, code: string, anno = if (!expressions[lastIdx].trim().startsWith("return")) { expressions[lastIdx] = "return " + expressions[lastIdx]; } - const patchedCode = ctx.jslibs.join("\n") + expressions.join(";"); + const patchedCode = expressions.join(";"); const EXPORT_KEY = "__exports__"; ctx.state[EXPORT_KEY] = null; try { const wrapCode = `${EXPORT_KEY} = (function(){${patchedCode};}())`; const script = new vm.Script(wrapCode); + _.merge(ctx.state, ctx.jslib); script.runInNewContext(ctx.state); return ctx.state[EXPORT_KEY]; } catch (err) { diff --git a/tests/__snapshots__/loader.test.js.snap b/tests/__snapshots__/loader.test.js.snap index a45a5bf..0629abe 100644 --- a/tests/__snapshots__/loader.test.js.snap +++ b/tests/__snapshots__/loader.test.js.snap @@ -11,11 +11,6 @@ exports[`loader invalid jslib 1`] = ` `; exports[`loader invalid jslib js 1`] = ` -"main@jslib(invalid-jslib-404): load invalid-jslib-404.js failed -" -`; - -exports[`loader invalid jslib js2 1`] = ` "main@jslib(invalid-jslib): load invalid-jslib.js throw Unexpected end of input at line 2 col 4 " `; diff --git a/tests/fixtures/loader/invalid-jslib-js.jsona b/tests/fixtures/loader/invalid-jslib-js.jsona index 2e8e689..4e38af9 100644 --- a/tests/fixtures/loader/invalid-jslib-js.jsona +++ b/tests/fixtures/loader/invalid-jslib-js.jsona @@ -1,3 +1,3 @@ { - @jslib("invalid-jslib-404") + @jslib("invalid-jslib") } \ No newline at end of file diff --git a/tests/fixtures/loader/invalid-jslib-js2.jsona b/tests/fixtures/loader/invalid-jslib-js2.jsona deleted file mode 100644 index 4e38af9..0000000 --- a/tests/fixtures/loader/invalid-jslib-js2.jsona +++ /dev/null @@ -1,3 +0,0 @@ -{ - @jslib("invalid-jslib") -} \ No newline at end of file diff --git a/tests/fixtures/loader/jslib.js b/tests/fixtures/loader/jslib.js new file mode 100644 index 0000000..3c8d0dd --- /dev/null +++ b/tests/fixtures/loader/jslib.js @@ -0,0 +1,12 @@ +exports.makeColor = function () { + const letters = "0123456789ABCDEF"; + let color = "#"; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +}; + +exports.isDate = function (date) { + return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(date); +}; diff --git a/tests/fixtures/loader/jslib.jsona b/tests/fixtures/loader/jslib.jsona new file mode 100644 index 0000000..9044eba --- /dev/null +++ b/tests/fixtures/loader/jslib.jsona @@ -0,0 +1,11 @@ +{ + @jslib("jslib") + test1: { @client("echo") + req: { + color: 'makeColor()', @eval + }, + res: { + color: `/#[0-9A-F]{6}/.test($)`, @eval + } + } +} \ No newline at end of file diff --git a/tests/loader.test.js b/tests/loader.test.js index 4e8a310..8c1756e 100644 --- a/tests/loader.test.js +++ b/tests/loader.test.js @@ -11,11 +11,6 @@ describe("loader", () => { expect(code).toEqual(1); expect(stdout).toMatchSnapshot(); }); - test("invalid jslib js2", async () => { - const { stdout, code } = await spwanTest("loader/invalid-jslib-js2.jsona", ["--ci"]); - expect(code).toEqual(1); - expect(stdout).toMatchSnapshot(); - }); test("invalid jslib", async () => { const { stdout, code } = await spwanTest("loader/invalid-jslib.jsona", ["--ci"]); expect(code).toEqual(1); @@ -66,7 +61,10 @@ describe("loader", () => { expect(code).toEqual(1); expect(stdout).toMatchSnapshot(); }); - + test("jslib", async () => { + const { code } = await spwanTest("loader/jslib.jsona", ["--ci"]); + expect(code).toEqual(0); + }); test("target file not found", async () => { const { stdout, code } = await spwanTest("loader/notfound.jsona", ["--ci"]); expect(code).toEqual(1);