add test for failing to send confirmation email when signup

This commit is contained in:
Hongbo Wu
2022-07-21 14:55:11 +08:00
committed by Jackson Harper
parent d284a3d302
commit 068684d16b
6 changed files with 122 additions and 71 deletions

View File

@ -1834,6 +1834,7 @@ export enum SignupErrorCode {
AccessDenied = 'ACCESS_DENIED',
ExpiredToken = 'EXPIRED_TOKEN',
GoogleAuthError = 'GOOGLE_AUTH_ERROR',
InvalidEmail = 'INVALID_EMAIL',
InvalidPassword = 'INVALID_PASSWORD',
InvalidUsername = 'INVALID_USERNAME',
Unknown = 'UNKNOWN',

View File

@ -1355,6 +1355,7 @@ enum SignupErrorCode {
ACCESS_DENIED
EXPIRED_TOKEN
GOOGLE_AUTH_ERROR
INVALID_EMAIL
INVALID_PASSWORD
INVALID_USERNAME
UNKNOWN

View File

@ -168,6 +168,7 @@ const schema = gql`
USER_EXISTS
EXPIRED_TOKEN
INVALID_PASSWORD
INVALID_EMAIL
}
type GoogleSignupError {

View File

@ -110,9 +110,11 @@ export const createUser = async (input: {
// delete user if email failed to send
await AppDataSource.transaction(async (e) => {
await setClaims(e, user.id)
return e.getRepository(User).delete(user.id)
})
return Promise.reject({ errorCode: SignupErrorCode.Unknown })
return Promise.reject({ errorCode: SignupErrorCode.InvalidEmail })
}
}

View File

@ -333,6 +333,7 @@ describe('User API', () => {
let email: string
let password: string
let username: string
let fake: (msg: MailDataRequired) => Promise<boolean>
beforeEach(() => {
query = `
@ -363,29 +364,52 @@ describe('User API', () => {
})
context('when inputs are valid and user not exists', () => {
let fake: (msg: MailDataRequired) => Promise<boolean>
beforeEach(() => {
password = correctPassword
username = 'Some_username'
email = `${username}@fake.com`
fake = sinon.replace(util, 'sendEmail', sinon.fake.resolves(true))
})
afterEach(async () => {
await deleteTestUser(username)
sinon.restore()
})
it('responds with 200', async () => {
return graphqlRequest(query).expect(200)
context('when confirmation email sent', () => {
beforeEach(() => {
fake = sinon.replace(util, 'sendEmail', sinon.fake.resolves(true))
})
afterEach(() => {
sinon.restore()
})
it('responds with 200', async () => {
return graphqlRequest(query).expect(200)
})
it('returns the user with the lowercase username', async () => {
const res = await graphqlRequest(query).expect(200)
expect(res.body.data.signup.me.profile.username).to.eql(
username.toLowerCase()
)
})
})
it('returns the user with the lowercase username', async () => {
const res = await graphqlRequest(query).expect(200)
expect(res.body.data.signup.me.profile.username).to.eql(
username.toLowerCase()
)
context('when confirmation email not sent', () => {
before(() => {
fake = sinon.replace(util, 'sendEmail', sinon.fake.resolves(false))
})
after(() => {
sinon.restore()
})
it('responds with error code INVALID_EMAIL', async () => {
const res = await graphqlRequest(query).expect(200)
expect(res.body.data.signup.errorCodes).to.eql([
SignupErrorCode.InvalidEmail,
])
})
})
})

View File

@ -17,71 +17,93 @@ import sinonChai from 'sinon-chai'
import sinon from 'sinon'
import * as util from '../../src/utils/sendEmail'
import { MailDataRequired } from '@sendgrid/helpers/classes/mail'
import { getRepository } from '../../src/entity/utils'
import { User } from '../../src/entity/user'
chai.use(sinonChai)
describe('create a user with an invite', () => {
it('follows the other user in the group', async () => {
after(async () => {
await deleteTestUser(testOwner)
await deleteTestUser(testUser)
describe('create user', () => {
context('create a user with an invite', () => {
it('follows the other user in the group', async () => {
after(async () => {
await deleteTestUser(testOwner)
await deleteTestUser(testUser)
})
const testOwner = 'testowner'
const testUser = 'testuser'
const adminUser = await createTestUser(testOwner)
const [, invite] = await createGroup({
admin: adminUser,
name: 'testgroup',
})
const user = await createTestUser(testUser, invite.code)
expect(await getUserFollowers(user)).to.eql([adminUser])
expect(await getUserFollowing(user)).to.eql([adminUser])
expect(await getUserFollowers(adminUser)).to.eql([user])
expect(await getUserFollowing(adminUser)).to.eql([user])
}).timeout(10000)
it('creates profile when user exists but profile not', async () => {
after(async () => {
await deleteTestUser(name)
})
const name = 'userWithoutProfile'
const user = await createUserWithoutProfile(name)
await createTestUser(user.name)
const profile = await getProfile(user)
expect(profile).to.exist
})
})
context('create a user with pending confirmation', () => {
const name = 'pendingUser'
let fake: (msg: MailDataRequired) => Promise<boolean>
context('when email sends successfully', () => {
beforeEach(() => {
fake = sinon.replace(util, 'sendEmail', sinon.fake.resolves(true))
})
afterEach(async () => {
sinon.restore()
await deleteTestUser(name)
})
it('creates the user with pending status and correct name', async () => {
const user = await createTestUser(name, undefined, undefined, true)
expect(user.status).to.eql(StatusType.Pending)
expect(user.name).to.eql(name)
})
it('sends an email to the user', async () => {
await createTestUser(name, undefined, undefined, true)
expect(fake).to.have.been.calledOnce
})
})
const testOwner = 'testowner'
const testUser = 'testuser'
context('when failed to send email', () => {
before(() => {
fake = sinon.replace(util, 'sendEmail', sinon.fake.resolves(false))
})
const adminUser = await createTestUser(testOwner)
const [, invite] = await createGroup({
admin: adminUser,
name: 'testgroup',
after(() => {
sinon.restore()
})
it('does not create the user', async () => {
await expect(createTestUser(name, undefined, undefined, true)).to.be
.rejected
expect(await getRepository(User).findOneBy({ name })).to.be.null
})
})
const user = await createTestUser(testUser, invite.code)
expect(await getUserFollowers(user)).to.eql([adminUser])
expect(await getUserFollowing(user)).to.eql([adminUser])
expect(await getUserFollowers(adminUser)).to.eql([user])
expect(await getUserFollowing(adminUser)).to.eql([user])
}).timeout(10000)
it('creates profile when user exists but profile not', async () => {
after(async () => {
await deleteTestUser(name)
})
const name = 'userWithoutProfile'
const user = await createUserWithoutProfile(name)
await createTestUser(user.name)
const profile = await getProfile(user)
expect(profile).to.exist
})
})
describe('create a user with pending confirmation', () => {
const name = 'pendingUser'
let fake: (msg: MailDataRequired) => Promise<boolean>
beforeEach(() => {
fake = sinon.replace(util, 'sendEmail', sinon.fake.resolves(true))
})
afterEach(async () => {
sinon.restore()
await deleteTestUser(name)
})
it('creates the user with pending status and correct name', async () => {
const user = await createTestUser(name, undefined, undefined, true)
expect(user.status).to.eql(StatusType.Pending)
expect(user.name).to.eql(name)
})
it('sends an email to the user', async () => {
await createTestUser(name, undefined, undefined, true)
expect(fake).to.have.been.calledOnce
})
})