From aaf1e5bb4cf21f1bf694baf3481ea4b0a3cc03d8 Mon Sep 17 00:00:00 2001 From: sigoden Date: Sun, 6 Jun 2021 18:16:34 +0800 Subject: [PATCH] feat: add annotation @trans --- README.md | 32 ++++++++++++++++++++++++++++++++ README.zh-CN.md | 32 ++++++++++++++++++++++++++++++++ package.json | 2 +- src/compareRes.ts | 6 ++++++ src/createReq.ts | 26 ++++++++++++++++++-------- tests/fixtures/req/trans.jsona | 13 +++++++++++++ tests/fixtures/res/trans.jsona | 13 +++++++++++++ tests/req.test.js | 4 ++++ tests/res.test.js | 4 ++++ 9 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 tests/fixtures/req/trans.jsona create mode 100644 tests/fixtures/res/trans.jsona diff --git a/README.md b/README.md index 4f9030a..d5a6eea 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Read this in other languages: [中文](./README.zh-CN.md) - [@group](#group) - [@eval](#eval) - [@mock](#mock) + - [@trans](#trans) - [@every](#every) - [@some](#some) - [@partial](#partial) @@ -599,6 +600,37 @@ The test cases in the group will inherit the group's `@client` and `@mixin`. The Apitest supports nearly 40 mock functions. For a detailed list, see [sigodne/fake.js](https://github.com/sigoden/fake-js#doc) +### @trans + +**Transform data** + +``` +{ + test1: { @client("echo") + req: { + v1: { @trans(`JSON.stringify($)`) + v1: 1, + v2: 2, + } + }, + res: { + v1: `{"v1":1,"v2":2}`, + } + }, + test2: { @client("echo") + req: { + v1: `{"v1":1,"v2":2}`, + }, + res: { + v2: { @trans(`JSON.parse($)`) + v1: 1, + v2: 2, + } + } + } +} +``` + ### @every **A set of assertions are passed before the test passes** diff --git a/README.zh-CN.md b/README.zh-CN.md index 38d6870..096b969 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -31,6 +31,7 @@ Apitest 是一款使用类JSON的DSL编写测试用例的自动化测试工具 - [@group](#group) - [@eval](#eval) - [@mock](#mock) + - [@trans](#trans) - [@every](#every) - [@some](#some) - [@partial](#partial) @@ -592,6 +593,37 @@ main Apitest 支持近40个mock函数。详细清单见[sigodne/fake.js](https://github.com/sigoden/fake-js#doc)。 +### @trans + +功能: 变换数据 + +``` +{ + test1: { @client("echo") + req: { + v1: { @trans(`JSON.stringify($)`) + v1: 1, + v2: 2, + } + }, + res: { + v1: `{"v1":1,"v2":2}`, + } + }, + test2: { @client("echo") + req: { + v1: `{"v1":1,"v2":2}`, + }, + res: { + v2: { @trans(`JSON.parse($)`) + v1: 1, + v2: 2, + } + } + } +} +``` + ### @every 功能: 一组断言全部通过才测试通过 diff --git a/package.json b/package.json index 13a6f89..02c6650 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@sigodenjs/apitest", "description": "declartive api testing tool", - "version": "0.5.1", + "version": "0.6.0", "bin": { "apitest": "dist/bin.js" }, diff --git a/src/compareRes.ts b/src/compareRes.ts index f7a587a..162a3aa 100644 --- a/src/compareRes.ts +++ b/src/compareRes.ts @@ -12,6 +12,12 @@ export default function compareRes(unit: Unit, ctx: VmContext, res: any) { } function compareValue(paths: string[], ctx: VmContext, v1: JsonaValue, v2: any) { + if (existAnno(paths, v1, "trans", "any")) { + const transAnno = v1.annotations.find(v => v.name === "trans"); + _.set(ctx.state, "$", v2); + v2 = evalValue(paths, ctx, transAnno.value, "trans"); + _.set(ctx.state, "$", null); + } if (existAnno(paths, v1, "eval", "string")) { ctx.state.$ = v2; const value = evalValue(paths, ctx, (v1 as JsonaString).value); diff --git a/src/createReq.ts b/src/createReq.ts index ddb3238..af4955b 100644 --- a/src/createReq.ts +++ b/src/createReq.ts @@ -13,16 +13,17 @@ export default function createReq(unit: Unit, ctx: VmContext): any { } function createValue(paths: string[], ctx: VmContext, jsa: JsonaValue) { + let result: any; if (existAnno(paths, jsa, "eval", "string")) { const value = evalValue(paths, ctx, (jsa as JsonaString).value); _.set(ctx.state, paths, value); - return value; + result = value; } else if(existAnno(paths, jsa, "mock", "string")) { const value = (jsa as JsonaString).value; try { const mockValue = fake(value); _.set(ctx.state, paths, mockValue); - return mockValue; + result = mockValue; } catch(err) { throw new RunCaseError(paths, "mock", `bad mock '${value}'`); } @@ -33,23 +34,32 @@ function createValue(paths: string[], ctx: VmContext, jsa: JsonaValue) { for (const [i, ele] of jsa.elements.entries()) { output.push(createValue(paths.concat([String(i)]), ctx, ele)); } - return output; + result = output; } else if (jsa.type === "Object") { _.set(ctx.state, paths, _.get(ctx.state, paths, {})); const output = _.get(ctx.state, paths); for (const prop of jsa.properties) { output[prop.key] = createValue(paths.concat([prop.key]), ctx, prop.value); } - return output; + result = output; } else if (jsa.type === "Null") { - return null; + result = null; } else { - return jsa.value; + result = jsa.value; } } + if (existAnno(paths, jsa, "trans", "any")) { + const transAnno = jsa.annotations.find(v => v.name === "trans"); + _.set(ctx.state, "$", result); + const value = evalValue(paths, ctx, transAnno.value, "trans"); + _.set(ctx.state, "$", null); + _.set(ctx.state, paths, value); + result = value; + } + return result; } -export function evalValue(paths: string[], ctx: VmContext, code: string): any { +export function evalValue(paths: string[], ctx: VmContext, code: string, anno = "eval"): any { if (!code) return null; const expressions = _.trimEnd(code.trim(), ";").split(";").map(v => v.trim()); const lastIdx = expressions.length - 1; @@ -65,7 +75,7 @@ export function evalValue(paths: string[], ctx: VmContext, code: string): any { script.runInNewContext(ctx.state); return ctx.state[EXPORT_KEY]; } catch (err) { - throw new RunCaseError(paths, "eval", `throw err, ${err.message}`); + throw new RunCaseError(paths, anno, `throw err, ${err.message}`); } } diff --git a/tests/fixtures/req/trans.jsona b/tests/fixtures/req/trans.jsona new file mode 100644 index 0000000..e090605 --- /dev/null +++ b/tests/fixtures/req/trans.jsona @@ -0,0 +1,13 @@ +{ + test1: { @client("echo") + req: { + v1: { @trans(`JSON.stringify($)`) + v1: 1, + v2: 2, + } + }, + res: { + v1: `{"v1":1,"v2":2}`, + } + }, +} \ No newline at end of file diff --git a/tests/fixtures/res/trans.jsona b/tests/fixtures/res/trans.jsona new file mode 100644 index 0000000..ea7261a --- /dev/null +++ b/tests/fixtures/res/trans.jsona @@ -0,0 +1,13 @@ +{ + test1: { @client("echo") + req: { + v1: `{"v1":1,"v2":2}`, + }, + res: { + v1: { @trans(`JSON.parse($)`) + v1: 1, + v2: 2, + } + } + } +} \ No newline at end of file diff --git a/tests/req.test.js b/tests/req.test.js index 10972da..ed2e457 100644 --- a/tests/req.test.js +++ b/tests/req.test.js @@ -16,4 +16,8 @@ describe("req", () => { expect(code).toEqual(1); expect(stdout).toMatchSnapshot(); }); + test("trans", async () => { + const { code } = await spwanTest("req/trans.jsona", ["--ci"]); + expect(code).toEqual(0); + }); }); diff --git a/tests/res.test.js b/tests/res.test.js index 91f28d2..de2910f 100644 --- a/tests/res.test.js +++ b/tests/res.test.js @@ -26,6 +26,10 @@ describe("res", () => { expect(code).toEqual(1); expect(stdout).toMatchSnapshot(); }); + test("trans", async () => { + const { code } = await spwanTest("res/trans.jsona", ["--ci"]); + expect(code).toEqual(0); + }); test("type", async () => { const { stdout, code } = await spwanTest("res/type.jsona", ["--ci"]); expect(code).toEqual(1);