import { getCurrentMailMessageCount, getLatestMailMessage, } from '@affine-test/kit/utils/cloud'; import type { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { PrismaClient } from '@prisma/client'; import ava, { type TestFn } from 'ava'; import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs'; import { AppModule } from '../src/app'; import { RevertCommand, RunCommand } from '../src/data/commands/run'; import { MailService } from '../src/modules/auth/mailer'; import { AuthService } from '../src/modules/auth/service'; import { changeEmail, createWorkspace, initFeatureConfigs, sendChangeEmail, sendVerifyChangeEmail, signUp, } from './utils'; const test = ava as TestFn<{ app: INestApplication; client: PrismaClient; auth: AuthService; mail: MailService; }>; test.beforeEach(async t => { const client = new PrismaClient(); t.context.client = client; await client.$connect(); await client.user.deleteMany({}); await client.snapshot.deleteMany({}); await client.update.deleteMany({}); await client.workspace.deleteMany({}); await client.$disconnect(); const module = await Test.createTestingModule({ imports: [AppModule], providers: [RevertCommand, RunCommand], }).compile(); const app = module.createNestApplication(); app.use( graphqlUploadExpress({ maxFileSize: 10 * 1024 * 1024, maxFiles: 5, }) ); await app.init(); const auth = module.get(AuthService); const mail = module.get(MailService); t.context.app = app; t.context.auth = auth; t.context.mail = mail; // init features await initFeatureConfigs(module); }); test.afterEach(async t => { await t.context.app.close(); }); test('change email', async t => { const { mail, app } = t.context; if (mail.hasConfigured()) { const u1Email = 'u1@affine.pro'; const u2Email = 'u2@affine.pro'; const tokenRegex = /token=3D([^"&\s]+)/; const u1 = await signUp(app, 'u1', u1Email, '1'); await createWorkspace(app, u1.token.token); const primitiveMailCount = await getCurrentMailMessageCount(); await sendChangeEmail(app, u1.token.token, u1Email, 'affine.pro'); const afterSendChangeMailCount = await getCurrentMailMessageCount(); t.is( primitiveMailCount + 1, afterSendChangeMailCount, 'failed to send change email' ); const changeEmailContent = await getLatestMailMessage(); const changeTokenMatch = changeEmailContent.Content.Body.match(tokenRegex); const changeEmailToken = changeTokenMatch ? decodeURIComponent(changeTokenMatch[1].replace(/=3D/g, '=')) : null; t.not( changeEmailToken, null, 'fail to get change email token from email content' ); await sendVerifyChangeEmail( app, u1.token.token, changeEmailToken as string, u2Email, 'affine.pro' ); const afterSendVerifyMailCount = await getCurrentMailMessageCount(); t.is( afterSendChangeMailCount + 1, afterSendVerifyMailCount, 'failed to send verify email' ); const verifyEmailContent = await getLatestMailMessage(); const verifyTokenMatch = verifyEmailContent.Content.Body.match(tokenRegex); const verifyEmailToken = verifyTokenMatch ? decodeURIComponent(verifyTokenMatch[1].replace(/=3D/g, '=')) : null; t.not( verifyEmailToken, null, 'fail to get verify change email token from email content' ); await changeEmail(app, u1.token.token, verifyEmailToken as string); const afterNotificationMailCount = await getCurrentMailMessageCount(); t.is( afterSendVerifyMailCount + 1, afterNotificationMailCount, 'failed to send notification email' ); } t.pass(); });