AFFiNE/packages/backend/server/tests/mailer.spec.ts
2024-01-10 07:28:53 +00:00

193 lines
4.5 KiB
TypeScript

import { randomUUID } from 'node:crypto';
import type { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { hashSync } from '@node-rs/argon2';
import { type User } from '@prisma/client';
import ava, { type TestFn } from 'ava';
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
import { AppModule } from '../src/app';
import { MailService } from '../src/modules/auth/mailer';
import { FeatureKind, FeatureManagementService } from '../src/modules/features';
import { Quotas } from '../src/modules/quota';
import { PrismaService } from '../src/prisma';
import { createWorkspace, getInviteInfo, inviteUser, signUp } from './utils';
const FakePrisma = {
fakeUser: {
id: randomUUID(),
name: 'Alex Yang',
avatarUrl: '',
email: 'alex.yang@example.org',
password: hashSync('123456'),
emailVerified: new Date(),
createdAt: new Date(),
} satisfies User,
get user() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const prisma = this;
return {
async findFirst() {
return null;
},
async create({ data }: any) {
return {
...prisma.fakeUser,
...data,
};
},
async findUnique() {
return prisma.fakeUser;
},
};
},
get workspace() {
return {
id: randomUUID(),
async create({ data }: any) {
return {
id: this.id,
public: data.public ?? false,
createdAt: new Date(),
};
},
};
},
snapshot: {
id: randomUUID(),
async create() {},
async findFirstOrThrow() {
return { id: this.id, blob: Buffer.from([0, 0]) };
},
},
get workspaceUserPermission() {
return {
id: randomUUID(),
prisma: this,
async count() {
return 1;
},
async create() {
return { id: this.id };
},
async findUniqueOrThrow() {
return { id: this.id, workspaceId: this.prisma.workspace.id };
},
async findFirst() {
return { id: this.id };
},
async findFirstOrThrow() {
return { id: this.id, user: this.prisma.fakeUser };
},
async workspaceUserPermission() {
return {
id: randomUUID(),
createdAt: new Date(),
};
},
};
},
get features() {
return {
async findFirst() {
return {
id: 1,
type: FeatureKind.Quota,
feature: Quotas[0].feature,
configs: Quotas[0].configs,
version: Quotas[0].version,
createdAt: new Date(),
};
},
};
},
get userFeatures() {
return {
async findFirst() {
return {
createdAt: new Date(),
featureId: 1,
reason: '',
expiredAt: null,
};
},
};
},
};
const test = ava as TestFn<{
app: INestApplication;
mail: MailService;
}>;
test.beforeEach(async t => {
const module = await Test.createTestingModule({
imports: [AppModule],
})
.overrideProvider(PrismaService)
.useValue(FakePrisma)
.overrideProvider(FeatureManagementService)
.useValue({
hasWorkspaceFeature() {
return false;
},
})
.compile();
const app = module.createNestApplication();
app.use(
graphqlUploadExpress({
maxFileSize: 10 * 1024 * 1024,
maxFiles: 5,
})
);
await app.init();
const mail = module.get(MailService);
t.context.app = app;
t.context.mail = mail;
});
test.afterEach.always(async t => {
await t.context.app.close();
});
test('should send invite email', async t => {
const { mail, app } = t.context;
if (mail.hasConfigured()) {
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
const workspace = await createWorkspace(app, u1.token.token);
const inviteId = await inviteUser(
app,
u1.token.token,
workspace.id,
u2.email,
'Admin'
);
const inviteInfo = await getInviteInfo(app, u1.token.token, inviteId);
const resp = await mail.sendInviteEmail(
'production@toeverything.info',
inviteId,
{
workspace: {
id: inviteInfo.workspace.id,
name: inviteInfo.workspace.name,
avatar: '',
},
user: {
avatar: inviteInfo.user?.avatarUrl || '',
name: inviteInfo.user?.name || '',
},
}
);
t.is(resp.accepted.length, 1, 'failed to send invite email');
}
t.pass();
});