From 8ceab684955589d1c2579687db166345d9a7e1df Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 21:01:15 +0200 Subject: [PATCH 01/11] Sample integration test. --- .gitignore | 4 +++ package.json | 3 +- tests/integration/package.json | 19 ++++++++++ tests/integration/quick-start.spec.ts | 50 +++++++++++++++++++++++++++ tests/integration/tsconfig.json | 3 ++ tools/generate-integration-test.ts | 46 ++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 tests/integration/package.json create mode 100644 tests/integration/quick-start.spec.ts create mode 100644 tests/integration/tsconfig.json create mode 100644 tools/generate-integration-test.ts diff --git a/.gitignore b/.gitignore index a5b3bfe0a..cc588dc4d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ dist yarn-error.log .npmrc coverage +tests/integration/node_modules +tests/integration/yarn-error.log +tests/integration/yarn.lock +tests/integration/quick-start.ts diff --git a/package.json b/package.json index 198a3f29c..0219fcb6b 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,10 @@ "build:compile": "tsc --build tsconfig.build.json", "build:swagger": "ts-node example/generate-open-api-schema.ts > example/example.swagger.yaml", "build:license": "ts-node tools/generate-license.ts > ./LICENSE", + "build:intTest": "yarn install --cwd ./tests/integration && ts-node tools/generate-integration-test.ts > ./tests/integration/quick-start.ts", "test": "yarn test:jest && yarn test:badge", "test:u": "yarn test:jest -u", - "test:jest": "yarn jest --detectOpenHandles ./tests/unit ./tests/system", + "test:jest": "yarn jest --detectOpenHandles ./tests/unit ./tests/system ./tests/integration", "test:badge": "yarn make-coverage-badge --output-path ./coverage.svg", "lint": "yarn eslint ./src ./example ./tests", "precommit": "yarn lint && yarn test && yarn build && git add example/example.swagger.yaml ./LICENSE ./coverage.svg", diff --git a/tests/integration/package.json b/tests/integration/package.json new file mode 100644 index 000000000..8987b28d4 --- /dev/null +++ b/tests/integration/package.json @@ -0,0 +1,19 @@ +{ + "name": "express-zod-api-integration-test", + "version": "1.0.0", + "scripts": { + "start": "ts-node quick-start.ts" + }, + "author": { + "name": "Anna Bocharova", + "url": "https://robintail.cz", + "email": "me@robintail.cz" + }, + "license": "MIT", + "dependencies": { + "@tsconfig/node12": "1.0.9", + "express-zod-api": "latest", + "ts-node": "10.3.0", + "typescript": "4.4.4" + } +} diff --git a/tests/integration/quick-start.spec.ts b/tests/integration/quick-start.spec.ts new file mode 100644 index 000000000..b42f0d746 --- /dev/null +++ b/tests/integration/quick-start.spec.ts @@ -0,0 +1,50 @@ +import {ChildProcessWithoutNullStreams, spawn} from 'child_process'; +import fetch from 'node-fetch'; +import {waitFor} from '../helpers'; + +describe('Integration Test', () => { + let example: ChildProcessWithoutNullStreams; + let out = ''; + const listener = (chunk: Buffer) => { + out += chunk.toString(); + }; + + beforeAll(() => { + example = spawn( + 'yarn', + ['start'], + {cwd: './tests/integration'} + ); + example.stdout.on('data', listener); + example.stdout.on('data', listener); + }); + + afterAll(async () => { + example.stdout.removeListener('data', listener); + example.kill(); + await waitFor(() => example.killed); + }); + + afterEach(() => { + out = ''; + }); + + describe('Quick Start from Readme', () => { + test('Should listen', async () => { + await waitFor(() => /Listening 8090/.test(out)); + expect(true).toBeTruthy(); + }); + + test('Should handle valid GET request', async () => { + const response = await fetch('http://localhost:8090/v1/hello?name=Rick'); + expect(response.status).toBe(200); + const json = await response.json(); + expect(json).toEqual({ + status: 'success', + data: { + greetings: 'Hello, Rick. Happy coding!' + } + }); + }); + }); +}); diff --git a/tests/integration/tsconfig.json b/tests/integration/tsconfig.json new file mode 100644 index 000000000..76603f1cd --- /dev/null +++ b/tests/integration/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@tsconfig/node12/tsconfig.json", +} diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts new file mode 100644 index 000000000..d0af95017 --- /dev/null +++ b/tools/generate-integration-test.ts @@ -0,0 +1,46 @@ +const out = ` +import {createConfig} from 'express-zod-api'; + +const config = createConfig({ + server: { + listen: 8090, // port or socket + }, + cors: true, + logger: { + level: 'debug', + color: true + } +}); + +import {defaultEndpointsFactory} from 'express-zod-api'; + +import {z} from 'express-zod-api'; + +const helloWorldEndpoint = defaultEndpointsFactory.build({ + method: 'get', + input: z.object({ // for empty input use z.object({}) + name: z.string().optional(), + }), + output: z.object({ + greetings: z.string(), + }), + handler: async ({input: {name}, options, logger}) => { + logger.debug('Options:', options); // middlewares provide options + return { greetings: \`Hello, \${name || 'World'}. Happy coding!\` }; + } +}); + +import {Routing} from 'express-zod-api'; + +const routing: Routing = { + v1: { + hello: helloWorldEndpoint + } +}; + +import {createServer} from 'express-zod-api'; + +createServer(config, routing); +`; + +console.log(out); From 260eb6ff0da565d0d7ea8af7e7faae59f687723f Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 21:10:13 +0200 Subject: [PATCH 02/11] Run integration test in CI. --- .github/workflows/node.js.yml | 1 + package.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 7fa16c1dd..532f21c08 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -39,4 +39,5 @@ jobs: run: | yarn lint yarn test + yarn test:int yarn build diff --git a/package.json b/package.json index 0219fcb6b..262997ebe 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,9 @@ "build:license": "ts-node tools/generate-license.ts > ./LICENSE", "build:intTest": "yarn install --cwd ./tests/integration && ts-node tools/generate-integration-test.ts > ./tests/integration/quick-start.ts", "test": "yarn test:jest && yarn test:badge", + "test:int": "yarn build:intTest && yarn jest --detectOpenHandles ./tests/integration", "test:u": "yarn test:jest -u", - "test:jest": "yarn jest --detectOpenHandles ./tests/unit ./tests/system ./tests/integration", + "test:jest": "yarn jest --detectOpenHandles ./tests/unit ./tests/system", "test:badge": "yarn make-coverage-badge --output-path ./coverage.svg", "lint": "yarn eslint ./src ./example ./tests", "precommit": "yarn lint && yarn test && yarn build && git add example/example.swagger.yaml ./LICENSE ./coverage.svg", From 4a00e73c39a1f508761ce39674929773c3dbac10 Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 21:48:49 +0200 Subject: [PATCH 03/11] Generation of package.json and tsconfig files for integration test according to node version. --- .gitignore | 2 ++ package.json | 2 +- tests/integration/package.json | 19 --------------- tests/integration/tsconfig.json | 3 --- tools/generate-integration-test.ts | 39 ++++++++++++++++++++++++++++-- 5 files changed, 40 insertions(+), 25 deletions(-) delete mode 100644 tests/integration/package.json delete mode 100644 tests/integration/tsconfig.json diff --git a/.gitignore b/.gitignore index cc588dc4d..fa41f61c7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ tests/integration/node_modules tests/integration/yarn-error.log tests/integration/yarn.lock tests/integration/quick-start.ts +tests/integration/package.json +tests/integration/tsconfig.json diff --git a/package.json b/package.json index 262997ebe..5a0a4fccb 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build:compile": "tsc --build tsconfig.build.json", "build:swagger": "ts-node example/generate-open-api-schema.ts > example/example.swagger.yaml", "build:license": "ts-node tools/generate-license.ts > ./LICENSE", - "build:intTest": "yarn install --cwd ./tests/integration && ts-node tools/generate-integration-test.ts > ./tests/integration/quick-start.ts", + "build:intTest": "yarn install --cwd ./tests/integration && ts-node tools/generate-integration-test.ts", "test": "yarn test:jest && yarn test:badge", "test:int": "yarn build:intTest && yarn jest --detectOpenHandles ./tests/integration", "test:u": "yarn test:jest -u", diff --git a/tests/integration/package.json b/tests/integration/package.json deleted file mode 100644 index 8987b28d4..000000000 --- a/tests/integration/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "express-zod-api-integration-test", - "version": "1.0.0", - "scripts": { - "start": "ts-node quick-start.ts" - }, - "author": { - "name": "Anna Bocharova", - "url": "https://robintail.cz", - "email": "me@robintail.cz" - }, - "license": "MIT", - "dependencies": { - "@tsconfig/node12": "1.0.9", - "express-zod-api": "latest", - "ts-node": "10.3.0", - "typescript": "4.4.4" - } -} diff --git a/tests/integration/tsconfig.json b/tests/integration/tsconfig.json deleted file mode 100644 index 76603f1cd..000000000 --- a/tests/integration/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@tsconfig/node12/tsconfig.json", -} diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts index d0af95017..0e6407962 100644 --- a/tools/generate-integration-test.ts +++ b/tools/generate-integration-test.ts @@ -1,4 +1,36 @@ -const out = ` +import fs from 'fs'; + +const nodeVersion = process.versions.node.split('.').shift(); + +const packageJson = ` +{ + "name": "express-zod-api-integration-test", + "version": "1.0.0", + "scripts": { + "start": "ts-node quick-start.ts" + }, + "author": { + "name": "Anna Bocharova", + "url": "https://robintail.cz", + "email": "me@robintail.cz" + }, + "license": "MIT", + "dependencies": { + "@tsconfig/node${nodeVersion}": "latest", + "express-zod-api": "latest", + "ts-node": "10.3.0", + "typescript": "4.4.4" + } +} +`; + +const tsConfigJson = ` +{ + "extends": "@tsconfig/node${nodeVersion}/tsconfig.json", +} +`; + +const quickStart = ` import {createConfig} from 'express-zod-api'; const config = createConfig({ @@ -43,4 +75,7 @@ import {createServer} from 'express-zod-api'; createServer(config, routing); `; -console.log(out); +const dir = './tests/integration'; +fs.writeFileSync(`${dir}/package.json`, packageJson.trim()); +fs.writeFileSync(`${dir}/tsconfig.json`, packageJson.trim()); +fs.writeFileSync(`${dir}/quick-start.ts`, quickStart.trim()); From 4aa80dfbf93f3c29f270693f231372ca71c5f64e Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 21:55:32 +0200 Subject: [PATCH 04/11] Fix build:intTest command. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a0a4fccb..b2af90650 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build:compile": "tsc --build tsconfig.build.json", "build:swagger": "ts-node example/generate-open-api-schema.ts > example/example.swagger.yaml", "build:license": "ts-node tools/generate-license.ts > ./LICENSE", - "build:intTest": "yarn install --cwd ./tests/integration && ts-node tools/generate-integration-test.ts", + "build:intTest": "ts-node tools/generate-integration-test.ts && yarn install --cwd ./tests/integration", "test": "yarn test:jest && yarn test:badge", "test:int": "yarn build:intTest && yarn jest --detectOpenHandles ./tests/integration", "test:u": "yarn test:jest -u", From d75a1ab39f1e228eb6020c82e3d1747e49218b77 Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 21:59:54 +0200 Subject: [PATCH 05/11] Changing version of ts-node. --- tools/generate-integration-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts index 0e6407962..6348c027a 100644 --- a/tools/generate-integration-test.ts +++ b/tools/generate-integration-test.ts @@ -18,7 +18,7 @@ const packageJson = ` "dependencies": { "@tsconfig/node${nodeVersion}": "latest", "express-zod-api": "latest", - "ts-node": "10.3.0", + "ts-node": "9.1.1", "typescript": "4.4.4" } } From 98ccd25a0510a11beae6e317cd1d482027235a6d Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 22:03:59 +0200 Subject: [PATCH 06/11] Exception for Node 15. --- tools/generate-integration-test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts index 6348c027a..cc6da6966 100644 --- a/tools/generate-integration-test.ts +++ b/tools/generate-integration-test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; const nodeVersion = process.versions.node.split('.').shift(); +const tsconfigBase = nodeVersion === '15' ? '14' : nodeVersion; const packageJson = ` { @@ -16,7 +17,7 @@ const packageJson = ` }, "license": "MIT", "dependencies": { - "@tsconfig/node${nodeVersion}": "latest", + "@tsconfig/node${tsconfigBase}": "latest", "express-zod-api": "latest", "ts-node": "9.1.1", "typescript": "4.4.4" @@ -26,7 +27,7 @@ const packageJson = ` const tsConfigJson = ` { - "extends": "@tsconfig/node${nodeVersion}/tsconfig.json", + "extends": "@tsconfig/node${tsconfigBase}/tsconfig.json", } `; From c1d2ca001ead81a3ab9718a43c501477c200649a Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 22:10:31 +0200 Subject: [PATCH 07/11] Changing CI to prepare and run int test separately. --- .github/workflows/node.js.yml | 8 ++++++-- package.json | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 532f21c08..b4789d8ab 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -34,10 +34,14 @@ jobs: path: ${{ steps.yarnCache.outputs.dir }} key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }} - name: Install dependencies - run: yarn install + run: | + yarn install + yarn build:intTest - name: Test and build run: | yarn lint yarn test - yarn test:int yarn build + - name: Integration test + run: | + yarn test:int diff --git a/package.json b/package.json index b2af90650..6c22d1464 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build:license": "ts-node tools/generate-license.ts > ./LICENSE", "build:intTest": "ts-node tools/generate-integration-test.ts && yarn install --cwd ./tests/integration", "test": "yarn test:jest && yarn test:badge", - "test:int": "yarn build:intTest && yarn jest --detectOpenHandles ./tests/integration", + "test:int": "yarn jest ./tests/integration", "test:u": "yarn test:jest -u", "test:jest": "yarn jest --detectOpenHandles ./tests/unit ./tests/system", "test:badge": "yarn make-coverage-badge --output-path ./coverage.svg", From a6df4f7d4f8af446490b7717232afde837e99959 Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 22:53:29 +0200 Subject: [PATCH 08/11] Using lib version from dist. --- .github/workflows/node.js.yml | 7 +++---- tools/generate-integration-test.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index b4789d8ab..3c2ee3498 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -34,14 +34,13 @@ jobs: path: ${{ steps.yarnCache.outputs.dir }} key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }} - name: Install dependencies - run: | - yarn install - yarn build:intTest - - name: Test and build + run: yarn install + - name: Test and build run: | yarn lint yarn test yarn build - name: Integration test run: | + yarn build:intTest yarn test:int diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts index cc6da6966..9a8412445 100644 --- a/tools/generate-integration-test.ts +++ b/tools/generate-integration-test.ts @@ -18,7 +18,7 @@ const packageJson = ` "license": "MIT", "dependencies": { "@tsconfig/node${tsconfigBase}": "latest", - "express-zod-api": "latest", + "express-zod-api": "../../dist", "ts-node": "9.1.1", "typescript": "4.4.4" } From b5203f4f273b8f0c6ac9125b889db9c952cbeef1 Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 23:26:57 +0200 Subject: [PATCH 09/11] Generating quick start code from readme. --- tools/generate-integration-test.ts | 54 +++++++----------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts index 9a8412445..9e0f0eedd 100644 --- a/tools/generate-integration-test.ts +++ b/tools/generate-integration-test.ts @@ -31,52 +31,24 @@ const tsConfigJson = ` } `; -const quickStart = ` -import {createConfig} from 'express-zod-api'; +const readme = fs.readFileSync('README.md', 'utf-8'); +const quickStartSection = readme.match(/# Quick start(.+)# Fascinating features/is); -const config = createConfig({ - server: { - listen: 8090, // port or socket - }, - cors: true, - logger: { - level: 'debug', - color: true - } -}); - -import {defaultEndpointsFactory} from 'express-zod-api'; - -import {z} from 'express-zod-api'; - -const helloWorldEndpoint = defaultEndpointsFactory.build({ - method: 'get', - input: z.object({ // for empty input use z.object({}) - name: z.string().optional(), - }), - output: z.object({ - greetings: z.string(), - }), - handler: async ({input: {name}, options, logger}) => { - logger.debug('Options:', options); // middlewares provide options - return { greetings: \`Hello, \${name || 'World'}. Happy coding!\` }; - } -}); - -import {Routing} from 'express-zod-api'; +if (!quickStartSection) { + throw new Error('Can not find Quick Start section'); +} -const routing: Routing = { - v1: { - hello: helloWorldEndpoint - } -}; +const tsParts = quickStartSection[1].match(/```typescript(.+?)```/gis); -import {createServer} from 'express-zod-api'; +if (!tsParts) { + throw new Error('Can not find typescript code samples'); +} -createServer(config, routing); -`; +const quickStart = tsParts.map( + (part) => part.split('\n').slice(1,-1).join('\n') +).join('\n\n'); const dir = './tests/integration'; fs.writeFileSync(`${dir}/package.json`, packageJson.trim()); -fs.writeFileSync(`${dir}/tsconfig.json`, packageJson.trim()); +fs.writeFileSync(`${dir}/tsconfig.json`, tsConfigJson.trim()); fs.writeFileSync(`${dir}/quick-start.ts`, quickStart.trim()); From 358d8e1ee54bd0dca9b25654c740eb6331c5fd29 Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 23:36:50 +0200 Subject: [PATCH 10/11] Using only Quick start marker in regex. --- tools/generate-integration-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generate-integration-test.ts b/tools/generate-integration-test.ts index 9e0f0eedd..2a91f52b4 100644 --- a/tools/generate-integration-test.ts +++ b/tools/generate-integration-test.ts @@ -32,7 +32,7 @@ const tsConfigJson = ` `; const readme = fs.readFileSync('README.md', 'utf-8'); -const quickStartSection = readme.match(/# Quick start(.+)# Fascinating features/is); +const quickStartSection = readme.match(/# Quick start(.+?)\n#\s[A-Z]+/s); if (!quickStartSection) { throw new Error('Can not find Quick Start section'); From 70ee0ef2a856ea79a21b31bda591305dad53ad4e Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Mon, 18 Oct 2021 23:41:14 +0200 Subject: [PATCH 11/11] Minor: naming. --- tests/integration/quick-start.spec.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/integration/quick-start.spec.ts b/tests/integration/quick-start.spec.ts index b42f0d746..47d5c7d07 100644 --- a/tests/integration/quick-start.spec.ts +++ b/tests/integration/quick-start.spec.ts @@ -3,26 +3,26 @@ import fetch from 'node-fetch'; import {waitFor} from '../helpers'; describe('Integration Test', () => { - let example: ChildProcessWithoutNullStreams; + let quickStart: ChildProcessWithoutNullStreams; let out = ''; const listener = (chunk: Buffer) => { out += chunk.toString(); }; beforeAll(() => { - example = spawn( + quickStart = spawn( 'yarn', ['start'], {cwd: './tests/integration'} ); - example.stdout.on('data', listener); - example.stdout.on('data', listener); + quickStart.stdout.on('data', listener); + quickStart.stdout.on('data', listener); }); afterAll(async () => { - example.stdout.removeListener('data', listener); - example.kill(); - await waitFor(() => example.killed); + quickStart.stdout.removeListener('data', listener); + quickStart.kill(); + await waitFor(() => quickStart.killed); }); afterEach(() => {