diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9c7f9b7c2..c1e363b52 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -431,7 +431,7 @@ jobs: unit_test_backend: name: Unit tests - Backend runs-on: ubuntu-latest - needs: [build_test_backend,build_test_mariadb] + needs: [build_test_mariadb] steps: ########################################################################## # CHECKOUT CODE ########################################################## @@ -448,13 +448,6 @@ jobs: path: /tmp - name: Load Docker Image run: docker load < /tmp/mariadb.tar - - name: Download Docker Image (Backend) - uses: actions/download-artifact@v2 - with: - name: docker-backend-test - path: /tmp - - name: Load Docker Image - run: docker load < /tmp/backend.tar ########################################################################## # UNIT TESTS BACKEND ##################################################### ########################################################################## @@ -469,7 +462,7 @@ jobs: run: sleep 30s shell: bash - name: backend Unit tests | test - run: cd database && yarn && yarn build && cd ../backend && yarn && yarn CI_workflow_test + run: cd database && yarn && yarn build && cd ../backend && yarn && yarn test # run: docker-compose -f docker-compose.yml -f docker-compose.test.yml exec -T backend yarn test ########################################################################## # COVERAGE CHECK BACKEND ################################################# @@ -480,7 +473,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 38 + min_coverage: 48 token: ${{ github.token }} ########################################################################## diff --git a/backend/jest.config.js b/backend/jest.config.js index 75b674cb1..0e4643c63 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -1,21 +1,18 @@ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ -module.exports = async () => { - process.env.TZ = 'UTC' - return { - verbose: true, - preset: 'ts-jest', - collectCoverage: true, - collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**'], - moduleNameMapper: { - '@entity/(.*)': '/../database/build/entity/$1', - // This is hack to fix a problem with the library `ts-mysql-migrate` which does differentiate between its ts/js state - '@dbTools/(.*)': '/../database/src/$1', - /* - '@dbTools/(.*)': - process.env.NODE_ENV === 'development' - ? '/../database/src/$1' - : '/../database/build/src/$1', - */ - }, - } +module.exports = { + verbose: true, + preset: 'ts-jest', + collectCoverage: true, + collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**'], + setupFiles: ['/test/testSetup.ts'], + moduleNameMapper: { + '@entity/(.*)': + process.env.NODE_ENV === 'development' + ? '/../database/entity/$1' + : '/../database/build/entity/$1', + '@dbTools/(.*)': + process.env.NODE_ENV === 'development' + ? '/../database/src/$1' + : '/../database/build/src/$1', + }, } diff --git a/backend/package.json b/backend/package.json index 7f4cfc239..93a954d3f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,8 +13,7 @@ "start": "node build/index.js", "dev": "nodemon -w src --ext ts --exec ts-node src/index.ts", "lint": "eslint . --ext .js,.ts", - "CI_workflow_test": "jest --runInBand --coverage ", - "test": "NODE_ENV=development jest --runInBand --coverage " + "test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles" }, "dependencies": { "@types/jest": "^27.0.2", diff --git a/backend/src/graphql/resolver/UserResolver.test.ts.disabled b/backend/src/graphql/resolver/UserResolver.test.ts similarity index 70% rename from backend/src/graphql/resolver/UserResolver.test.ts.disabled rename to backend/src/graphql/resolver/UserResolver.test.ts index 02e490edd..b01c99552 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts.disabled +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -6,14 +6,13 @@ import gql from 'graphql-tag' import { GraphQLError } from 'graphql' import createServer from '../../server/createServer' import { resetDB, initialize } from '@dbTools/helpers' -import { getRepository } from 'typeorm' -import { LoginUser } from '@entity/LoginUser' -import { LoginUserBackup } from '@entity/LoginUserBackup' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' import CONFIG from '../../config' import { sendAccountActivationEmail } from '../../mailer/sendAccountActivationEmail' -import { klicktippSignIn } from '../../apis/KlicktippController' +// import { klicktippSignIn } from '../../apis/KlicktippController' + +jest.setTimeout(10000) jest.mock('../../mailer/sendAccountActivationEmail', () => { return { @@ -22,12 +21,14 @@ jest.mock('../../mailer/sendAccountActivationEmail', () => { } }) +/* jest.mock('../../apis/KlicktippController', () => { return { __esModule: true, klicktippSignIn: jest.fn(), } }) +*/ let mutate: any let con: any @@ -40,6 +41,11 @@ beforeAll(async () => { await resetDB() }) +afterAll(async () => { + await resetDB(true) + await con.close() +}) + describe('UserResolver', () => { describe('createUser', () => { const variables = { @@ -84,70 +90,32 @@ describe('UserResolver', () => { }) describe('valid input data', () => { - let loginUser: LoginUser[] let user: User[] - let loginUserBackup: LoginUserBackup[] let loginEmailOptIn: LoginEmailOptIn[] beforeAll(async () => { - loginUser = await getRepository(LoginUser).createQueryBuilder('login_user').getMany() - user = await getRepository(User).createQueryBuilder('state_user').getMany() - loginUserBackup = await getRepository(LoginUserBackup) - .createQueryBuilder('login_user_backup') - .getMany() - loginEmailOptIn = await getRepository(LoginEmailOptIn) - .createQueryBuilder('login_email_optin') - .getMany() + user = await User.find() + loginEmailOptIn = await LoginEmailOptIn.find() emailOptIn = loginEmailOptIn[0].verificationCode.toString() }) describe('filling all tables', () => { it('saves the user in login_user table', () => { - expect(loginUser).toEqual([ + expect(user).toEqual([ { id: expect.any(Number), email: 'peter@lustig.de', firstName: 'Peter', lastName: 'Lustig', - username: '', - description: '', password: '0', pubKey: null, privKey: null, emailHash: expect.any(Buffer), createdAt: expect.any(Date), emailChecked: false, - passphraseShown: false, - language: 'de', - disabled: false, - groupId: 1, - publisherId: 1234, - }, - ]) - }) - - it('saves the user in state_user table', () => { - expect(user).toEqual([ - { - id: expect.any(Number), - indexId: 0, - groupId: 0, - pubkey: expect.any(Buffer), - email: 'peter@lustig.de', - firstName: 'Peter', - lastName: 'Lustig', - username: '', - disabled: false, - }, - ]) - }) - - it('saves the user in login_user_backup table', () => { - expect(loginUserBackup).toEqual([ - { - id: expect.any(Number), passphrase: expect.any(String), - userId: loginUser[0].id, - mnemonicType: 2, + language: 'de', + deletedAt: null, + publisherId: 1234, }, ]) }) @@ -156,7 +124,7 @@ describe('UserResolver', () => { expect(loginEmailOptIn).toEqual([ { id: expect.any(Number), - userId: loginUser[0].id, + userId: user[0].id, verificationCode: expect.any(String), emailOptInTypeId: 1, createdAt: expect.any(Date), @@ -196,9 +164,7 @@ describe('UserResolver', () => { mutation, variables: { ...variables, email: 'bibi@bloxberg.de', language: 'es' }, }) - await expect( - getRepository(LoginUser).createQueryBuilder('login_user').getMany(), - ).resolves.toEqual( + await expect(User.find()).resolves.toEqual( expect.arrayContaining([ expect.objectContaining({ email: 'bibi@bloxberg.de', @@ -215,9 +181,7 @@ describe('UserResolver', () => { mutation, variables: { ...variables, email: 'raeuber@hotzenplotz.de', publisherId: undefined }, }) - await expect( - getRepository(LoginUser).createQueryBuilder('login_user').getMany(), - ).resolves.toEqual( + await expect(User.find()).resolves.toEqual( expect.arrayContaining([ expect.objectContaining({ email: 'raeuber@hotzenplotz.de', @@ -265,23 +229,17 @@ describe('UserResolver', () => { let emailOptIn: string describe('valid optin code and valid password', () => { - let loginUser: any - let newLoginUser: any let newUser: any beforeAll(async () => { await mutate({ mutation: createUserMutation, variables: createUserVariables }) - const loginEmailOptIn = await getRepository(LoginEmailOptIn) - .createQueryBuilder('login_email_optin') - .getMany() - loginUser = await getRepository(LoginUser).createQueryBuilder('login_user').getMany() + const loginEmailOptIn = await LoginEmailOptIn.find() emailOptIn = loginEmailOptIn[0].verificationCode.toString() result = await mutate({ mutation: setPasswordMutation, variables: { code: emailOptIn, password: 'Aa12345_' }, }) - newLoginUser = await getRepository(LoginUser).createQueryBuilder('login_user').getMany() - newUser = await getRepository(User).createQueryBuilder('state_user').getMany() + newUser = await User.find() }) afterAll(async () => { @@ -289,38 +247,27 @@ describe('UserResolver', () => { }) it('sets email checked to true', () => { - expect(newLoginUser[0].emailChecked).toBeTruthy() + expect(newUser[0].emailChecked).toBeTruthy() }) it('updates the password', () => { - expect(newLoginUser[0].password).toEqual('3917921995996627700') - }) - - it('updates the public Key on both user tables', () => { - expect(newLoginUser[0].pubKey).toEqual(expect.any(Buffer)) - expect(newLoginUser[0].pubKey).not.toEqual(loginUser[0].pubKey) - expect(newLoginUser[0].pubKey).toEqual(newUser[0].pubkey) - }) - - it('updates the private Key', () => { - expect(newLoginUser[0].privKey).toEqual(expect.any(Buffer)) - expect(newLoginUser[0].privKey).not.toEqual(loginUser[0].privKey) + expect(newUser[0].password).toEqual('3917921995996627700') }) it('removes the optin', async () => { - await expect( - getRepository(LoginEmailOptIn).createQueryBuilder('login_email_optin').getMany(), - ).resolves.toHaveLength(0) + await expect(LoginEmailOptIn.find()).resolves.toHaveLength(0) }) + /* it('calls the klicktipp API', () => { expect(klicktippSignIn).toBeCalledWith( - loginUser[0].email, - loginUser[0].language, - loginUser[0].firstName, - loginUser[0].lastName, + user[0].email, + user[0].language, + user[0].firstName, + user[0].lastName, ) }) + */ it('returns true', () => { expect(result).toBeTruthy() @@ -330,9 +277,7 @@ describe('UserResolver', () => { describe('no valid password', () => { beforeAll(async () => { await mutate({ mutation: createUserMutation, variables: createUserVariables }) - const loginEmailOptIn = await getRepository(LoginEmailOptIn) - .createQueryBuilder('login_email_optin') - .getMany() + const loginEmailOptIn = await LoginEmailOptIn.find() emailOptIn = loginEmailOptIn[0].verificationCode.toString() result = await mutate({ mutation: setPasswordMutation, @@ -380,8 +325,3 @@ describe('UserResolver', () => { }) }) }) - -afterAll(async () => { - await resetDB(true) - await con.close() -}) diff --git a/backend/src/server/plugins.ts b/backend/src/server/plugins.ts index 049f63a08..a407135ea 100644 --- a/backend/src/server/plugins.ts +++ b/backend/src/server/plugins.ts @@ -4,40 +4,42 @@ import { ApolloLogPlugin, LogMutateData } from 'apollo-log' import cloneDeep from 'lodash.clonedeep' -const plugins = [ - { - requestDidStart() { - return { - willSendResponse(requestContext: any) { - const { setHeaders = [] } = requestContext.context - setHeaders.forEach(({ key, value }: { [key: string]: string }) => { - if (requestContext.response.http.headers.get(key)) { - requestContext.response.http.headers.set(key, value) - } else { - requestContext.response.http.headers.append(key, value) - } - }) - return requestContext - }, - } - }, +const setHeadersPlugin = { + requestDidStart() { + return { + willSendResponse(requestContext: any) { + const { setHeaders = [] } = requestContext.context + setHeaders.forEach(({ key, value }: { [key: string]: string }) => { + if (requestContext.response.http.headers.get(key)) { + requestContext.response.http.headers.set(key, value) + } else { + requestContext.response.http.headers.append(key, value) + } + }) + return requestContext + }, + } }, - ApolloLogPlugin({ - mutate: (data: LogMutateData) => { - // We need to deep clone the object in order to not modify the actual request - const dataCopy = cloneDeep(data) +} - // mask password if part of the query - if (dataCopy.context.request.variables && dataCopy.context.request.variables.password) { - dataCopy.context.request.variables.password = '***' - } +const apolloLogPlugin = ApolloLogPlugin({ + mutate: (data: LogMutateData) => { + // We need to deep clone the object in order to not modify the actual request + const dataCopy = cloneDeep(data) - // mask token at all times - dataCopy.context.context.token = '***' + // mask password if part of the query + if (dataCopy.context.request.variables && dataCopy.context.request.variables.password) { + dataCopy.context.request.variables.password = '***' + } - return dataCopy - }, - }), -] + // mask token at all times + dataCopy.context.context.token = '***' + + return dataCopy + }, +}) + +const plugins = + process.env.NODE_ENV === 'development' ? [setHeadersPlugin] : [setHeadersPlugin, apolloLogPlugin] export default plugins diff --git a/backend/test/testSetup.ts b/backend/test/testSetup.ts new file mode 100644 index 000000000..ed2c5cf49 --- /dev/null +++ b/backend/test/testSetup.ts @@ -0,0 +1,6 @@ +/* eslint-disable no-console */ + +// disable console.info for apollo log + +// eslint-disable-next-line @typescript-eslint/no-empty-function +console.info = () => {} diff --git a/database/migrations/0012-login_user_backups_unify_wordlist.ts b/database/migrations/0012-login_user_backups_unify_wordlist.ts index a59a8da7f..0c04693ec 100644 --- a/database/migrations/0012-login_user_backups_unify_wordlist.ts +++ b/database/migrations/0012-login_user_backups_unify_wordlist.ts @@ -5,19 +5,20 @@ * This also removes the trailing space */ import fs from 'fs' +import path from 'path' const TARGET_MNEMONIC_TYPE = 2 const PHRASE_WORD_COUNT = 24 const WORDS_MNEMONIC_0 = fs - .readFileSync('src/config/mnemonic.uncompressed_buffer18112.txt') + .readFileSync(path.resolve(__dirname, '../src/config/mnemonic.uncompressed_buffer18112.txt')) .toString() .split(',') const WORDS_MNEMONIC_1 = fs - .readFileSync('src/config/mnemonic.uncompressed_buffer18113.txt') + .readFileSync(path.resolve(__dirname, '../src/config/mnemonic.uncompressed_buffer18113.txt')) .toString() .split(',') const WORDS_MNEMONIC_2 = fs - .readFileSync('src/config/mnemonic.uncompressed_buffer13116.txt') + .readFileSync(path.resolve(__dirname, '../src/config/mnemonic.uncompressed_buffer13116.txt')) .toString() .split(',') const WORDS_MNEMONIC = [WORDS_MNEMONIC_0, WORDS_MNEMONIC_1, WORDS_MNEMONIC_2] diff --git a/database/package.json b/database/package.json index 964bb07c7..d3bda1bc4 100644 --- a/database/package.json +++ b/database/package.json @@ -8,7 +8,7 @@ "license": "MIT", "private": false, "scripts": { - "build": "tsc --build", + "build": "mkdir -p build/src/config/ && cp src/config/*.txt build/src/config/ && tsc --build", "clean": "tsc --build --clean", "up": "node build/src/index.js up", "down": "node build/src/index.js down",