From 84ad7661af714c04c4ab4f8dd14e83d51598cc48 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:38:52 +0100 Subject: [PATCH 01/22] raise test cov --- src/index.ts | 1 + src/schema.ts | 1 + tests/coreunit.test.ts | 56 ++++++++++++++++++++++++++++++++++++++++++ vitest.config.ts | 6 ++--- 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 tests/coreunit.test.ts diff --git a/src/index.ts b/src/index.ts index 3fd03f87..a339329c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import { createApp } from './app'; import { startServer } from './server'; const application = createApp(); +/* istanbul ignore next @preserve */ startServer(application) .then(() => { // This should never happen, is only here until we add the real API which of course runs forever diff --git a/src/schema.ts b/src/schema.ts index e13aa0f2..56dcc3c4 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -4,6 +4,7 @@ import { validationPlugin } from 'nexus-validation-plugin'; import { applyMiddleware } from 'graphql-middleware'; import * as types from './modules'; +/* istanbul ignore next @preserve */ export const schema = makeSchema({ types, plugins: [ diff --git a/tests/coreunit.test.ts b/tests/coreunit.test.ts new file mode 100644 index 00000000..a7d868af --- /dev/null +++ b/tests/coreunit.test.ts @@ -0,0 +1,56 @@ +import { test, expect } from 'vitest'; +import builder from 'gql-query-builder'; +import { cleanDatabase as cleanDatabaseBeforeAfterEachTest } from './helpers/database'; +import { executeGraphQlQuery } from './helpers/server'; +import { getPrisma } from '../src/database'; +import { CoreUnit } from '@prisma/client'; + +cleanDatabaseBeforeAfterEachTest() + +test('Core Unit: get all', async () => { + const prisma = getPrisma() + await prisma.coreUnit.create({ + data: { + code: 'asdf', + shortCode: 'a', + name: 'name', + imageSource: '', + descriptionSentence: '', + descriptionParagraph: '', + descriptionParagraphImageSource: '' + } + }) + const query = builder.query({ + operation: 'coreUnits', + fields: ['code', 'shortCode', 'name'] + }) + const response = await executeGraphQlQuery(query) as {coreUnits: CoreUnit[]} + expect(response.coreUnits).toHaveLength(1) + expect(response.coreUnits[0].code).toBe('asdf') + expect(response.coreUnits[0].shortCode).toBe('a') + expect(response.coreUnits[0].name).toBe('name') +}) + +test('Core Unit: get by id', async () => { + const prisma = getPrisma() + const created = await prisma.coreUnit.create({ + data: { + code: 'asdf', + shortCode: 'a', + name: 'name', + imageSource: '', + descriptionSentence: '', + descriptionParagraph: '', + descriptionParagraphImageSource: '' + } + }) + const query = builder.query({ + operation: 'coreUnit', + variables: { + id: created.id + }, + fields: ['id'] + }) + const response = await executeGraphQlQuery(query) as {coreUnit: CoreUnit} + expect(response.coreUnit.id).toBe(created.id) +}) diff --git a/vitest.config.ts b/vitest.config.ts index 8c6742b6..b3a91de2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -4,9 +4,9 @@ export default defineConfig({ test: { coverage: { provider: 'istanbul', - lines: 0, - functions: 0, - statements: 0, + lines: 90, + functions: 90, + statements: 90, all: true, }, singleThread: true, From abc32ca046255c6811eaafd37de969dc94aec046 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:43:51 +0100 Subject: [PATCH 02/22] revert me --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index a339329c..3fd03f87 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,6 @@ import { createApp } from './app'; import { startServer } from './server'; const application = createApp(); -/* istanbul ignore next @preserve */ startServer(application) .then(() => { // This should never happen, is only here until we add the real API which of course runs forever From f4aa1fc58101eb5149a2be0d4f98d88f12ff2d22 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:47:52 +0100 Subject: [PATCH 03/22] lint --- tests/coreunit.test.ts | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/coreunit.test.ts b/tests/coreunit.test.ts index a7d868af..5031fc88 100644 --- a/tests/coreunit.test.ts +++ b/tests/coreunit.test.ts @@ -1,14 +1,14 @@ import { test, expect } from 'vitest'; import builder from 'gql-query-builder'; +import { CoreUnit } from '@prisma/client'; import { cleanDatabase as cleanDatabaseBeforeAfterEachTest } from './helpers/database'; import { executeGraphQlQuery } from './helpers/server'; import { getPrisma } from '../src/database'; -import { CoreUnit } from '@prisma/client'; -cleanDatabaseBeforeAfterEachTest() +cleanDatabaseBeforeAfterEachTest(); test('Core Unit: get all', async () => { - const prisma = getPrisma() + const prisma = getPrisma(); await prisma.coreUnit.create({ data: { code: 'asdf', @@ -17,22 +17,22 @@ test('Core Unit: get all', async () => { imageSource: '', descriptionSentence: '', descriptionParagraph: '', - descriptionParagraphImageSource: '' - } - }) + descriptionParagraphImageSource: '', + }, + }); const query = builder.query({ operation: 'coreUnits', - fields: ['code', 'shortCode', 'name'] - }) - const response = await executeGraphQlQuery(query) as {coreUnits: CoreUnit[]} - expect(response.coreUnits).toHaveLength(1) - expect(response.coreUnits[0].code).toBe('asdf') - expect(response.coreUnits[0].shortCode).toBe('a') - expect(response.coreUnits[0].name).toBe('name') -}) + fields: ['code', 'shortCode', 'name'], + }); + const response = await executeGraphQlQuery(query) as { coreUnits: CoreUnit[] }; + expect(response.coreUnits).toHaveLength(1); + expect(response.coreUnits[0].code).toBe('asdf'); + expect(response.coreUnits[0].shortCode).toBe('a'); + expect(response.coreUnits[0].name).toBe('name'); +}); test('Core Unit: get by id', async () => { - const prisma = getPrisma() + const prisma = getPrisma(); const created = await prisma.coreUnit.create({ data: { code: 'asdf', @@ -41,16 +41,16 @@ test('Core Unit: get by id', async () => { imageSource: '', descriptionSentence: '', descriptionParagraph: '', - descriptionParagraphImageSource: '' - } - }) + descriptionParagraphImageSource: '', + }, + }); const query = builder.query({ operation: 'coreUnit', variables: { - id: created.id + id: created.id, }, - fields: ['id'] - }) - const response = await executeGraphQlQuery(query) as {coreUnit: CoreUnit} - expect(response.coreUnit.id).toBe(created.id) -}) + fields: ['id'], + }); + const response = await executeGraphQlQuery(query) as { coreUnit: CoreUnit }; + expect(response.coreUnit.id).toBe(created.id); +}); From 42eefe43664b584bc24116cb9cd30754cf51f1a1 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:49:27 +0100 Subject: [PATCH 04/22] revert --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 3fd03f87..a339329c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import { createApp } from './app'; import { startServer } from './server'; const application = createApp(); +/* istanbul ignore next @preserve */ startServer(application) .then(() => { // This should never happen, is only here until we add the real API which of course runs forever From c1b03a40a1f201a3f72aa4d9952123adbc4fa0be Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Wed, 22 Mar 2023 22:16:04 +0100 Subject: [PATCH 05/22] add more tests --- src/env.ts | 14 +++++++++----- src/server.ts | 6 +----- tests/auxilary.test.ts | 11 +++++++++++ tests/coreunit.test.ts | 9 +++++++++ tests/helpers/env.ts | 8 ++++++++ 5 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 tests/auxilary.test.ts create mode 100644 tests/helpers/env.ts diff --git a/src/env.ts b/src/env.ts index 6f9c62ef..28c920a4 100644 --- a/src/env.ts +++ b/src/env.ts @@ -2,12 +2,16 @@ import dotenv from 'dotenv'; dotenv.config(); -if (!process.env.JWT_SECRET) { - if (process.env.NODE_ENV === 'production') { - throw new Error('JWT_SECRET is not defined'); +export const getJwtSecret = (): string => { + if (!process.env.JWT_SECRET) { + if (process.env.NODE_ENV === 'production') { + throw new Error('JWT_SECRET is not defined'); + } } -} -export const JWT_SECRET = process.env.JWT_SECRET || 'dev'; + return process.env.JWT_SECRET || 'dev'; +}; + +export const JWT_SECRET = getJwtSecret(); export const PORT = Number(process.env.PORT ?? '3000'); export const isDevelopment = process.env.NODE_ENV === 'development'; export const AUTH_SIGNUP_ENABLED = Boolean(process.env.AUTH_SIGNUP_ENABLED); diff --git a/src/server.ts b/src/server.ts index 03dcc3cc..133496ec 100644 --- a/src/server.ts +++ b/src/server.ts @@ -21,9 +21,5 @@ export const startServer = async ( await apollo.start(); apollo.applyMiddleware({ app }); const usedPort = port || PORT; - return httpServer.listen({ port: usedPort }, () => { - process.stdout.write( - `🚀 Server ready at port ${usedPort}`, - ); - }); + return httpServer.listen({ port: usedPort }, () => {}); }; diff --git a/tests/auxilary.test.ts b/tests/auxilary.test.ts new file mode 100644 index 00000000..abb7b0b0 --- /dev/null +++ b/tests/auxilary.test.ts @@ -0,0 +1,11 @@ +import { test, expect } from 'vitest'; +import { getJwtSecret } from '../src/env'; +import { restoreEnvAfterEach } from './helpers/env'; + +restoreEnvAfterEach(); + +test('Env: production has jwt secret defined', async () => { + process.env.JWT_SECRET = ''; + process.env.NODE_ENV = 'production'; + expect(getJwtSecret).toThrowError('JWT_SECRET is not defined'); +}); diff --git a/tests/coreunit.test.ts b/tests/coreunit.test.ts index 5031fc88..c009886e 100644 --- a/tests/coreunit.test.ts +++ b/tests/coreunit.test.ts @@ -54,3 +54,12 @@ test('Core Unit: get by id', async () => { const response = await executeGraphQlQuery(query) as { coreUnit: CoreUnit }; expect(response.coreUnit.id).toBe(created.id); }); + +test('Core Unit: get by id without id field throws', async () => { + const query = builder.query({ + operation: 'coreUnit', + fields: ['id'], + }); + const response = await executeGraphQlQuery(query) as { errors: Record[] }; + expect(response.errors[0].message).toBe('please provide id'); +}); diff --git a/tests/helpers/env.ts b/tests/helpers/env.ts new file mode 100644 index 00000000..2854f705 --- /dev/null +++ b/tests/helpers/env.ts @@ -0,0 +1,8 @@ +import { afterEach } from 'vitest'; + +const originalEnv = process.env; +export function restoreEnvAfterEach() { + afterEach(() => { + process.env = { ...originalEnv }; + }); +} From 618e21f897b2ccc2a6f90e6be1dd18ca667f6755 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Wed, 22 Mar 2023 22:40:57 +0100 Subject: [PATCH 06/22] refactor env dir --- src/env/getters.ts | 8 ++++++++ src/{env.ts => env/index.ts} | 10 +--------- tests/auxilary.test.ts | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 src/env/getters.ts rename src/{env.ts => env/index.ts} (64%) diff --git a/src/env/getters.ts b/src/env/getters.ts new file mode 100644 index 00000000..15a5cee8 --- /dev/null +++ b/src/env/getters.ts @@ -0,0 +1,8 @@ +export const getJwtSecret = (): string => { + if (!process.env.JWT_SECRET) { + if (process.env.NODE_ENV === 'production') { + throw new Error('JWT_SECRET is not defined'); + } + } + return process.env.JWT_SECRET || 'dev'; +}; diff --git a/src/env.ts b/src/env/index.ts similarity index 64% rename from src/env.ts rename to src/env/index.ts index 28c920a4..fbdf9934 100644 --- a/src/env.ts +++ b/src/env/index.ts @@ -1,16 +1,8 @@ import dotenv from 'dotenv'; +import { getJwtSecret } from './getters' dotenv.config(); -export const getJwtSecret = (): string => { - if (!process.env.JWT_SECRET) { - if (process.env.NODE_ENV === 'production') { - throw new Error('JWT_SECRET is not defined'); - } - } - return process.env.JWT_SECRET || 'dev'; -}; - export const JWT_SECRET = getJwtSecret(); export const PORT = Number(process.env.PORT ?? '3000'); export const isDevelopment = process.env.NODE_ENV === 'development'; diff --git a/tests/auxilary.test.ts b/tests/auxilary.test.ts index abb7b0b0..49edf9d5 100644 --- a/tests/auxilary.test.ts +++ b/tests/auxilary.test.ts @@ -1,5 +1,5 @@ import { test, expect } from 'vitest'; -import { getJwtSecret } from '../src/env'; +import { getJwtSecret } from '../src/env/getters'; import { restoreEnvAfterEach } from './helpers/env'; restoreEnvAfterEach(); From 5c2688b3141128a2f7f7edb728b719f8bc611c39 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 12:34:02 +0100 Subject: [PATCH 07/22] lint --- src/env/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env/index.ts b/src/env/index.ts index fbdf9934..ca477dd2 100644 --- a/src/env/index.ts +++ b/src/env/index.ts @@ -1,5 +1,5 @@ import dotenv from 'dotenv'; -import { getJwtSecret } from './getters' +import { getJwtSecret } from './getters'; dotenv.config(); From 98f9813b14293523b4ea24d714859fcf25868303 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 12:51:10 +0100 Subject: [PATCH 08/22] rm unused branch --- src/context.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/context.ts b/src/context.ts index bc4154fd..593764ae 100644 --- a/src/context.ts +++ b/src/context.ts @@ -36,9 +36,6 @@ export function createContext(params: CreateContextParams): Context { const authorizationHeader = req.get('Authorization'); const token = authorizationHeader?.replace('Bearer ', ''); - if (!JWT_SECRET) { - throw new Error('Missing JWT_SECRET environment variable'); - } return { request: params, prisma, From bd7ec258b725a295675fa4cdd201b3e50eec95e8 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:12:19 +0100 Subject: [PATCH 09/22] add test to cover token expired --- tests/auth.test.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/auth.test.ts b/tests/auth.test.ts index 7affa591..7c70dd60 100644 --- a/tests/auth.test.ts +++ b/tests/auth.test.ts @@ -1,7 +1,9 @@ -import { test, expect } from 'vitest'; +import { test, expect, vi } from 'vitest'; import builder from 'gql-query-builder'; import { cleanDatabase as cleanDatabaseBeforeAfterEachTest } from './helpers/database'; import { ctx, executeGraphQlQuery } from './helpers/server'; +import { restoreEnvAfterEach } from './helpers/env'; +import * as env from '../src/env' const signUpMutation = builder.mutation({ operation: 'signUp', @@ -39,6 +41,7 @@ const meQuery = builder.query({ }); cleanDatabaseBeforeAfterEachTest(); +restoreEnvAfterEach(); test('Authentication: sign up, sign in, request protected enpoint', async () => { const signUpResponse = (await executeGraphQlQuery(signUpMutation)) as Record< @@ -110,3 +113,30 @@ test('Authentication: access protected endpoint without valid token', async () = const response = (await executeGraphQlQuery(meQuery)) as any; expect(response.errors[0].message).toBe('Invalid authentication token'); }); + +test('Authentication: token expiration error', async () => { + vi.spyOn(env, 'JWT_EXPIRATION_PERIOD', 'get').mockReturnValue('1ms'); + const signUpResponse = (await executeGraphQlQuery(signUpMutation)) as Record< + string, + any + >; + expect(signUpResponse?.signUp?.user?.username).toBe('asdf'); + expect(signUpResponse?.signUp?.token).toBeTruthy(); + + const signInResponse = (await executeGraphQlQuery(singInMutation)) as Record< + string, + any + >; + expect(signInResponse?.signIn?.user?.username).toBe('asdf'); + expect(signInResponse?.signIn?.token).toBeTruthy(); + + const token = signInResponse?.signIn?.token; + ctx.client.setHeader('Authorization', `Bearer ${token}`); + + const meResponse = (await executeGraphQlQuery(meQuery)) as Record< + string, + any + >; + await new Promise(resolve => setTimeout(resolve, 2000)); + expect(meResponse?.errors[0].message).toBe('Token expired'); +}) From 7a2e2006f38a289a9850e8831f55ea3b002ce9fd Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:24:09 +0100 Subject: [PATCH 10/22] test to cover token expired --- src/env/index.ts | 3 ++- tests/auth.test.ts | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/env/index.ts b/src/env/index.ts index ca477dd2..515a1bdb 100644 --- a/src/env/index.ts +++ b/src/env/index.ts @@ -7,4 +7,5 @@ export const JWT_SECRET = getJwtSecret(); export const PORT = Number(process.env.PORT ?? '3000'); export const isDevelopment = process.env.NODE_ENV === 'development'; export const AUTH_SIGNUP_ENABLED = Boolean(process.env.AUTH_SIGNUP_ENABLED); -export const JWT_EXPIRATION_PERIOD = process.env.JWT_EXPIRATION_PERIOD_SECONDS ? Number(process.env.JWT_EXPIRATION_PERIOD_SECONDS) : '7d'; +// https://www.npmjs.com/package/jsonwebtoken for `expiresIn` format +export const JWT_EXPIRATION_PERIOD: number | string = process.env.JWT_EXPIRATION_PERIOD_SECONDS ? Number(process.env.JWT_EXPIRATION_PERIOD_SECONDS) : '7d'; diff --git a/tests/auth.test.ts b/tests/auth.test.ts index 7c70dd60..a7cc8bda 100644 --- a/tests/auth.test.ts +++ b/tests/auth.test.ts @@ -3,7 +3,7 @@ import builder from 'gql-query-builder'; import { cleanDatabase as cleanDatabaseBeforeAfterEachTest } from './helpers/database'; import { ctx, executeGraphQlQuery } from './helpers/server'; import { restoreEnvAfterEach } from './helpers/env'; -import * as env from '../src/env' +import * as env from '../src/env'; const signUpMutation = builder.mutation({ operation: 'signUp', @@ -137,6 +137,7 @@ test('Authentication: token expiration error', async () => { string, any >; - await new Promise(resolve => setTimeout(resolve, 2000)); + // wait 2 seconds + await new Promise((resolve) => { setTimeout(resolve, 2000); resolve(null); }); expect(meResponse?.errors[0].message).toBe('Token expired'); -}) +}); From 65c50c4aba0efd27a192b1bd97fce171d732af69 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:27:06 +0100 Subject: [PATCH 11/22] faster test --- tests/auth.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/auth.test.ts b/tests/auth.test.ts index a7cc8bda..9c535b2f 100644 --- a/tests/auth.test.ts +++ b/tests/auth.test.ts @@ -121,7 +121,6 @@ test('Authentication: token expiration error', async () => { any >; expect(signUpResponse?.signUp?.user?.username).toBe('asdf'); - expect(signUpResponse?.signUp?.token).toBeTruthy(); const signInResponse = (await executeGraphQlQuery(singInMutation)) as Record< string, @@ -137,7 +136,7 @@ test('Authentication: token expiration error', async () => { string, any >; - // wait 2 seconds - await new Promise((resolve) => { setTimeout(resolve, 2000); resolve(null); }); + // wait until token expires + await new Promise((resolve) => { setTimeout(resolve, 20); resolve(null); }); expect(meResponse?.errors[0].message).toBe('Token expired'); }); From 6951efb5256621c67d79336199dd808d204ee5a7 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:34:47 +0100 Subject: [PATCH 12/22] Add test sign up disabled --- src/modules/User/model.ts | 2 +- tests/auth.test.ts | 6 ++++++ tests/auxilary.test.ts | 5 +++++ tests/helpers/env.ts | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/modules/User/model.ts b/src/modules/User/model.ts index 91cce5a3..0518b0be 100644 --- a/src/modules/User/model.ts +++ b/src/modules/User/model.ts @@ -75,7 +75,7 @@ export function getUserCrud(prisma: PrismaClient) { if ('code' in e && e.code === 'P2002') { throw new ApolloError('Username already taken', 'USERNAME_TAKEN'); } - throw new ApolloError('Failed to create user', 'USER_CREATE_FAILED'); + throw e; } return { token: sign({ userId: created.id }, JWT_SECRET), diff --git a/tests/auth.test.ts b/tests/auth.test.ts index 9c535b2f..26793bbc 100644 --- a/tests/auth.test.ts +++ b/tests/auth.test.ts @@ -140,3 +140,9 @@ test('Authentication: token expiration error', async () => { await new Promise((resolve) => { setTimeout(resolve, 20); resolve(null); }); expect(meResponse?.errors[0].message).toBe('Token expired'); }); + +test('Authentication: sign up disabled', async () => { + vi.spyOn(env, 'AUTH_SIGNUP_ENABLED', 'get').mockReturnValue(false); + const response = (await executeGraphQlQuery(signUpMutation)) as any; + expect(response.errors[0].message).toBe('Sign up is disabled'); +}); diff --git a/tests/auxilary.test.ts b/tests/auxilary.test.ts index 49edf9d5..e5267df9 100644 --- a/tests/auxilary.test.ts +++ b/tests/auxilary.test.ts @@ -9,3 +9,8 @@ test('Env: production has jwt secret defined', async () => { process.env.NODE_ENV = 'production'; expect(getJwtSecret).toThrowError('JWT_SECRET is not defined'); }); + +test('Env: dev environment has jwt secret automatically set', async () => { + process.env.JWT_SECRET = ''; + expect(getJwtSecret()).toBe('dev'); +}); diff --git a/tests/helpers/env.ts b/tests/helpers/env.ts index 2854f705..e2ff1cc6 100644 --- a/tests/helpers/env.ts +++ b/tests/helpers/env.ts @@ -1,6 +1,6 @@ import { afterEach } from 'vitest'; -const originalEnv = process.env; +const originalEnv = {...process.env}; export function restoreEnvAfterEach() { afterEach(() => { process.env = { ...originalEnv }; From 044b16db28316e9f1183e04f5c0208d0847c1927 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:34:54 +0100 Subject: [PATCH 13/22] lint --- tests/helpers/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers/env.ts b/tests/helpers/env.ts index e2ff1cc6..4969828e 100644 --- a/tests/helpers/env.ts +++ b/tests/helpers/env.ts @@ -1,6 +1,6 @@ import { afterEach } from 'vitest'; -const originalEnv = {...process.env}; +const originalEnv = { ...process.env }; export function restoreEnvAfterEach() { afterEach(() => { process.env = { ...originalEnv }; From 017bb20e9dfbe4d4bb2aa3d616fb8aa9f03bcffd Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:00:48 +0100 Subject: [PATCH 14/22] minor --- src/modules/User/model.ts | 3 ++- vitest.full-coverage.config.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 vitest.full-coverage.config.ts diff --git a/src/modules/User/model.ts b/src/modules/User/model.ts index 0518b0be..d9a1113a 100644 --- a/src/modules/User/model.ts +++ b/src/modules/User/model.ts @@ -46,7 +46,7 @@ export function getUserCrud(prisma: PrismaClient) { if (!user) { throw new ApolloError('User not found', 'USER_NOT_FOUND'); } - const passwordValid = (await compare(password, user.password || '')) || false; + const passwordValid = await compare(password, user.password); if (!passwordValid) { throw new ApolloError('Invalid password', 'INVALID_PASSWORD'); } @@ -75,6 +75,7 @@ export function getUserCrud(prisma: PrismaClient) { if ('code' in e && e.code === 'P2002') { throw new ApolloError('Username already taken', 'USERNAME_TAKEN'); } + /* istanbul ignore next @preserve */ throw e; } return { diff --git a/vitest.full-coverage.config.ts b/vitest.full-coverage.config.ts new file mode 100644 index 00000000..3274809c --- /dev/null +++ b/vitest.full-coverage.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + coverage: { + provider: 'istanbul', + lines: 100, + functions: 100, + statements: 100, + include: [ + 'src/modules/**', + ] + }, + singleThread: true, + }, +}); From b9e3b95eda1f6fd5a4526e5b7ad96bc5cbef36ab Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:35:43 +0100 Subject: [PATCH 15/22] 2 test runs --- package.json | 2 +- vitest.config.ts | 29 +++++++++++++++++------------ vitest.full-coverage.config.ts | 20 ++++++-------------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 7b05f348..fdfae604 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "postinstall": "prisma generate", "lint": "eslint \"./**/*.{ts,tsx}\" --max-warnings=0", "typecheck": "tsc --noEmit", - "test": "vitest run --coverage" + "test": "vitest run --coverage --config ./vitest.full-coverage.config.ts && vitest run --coverage" }, "dependencies": { "@prisma/client": "^4.11.0", diff --git a/vitest.config.ts b/vitest.config.ts index b3a91de2..655485e3 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,14 +1,19 @@ -import { defineConfig } from 'vitest/config'; +import { defineConfig, UserConfigExport } from 'vitest/config'; -export default defineConfig({ - test: { - coverage: { - provider: 'istanbul', - lines: 90, - functions: 90, - statements: 90, - all: true, +export const getVitestConfig = (modulesWithFullCoverage?: string[]): UserConfigExport => { + const coverage = !!modulesWithFullCoverage && modulesWithFullCoverage.length !== 0 ? 100 : 90; + return { + test: { + coverage: { + provider: 'istanbul', + lines: coverage, + functions: coverage, + statements: coverage, + include: modulesWithFullCoverage || undefined, + }, + singleThread: true, }, - singleThread: true, - }, -}); + }; +}; + +export default defineConfig(getVitestConfig()); diff --git a/vitest.full-coverage.config.ts b/vitest.full-coverage.config.ts index 3274809c..1ad05573 100644 --- a/vitest.full-coverage.config.ts +++ b/vitest.full-coverage.config.ts @@ -1,16 +1,8 @@ import { defineConfig } from 'vitest/config'; +import { getVitestConfig } from './vitest.config'; -export default defineConfig({ - test: { - coverage: { - provider: 'istanbul', - lines: 100, - functions: 100, - statements: 100, - include: [ - 'src/modules/**', - ] - }, - singleThread: true, - }, -}); +const fullyCoveredModules = [ + 'src/modules/**', +]; + +export default defineConfig(getVitestConfig(fullyCoveredModules)); From bbf166b87e5094114b4450fb4f2f09c99351de24 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:42:49 +0100 Subject: [PATCH 16/22] rename variable --- vitest.config.ts | 6 +++--- vitest.full-coverage.config.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/vitest.config.ts b/vitest.config.ts index 655485e3..4424b4b1 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,7 +1,7 @@ import { defineConfig, UserConfigExport } from 'vitest/config'; -export const getVitestConfig = (modulesWithFullCoverage?: string[]): UserConfigExport => { - const coverage = !!modulesWithFullCoverage && modulesWithFullCoverage.length !== 0 ? 100 : 90; +export const getVitestConfig = (fullyCoveredModulePaths?: string[]): UserConfigExport => { + const coverage = !!fullyCoveredModulePaths && fullyCoveredModulePaths.length !== 0 ? 100 : 90; return { test: { coverage: { @@ -9,7 +9,7 @@ export const getVitestConfig = (modulesWithFullCoverage?: string[]): UserConfigE lines: coverage, functions: coverage, statements: coverage, - include: modulesWithFullCoverage || undefined, + include: fullyCoveredModulePaths || undefined, }, singleThread: true, }, diff --git a/vitest.full-coverage.config.ts b/vitest.full-coverage.config.ts index 1ad05573..3f0e3140 100644 --- a/vitest.full-coverage.config.ts +++ b/vitest.full-coverage.config.ts @@ -1,8 +1,8 @@ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from './vitest.config'; -const fullyCoveredModules = [ +const fullyCoveredModulePaths = [ 'src/modules/**', ]; -export default defineConfig(getVitestConfig(fullyCoveredModules)); +export default defineConfig(getVitestConfig(fullyCoveredModulePaths)); From 98eebd401279e7a23805be13bc632d6d1c0430d1 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:46:42 +0100 Subject: [PATCH 17/22] order of test runs --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fdfae604..f0428b4d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "postinstall": "prisma generate", "lint": "eslint \"./**/*.{ts,tsx}\" --max-warnings=0", "typecheck": "tsc --noEmit", - "test": "vitest run --coverage --config ./vitest.full-coverage.config.ts && vitest run --coverage" + "test": "vitest run --coverage && vitest run --coverage --config ./vitest.full-coverage.config.ts" }, "dependencies": { "@prisma/client": "^4.11.0", From 786e63df16f8f2379cb368d556bc56c856af7d0d Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:53:03 +0100 Subject: [PATCH 18/22] minor --- package.json | 2 +- vitest.config.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f0428b4d..305b2808 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "postinstall": "prisma generate", "lint": "eslint \"./**/*.{ts,tsx}\" --max-warnings=0", "typecheck": "tsc --noEmit", - "test": "vitest run --coverage && vitest run --coverage --config ./vitest.full-coverage.config.ts" + "test": "vitest run && vitest run --config ./vitest.full-coverage.config.ts" }, "dependencies": { "@prisma/client": "^4.11.0", diff --git a/vitest.config.ts b/vitest.config.ts index 4424b4b1..47de4bfd 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,10 +1,12 @@ import { defineConfig, UserConfigExport } from 'vitest/config'; export const getVitestConfig = (fullyCoveredModulePaths?: string[]): UserConfigExport => { - const coverage = !!fullyCoveredModulePaths && fullyCoveredModulePaths.length !== 0 ? 100 : 90; + const enableFullCoverage = !!fullyCoveredModulePaths && fullyCoveredModulePaths.length !== 0; + const coverage = enableFullCoverage ? 100 : 90; return { test: { coverage: { + enabled: !enableFullCoverage, provider: 'istanbul', lines: coverage, functions: coverage, From dc587c667eba31103d674c234afc0332daa2433d Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:58:14 +0100 Subject: [PATCH 19/22] print both tables --- vitest.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vitest.config.ts b/vitest.config.ts index 47de4bfd..0ff078db 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -6,7 +6,7 @@ export const getVitestConfig = (fullyCoveredModulePaths?: string[]): UserConfigE return { test: { coverage: { - enabled: !enableFullCoverage, + enabled: true, provider: 'istanbul', lines: coverage, functions: coverage, From 559142cde363d69d8332bb0932f3d8ab1ee20954 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 17:00:17 +0100 Subject: [PATCH 20/22] add watch mode --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 305b2808..fd092bc4 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "postinstall": "prisma generate", "lint": "eslint \"./**/*.{ts,tsx}\" --max-warnings=0", "typecheck": "tsc --noEmit", - "test": "vitest run && vitest run --config ./vitest.full-coverage.config.ts" + "test": "vitest run && vitest run --config ./vitest.full-coverage.config.ts", + "watch": "vitest watch" }, "dependencies": { "@prisma/client": "^4.11.0", From beddc41bb6b451ddd6dfc056410501df4aba3b95 Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 17:14:32 +0100 Subject: [PATCH 21/22] contribution record --- CONTRIBUTION.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 CONTRIBUTION.md diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md new file mode 100644 index 00000000..c63c1489 --- /dev/null +++ b/CONTRIBUTION.md @@ -0,0 +1,9 @@ +### Testing structure + +The test suite is designed to ensure that some of the modules are fully covered by tests. +Therefore, there're 2 runs of tests: one validates that overall code coverage is on appropriate level, another validates that the code coverage for +a subset of modules is maximal. + +The coverage report will therefore contain two tables. + +See corresponding convigs in `./vitest.config.ts` and `./vitest.full-coverage.config.ts` From 00edaee8e22563d854369624a80f224a171e0d2b Mon Sep 17 00:00:00 2001 From: KirillDogadin-std <59374892+KirillDogadin-std@users.noreply.github.com> Date: Thu, 23 Mar 2023 17:15:42 +0100 Subject: [PATCH 22/22] typo --- CONTRIBUTION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index c63c1489..715a9a2e 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -6,4 +6,4 @@ a subset of modules is maximal. The coverage report will therefore contain two tables. -See corresponding convigs in `./vitest.config.ts` and `./vitest.full-coverage.config.ts` +See corresponding configs in `./vitest.config.ts` and `./vitest.full-coverage.config.ts`