emails spec with correct context, clean up

This commit is contained in:
Moriz Wahl 2025-06-26 17:54:19 +02:00
parent 78238606d9
commit 33b06f61c5
4 changed files with 70 additions and 50 deletions

View File

@ -165,7 +165,7 @@ describe('Badges', () => {
errors: [
{
message:
'Error: Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
'UserInputError: Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
},
],
})
@ -184,7 +184,7 @@ describe('Badges', () => {
errors: [
{
message:
'Error: Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
'UserInputError: Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
},
],
})
@ -203,7 +203,7 @@ describe('Badges', () => {
errors: [
{
message:
'Error: Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
'UserInputError: Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
},
],
})

View File

@ -4,6 +4,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { UserInputError } from 'apollo-server'
import { neo4jgraphql } from 'neo4j-graphql-js'
import { TROPHY_BADGES_SELECTED_MAX } from '@constants/badges'
@ -62,10 +63,7 @@ export default {
try {
const { relation, user } = await writeTxResultPromise
if (!relation) {
context.logger.error(
'Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
)
throw new Error(
throw new UserInputError(
'Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
)
}
@ -129,10 +127,7 @@ export default {
).records.map((record) => record.get('user'))
if (users.length !== 1) {
context.logger.error(
'Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
)
throw new Error(
throw new UserInputError(
'Could not reward badge! Ensure the user and the badge exist and the badge is of the correct type.',
)
}
@ -140,7 +135,7 @@ export default {
return users[0]
},
revokeBadge: async (_object, args, context, _resolveInfo) => {
revokeBadge: async (_object, args, context: Context, _resolveInfo) => {
const { badgeId, userId } = args
const session = context.driver.session()
@ -167,7 +162,7 @@ export default {
context.logger.error('revokeBadge', error)
throw new Error(error)
} finally {
session.close()
await session.close()
}
},
},

View File

@ -1,22 +1,25 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/await-thenable */
/* eslint-disable @typescript-eslint/require-await */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ApolloServer } from 'apollo-server-express'
import { createTestClient } from 'apollo-server-testing'
import gql from 'graphql-tag'
import databaseContext from '@context/database'
import Factory, { cleanDatabase } from '@db/factories'
import { getDriver, getNeode } from '@db/neo4j'
import createServer from '@src/server'
const neode = getNeode()
import createServer, { getContext } from '@src/server'
let mutate, query
let authenticatedUser
let user
let variables
const driver = getDriver()
const database = databaseContext()
let server: ApolloServer
const loggerErrorMock: (e) => void = jest.fn()
@ -27,22 +30,21 @@ jest.mock('@src/logger', () => ({
beforeAll(async () => {
await cleanDatabase()
const { server } = createServer({
context: () => {
return {
driver,
neode,
user: authenticatedUser,
}
},
})
mutate = createTestClient(server).mutate
query = createTestClient(server).query
const contextUser = async (_req) => authenticatedUser
const context = getContext({ user: contextUser, database })
server = createServer({ context }).server
const createTestClientResult = createTestClient(server)
query = createTestClientResult.query
mutate = createTestClientResult.mutate
})
afterAll(async () => {
await cleanDatabase()
await driver.close()
void server.stop()
void database.driver.close()
database.neode.close()
})
beforeEach(async () => {
@ -116,7 +118,7 @@ describe('AddEmailAddress', () => {
it('connects `UnverifiedEmailAddress` to the authenticated user', async () => {
await mutate({ mutation, variables })
const result = await neode.cypher(
const result = await database.neode.cypher(
`
MATCH(u:User)-[:PRIMARY_EMAIL]->(:EmailAddress {email: "user@example.org"})
MATCH(u:User)<-[:BELONGS_TO]-(e:UnverifiedEmailAddress {email: "new-email@example.org"})
@ -124,7 +126,11 @@ describe('AddEmailAddress', () => {
`,
{},
)
const email = neode.hydrateFirst(result, 'e', neode.model('UnverifiedEmailAddress'))
const email = database.neode.hydrateFirst(
result,
'e',
database.neode.model('UnverifiedEmailAddress'),
)
await expect(email.toJson()).resolves.toMatchObject({
email: 'new-email@example.org',
nonce: expect.any(String),
@ -266,14 +272,18 @@ describe('VerifyEmailAddress', () => {
it('connects the new `EmailAddress` as PRIMARY', async () => {
await mutate({ mutation, variables })
const result = await neode.cypher(
const result = await database.neode.cypher(
`
MATCH(u:User {id: "567"})-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "to-be-verified@example.org"})
RETURN e
`,
{},
)
const email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
const email = database.neode.hydrateFirst(
result,
'e',
database.neode.model('EmailAddress'),
)
await expect(email.toJson()).resolves.toMatchObject({
email: 'to-be-verified@example.org',
})
@ -284,14 +294,18 @@ describe('VerifyEmailAddress', () => {
MATCH(u:User {id: "567"})-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "user@example.org"})
RETURN e
`
let result = await neode.cypher(cypherStatement, {})
let email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
let result = await database.neode.cypher(cypherStatement, {})
let email = database.neode.hydrateFirst(
result,
'e',
database.neode.model('EmailAddress'),
)
await expect(email.toJson()).resolves.toMatchObject({
email: 'user@example.org',
})
await mutate({ mutation, variables })
result = await neode.cypher(cypherStatement, {})
email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
result = await database.neode.cypher(cypherStatement, {})
email = database.neode.hydrateFirst(result, 'e', database.neode.model('EmailAddress'))
await expect(email).toBe(false)
})
@ -300,14 +314,18 @@ describe('VerifyEmailAddress', () => {
MATCH(u:User {id: "567"})<-[:BELONGS_TO]-(e:EmailAddress {email: "user@example.org"})
RETURN e
`
let result = await neode.cypher(cypherStatement, {})
let email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
let result = await database.neode.cypher(cypherStatement, {})
let email = database.neode.hydrateFirst(
result,
'e',
database.neode.model('EmailAddress'),
)
await expect(email.toJson()).resolves.toMatchObject({
email: 'user@example.org',
})
await mutate({ mutation, variables })
result = await neode.cypher(cypherStatement, {})
email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
result = await database.neode.cypher(cypherStatement, {})
email = database.neode.hydrateFirst(result, 'e', database.neode.model('EmailAddress'))
await expect(email).toBe(false)
})
@ -331,14 +349,18 @@ describe('VerifyEmailAddress', () => {
it('connects the new `EmailAddress` as PRIMARY', async () => {
await mutate({ mutation, variables })
const result = await neode.cypher(
const result = await database.neode.cypher(
`
MATCH(u:User {id: "567"})-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "to-be-verified@example.org"})
RETURN e
`,
{},
)
const email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
const email = database.neode.hydrateFirst(
result,
'e',
database.neode.model('EmailAddress'),
)
await expect(email.toJson()).resolves.toMatchObject({
email: 'to-be-verified@example.org',
})

View File

@ -16,7 +16,7 @@ import Resolver from './helpers/Resolver'
export default {
Query: {
VerifyNonce: async (_parent, args, context, _resolveInfo) => {
VerifyNonce: async (_parent, args, context: Context, _resolveInfo) => {
args.email = normalizeEmail(args.email)
const session = context.driver.session()
const readTxResultPromise = session.readTransaction(async (txc) => {
@ -32,8 +32,11 @@ export default {
try {
const txResult = await readTxResultPromise
return txResult.records[0].get('result')
} catch (e) {
context.logger.error('VerifyNonce query', e)
throw new Error(e.message)
} finally {
session.close()
await session.close()
}
},
},
@ -45,7 +48,6 @@ export default {
const { neode } = context
await new Validator(neode, neode.model('UnverifiedEmailAddress'), args)
} catch (e) {
// context.logger.error('must be a valid email')
throw new UserInputError('must be a valid email')
}
@ -79,6 +81,9 @@ export default {
try {
const txResult = await writeTxResultPromise
response = txResult[0]
} catch (e) {
context.logger.error('AddEmailAddress mutation', e)
throw new Error(e.message)
} finally {
await session.close()
}
@ -115,16 +120,14 @@ export default {
response = txResult[0]
} catch (e) {
if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed') {
// context.logger.error('A user account with this email already exists.')
throw new UserInputError('A user account with this email already exists.')
}
// context.logger.error('VerifyEmailAddress', e)
context.logger.error('VerifyEmailAddress', e)
throw new Error(e)
} finally {
await session.close()
}
if (!response) {
// context.logger.error('Invalid nonce or no email address found.')
throw new UserInputError('Invalid nonce or no email address found.')
}
return response