From 58456ff63c58de2886b429f04df249f4c51baa20 Mon Sep 17 00:00:00 2001 From: Pawel Pograniczny Date: Mon, 8 Apr 2024 10:26:20 +0200 Subject: [PATCH] test: add example lambda tests --- .github/workflows/tests.yml | 2 +- functions/example-lambda/handler.ts | 5 +- .../example-lambda/tests/handler.spec.ts | 91 ++++++++++-- package-lock.json | 133 +++++++++++++++++- package.json | 2 + 5 files changed, 217 insertions(+), 16 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 29c4c9d..58f3acc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,5 +37,5 @@ jobs: - name: SonarQube Scan uses: sonarsource/sonarqube-scan-action@master env: - SONAR_TOKEN: sqp_cdf796a422338de063410c70229532ccd1326375 + SONAR_TOKEN: sqp_b71429573ea73ed4c73e5fe20749c635ed7b611d SONAR_HOST_URL: https://sonarqube.aws.tshdev.io \ No newline at end of file diff --git a/functions/example-lambda/handler.ts b/functions/example-lambda/handler.ts index 19b4925..1b41c7a 100644 --- a/functions/example-lambda/handler.ts +++ b/functions/example-lambda/handler.ts @@ -17,15 +17,14 @@ import { httpErrorHandlerConfigured } from "../../shared/middleware/http-error-h import { createFindManyOptions, makePaginationResult } from "../../shared/pagination-utils/pagination-utils"; import { Like } from "typeorm"; -const connectToDb = dataSource.initialize(); const config = createConfig(process.env); const userRepository = dataSource.getRepository(ExampleModel); -const lambdaHandler = async (event: ExampleLambdaPayload) => { +export const lambdaHandler = async (event: ExampleLambdaPayload) => { const queryParams = event.queryStringParameters; winstonLogger.info(`Hello from ${config.appName}. Example param is: ${queryParams.exampleParam}`); - await connectToDb; + await dataSource.initialize(); const findOptions = createFindManyOptions(userRepository, queryParams); diff --git a/functions/example-lambda/tests/handler.spec.ts b/functions/example-lambda/tests/handler.spec.ts index df677fd..3d6d812 100644 --- a/functions/example-lambda/tests/handler.spec.ts +++ b/functions/example-lambda/tests/handler.spec.ts @@ -1,19 +1,90 @@ -import request from "supertest"; +import sinon from "sinon"; +import { DataSource, Repository } from "typeorm"; +import { lambdaHandler } from "../handler"; +import assert from "assert"; +import { StatusCodes } from "http-status-codes"; describe("test endpoint", () => { - const server = request("http://localhost:1337/"); + let sandbox: sinon.SinonSandbox; + let userRepositoryStub: sinon.SinonStub; + let dataSourceStub: sinon.SinonStub; + let metadataStub: sinon.SinonStub; - describe("Test obligatory query parameter", () => { - it("GET `dev/?exampleParam=test` returns 200", () => { - return server.get("dev/users").query("exampleParam=test").expect(200); - }); + const data = [ + { + id: "50ece88a-61ac-4435-8457-051693716276", + firstName: "John", + lastName: "Doe", + email: "john@doe.com", + }, + { + id: "8eb91b5f-63ef-4ca8-9db4-3fa6f173f1ae", + firstName: "Mark", + lastName: "Smith", + email: "mark@smith.com", + } + ]; + + const pagination = { + page: 1, + limit: 3, + total: 2, + totalPages: 1 + }; + + const params = { + exampleParam: "example", + page: "1", + limit: "3", + }; - it("GET `dev` returns bad request", () => { - return server.get("dev/users").expect(400); + beforeEach(() => { + sandbox = sinon.createSandbox(); + userRepositoryStub = sandbox.stub(Repository.prototype, "findAndCount").resolves([data, 2]); + dataSourceStub = sandbox.stub(DataSource.prototype, "initialize").resolves(); + metadataStub = sandbox.stub(Repository.prototype, "metadata"); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe("GET dev/users", () => { + it("should return users", async () => { + metadataStub.value({ + columns: [{ propertyName: "email", }, { propertyName: "firstName" }] + }); + const filters = { + sort: { email: "ASC" }, + filter: { firstName: "John" }, + search: "Doe", + }; + + const response = await lambdaHandler({ + queryStringParameters: { ...params, ...filters } + }); + + const parshedResponse = JSON.parse(response.body); + assert.equal(response.statusCode, StatusCodes.OK); + assert.deepEqual(parshedResponse, { meta: { pagination, ...filters }, data }); }); - it("GET 'any' returns not found", () => { - return server.get("any").expect(404); + it("shouldn't return filters if they are not available", async () => { + metadataStub.value({ + columns: [{ propertyName: "id", }, { propertyName: "lastName" }] + }); + + const response = await lambdaHandler({ + queryStringParameters: { + ...params, + sort: { email: "ASC", id: "ASC" }, + filter: { firstName: "John", lastName: "Doe" }, + } + }); + + const parshedResponse = JSON.parse(response.body); + assert.equal(response.statusCode, StatusCodes.OK); + assert.deepEqual(parshedResponse, { meta: { pagination, sort: { id: "ASC" }, filter: { lastName: "Doe" }}, data }); }); }); }); diff --git a/package-lock.json b/package-lock.json index f0297db..8a3a0b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "dotenv": "^16.3.1", "http-status-codes": "^2.3.0", "pg": "^8.11.3", + "sinon": "^17.0.1", "ts-pipe-compose": "^0.2.1", "typeorm": "^0.3.17", "winston": "^3.11.0", @@ -33,6 +34,7 @@ "@types/aws-lambda": "^8.10.124", "@types/mocha": "^10.0.2", "@types/node": "^20.11.17", + "@types/sinon": "^17.0.3", "@types/supertest": "^2.0.14", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", @@ -3657,6 +3659,45 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==" + }, "node_modules/@smithy/abort-controller": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.1.tgz", @@ -4517,6 +4558,21 @@ "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", "dev": true }, + "node_modules/@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, "node_modules/@types/superagent": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.18.tgz", @@ -11548,6 +11604,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==" + }, "node_modules/jwt-decode": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", @@ -11729,8 +11790,7 @@ "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, "node_modules/lodash.isfunction": { "version": "3.0.9", @@ -12635,6 +12695,18 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/nise": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/text-encoding": "^0.7.2", + "just-extend": "^6.2.0", + "path-to-regexp": "^6.2.1" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -14309,6 +14381,11 @@ "node": ">=0.10.0" } }, + "node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -16333,6 +16410,50 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, + "node_modules/sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -17877,6 +17998,14 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", diff --git a/package.json b/package.json index 78399c3..4edea9e 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "dotenv": "^16.3.1", "http-status-codes": "^2.3.0", "pg": "^8.11.3", + "sinon": "^17.0.1", "ts-pipe-compose": "^0.2.1", "typeorm": "^0.3.17", "winston": "^3.11.0", @@ -57,6 +58,7 @@ "@types/aws-lambda": "^8.10.124", "@types/mocha": "^10.0.2", "@types/node": "^20.11.17", + "@types/sinon": "^17.0.3", "@types/supertest": "^2.0.14", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4",