From 455a0ab754cc18eb315ac55fdc39b0ab93e05d16 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 09:49:15 +0100 Subject: [PATCH 01/12] add user interface and standard users --- backend/src/seeds/users/UserInterface.ts | 11 +++++++++++ backend/src/seeds/users/bibi-bloxberg.ts | 10 ++++++++++ backend/src/seeds/users/bob-baumeister.ts | 10 ++++++++++ backend/src/seeds/users/peter-lustig.ts | 12 ++++++++++++ backend/src/seeds/users/raeuber-hotzenplotz.ts | 10 ++++++++++ 5 files changed, 53 insertions(+) create mode 100644 backend/src/seeds/users/UserInterface.ts create mode 100644 backend/src/seeds/users/bibi-bloxberg.ts create mode 100644 backend/src/seeds/users/bob-baumeister.ts create mode 100644 backend/src/seeds/users/peter-lustig.ts create mode 100644 backend/src/seeds/users/raeuber-hotzenplotz.ts diff --git a/backend/src/seeds/users/UserInterface.ts b/backend/src/seeds/users/UserInterface.ts new file mode 100644 index 000000000..b2379c8d5 --- /dev/null +++ b/backend/src/seeds/users/UserInterface.ts @@ -0,0 +1,11 @@ +export interface UserInterface { + email?: string + firstName?: string + lastName?: string + // description?: string + createdAt?: Date + emailChecked?: boolean + language?: string + deletedAt?: Date + isAdmin?: boolean +} diff --git a/backend/src/seeds/users/bibi-bloxberg.ts b/backend/src/seeds/users/bibi-bloxberg.ts new file mode 100644 index 000000000..81364eb03 --- /dev/null +++ b/backend/src/seeds/users/bibi-bloxberg.ts @@ -0,0 +1,10 @@ +import { UserInterface } from './UserInterface' + +export const bibiBloxberg: UserInterface = { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + // description: 'Hex Hex', + emailChecked: true, + language: 'de', +} diff --git a/backend/src/seeds/users/bob-baumeister.ts b/backend/src/seeds/users/bob-baumeister.ts new file mode 100644 index 000000000..ac88611b8 --- /dev/null +++ b/backend/src/seeds/users/bob-baumeister.ts @@ -0,0 +1,10 @@ +import { UserInterface } from './UserInterface' + +export const bobBaumeister: UserInterface = { + email: 'bob@baumeister.de', + firstName: 'Bob', + lastName: 'der Baumeister', + // description: 'Können wir das schaffen? Ja, wir schaffen das!', + emailChecked: true, + language: 'de', +} diff --git a/backend/src/seeds/users/peter-lustig.ts b/backend/src/seeds/users/peter-lustig.ts new file mode 100644 index 000000000..0cdc67829 --- /dev/null +++ b/backend/src/seeds/users/peter-lustig.ts @@ -0,0 +1,12 @@ +import { UserInterface } from './UserInterface' + +export const peterLustig: UserInterface = { + email: 'peter@lustig.de', + firstName: 'Peter', + lastName: 'Lustig', + // description: 'Latzhose und Nickelbrille', + createdAt: new Date('2020-11-25T10:48:43'), + emailChecked: true, + language: 'de', + isAdmin: true, +} diff --git a/backend/src/seeds/users/raeuber-hotzenplotz.ts b/backend/src/seeds/users/raeuber-hotzenplotz.ts new file mode 100644 index 000000000..62601efff --- /dev/null +++ b/backend/src/seeds/users/raeuber-hotzenplotz.ts @@ -0,0 +1,10 @@ +import { UserInterface } from './UserInterface' + +export const raeuberHotzenplotz: UserInterface = { + email: 'raeuber@hotzenplotz.de', + firstName: 'Räuber', + lastName: 'Hotzenplotz', + // description: 'Pfefferpistole', + emailChecked: true, + language: 'de', +} From 69dddc9ea7386e889f8a2279610c615acecaad04 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 09:51:09 +0100 Subject: [PATCH 02/12] add stephen hawking as disabled user --- backend/src/seeds/users/stephen-hawking.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 backend/src/seeds/users/stephen-hawking.ts diff --git a/backend/src/seeds/users/stephen-hawking.ts b/backend/src/seeds/users/stephen-hawking.ts new file mode 100644 index 000000000..a683b7579 --- /dev/null +++ b/backend/src/seeds/users/stephen-hawking.ts @@ -0,0 +1,12 @@ +import { UserInterface } from './UserInterface' + +export const stephenHawking: UserInterface = { + email: 'stephen@hawking.uk', + firstName: 'Stephen', + lastName: 'Hawking', + // description: 'A Brief History of Time', + emailChecked: true, + createdAt: new Date('1942-01-08T09:17:52'), + deletedAt: new Date('2018-03-14T09:17:52'), + language: 'en', +} From 121d2b9853621eea9a72f9341c68eecf4c84075b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 09:58:58 +0100 Subject: [PATCH 03/12] exclude seeds folder from coverage --- backend/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/jest.config.js b/backend/jest.config.js index 41e464b8e..497b4b389 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -3,7 +3,7 @@ module.exports = { verbose: true, preset: 'ts-jest', collectCoverage: true, - collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**'], + collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**'], setupFiles: ['/test/testSetup.ts'], moduleNameMapper: { '@/(.*)': '/src/$1', From b30f4dfa5d692897ea30e27ef79299d75e769532 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 10:17:36 +0100 Subject: [PATCH 04/12] copy queries and mutations from frontend and use them --- .../src/graphql/resolver/UserResolver.test.ts | 76 ++++----- backend/src/seeds/graphql/enums.ts | 9 ++ backend/src/seeds/graphql/mutations.ts | 71 +++++++++ backend/src/seeds/graphql/queries.ts | 144 ++++++++++++++++++ backend/test/graphql.ts | 25 --- backend/test/helpers.ts | 8 +- 6 files changed, 256 insertions(+), 77 deletions(-) create mode 100644 backend/src/seeds/graphql/enums.ts create mode 100644 backend/src/seeds/graphql/mutations.ts create mode 100644 backend/src/seeds/graphql/queries.ts delete mode 100644 backend/test/graphql.ts diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 947636aa4..6bcbbfc74 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,9 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, createUser, headerPushMock, cleanDB, resetToken } from '@test/helpers' -import { createUserMutation, setPasswordMutation } from '@test/graphql' -import gql from 'graphql-tag' +import { + testEnvironment, + createConfirmedUser, + headerPushMock, + cleanDB, + resetToken, +} from '@test/helpers' +import { createUser, setPassword } from '@/seeds/graphql/mutations' +import { login, logout } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' @@ -11,8 +17,6 @@ import CONFIG from '@/config' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' // import { klicktippSignIn } from '@/apis/KlicktippController' -jest.setTimeout(1000000) - jest.mock('@/mailer/sendAccountActivationEmail', () => { return { __esModule: true, @@ -31,24 +35,6 @@ jest.mock('@/apis/KlicktippController', () => { let mutate: any, query: any, con: any -const loginQuery = gql` - query ($email: String!, $password: String!, $publisherId: Int) { - login(email: $email, password: $password, publisherId: $publisherId) { - email - firstName - lastName - language - coinanimation - klickTipp { - newsletterState - } - hasElopage - publisherId - isAdmin - } - } -` - beforeAll(async () => { const testEnv = await testEnvironment() mutate = testEnv.mutate @@ -77,7 +63,7 @@ describe('UserResolver', () => { beforeAll(async () => { jest.clearAllMocks() - result = await mutate({ mutation: createUserMutation, variables }) + result = await mutate({ mutation: createUser, variables }) }) afterAll(async () => { @@ -149,7 +135,7 @@ describe('UserResolver', () => { describe('email already exists', () => { it('throws an error', async () => { - await expect(mutate({ mutation: createUserMutation, variables })).resolves.toEqual( + await expect(mutate({ mutation: createUser, variables })).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('User already exists.')], }), @@ -160,7 +146,7 @@ describe('UserResolver', () => { describe('unknown language', () => { it('sets "de" as default language', async () => { await mutate({ - mutation: createUserMutation, + mutation: createUser, variables: { ...variables, email: 'bibi@bloxberg.de', language: 'es' }, }) await expect(User.find()).resolves.toEqual( @@ -177,7 +163,7 @@ describe('UserResolver', () => { describe('no publisher id', () => { it('sets publisher id to null', async () => { await mutate({ - mutation: createUserMutation, + mutation: createUser, variables: { ...variables, email: 'raeuber@hotzenplotz.de', publisherId: undefined }, }) await expect(User.find()).resolves.toEqual( @@ -208,11 +194,11 @@ describe('UserResolver', () => { let newUser: any beforeAll(async () => { - await mutate({ mutation: createUserMutation, variables: createUserVariables }) + await mutate({ mutation: createUser, variables: createUserVariables }) const loginEmailOptIn = await LoginEmailOptIn.find() emailOptIn = loginEmailOptIn[0].verificationCode.toString() result = await mutate({ - mutation: setPasswordMutation, + mutation: setPassword, variables: { code: emailOptIn, password: 'Aa12345_' }, }) newUser = await User.find() @@ -252,11 +238,11 @@ describe('UserResolver', () => { describe('no valid password', () => { beforeAll(async () => { - await mutate({ mutation: createUserMutation, variables: createUserVariables }) + await mutate({ mutation: createUser, variables: createUserVariables }) const loginEmailOptIn = await LoginEmailOptIn.find() emailOptIn = loginEmailOptIn[0].verificationCode.toString() result = await mutate({ - mutation: setPasswordMutation, + mutation: setPassword, variables: { code: emailOptIn, password: 'not-valid' }, }) }) @@ -280,9 +266,9 @@ describe('UserResolver', () => { describe('no valid optin code', () => { beforeAll(async () => { - await mutate({ mutation: createUserMutation, variables: createUserVariables }) + await mutate({ mutation: createUser, variables: createUserVariables }) result = await mutate({ - mutation: setPasswordMutation, + mutation: setPassword, variables: { code: 'not valid', password: 'Aa12345_' }, }) }) @@ -316,7 +302,7 @@ describe('UserResolver', () => { describe('no users in database', () => { beforeAll(async () => { - result = await query({ query: loginQuery, variables }) + result = await query({ query: login, variables }) }) it('throws an error', () => { @@ -330,14 +316,14 @@ describe('UserResolver', () => { describe('user is in database and correct login data', () => { beforeAll(async () => { - await createUser(mutate, { + await createConfirmedUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', lastName: 'Lustig', language: 'de', publisherId: 1234, }) - result = await query({ query: loginQuery, variables }) + result = await query({ query: login, variables }) }) afterAll(async () => { @@ -373,7 +359,7 @@ describe('UserResolver', () => { describe('user is in database and wrong password', () => { beforeAll(async () => { - await createUser(mutate, { + await createConfirmedUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', lastName: 'Lustig', @@ -388,7 +374,7 @@ describe('UserResolver', () => { it('returns an error', () => { expect( - query({ query: loginQuery, variables: { ...variables, password: 'wrong' } }), + query({ query: login, variables: { ...variables, password: 'wrong' } }), ).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('No user with this credentials')], @@ -399,16 +385,10 @@ describe('UserResolver', () => { }) describe('logout', () => { - const logoutQuery = gql` - query { - logout - } - ` - describe('unauthenticated', () => { it('throws an error', async () => { resetToken() - await expect(query({ query: logoutQuery })).resolves.toEqual( + await expect(query({ query: logout })).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('401 Unauthorized')], }), @@ -423,14 +403,14 @@ describe('UserResolver', () => { } beforeAll(async () => { - await createUser(mutate, { + await createConfirmedUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', lastName: 'Lustig', language: 'de', publisherId: 1234, }) - await query({ query: loginQuery, variables }) + await query({ query: login, variables }) }) afterAll(async () => { @@ -438,7 +418,7 @@ describe('UserResolver', () => { }) it('returns true', async () => { - await expect(query({ query: logoutQuery })).resolves.toEqual( + await expect(query({ query: logout })).resolves.toEqual( expect.objectContaining({ data: { logout: 'true' }, errors: undefined, diff --git a/backend/src/seeds/graphql/enums.ts b/backend/src/seeds/graphql/enums.ts new file mode 100644 index 000000000..6e40dd19c --- /dev/null +++ b/backend/src/seeds/graphql/enums.ts @@ -0,0 +1,9 @@ +export const GdtEntryType = { + FORM: 'FORM', + CVS: 'CVS', + ELOPAGE: 'ELOPAGE', + ELOPAGE_PUBLISHER: 'ELOPAGE_PUBLISHER', + DIGISTORE: 'DIGISTORE', + CVS2: 'CVS2', + GLOBAL_MODIFICATOR: 'GLOBAL_MODIFICATOR', +} diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts new file mode 100644 index 000000000..8f425cdec --- /dev/null +++ b/backend/src/seeds/graphql/mutations.ts @@ -0,0 +1,71 @@ +import gql from 'graphql-tag' + +export const subscribeNewsletter = gql` + mutation ($email: String!, $language: String!) { + subscribeNewsletter(email: $email, language: $language) + } +` + +export const unsubscribeNewsletter = gql` + mutation ($email: String!) { + unsubscribeNewsletter(email: $email) + } +` + +export const setPassword = gql` + mutation ($code: String!, $password: String!) { + setPassword(code: $code, password: $password) + } +` + +export const updateUserInfos = gql` + mutation ( + $firstName: String + $lastName: String + $password: String + $passwordNew: String + $locale: String + $coinanimation: Boolean + ) { + updateUserInfos( + firstName: $firstName + lastName: $lastName + password: $password + passwordNew: $passwordNew + language: $locale + coinanimation: $coinanimation + ) + } +` + +export const createUser = gql` + mutation ( + $firstName: String! + $lastName: String! + $email: String! + $language: String! + $publisherId: Int + ) { + createUser( + email: $email + firstName: $firstName + lastName: $lastName + language: $language + publisherId: $publisherId + ) + } +` + +export const sendCoins = gql` + mutation ($email: String!, $amount: Decimal!, $memo: String!) { + sendCoins(email: $email, amount: $amount, memo: $memo) + } +` + +export const createTransactionLink = gql` + mutation ($amount: Decimal!, $memo: String!) { + createTransactionLink(amount: $amount, memo: $memo) { + code + } + } +` diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts new file mode 100644 index 000000000..942258fde --- /dev/null +++ b/backend/src/seeds/graphql/queries.ts @@ -0,0 +1,144 @@ +import gql from 'graphql-tag' + +export const login = gql` + query ($email: String!, $password: String!, $publisherId: Int) { + login(email: $email, password: $password, publisherId: $publisherId) { + email + firstName + lastName + language + coinanimation + klickTipp { + newsletterState + } + hasElopage + publisherId + isAdmin + } + } +` + +export const verifyLogin = gql` + query { + verifyLogin { + email + firstName + lastName + language + coinanimation + klickTipp { + newsletterState + } + hasElopage + publisherId + isAdmin + } + } +` + +export const logout = gql` + query { + logout + } +` + +export const transactionsQuery = gql` + query ( + $currentPage: Int = 1 + $pageSize: Int = 25 + $order: Order = DESC + $onlyCreations: Boolean = false + ) { + transactionList( + currentPage: $currentPage + pageSize: $pageSize + order: $order + onlyCreations: $onlyCreations + ) { + balanceGDT + count + balance + decayStartBlock + transactions { + id + typeId + amount + balance + balanceDate + memo + linkedUser { + firstName + lastName + } + decay { + decay + start + end + duration + } + } + } + } +` + +export const sendResetPasswordEmail = gql` + query ($email: String!) { + sendResetPasswordEmail(email: $email) + } +` + +export const listGDTEntriesQuery = gql` + query ($currentPage: Int!, $pageSize: Int!) { + listGDTEntries(currentPage: $currentPage, pageSize: $pageSize) { + count + gdtEntries { + id + amount + date + comment + gdtEntryType + factor + gdt + } + gdtSum + } + } +` + +export const communityInfo = gql` + query { + getCommunityInfo { + name + description + registerUrl + url + } + } +` + +export const communities = gql` + query { + communities { + id + name + url + description + registerUrl + } + } +` + +export const queryTransactionLink = gql` + query ($code: String!) { + queryTransactionLink(code: $code) { + amount + memo + createdAt + validUntil + user { + firstName + publisherId + } + } + } +` diff --git a/backend/test/graphql.ts b/backend/test/graphql.ts deleted file mode 100644 index 89393876e..000000000 --- a/backend/test/graphql.ts +++ /dev/null @@ -1,25 +0,0 @@ -import gql from 'graphql-tag' - -export const createUserMutation = gql` - mutation ( - $email: String! - $firstName: String! - $lastName: String! - $language: String! - $publisherId: Int - ) { - createUser( - email: $email - firstName: $firstName - lastName: $lastName - language: $language - publisherId: $publisherId - ) - } -` - -export const setPasswordMutation = gql` - mutation ($code: String!, $password: String!) { - setPassword(code: $code, password: $password) - } -` diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index edb4eb3e4..95d1b3e59 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -4,7 +4,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../src/server/createServer' import { initialize } from '@dbTools/helpers' -import { createUserMutation, setPasswordMutation } from './graphql' +import { createUser, setPassword } from '@/seeds/graphql/mutations' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' import { entities } from '@entity/index' @@ -46,15 +46,15 @@ export const resetEntity = async (entity: any) => { } } -export const createUser = async (mutate: any, user: any) => { +export const createConfirmedUser = async (mutate: any, user: any) => { // resetToken() - await mutate({ mutation: createUserMutation, variables: user }) + await mutate({ mutation: createUser, variables: user }) const dbUser = await User.findOne({ where: { email: user.email } }) if (!dbUser) throw new Error('Ups, no user found') const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) if (!optin) throw new Error('Ups, no optin found') await mutate({ - mutation: setPasswordMutation, + mutation: setPassword, variables: { password: 'Aa12345_', code: optin.verificationCode }, }) } From 004627ddcf802152fe2a17cb746afd906e8d6da4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 10:23:24 +0100 Subject: [PATCH 05/12] create factory folder, move user creation in factory --- .../src/graphql/resolver/UserResolver.test.ts | 9 ++------- backend/src/seeds/factory/user.ts | 19 +++++++++++++++++++ backend/test/helpers.ts | 16 ---------------- 3 files changed, 21 insertions(+), 23 deletions(-) create mode 100644 backend/src/seeds/factory/user.ts diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 6bcbbfc74..d22ef5f99 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,13 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { - testEnvironment, - createConfirmedUser, - headerPushMock, - cleanDB, - resetToken, -} from '@test/helpers' +import { testEnvironment, headerPushMock, cleanDB, resetToken } from '@test/helpers' +import { createConfirmedUser } from '@/seeds/factory/user' import { createUser, setPassword } from '@/seeds/graphql/mutations' import { login, logout } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts new file mode 100644 index 000000000..e38cb9a2d --- /dev/null +++ b/backend/src/seeds/factory/user.ts @@ -0,0 +1,19 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ + +import { createUser, setPassword } from '@/seeds/graphql/mutations' +import { User } from '@entity/User' +import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' + +export const createConfirmedUser = async (mutate: any, user: any) => { + // resetToken() + await mutate({ mutation: createUser, variables: user }) + const dbUser = await User.findOne({ where: { email: user.email } }) + if (!dbUser) throw new Error('Ups, no user found') + const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) + if (!optin) throw new Error('Ups, no optin found') + await mutate({ + mutation: setPassword, + variables: { password: 'Aa12345_', code: optin.verificationCode }, + }) +} diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index 95d1b3e59..51610b07e 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -4,9 +4,6 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../src/server/createServer' import { initialize } from '@dbTools/helpers' -import { createUser, setPassword } from '@/seeds/graphql/mutations' -import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' -import { User } from '@entity/User' import { entities } from '@entity/index' export const headerPushMock = jest.fn((t) => { @@ -46,19 +43,6 @@ export const resetEntity = async (entity: any) => { } } -export const createConfirmedUser = async (mutate: any, user: any) => { - // resetToken() - await mutate({ mutation: createUser, variables: user }) - const dbUser = await User.findOne({ where: { email: user.email } }) - if (!dbUser) throw new Error('Ups, no user found') - const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) - if (!optin) throw new Error('Ups, no optin found') - await mutate({ - mutation: setPassword, - variables: { password: 'Aa12345_', code: optin.verificationCode }, - }) -} - export const resetToken = () => { context.token = '' } From 00c70311a1ff5023537efa5f96fb4ca654a621dc Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 11:19:19 +0100 Subject: [PATCH 06/12] use factory to create user in test, use bibi bloxberg as seeded user (no admin) --- .../src/graphql/resolver/UserResolver.test.ts | 37 +++++-------------- backend/src/seeds/factory/user.ts | 22 ++++++----- backend/src/seeds/users/UserInterface.ts | 1 + backend/src/seeds/users/bibi-bloxberg.ts | 1 + 4 files changed, 24 insertions(+), 37 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index d22ef5f99..1e43a60b2 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -2,7 +2,8 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { testEnvironment, headerPushMock, cleanDB, resetToken } from '@test/helpers' -import { createConfirmedUser } from '@/seeds/factory/user' +import { createUserFactory } from '@/seeds/factory/user' +import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { createUser, setPassword } from '@/seeds/graphql/mutations' import { login, logout } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' @@ -284,7 +285,7 @@ describe('UserResolver', () => { describe('login', () => { const variables = { - email: 'peter@lustig.de', + email: 'bibi@bloxberg.de', password: 'Aa12345_', publisherId: 1234, } @@ -311,13 +312,7 @@ describe('UserResolver', () => { describe('user is in database and correct login data', () => { beforeAll(async () => { - await createConfirmedUser(mutate, { - email: 'peter@lustig.de', - firstName: 'Peter', - lastName: 'Lustig', - language: 'de', - publisherId: 1234, - }) + await createUserFactory(mutate, bibiBloxberg) result = await query({ query: login, variables }) }) @@ -331,15 +326,15 @@ describe('UserResolver', () => { data: { login: { coinanimation: true, - email: 'peter@lustig.de', - firstName: 'Peter', + email: 'bibi@bloxberg.de', + firstName: 'Bibi', hasElopage: false, isAdmin: false, klickTipp: { newsletterState: false, }, language: 'de', - lastName: 'Lustig', + lastName: 'Bloxberg', publisherId: 1234, }, }, @@ -354,13 +349,7 @@ describe('UserResolver', () => { describe('user is in database and wrong password', () => { beforeAll(async () => { - await createConfirmedUser(mutate, { - email: 'peter@lustig.de', - firstName: 'Peter', - lastName: 'Lustig', - language: 'de', - publisherId: 1234, - }) + await createUserFactory(mutate, bibiBloxberg) }) afterAll(async () => { @@ -393,18 +382,12 @@ describe('UserResolver', () => { describe('authenticated', () => { const variables = { - email: 'peter@lustig.de', + email: 'bibi@bloxberg.de', password: 'Aa12345_', } beforeAll(async () => { - await createConfirmedUser(mutate, { - email: 'peter@lustig.de', - firstName: 'Peter', - lastName: 'Lustig', - language: 'de', - publisherId: 1234, - }) + await createUserFactory(mutate, bibiBloxberg) await query({ query: login, variables }) }) diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index e38cb9a2d..e46cb173c 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -4,16 +4,18 @@ import { createUser, setPassword } from '@/seeds/graphql/mutations' import { User } from '@entity/User' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' +import { UserInterface } from '@/seeds/users/UserInterface' -export const createConfirmedUser = async (mutate: any, user: any) => { - // resetToken() +export const createUserFactory = async (mutate: any, user: UserInterface): Promise => { await mutate({ mutation: createUser, variables: user }) - const dbUser = await User.findOne({ where: { email: user.email } }) - if (!dbUser) throw new Error('Ups, no user found') - const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) - if (!optin) throw new Error('Ups, no optin found') - await mutate({ - mutation: setPassword, - variables: { password: 'Aa12345_', code: optin.verificationCode }, - }) + if (user.emailChecked) { + const dbUser = await User.findOne({ where: { email: user.email } }) + if (!dbUser) throw new Error('Ups, no user found') + const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) + if (!optin) throw new Error('Ups, no optin found') + await mutate({ + mutation: setPassword, + variables: { password: 'Aa12345_', code: optin.verificationCode }, + }) + } } diff --git a/backend/src/seeds/users/UserInterface.ts b/backend/src/seeds/users/UserInterface.ts index b2379c8d5..08aa5d19d 100644 --- a/backend/src/seeds/users/UserInterface.ts +++ b/backend/src/seeds/users/UserInterface.ts @@ -7,5 +7,6 @@ export interface UserInterface { emailChecked?: boolean language?: string deletedAt?: Date + publisherId?: number isAdmin?: boolean } diff --git a/backend/src/seeds/users/bibi-bloxberg.ts b/backend/src/seeds/users/bibi-bloxberg.ts index 81364eb03..7c372848e 100644 --- a/backend/src/seeds/users/bibi-bloxberg.ts +++ b/backend/src/seeds/users/bibi-bloxberg.ts @@ -7,4 +7,5 @@ export const bibiBloxberg: UserInterface = { // description: 'Hex Hex', emailChecked: true, language: 'de', + publisherId: 1234, } From e45e5806274b8286b4c7db22f70f65b43eb14825 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 12:30:02 +0100 Subject: [PATCH 07/12] setup testClient for seeding --- backend/package.json | 3 +- .../src/graphql/resolver/UserResolver.test.ts | 2 +- backend/src/seeds/index.ts | 51 +++++++++++++++++++ backend/src/seeds/users/index.ts | 7 +++ 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 backend/src/seeds/index.ts create mode 100644 backend/src/seeds/users/index.ts diff --git a/backend/package.json b/backend/package.json index 79e5fd130..f1797dd61 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,7 +13,8 @@ "start": "node build/src/index.js", "dev": "nodemon -w src --ext ts --exec ts-node src/index.ts", "lint": "eslint --max-warnings=0 --ext .js,.ts .", - "test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles" + "test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles", + "seed": "TZ=UTC ts-node src/seeds/index.ts" }, "dependencies": { "@types/jest": "^27.0.2", diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 1e43a60b2..61625a8ae 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, headerPushMock, cleanDB, resetToken } from '@test/helpers' +import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { createUserFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { createUser, setPassword } from '@/seeds/graphql/mutations' diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts new file mode 100644 index 000000000..3bad52642 --- /dev/null +++ b/backend/src/seeds/index.ts @@ -0,0 +1,51 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ + +import createServer from '../server/createServer' +import { createTestClient } from 'apollo-server-testing' + +import { users } from './users/index' +import { createUserFactory } from './factory/user' +import { entities } from '@entity/index' + +const context = { + token: '', + setHeaders: { + push: (value: string): void => { + context.token = value + }, + // eslint-disable-next-line @typescript-eslint/no-empty-function + forEach: (): void => {}, + }, +} + +export const cleanDB = async () => { + // this only works as lond we do not have foreign key constraints + for (let i = 0; i < entities.length; i++) { + await resetEntity(entities[i]) + } +} + +const resetEntity = async (entity: any) => { + const items = await entity.find({ withDeleted: true }) + if (items.length > 0) { + const ids = items.map((i: any) => i.id) + await entity.delete(ids) + } +} + +const run = async () => { + const server = await createServer(context) + const testClient = createTestClient(server.apollo) + const { mutate } = testClient + const { con } = server + await cleanDB() + + for (let i = 0; i < users.length; i++) { + await createUserFactory(mutate, users[i]) + } + + await con.close() +} + +run() diff --git a/backend/src/seeds/users/index.ts b/backend/src/seeds/users/index.ts new file mode 100644 index 000000000..76e242f84 --- /dev/null +++ b/backend/src/seeds/users/index.ts @@ -0,0 +1,7 @@ +import { peterLustig } from './peter-lustig' +import { bibiBloxberg } from './bibi-bloxberg' +import { bobBaumeister } from './bob-baumeister' +import { raeuberHotzenplotz } from './raeuber-hotzenplotz' +import { stephenHawking } from './stephen-hawking' + +export const users = [peterLustig, bibiBloxberg, bobBaumeister, raeuberHotzenplotz, stephenHawking] From e23ad723d06bb5b5c4c96c29fe219aac79d37553 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 12:41:26 +0100 Subject: [PATCH 08/12] set global timeout ver high --- backend/test/testSetup.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/test/testSetup.ts b/backend/test/testSetup.ts index ed2c5cf49..d42836626 100644 --- a/backend/test/testSetup.ts +++ b/backend/test/testSetup.ts @@ -4,3 +4,4 @@ // eslint-disable-next-line @typescript-eslint/no-empty-function console.info = () => {} +jest.setTimeout(1000000) From d55caacf6b0908cd0cab2e774144eb69f977f215 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 14:57:27 +0100 Subject: [PATCH 09/12] seed peter lustig as admin --- backend/src/seeds/factory/user.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index e46cb173c..51c9050a2 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -4,13 +4,15 @@ import { createUser, setPassword } from '@/seeds/graphql/mutations' import { User } from '@entity/User' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' +import { ServerUser } from '@entity/ServerUser' import { UserInterface } from '@/seeds/users/UserInterface' export const createUserFactory = async (mutate: any, user: UserInterface): Promise => { await mutate({ mutation: createUser, variables: user }) + const dbUser = await User.findOne({ where: { email: user.email } }) + if (!dbUser) throw new Error('Ups, no user found') + if (user.emailChecked) { - const dbUser = await User.findOne({ where: { email: user.email } }) - if (!dbUser) throw new Error('Ups, no user found') const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) if (!optin) throw new Error('Ups, no optin found') await mutate({ @@ -18,4 +20,17 @@ export const createUserFactory = async (mutate: any, user: UserInterface): Promi variables: { password: 'Aa12345_', code: optin.verificationCode }, }) } + + if (user.isAdmin) { + const admin = new ServerUser() + admin.username = dbUser.firstName + admin.password = 'please_refactor' + admin.email = dbUser.email + admin.role = 'admin' + admin.activated = 1 + admin.lastLogin = new Date() + admin.created = dbUser.createdAt + admin.modified = dbUser.createdAt + admin.save() + } } From 764f1ee572ef78b79ec8e2eaa396b3009e7db8f4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 16:32:32 +0100 Subject: [PATCH 10/12] optional data set correctly --- backend/src/seeds/factory/user.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 51c9050a2..89bff6852 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -9,18 +9,25 @@ import { UserInterface } from '@/seeds/users/UserInterface' export const createUserFactory = async (mutate: any, user: UserInterface): Promise => { await mutate({ mutation: createUser, variables: user }) - const dbUser = await User.findOne({ where: { email: user.email } }) - if (!dbUser) throw new Error('Ups, no user found') + let dbUser = await User.findOneOrFail({ where: { email: user.email } }) if (user.emailChecked) { - const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) - if (!optin) throw new Error('Ups, no optin found') + const optin = await LoginEmailOptIn.findOneOrFail({ where: { userId: dbUser.id } }) await mutate({ mutation: setPassword, variables: { password: 'Aa12345_', code: optin.verificationCode }, }) } + // refetch data + dbUser = await User.findOneOrFail({ where: { email: user.email } }) + + if (user.createdAt || user.deletedAt) { + if (user.createdAt) dbUser.createdAt = user.createdAt + if (user.deletedAt) dbUser.deletedAt = user.deletedAt + await dbUser.save() + } + if (user.isAdmin) { const admin = new ServerUser() admin.username = dbUser.firstName @@ -31,6 +38,6 @@ export const createUserFactory = async (mutate: any, user: UserInterface): Promi admin.lastLogin = new Date() admin.created = dbUser.createdAt admin.modified = dbUser.createdAt - admin.save() + await admin.save() } } From 99c0ef1cf5d93de39f777977c8c9831b711f7f2a Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 17:05:55 +0100 Subject: [PATCH 11/12] add faker, seed 100 random users --- backend/package.json | 3 ++- backend/src/seeds/index.ts | 13 +++++++++++++ backend/src/seeds/users/garrick-ollivander.ts | 12 ++++++++++++ backend/src/seeds/users/index.ts | 10 +++++++++- backend/yarn.lock | 10 ++++++++++ 5 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 backend/src/seeds/users/garrick-ollivander.ts diff --git a/backend/package.json b/backend/package.json index f1797dd61..c4ec42298 100644 --- a/backend/package.json +++ b/backend/package.json @@ -42,7 +42,7 @@ "type-graphql": "^1.1.1" }, "devDependencies": { - "@types/express": "^4.17.12", + "@types/faker": "^5.5.9", "@types/jsonwebtoken": "^8.5.2", "@types/node": "^16.10.3", "@types/nodemailer": "^6.4.4", @@ -55,6 +55,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-promise": "^5.1.0", + "faker": "^5.5.3", "nodemon": "^2.0.7", "prettier": "^2.3.1", "ts-node": "^10.0.0", diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index 3bad52642..b68bcbdd9 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -4,6 +4,8 @@ import createServer from '../server/createServer' import { createTestClient } from 'apollo-server-testing' +import { name, internet, random } from 'faker' + import { users } from './users/index' import { createUserFactory } from './factory/user' import { entities } from '@entity/index' @@ -41,10 +43,21 @@ const run = async () => { const { con } = server await cleanDB() + // seed the standard users for (let i = 0; i < users.length; i++) { await createUserFactory(mutate, users[i]) } + // seed 100 random users + for (let i = 0; i < 100; i++) { + await createUserFactory(mutate, { + firstName: name.firstName(), + lastName: name.lastName(), + email: internet.email(), + language: random.boolean() ? 'en' : 'de', + }) + } + await con.close() } diff --git a/backend/src/seeds/users/garrick-ollivander.ts b/backend/src/seeds/users/garrick-ollivander.ts new file mode 100644 index 000000000..264a866bd --- /dev/null +++ b/backend/src/seeds/users/garrick-ollivander.ts @@ -0,0 +1,12 @@ +import { UserInterface } from './UserInterface' + +export const garrickOllivander: UserInterface = { + email: 'garrick@ollivander.com', + firstName: 'Garrick', + lastName: 'Ollivander', + // description: `Curious ... curious ... + // Renowned wandmaker Mr Ollivander owns the wand shop Ollivanders: Makers of Fine Wands Since 382 BC in Diagon Alley. His shop is widely considered the best place to purchase a wand.`, + createdAt: new Date('2022-01-10T10:23:17'), + emailChecked: false, + language: 'en', +} diff --git a/backend/src/seeds/users/index.ts b/backend/src/seeds/users/index.ts index 76e242f84..7a6dbe519 100644 --- a/backend/src/seeds/users/index.ts +++ b/backend/src/seeds/users/index.ts @@ -3,5 +3,13 @@ import { bibiBloxberg } from './bibi-bloxberg' import { bobBaumeister } from './bob-baumeister' import { raeuberHotzenplotz } from './raeuber-hotzenplotz' import { stephenHawking } from './stephen-hawking' +import { garrickOllivander } from './garrick-ollivander' -export const users = [peterLustig, bibiBloxberg, bobBaumeister, raeuberHotzenplotz, stephenHawking] +export const users = [ + peterLustig, + bibiBloxberg, + bobBaumeister, + raeuberHotzenplotz, + stephenHawking, + garrickOllivander, +] diff --git a/backend/yarn.lock b/backend/yarn.lock index 330a6d590..ee6b2d679 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -811,6 +811,11 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/faker@^5.5.9": + version "5.5.9" + resolved "https://registry.yarnpkg.com/@types/faker/-/faker-5.5.9.tgz#588ede92186dc557bff8341d294335d50d255f0c" + integrity sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA== + "@types/fs-capacitor@*": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e" @@ -2510,6 +2515,11 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" +faker@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" + integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" From c7e3d3d2248b549875fa794e2e5f8f062395a958 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 15 Mar 2022 17:08:41 +0100 Subject: [PATCH 12/12] fix package json --- backend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/package.json b/backend/package.json index c4ec42298..8ef168454 100644 --- a/backend/package.json +++ b/backend/package.json @@ -42,6 +42,7 @@ "type-graphql": "^1.1.1" }, "devDependencies": { + "@types/express": "^4.17.12", "@types/faker": "^5.5.9", "@types/jsonwebtoken": "^8.5.2", "@types/node": "^16.10.3",