From 2d7d6da2d5a6fb7ee992b7f2bac02f39e1384b1f Mon Sep 17 00:00:00 2001 From: Salam Suleymanov Date: Thu, 14 Nov 2024 13:39:38 +0100 Subject: [PATCH] Graphql plugin (#23) * graphql call plugin * add graphql plugin * add graphql plugin * add graphql plugin * add graphql plugin * add graphql plugin --------- Co-authored-by: Ab <219340+abdala@users.noreply.github.com> --- dtc-aws-plugin/package.json | 8 ++-- dtc-graphql-plugin/README.md | 3 ++ dtc-graphql-plugin/package.json | 28 +++++++++++ dtc-graphql-plugin/src/graphql-call-plugin.ts | 37 ++++++++++++++ dtc-graphql-plugin/src/index.ts | 1 + .../test/graphql-call-plugin.test.ts | 48 +++++++++++++++++++ dtc-graphql-plugin/test/nock-appsync.ts | 40 ++++++++++++++++ dtc-graphql-plugin/tsconfig.json | 6 +++ package-lock.json | 46 ++++++++++++++++++ package.json | 1 + 10 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 dtc-graphql-plugin/README.md create mode 100644 dtc-graphql-plugin/package.json create mode 100644 dtc-graphql-plugin/src/graphql-call-plugin.ts create mode 100644 dtc-graphql-plugin/src/index.ts create mode 100644 dtc-graphql-plugin/test/graphql-call-plugin.test.ts create mode 100644 dtc-graphql-plugin/test/nock-appsync.ts create mode 100644 dtc-graphql-plugin/tsconfig.json diff --git a/dtc-aws-plugin/package.json b/dtc-aws-plugin/package.json index a612b79..ee3cb51 100644 --- a/dtc-aws-plugin/package.json +++ b/dtc-aws-plugin/package.json @@ -15,15 +15,15 @@ "author": "Abdala Cerqueira", "license": "LGPL-3.0-or-later", "dependencies": { - "@cgauge/assert": "^0.8.0", - "@cgauge/dtc": "^0.8.0", - "@cgauge/nock-aws": "^0.8.0", "@aws-sdk/client-dynamodb": "^3.645.0", "@aws-sdk/client-eventbridge": "^3.645.0", "@aws-sdk/client-lambda": "^3.645.0", "@aws-sdk/client-sns": "^3.645.0", "@aws-sdk/lib-dynamodb": "^3.645.0", - "@aws-sdk/util-dynamodb": "^3.645.0" + "@aws-sdk/util-dynamodb": "^3.645.0", + "@cgauge/assert": "^0.8.0", + "@cgauge/dtc": "^0.8.0", + "@cgauge/nock-aws": "^0.8.0" }, "scripts": { "build": "rm -rf dist && tsc", diff --git a/dtc-graphql-plugin/README.md b/dtc-graphql-plugin/README.md new file mode 100644 index 0000000..b179200 --- /dev/null +++ b/dtc-graphql-plugin/README.md @@ -0,0 +1,3 @@ +# DTC GraphQl Plugin + +Interact with GraphQl client diff --git a/dtc-graphql-plugin/package.json b/dtc-graphql-plugin/package.json new file mode 100644 index 0000000..2055b95 --- /dev/null +++ b/dtc-graphql-plugin/package.json @@ -0,0 +1,28 @@ +{ + "name": "@cgauge/dtc-graphql-plugin", + "version": "0.8.2", + "description": "GraphQl plugin for Declarative TestCases", + "repository": { + "type": "git", + "url": "git+https://github.com/cgauge/packages.git" + }, + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "author": "Salam Suleymanov", + "license": "LGPL-3.0-or-later", + "dependencies": { + "@cgauge/assert": "^0.8.0", + "@cgauge/dtc": "^0.8.0", + "graphql-request": "^7.1.2" + }, + "scripts": { + "build": "rm -rf dist && tsc", + "test": "tsx --test test/*.test.ts", + "test:only": "tsx --test --test-only test/*.test.ts", + "test:coverage": "tsx --experimental-test-coverage --test test/*.test.ts" + } +} diff --git a/dtc-graphql-plugin/src/graphql-call-plugin.ts b/dtc-graphql-plugin/src/graphql-call-plugin.ts new file mode 100644 index 0000000..efdfe82 --- /dev/null +++ b/dtc-graphql-plugin/src/graphql-call-plugin.ts @@ -0,0 +1,37 @@ +import extraAssert from '@cgauge/assert' +import {isRecord} from '@cgauge/dtc' +import {GraphQLClient} from 'graphql-request' + +type GraphQlCall = {url: string; query: string; variables: {}; headers?: Record} + +const isGraphQlCall = (v: unknown): v is GraphQlCall => isRecord(v) && 'url' in v + +let response: Response + +export const act = async (args: unknown) => { + if (!isGraphQlCall(args)) { + return + } + + const graphQLClient = new GraphQLClient(args.url, { + headers: { + ...args.headers, + authorization: process.env.AUTHORIZATION_TOKEN || '', + }, + ...args, + }) + + response = await graphQLClient.request(args.query, args.variables) +} + +export const assert = async (args: unknown) => { + if (!isRecord(args)) { + return + } + + if (!args.graphql) { + return + } + + extraAssert.objectContains(response, args.graphql) +} diff --git a/dtc-graphql-plugin/src/index.ts b/dtc-graphql-plugin/src/index.ts new file mode 100644 index 0000000..0c29f2c --- /dev/null +++ b/dtc-graphql-plugin/src/index.ts @@ -0,0 +1 @@ +export * as GraphQlPlugin from './graphql-call-plugin.js' diff --git a/dtc-graphql-plugin/test/graphql-call-plugin.test.ts b/dtc-graphql-plugin/test/graphql-call-plugin.test.ts new file mode 100644 index 0000000..e3577c7 --- /dev/null +++ b/dtc-graphql-plugin/test/graphql-call-plugin.test.ts @@ -0,0 +1,48 @@ +import {afterEach, test} from 'node:test' +import {act, assert} from '../src/graphql-call-plugin' +import nock from 'nock' +import {appsync, checkForPendingMocks} from './nock-appsync' + +nock.disableNetConnect() +afterEach(() => { + checkForPendingMocks() +}) + +test('It calls a graphql endpoint with the token', async () => { + process.env.AUTHORIZATION_TOKEN = 'token' + const response = {data: {key: 'value'}} + const query = `myQuery { items: {name, status} }` + const variables = {id: 1} + + const expectedHeaders = { + authorization: process.env.AUTHORIZATION_TOKEN, + } + + appsync({query, variables}, expectedHeaders, response) + + await act({ + url: `https://appsync.eu-west-1.amazonaws.com`, + query, + variables: {id: 1}, + }) + + await assert({graphql: response}) +}) + +test('It calls a graphql endpoint without the token', async () => { + delete process.env.AUTHORIZATION_TOKEN + const response = {data: {key: 'value'}} + const query = `myQuery { items: {name, status} }` + const expectedHeaders = { + authorization: '', + } + + appsync({query}, expectedHeaders, response) + + await act({ + url: `https://appsync.eu-west-1.amazonaws.com`, + query, + }) + + await assert({graphql: response}) +}) diff --git a/dtc-graphql-plugin/test/nock-appsync.ts b/dtc-graphql-plugin/test/nock-appsync.ts new file mode 100644 index 0000000..3661283 --- /dev/null +++ b/dtc-graphql-plugin/test/nock-appsync.ts @@ -0,0 +1,40 @@ +import nock from 'nock' +import {RequestDocument} from 'graphql-request' +import nodeAssert from 'node:assert/strict' +import extraAssert from '@cgauge/assert' + +nock.disableNetConnect() + +export interface AppSyncRequest { + query: string | RequestDocument + variables?: Record +} + +export const partialBodyCheck = (expected: AppSyncRequest) => (body: Record) => { + if (typeof expected === 'string') { + nodeAssert.equal(body, expected) + return true + } + + extraAssert.objectContains(body, expected) + return true +} + +export const appsync = ( + request: AppSyncRequest, + expectedHeaders: Record, + response: string | Record, +): void => { + nock('https://appsync.eu-west-1.amazonaws.com') + .post('/', partialBodyCheck(request)) + .matchHeader('authorization', expectedHeaders.authorization) + .reply(200, response) +} + +export const checkForPendingMocks = (): void => { + if (!nock.isDone()) { + const error = nock.pendingMocks() + nock.cleanAll() + throw new Error('Not all nock interceptors were used!') + } +} diff --git a/dtc-graphql-plugin/tsconfig.json b/dtc-graphql-plugin/tsconfig.json new file mode 100644 index 0000000..79baa5f --- /dev/null +++ b/dtc-graphql-plugin/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + }, +} diff --git a/package-lock.json b/package-lock.json index 3f90207..667aeb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "dtc-aws-plugin", "dtc-mysql-plugin", "dtc-playwright-plugin", + "dtc-graphql-plugin", "nock-aws", "yaml" ], @@ -55,6 +56,16 @@ "@cgauge/nock-aws": "^0.8.0" } }, + "dtc-graphql-plugin": { + "name": "@cgauge/dtc-graphql-plugin", + "version": "0.8.2", + "license": "LGPL-3.0-or-later", + "dependencies": { + "@cgauge/assert": "^0.8.0", + "@cgauge/dtc": "^0.8.0", + "graphql-request": "^7.1.2" + } + }, "dtc-mysql-plugin": { "name": "@cgauge/dtc-mysql-plugin", "version": "0.8.2", @@ -1177,6 +1188,10 @@ "resolved": "dtc-aws-plugin", "link": true }, + "node_modules/@cgauge/dtc-graphql-plugin": { + "resolved": "dtc-graphql-plugin", + "link": true + }, "node_modules/@cgauge/dtc-mysql-plugin": { "resolved": "dtc-mysql-plugin", "link": true @@ -1601,6 +1616,15 @@ "node": ">=18" } }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@mswjs/interceptors": { "version": "0.36.4", "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.36.4.tgz", @@ -2463,6 +2487,28 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/graphql": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-request": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-7.1.2.tgz", + "integrity": "sha512-+XE3iuC55C2di5ZUrB4pjgwe+nIQBuXVIK9J98wrVwojzDW3GMdSBZfxUk8l4j9TieIpjpggclxhNEU9ebGF8w==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0" + }, + "peerDependencies": { + "graphql": "14 - 16" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", diff --git a/package.json b/package.json index 9813de5..08c4355 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dtc-aws-plugin", "dtc-mysql-plugin", "dtc-playwright-plugin", + "dtc-graphql-plugin", "nock-aws", "yaml" ],