Merge branch 'master' into fix_database_version

This commit is contained in:
Moriz Wahl 2022-04-25 16:40:07 +02:00 committed by GitHub
commit 1f19b3e4de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 377 additions and 22 deletions

View File

@ -528,7 +528,7 @@ jobs:
report_name: Coverage Backend
type: lcov
result_path: ./backend/coverage/lcov.info
min_coverage: 55
min_coverage: 58
token: ${{ github.token }}
##########################################################################

View File

@ -1,17 +1,18 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers'
import { testEnvironment, headerPushMock, resetToken, cleanDB, resetEntity } from '@test/helpers'
import { userFactory } 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 { createUser, setPassword, forgotPassword, updateUserInfos } from '@/seeds/graphql/mutations'
import { login, logout, verifyLogin, queryOptIn } from '@/seeds/graphql/queries'
import { GraphQLError } from 'graphql'
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
import { User } from '@entity/User'
import CONFIG from '@/config'
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
import { printTimeDuration } from './UserResolver'
import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail'
import { printTimeDuration, activationLink } from './UserResolver'
// import { klicktippSignIn } from '@/apis/KlicktippController'
@ -22,6 +23,13 @@ jest.mock('@/mailer/sendAccountActivationEmail', () => {
}
})
jest.mock('@/mailer/sendResetPasswordEmail', () => {
return {
__esModule: true,
sendResetPasswordEmail: jest.fn(),
}
})
/*
jest.mock('@/apis/KlicktippController', () => {
return {
@ -85,7 +93,7 @@ describe('UserResolver', () => {
})
describe('filling all tables', () => {
it('saves the user in login_user table', () => {
it('saves the user in users table', () => {
expect(user).toEqual([
{
id: expect.any(Number),
@ -413,6 +421,356 @@ describe('UserResolver', () => {
})
})
})
describe('verifyLogin', () => {
describe('unauthenticated', () => {
it('throws an error', async () => {
resetToken()
await expect(query({ query: verifyLogin })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('user exists but is not logged in', () => {
beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg)
})
afterAll(async () => {
await cleanDB()
})
it('throws an error', async () => {
resetToken()
await expect(query({ query: verifyLogin })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
describe('authenticated', () => {
const variables = {
email: 'bibi@bloxberg.de',
password: 'Aa12345_',
}
beforeAll(async () => {
await query({ query: login, variables })
})
afterAll(() => {
resetToken()
})
it('returns user object', async () => {
await expect(query({ query: verifyLogin })).resolves.toEqual(
expect.objectContaining({
data: {
verifyLogin: {
email: 'bibi@bloxberg.de',
firstName: 'Bibi',
lastName: 'Bloxberg',
language: 'de',
coinanimation: true,
klickTipp: {
newsletterState: false,
},
hasElopage: false,
publisherId: 1234,
isAdmin: null,
},
},
}),
)
})
})
})
})
describe('forgotPassword', () => {
const variables = { email: 'bibi@bloxberg.de' }
describe('user is not in DB', () => {
it('returns true', async () => {
await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual(
expect.objectContaining({
data: {
forgotPassword: true,
},
}),
)
})
})
describe('user exists in DB', () => {
let result: any
let loginEmailOptIn: LoginEmailOptIn[]
beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg)
await resetEntity(LoginEmailOptIn)
result = await mutate({ mutation: forgotPassword, variables })
loginEmailOptIn = await LoginEmailOptIn.find()
})
afterAll(async () => {
await cleanDB()
})
it('returns true', async () => {
await expect(result).toEqual(
expect.objectContaining({
data: {
forgotPassword: true,
},
}),
)
})
it('sends reset password email', () => {
expect(sendResetPasswordEmail).toBeCalledWith({
link: activationLink(loginEmailOptIn[0]),
firstName: 'Bibi',
lastName: 'Bloxberg',
email: 'bibi@bloxberg.de',
duration: expect.any(String),
})
})
describe('request reset password again', () => {
it('thows an error', async () => {
await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('email already sent less than 10 minutes minutes ago')],
}),
)
})
})
})
})
describe('queryOptIn', () => {
let loginEmailOptIn: LoginEmailOptIn[]
beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg)
loginEmailOptIn = await LoginEmailOptIn.find()
})
afterAll(async () => {
await cleanDB()
})
describe('wrong optin code', () => {
it('throws an error', async () => {
await expect(
query({ query: queryOptIn, variables: { optIn: 'not-valid' } }),
).resolves.toEqual(
expect.objectContaining({
errors: [
// keep Whitspace in error message!
new GraphQLError(`Could not find any entity of type "LoginEmailOptIn" matching: {
"verificationCode": "not-valid"
}`),
],
}),
)
})
})
describe('correct optin code', () => {
it('returns true', async () => {
await expect(
query({
query: queryOptIn,
variables: { optIn: loginEmailOptIn[0].verificationCode.toString() },
}),
).resolves.toEqual(
expect.objectContaining({
data: {
queryOptIn: true,
},
}),
)
})
})
})
describe('updateUserInfos', () => {
describe('unauthenticated', () => {
it('throws an error', async () => {
resetToken()
await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('authenticated', () => {
beforeAll(async () => {
await userFactory(testEnv, bibiBloxberg)
await query({
query: login,
variables: {
email: 'bibi@bloxberg.de',
password: 'Aa12345_',
},
})
})
afterAll(async () => {
await cleanDB()
})
it('returns true', async () => {
await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual(
expect.objectContaining({
data: {
updateUserInfos: true,
},
}),
)
})
describe('first-name, last-name and language', () => {
it('updates the fields in DB', async () => {
await mutate({
mutation: updateUserInfos,
variables: {
firstName: 'Benjamin',
lastName: 'Blümchen',
locale: 'en',
},
})
await expect(User.findOne()).resolves.toEqual(
expect.objectContaining({
firstName: 'Benjamin',
lastName: 'Blümchen',
language: 'en',
}),
)
})
})
describe('language is not valid', () => {
it('thows an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
locale: 'not-valid',
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError(`"not-valid" isn't a valid language`)],
}),
)
})
})
describe('password', () => {
describe('wrong old password', () => {
it('throws an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
password: 'wrong password',
passwordNew: 'Aa12345_',
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Old password is invalid')],
}),
)
})
})
describe('invalid new password', () => {
it('throws an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
password: 'Aa12345_',
passwordNew: 'Aa12345',
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!',
),
],
}),
)
})
})
describe('correct old and new password', () => {
it('returns true', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
password: 'Aa12345_',
passwordNew: 'Bb12345_',
},
}),
).resolves.toEqual(
expect.objectContaining({
data: { updateUserInfos: true },
}),
)
})
it('can login wtih new password', async () => {
await expect(
query({
query: login,
variables: {
email: 'bibi@bloxberg.de',
password: 'Bb12345_',
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
login: expect.objectContaining({
email: 'bibi@bloxberg.de',
}),
},
}),
)
})
it('cannot login wtih old password', async () => {
await expect(
query({
query: login,
variables: {
email: 'bibi@bloxberg.de',
password: 'Aa12345_',
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('No user with this credentials')],
}),
)
})
})
})
})
})
})
describe('printTimeDuration', () => {

View File

@ -245,8 +245,6 @@ export class UserResolver {
user.hasElopage = await this.hasElopage({ ...context, user: dbUser })
if (!user.hasElopage && publisherId) {
user.publisherId = publisherId
// TODO: Check if we can use updateUserInfos
// await this.updateUserInfos({ publisherId }, { pubKey: loginUser.pubKey })
dbUser.publisherId = publisherId
DbUser.save(dbUser)
}
@ -519,15 +517,7 @@ export class UserResolver {
@Mutation(() => Boolean)
async updateUserInfos(
@Args()
{
firstName,
lastName,
language,
publisherId,
password,
passwordNew,
coinanimation,
}: UpdateUserInfosArgs,
{ firstName, lastName, language, password, passwordNew, coinanimation }: UpdateUserInfosArgs,
@Ctx() context: Context,
): Promise<boolean> {
const userEntity = getUser(context)
@ -571,11 +561,6 @@ export class UserResolver {
userEntity.privKey = encryptedPrivkey
}
// Save publisherId only if Elopage is not yet registered
if (publisherId && !(await this.hasElopage(context))) {
userEntity.publisherId = publisherId
}
const queryRunner = getConnection().createQueryRunner()
await queryRunner.connect()
await queryRunner.startTransaction('READ UNCOMMITTED')

View File

@ -18,6 +18,12 @@ export const setPassword = gql`
}
`
export const forgotPassword = gql`
mutation ($email: String!) {
forgotPassword(email: $email)
}
`
export const updateUserInfos = gql`
mutation (
$firstName: String

View File

@ -43,6 +43,12 @@ export const logout = gql`
}
`
export const queryOptIn = gql`
query ($optIn: String!) {
queryOptIn(optIn: $optIn)
}
`
export const transactionsQuery = gql`
query (
$currentPage: Int = 1