mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-30 00:29:46 +08:00
test(server): make server testing utils (#5544)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { DynamicModule, Module, Type } from '@nestjs/common';
|
||||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||||
|
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
@@ -13,7 +13,7 @@ import { PrismaModule } from './prisma';
|
|||||||
import { SessionModule } from './session';
|
import { SessionModule } from './session';
|
||||||
import { RateLimiterModule } from './throttler';
|
import { RateLimiterModule } from './throttler';
|
||||||
|
|
||||||
export const BasicModules = [
|
export const FunctionalityModules: Array<Type | DynamicModule> = [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
CacheModule,
|
CacheModule,
|
||||||
PrismaModule,
|
PrismaModule,
|
||||||
@@ -26,7 +26,7 @@ export const BasicModules = [
|
|||||||
|
|
||||||
// better module registration logic
|
// better module registration logic
|
||||||
if (AFFiNE.redis.enabled) {
|
if (AFFiNE.redis.enabled) {
|
||||||
BasicModules.push(RedisModule);
|
FunctionalityModules.push(RedisModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@@ -36,7 +36,7 @@ if (AFFiNE.redis.enabled) {
|
|||||||
useClass: CacheInterceptor,
|
useClass: CacheInterceptor,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
imports: [...BasicModules, ...BusinessModules],
|
imports: [...FunctionalityModules, ...BusinessModules],
|
||||||
controllers: SERVER_FLAVOR === 'selfhosted' ? [] : [AppController],
|
controllers: SERVER_FLAVOR === 'selfhosted' ? [] : [AppController],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -21,11 +21,12 @@ import { GQLLoggerPlugin } from './graphql/logger-plugin';
|
|||||||
csrfPrevention: {
|
csrfPrevention: {
|
||||||
requestHeaders: ['content-type'],
|
requestHeaders: ['content-type'],
|
||||||
},
|
},
|
||||||
autoSchemaFile: join(
|
autoSchemaFile: config.node.test
|
||||||
fileURLToPath(import.meta.url),
|
? join(
|
||||||
'..',
|
fileURLToPath(import.meta.url),
|
||||||
'schema.gql'
|
'../../node_modules/.cache/schema.gql'
|
||||||
),
|
)
|
||||||
|
: join(fileURLToPath(import.meta.url), '..', 'schema.gql'),
|
||||||
context: ({ req, res }: { req: Request; res: Response }) => ({
|
context: ({ req, res }: { req: Request; res: Response }) => ({
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { QuotaManagementService } from './storage';
|
|||||||
* - quota statistics
|
* - quota statistics
|
||||||
*/
|
*/
|
||||||
@Module({
|
@Module({
|
||||||
|
// FIXME: Quota really need to know `Storage`?
|
||||||
imports: [StorageModule],
|
imports: [StorageModule],
|
||||||
providers: [PermissionService, QuotaService, QuotaManagementService],
|
providers: [PermissionService, QuotaService, QuotaManagementService],
|
||||||
exports: [QuotaService, QuotaManagementService],
|
exports: [QuotaService, QuotaManagementService],
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ test('list recursively', async t => {
|
|||||||
t.is(r5.length, 20);
|
t.is(r5.length, 20);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.only('delete', async t => {
|
test('delete', async t => {
|
||||||
const provider = createProvider();
|
const provider = createProvider();
|
||||||
const key = 'testKey';
|
const key = 'testKey';
|
||||||
const body = Buffer.from('testBody');
|
const body = Buffer.from('testBody');
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module, Provider } from '@nestjs/common';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
import { PrismaService } from './service';
|
import { PrismaService } from './service';
|
||||||
|
|
||||||
|
// both `PrismaService` and `PrismaClient` can be injected
|
||||||
|
const clientProvider: Provider = {
|
||||||
|
provide: PrismaClient,
|
||||||
|
useExisting: PrismaService,
|
||||||
|
};
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
providers: [PrismaService],
|
providers: [PrismaService, clientProvider],
|
||||||
exports: [PrismaService],
|
exports: [PrismaService, clientProvider],
|
||||||
})
|
})
|
||||||
export class PrismaModule {}
|
export class PrismaModule {}
|
||||||
export { PrismaService } from './service';
|
export { PrismaService } from './service';
|
||||||
|
|||||||
@@ -3,17 +3,16 @@ import { randomUUID } from 'node:crypto';
|
|||||||
|
|
||||||
import { Transformer } from '@napi-rs/image';
|
import { Transformer } from '@napi-rs/image';
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { hashSync } from '@node-rs/argon2';
|
import { hashSync } from '@node-rs/argon2';
|
||||||
import { type User } from '@prisma/client';
|
import { type User } from '@prisma/client';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
import type { Express } from 'express';
|
import type { Express } from 'express';
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
import { AppModule } from '../src/app';
|
import { AppModule } from '../src/app';
|
||||||
import { FeatureManagementService } from '../src/modules/features';
|
import { FeatureManagementService } from '../src/modules/features';
|
||||||
import { PrismaService } from '../src/prisma/service';
|
import { PrismaService } from '../src/prisma/service';
|
||||||
|
import { createTestingApp } from './utils';
|
||||||
|
|
||||||
const gql = '/graphql';
|
const gql = '/graphql';
|
||||||
|
|
||||||
@@ -49,25 +48,18 @@ class FakePrisma {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const module = await Test.createTestingModule({
|
const { app } = await createTestingApp({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
})
|
tapModule(builder) {
|
||||||
.overrideProvider(PrismaService)
|
builder
|
||||||
.useClass(FakePrisma)
|
.overrideProvider(PrismaService)
|
||||||
.overrideProvider(FeatureManagementService)
|
.useClass(FakePrisma)
|
||||||
.useValue({ canEarlyAccess: () => true })
|
.overrideProvider(FeatureManagementService)
|
||||||
.compile();
|
.useValue({ canEarlyAccess: () => true });
|
||||||
t.context.app = module.createNestApplication({
|
},
|
||||||
cors: true,
|
|
||||||
bodyParser: true,
|
|
||||||
});
|
});
|
||||||
t.context.app.use(
|
|
||||||
graphqlUploadExpress({
|
t.context.app = app;
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
|
||||||
maxFiles: 5,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
await t.context.app.init();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
|
|||||||
@@ -3,19 +3,13 @@ import {
|
|||||||
getLatestMailMessage,
|
getLatestMailMessage,
|
||||||
} from '@affine-test/kit/utils/cloud';
|
} from '@affine-test/kit/utils/cloud';
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import ava, { type TestFn } from 'ava';
|
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 { MailService } from '../src/modules/auth/mailer';
|
||||||
import { AuthService } from '../src/modules/auth/service';
|
import { AuthService } from '../src/modules/auth/service';
|
||||||
import {
|
import {
|
||||||
changeEmail,
|
changeEmail,
|
||||||
createWorkspace,
|
createTestingApp,
|
||||||
initFeatureConfigs,
|
|
||||||
sendChangeEmail,
|
sendChangeEmail,
|
||||||
sendVerifyChangeEmail,
|
sendVerifyChangeEmail,
|
||||||
signUp,
|
signUp,
|
||||||
@@ -23,44 +17,20 @@ import {
|
|||||||
|
|
||||||
const test = ava as TestFn<{
|
const test = ava as TestFn<{
|
||||||
app: INestApplication;
|
app: INestApplication;
|
||||||
client: PrismaClient;
|
|
||||||
auth: AuthService;
|
auth: AuthService;
|
||||||
mail: MailService;
|
mail: MailService;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const client = new PrismaClient();
|
const { app } = await createTestingApp();
|
||||||
t.context.client = client;
|
const auth = app.get(AuthService);
|
||||||
await client.$connect();
|
const mail = app.get(MailService);
|
||||||
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.app = app;
|
||||||
t.context.auth = auth;
|
t.context.auth = auth;
|
||||||
t.context.mail = mail;
|
t.context.mail = mail;
|
||||||
|
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach(async t => {
|
test.afterEach.always(async t => {
|
||||||
await t.context.app.close();
|
await t.context.app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -73,8 +43,6 @@ test('change email', async t => {
|
|||||||
|
|
||||||
const u1 = await signUp(app, 'u1', u1Email, '1');
|
const u1 = await signUp(app, 'u1', u1Email, '1');
|
||||||
|
|
||||||
await createWorkspace(app, u1.token.token);
|
|
||||||
|
|
||||||
const primitiveMailCount = await getCurrentMailMessageCount();
|
const primitiveMailCount = await getCurrentMailMessageCount();
|
||||||
|
|
||||||
await sendChangeEmail(app, u1.token.token, u1Email, 'affine.pro');
|
await sendChangeEmail(app, u1.token.token, u1Email, 'affine.pro');
|
||||||
|
|||||||
@@ -1,34 +1,19 @@
|
|||||||
/// <reference types="../src/global.d.ts" />
|
/// <reference types="../src/global.d.ts" />
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
|
|
||||||
import { CacheModule } from '../src/cache';
|
|
||||||
import { ConfigModule } from '../src/config';
|
import { ConfigModule } from '../src/config';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
|
||||||
import { GqlModule } from '../src/graphql.module';
|
|
||||||
import { AuthModule } from '../src/modules/auth';
|
|
||||||
import { AuthResolver } from '../src/modules/auth/resolver';
|
import { AuthResolver } from '../src/modules/auth/resolver';
|
||||||
import { AuthService } from '../src/modules/auth/service';
|
import { AuthService } from '../src/modules/auth/service';
|
||||||
import { PrismaModule } from '../src/prisma';
|
|
||||||
import { mintChallengeResponse, verifyChallengeResponse } from '../src/storage';
|
import { mintChallengeResponse, verifyChallengeResponse } from '../src/storage';
|
||||||
import { RateLimiterModule } from '../src/throttler';
|
import { createTestingModule } from './utils';
|
||||||
import { initFeatureConfigs } from './utils';
|
|
||||||
|
|
||||||
let authService: AuthService;
|
let authService: AuthService;
|
||||||
let authResolver: AuthResolver;
|
let authResolver: AuthResolver;
|
||||||
let module: TestingModule;
|
let module: TestingModule;
|
||||||
|
|
||||||
// cleanup database before each test
|
|
||||||
test.beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const client = new PrismaClient();
|
module = await createTestingModule({
|
||||||
await client.$connect();
|
|
||||||
await client.user.deleteMany({});
|
|
||||||
await client.$disconnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
module = await Test.createTestingModule({
|
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
auth: {
|
auth: {
|
||||||
@@ -39,20 +24,11 @@ test.beforeEach(async () => {
|
|||||||
host: 'example.org',
|
host: 'example.org',
|
||||||
https: true,
|
https: true,
|
||||||
}),
|
}),
|
||||||
PrismaModule,
|
|
||||||
CacheModule,
|
|
||||||
GqlModule,
|
|
||||||
AuthModule,
|
|
||||||
RateLimiterModule,
|
|
||||||
RevertCommand,
|
|
||||||
RunCommand,
|
|
||||||
],
|
],
|
||||||
}).compile();
|
});
|
||||||
|
|
||||||
authService = module.get(AuthService);
|
authService = module.get(AuthService);
|
||||||
authResolver = module.get(AuthResolver);
|
authResolver = module.get(AuthResolver);
|
||||||
|
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async () => {
|
test.afterEach.always(async () => {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { mock } from 'node:test';
|
import { mock } from 'node:test';
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import { register } from 'prom-client';
|
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import {
|
import {
|
||||||
applyUpdate,
|
applyUpdate,
|
||||||
@@ -12,37 +10,19 @@ import {
|
|||||||
encodeStateAsUpdate,
|
encodeStateAsUpdate,
|
||||||
} from 'yjs';
|
} from 'yjs';
|
||||||
|
|
||||||
import { CacheModule } from '../src/cache';
|
import { Config } from '../src/config';
|
||||||
import { Config, ConfigModule } from '../src/config';
|
|
||||||
import {
|
|
||||||
collectMigrations,
|
|
||||||
RevertCommand,
|
|
||||||
RunCommand,
|
|
||||||
} from '../src/data/commands/run';
|
|
||||||
import { EventModule } from '../src/event';
|
|
||||||
import { DocManager, DocModule } from '../src/modules/doc';
|
import { DocManager, DocModule } from '../src/modules/doc';
|
||||||
import { QuotaModule } from '../src/modules/quota';
|
import { QuotaModule } from '../src/modules/quota';
|
||||||
import { StorageModule } from '../src/modules/storage';
|
import { StorageModule } from '../src/modules/storage';
|
||||||
import { PrismaModule, PrismaService } from '../src/prisma';
|
import { PrismaService } from '../src/prisma';
|
||||||
import { flushDB } from './utils';
|
import { createTestingModule, initTestingDB } from './utils';
|
||||||
|
|
||||||
const createModule = () => {
|
const createModule = () => {
|
||||||
return Test.createTestingModule({
|
return createTestingModule({
|
||||||
imports: [
|
imports: [QuotaModule, StorageModule, DocModule],
|
||||||
PrismaModule,
|
});
|
||||||
CacheModule,
|
|
||||||
EventModule,
|
|
||||||
QuotaModule,
|
|
||||||
StorageModule,
|
|
||||||
ConfigModule.forRoot(),
|
|
||||||
DocModule,
|
|
||||||
RevertCommand,
|
|
||||||
RunCommand,
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let app: INestApplication;
|
|
||||||
let m: TestingModule;
|
let m: TestingModule;
|
||||||
let timer: Sinon.SinonFakeTimers;
|
let timer: Sinon.SinonFakeTimers;
|
||||||
|
|
||||||
@@ -51,44 +31,34 @@ test.beforeEach(async () => {
|
|||||||
timer = Sinon.useFakeTimers({
|
timer = Sinon.useFakeTimers({
|
||||||
toFake: ['setInterval'],
|
toFake: ['setInterval'],
|
||||||
});
|
});
|
||||||
await flushDB();
|
|
||||||
m = await createModule();
|
m = await createModule();
|
||||||
app = m.createNestApplication();
|
await m.init();
|
||||||
app.enableShutdownHooks();
|
await initTestingDB(m.get(PrismaService));
|
||||||
await app.init();
|
|
||||||
|
|
||||||
// init features
|
|
||||||
const run = m.get(RunCommand);
|
|
||||||
const revert = m.get(RevertCommand);
|
|
||||||
const migrations = await collectMigrations();
|
|
||||||
await Promise.allSettled(migrations.map(m => revert.run([m.name])));
|
|
||||||
await run.run();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async () => {
|
test.afterEach.always(async () => {
|
||||||
await app.close();
|
|
||||||
await m.close();
|
await m.close();
|
||||||
timer.restore();
|
timer.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should setup update poll interval', async t => {
|
test('should setup update poll interval', async t => {
|
||||||
register.clear();
|
|
||||||
const m = await createModule();
|
const m = await createModule();
|
||||||
const manager = m.get(DocManager);
|
const manager = m.get(DocManager);
|
||||||
const fake = mock.method(manager, 'setup');
|
const fake = mock.method(manager, 'setup');
|
||||||
|
|
||||||
await m.createNestApplication().init();
|
await m.init();
|
||||||
|
|
||||||
t.is(fake.mock.callCount(), 1);
|
t.is(fake.mock.callCount(), 1);
|
||||||
// @ts-expect-error private member
|
// @ts-expect-error private member
|
||||||
t.truthy(manager.job);
|
t.truthy(manager.job);
|
||||||
|
m.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to stop poll', async t => {
|
test('should be able to stop poll', async t => {
|
||||||
const manager = m.get(DocManager);
|
const manager = m.get(DocManager);
|
||||||
const fake = mock.method(manager, 'destroy');
|
const fake = mock.method(manager, 'destroy');
|
||||||
|
|
||||||
await app.close();
|
await m.close();
|
||||||
|
|
||||||
t.is(fake.mock.callCount(), 1);
|
t.is(fake.mock.callCount(), 1);
|
||||||
// @ts-expect-error private member
|
// @ts-expect-error private member
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
/// <reference types="../src/global.d.ts" />
|
/// <reference types="../src/global.d.ts" />
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { INestApplication, Injectable } from '@nestjs/common';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
|
|
||||||
import { CacheModule } from '../src/cache';
|
|
||||||
import { ConfigModule } from '../src/config';
|
import { ConfigModule } from '../src/config';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
|
||||||
import { AuthModule } from '../src/modules/auth';
|
|
||||||
import { AuthService } from '../src/modules/auth/service';
|
import { AuthService } from '../src/modules/auth/service';
|
||||||
import {
|
import {
|
||||||
FeatureManagementService,
|
FeatureManagementService,
|
||||||
@@ -19,9 +14,8 @@ import {
|
|||||||
import { UserType } from '../src/modules/users/types';
|
import { UserType } from '../src/modules/users/types';
|
||||||
import { WorkspaceResolver } from '../src/modules/workspaces/resolvers';
|
import { WorkspaceResolver } from '../src/modules/workspaces/resolvers';
|
||||||
import { Permission } from '../src/modules/workspaces/types';
|
import { Permission } from '../src/modules/workspaces/types';
|
||||||
import { PrismaModule, PrismaService } from '../src/prisma';
|
import { PrismaService } from '../src/prisma';
|
||||||
import { RateLimiterModule } from '../src/throttler';
|
import { createTestingApp } from './utils';
|
||||||
import { initFeatureConfigs } from './utils';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class WorkspaceResolverMock {
|
class WorkspaceResolverMock {
|
||||||
@@ -53,20 +47,11 @@ const test = ava as TestFn<{
|
|||||||
feature: FeatureService;
|
feature: FeatureService;
|
||||||
workspace: WorkspaceResolver;
|
workspace: WorkspaceResolver;
|
||||||
management: FeatureManagementService;
|
management: FeatureManagementService;
|
||||||
app: TestingModule;
|
app: INestApplication;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// cleanup database before each test
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
const client = new PrismaClient();
|
|
||||||
await client.$connect();
|
|
||||||
await client.user.deleteMany({});
|
|
||||||
await client.workspace.deleteMany({});
|
|
||||||
await client.$disconnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const module = await Test.createTestingModule({
|
const { app } = await createTestingApp({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
auth: {
|
auth: {
|
||||||
@@ -80,28 +65,21 @@ test.beforeEach(async t => {
|
|||||||
earlyAccessPreview: true,
|
earlyAccessPreview: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
PrismaModule,
|
|
||||||
CacheModule,
|
|
||||||
AuthModule,
|
|
||||||
FeatureModule,
|
FeatureModule,
|
||||||
RateLimiterModule,
|
|
||||||
RevertCommand,
|
|
||||||
RunCommand,
|
|
||||||
],
|
],
|
||||||
providers: [WorkspaceResolver],
|
providers: [WorkspaceResolver],
|
||||||
})
|
tapModule: module => {
|
||||||
.overrideProvider(WorkspaceResolver)
|
module
|
||||||
.useClass(WorkspaceResolverMock)
|
.overrideProvider(WorkspaceResolver)
|
||||||
.compile();
|
.useClass(WorkspaceResolverMock);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
t.context.app = module;
|
t.context.app = app;
|
||||||
t.context.auth = module.get(AuthService);
|
t.context.auth = app.get(AuthService);
|
||||||
t.context.feature = module.get(FeatureService);
|
t.context.feature = app.get(FeatureService);
|
||||||
t.context.workspace = module.get(WorkspaceResolver);
|
t.context.workspace = app.get(WorkspaceResolver);
|
||||||
t.context.management = module.get(FeatureManagementService);
|
t.context.management = app.get(FeatureManagementService);
|
||||||
|
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
|
|||||||
@@ -1,40 +1,26 @@
|
|||||||
import { INestApplication } from '@nestjs/common';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import { ScheduleModule } from '@nestjs/schedule';
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import type { Snapshot } from '@prisma/client';
|
import type { Snapshot } from '@prisma/client';
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
|
|
||||||
import { ConfigModule } from '../src/config';
|
import { type EventPayload } from '../src/event';
|
||||||
import { EventModule, type EventPayload } from '../src/event';
|
|
||||||
import { DocHistoryManager } from '../src/modules/doc';
|
import { DocHistoryManager } from '../src/modules/doc';
|
||||||
import { QuotaModule } from '../src/modules/quota';
|
import { QuotaModule } from '../src/modules/quota';
|
||||||
import { StorageModule } from '../src/modules/storage';
|
import { StorageModule } from '../src/modules/storage';
|
||||||
import { PrismaModule, PrismaService } from '../src/prisma';
|
import { PrismaService } from '../src/prisma';
|
||||||
import { flushDB } from './utils';
|
import { createTestingModule } from './utils';
|
||||||
|
|
||||||
let app: INestApplication;
|
|
||||||
let m: TestingModule;
|
let m: TestingModule;
|
||||||
let manager: DocHistoryManager;
|
let manager: DocHistoryManager;
|
||||||
let db: PrismaService;
|
let db: PrismaService;
|
||||||
|
|
||||||
// cleanup database before each test
|
// cleanup database before each test
|
||||||
test.beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await flushDB();
|
m = await createTestingModule({
|
||||||
m = await Test.createTestingModule({
|
imports: [StorageModule, QuotaModule],
|
||||||
imports: [
|
|
||||||
PrismaModule,
|
|
||||||
QuotaModule,
|
|
||||||
EventModule,
|
|
||||||
StorageModule,
|
|
||||||
ScheduleModule.forRoot(),
|
|
||||||
ConfigModule.forRoot(),
|
|
||||||
],
|
|
||||||
providers: [DocHistoryManager],
|
providers: [DocHistoryManager],
|
||||||
}).compile();
|
});
|
||||||
|
|
||||||
app = m.createNestApplication();
|
|
||||||
await app.init();
|
|
||||||
manager = m.get(DocHistoryManager);
|
manager = m.get(DocHistoryManager);
|
||||||
Sinon.stub(manager, 'getExpiredDateFromNow').resolves(
|
Sinon.stub(manager, 'getExpiredDateFromNow').resolves(
|
||||||
new Date(Date.now() + 1000)
|
new Date(Date.now() + 1000)
|
||||||
@@ -42,8 +28,7 @@ test.beforeEach(async () => {
|
|||||||
db = m.get(PrismaService);
|
db = m.get(PrismaService);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach(async () => {
|
test.afterEach.always(async () => {
|
||||||
await app.close();
|
|
||||||
await m.close();
|
await m.close();
|
||||||
Sinon.restore();
|
Sinon.restore();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,19 +6,13 @@ import {
|
|||||||
getCurrentMailMessageCount,
|
getCurrentMailMessageCount,
|
||||||
getLatestMailMessage,
|
getLatestMailMessage,
|
||||||
} from '@affine-test/kit/utils/cloud';
|
} from '@affine-test/kit/utils/cloud';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
|
|
||||||
import { CacheModule } from '../src/cache';
|
|
||||||
import { ConfigModule } from '../src/config';
|
import { ConfigModule } from '../src/config';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
|
||||||
import { GqlModule } from '../src/graphql.module';
|
|
||||||
import { AuthModule } from '../src/modules/auth';
|
|
||||||
import { AuthService } from '../src/modules/auth/service';
|
import { AuthService } from '../src/modules/auth/service';
|
||||||
import { PrismaModule } from '../src/prisma';
|
import { createTestingModule } from './utils';
|
||||||
import { RateLimiterModule } from '../src/throttler';
|
|
||||||
import { initFeatureConfigs } from './utils';
|
|
||||||
|
|
||||||
const test = ava as TestFn<{
|
const test = ava as TestFn<{
|
||||||
auth: AuthService;
|
auth: AuthService;
|
||||||
@@ -34,7 +28,7 @@ test.beforeEach(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
t.context.module = await Test.createTestingModule({
|
t.context.module = await createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
auth: {
|
auth: {
|
||||||
@@ -43,18 +37,9 @@ test.beforeEach(async t => {
|
|||||||
leeway: 1,
|
leeway: 1,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
PrismaModule,
|
|
||||||
GqlModule,
|
|
||||||
AuthModule,
|
|
||||||
CacheModule,
|
|
||||||
RateLimiterModule,
|
|
||||||
],
|
],
|
||||||
providers: [RevertCommand, RunCommand],
|
});
|
||||||
}).compile();
|
|
||||||
t.context.auth = t.context.module.get(AuthService);
|
t.context.auth = t.context.module.get(AuthService);
|
||||||
|
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(t.context.module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
|
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { hashSync } from '@node-rs/argon2';
|
import { hashSync } from '@node-rs/argon2';
|
||||||
import { type User } from '@prisma/client';
|
import { type User } from '@prisma/client';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|
||||||
|
|
||||||
import { AppModule } from '../src/app';
|
import { AppModule } from '../src/app';
|
||||||
import { MailService } from '../src/modules/auth/mailer';
|
import { MailService } from '../src/modules/auth/mailer';
|
||||||
import { FeatureKind, FeatureManagementService } from '../src/modules/features';
|
import { FeatureKind, FeatureManagementService } from '../src/modules/features';
|
||||||
import { Quotas } from '../src/modules/quota';
|
import { Quotas } from '../src/modules/quota';
|
||||||
import { PrismaService } from '../src/prisma';
|
import { PrismaService } from '../src/prisma';
|
||||||
import { createWorkspace, getInviteInfo, inviteUser, signUp } from './utils';
|
import {
|
||||||
|
createTestingApp,
|
||||||
|
createWorkspace,
|
||||||
|
getInviteInfo,
|
||||||
|
inviteUser,
|
||||||
|
signUp,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
const FakePrisma = {
|
const FakePrisma = {
|
||||||
fakeUser: {
|
fakeUser: {
|
||||||
@@ -123,26 +127,20 @@ const test = ava as TestFn<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const module = await Test.createTestingModule({
|
const { module, app } = await createTestingApp({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
})
|
tapModule: module => {
|
||||||
.overrideProvider(PrismaService)
|
module
|
||||||
.useValue(FakePrisma)
|
.overrideProvider(PrismaService)
|
||||||
.overrideProvider(FeatureManagementService)
|
.useValue(FakePrisma)
|
||||||
.useValue({
|
.overrideProvider(FeatureManagementService)
|
||||||
hasWorkspaceFeature() {
|
.useValue({
|
||||||
return false;
|
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);
|
const mail = module.get(MailService);
|
||||||
t.context.app = app;
|
t.context.app = app;
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
/// <reference types="../src/global.d.ts" />
|
/// <reference types="../src/global.d.ts" />
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
|
|
||||||
import { CacheModule } from '../src/cache';
|
|
||||||
import { ConfigModule } from '../src/config';
|
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
|
||||||
import { EventModule } from '../src/event';
|
|
||||||
import { AuthModule } from '../src/modules/auth';
|
|
||||||
import { AuthService } from '../src/modules/auth/service';
|
import { AuthService } from '../src/modules/auth/service';
|
||||||
import {
|
import {
|
||||||
QuotaManagementService,
|
QuotaManagementService,
|
||||||
@@ -18,64 +12,32 @@ import {
|
|||||||
QuotaType,
|
QuotaType,
|
||||||
} from '../src/modules/quota';
|
} from '../src/modules/quota';
|
||||||
import { StorageModule } from '../src/modules/storage';
|
import { StorageModule } from '../src/modules/storage';
|
||||||
import { PrismaModule } from '../src/prisma';
|
import { createTestingModule } from './utils';
|
||||||
import { RateLimiterModule } from '../src/throttler';
|
|
||||||
import { initFeatureConfigs } from './utils';
|
|
||||||
|
|
||||||
const test = ava as TestFn<{
|
const test = ava as TestFn<{
|
||||||
auth: AuthService;
|
auth: AuthService;
|
||||||
quota: QuotaService;
|
quota: QuotaService;
|
||||||
storageQuota: QuotaManagementService;
|
storageQuota: QuotaManagementService;
|
||||||
app: TestingModule;
|
module: TestingModule;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// cleanup database before each test
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
const client = new PrismaClient();
|
|
||||||
await client.$connect();
|
|
||||||
await client.user.deleteMany({});
|
|
||||||
await client.$disconnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await createTestingModule({
|
||||||
imports: [
|
imports: [StorageModule, QuotaModule],
|
||||||
ConfigModule.forRoot({
|
});
|
||||||
auth: {
|
|
||||||
accessTokenExpiresIn: 1,
|
|
||||||
refreshTokenExpiresIn: 1,
|
|
||||||
leeway: 1,
|
|
||||||
},
|
|
||||||
host: 'example.org',
|
|
||||||
https: true,
|
|
||||||
}),
|
|
||||||
PrismaModule,
|
|
||||||
CacheModule,
|
|
||||||
AuthModule,
|
|
||||||
EventModule,
|
|
||||||
QuotaModule,
|
|
||||||
StorageModule,
|
|
||||||
RateLimiterModule,
|
|
||||||
RevertCommand,
|
|
||||||
RunCommand,
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
const quota = module.get(QuotaService);
|
const quota = module.get(QuotaService);
|
||||||
const storageQuota = module.get(QuotaManagementService);
|
const storageQuota = module.get(QuotaManagementService);
|
||||||
const auth = module.get(AuthService);
|
const auth = module.get(AuthService);
|
||||||
|
|
||||||
t.context.app = module;
|
t.context.module = module;
|
||||||
t.context.quota = quota;
|
t.context.quota = quota;
|
||||||
t.context.storageQuota = storageQuota;
|
t.context.storageQuota = storageQuota;
|
||||||
t.context.auth = auth;
|
t.context.auth = auth;
|
||||||
|
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
await t.context.app.close();
|
await t.context.module.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to set quota', async t => {
|
test('should be able to set quota', async t => {
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
/// <reference types="../src/global.d.ts" />
|
/// <reference types="../src/global.d.ts" />
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { TestingModule } from '@nestjs/testing';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
|
|
||||||
import { CacheModule } from '../src/cache';
|
import { CacheModule } from '../src/cache';
|
||||||
import { ConfigModule } from '../src/config';
|
import { ConfigModule } from '../src/config';
|
||||||
import { SessionModule, SessionService } from '../src/session';
|
import { SessionModule, SessionService } from '../src/session';
|
||||||
|
import { createTestingModule } from './utils';
|
||||||
|
|
||||||
const test = ava as TestFn<{
|
const test = ava as TestFn<{
|
||||||
session: SessionService;
|
session: SessionService;
|
||||||
app: TestingModule;
|
module: TestingModule;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
redis: {
|
redis: {
|
||||||
@@ -23,14 +24,14 @@ test.beforeEach(async t => {
|
|||||||
CacheModule,
|
CacheModule,
|
||||||
SessionModule,
|
SessionModule,
|
||||||
],
|
],
|
||||||
}).compile();
|
});
|
||||||
const session = module.get(SessionService);
|
const session = module.get(SessionService);
|
||||||
t.context.app = module;
|
t.context.module = module;
|
||||||
t.context.session = session;
|
t.context.session = session;
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
await t.context.app.close();
|
await t.context.module.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be able to set session', async t => {
|
test('should be able to set session', async t => {
|
||||||
|
|||||||
@@ -1,40 +1,17 @@
|
|||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
import { AppModule } from '../src/app';
|
import { AppModule } from '../src/app';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
import { createTestingApp, currentUser, signUp } from './utils';
|
||||||
import { currentUser, initFeatureConfigs, signUp } from './utils';
|
|
||||||
|
|
||||||
let app: INestApplication;
|
let app: INestApplication;
|
||||||
|
|
||||||
// cleanup database before each test
|
|
||||||
test.beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
const client = new PrismaClient();
|
const { app: testApp } = await createTestingApp({
|
||||||
await client.$connect();
|
|
||||||
await client.user.deleteMany({});
|
|
||||||
await client.$disconnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
const module = await Test.createTestingModule({
|
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
providers: [RevertCommand, RunCommand],
|
});
|
||||||
}).compile();
|
app = testApp;
|
||||||
app = module.createNestApplication();
|
|
||||||
app.use(
|
|
||||||
graphqlUploadExpress({
|
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
|
||||||
maxFiles: 5,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
await app.init();
|
|
||||||
|
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async () => {
|
test.afterEach.always(async () => {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
import { INestApplication, ModuleMetadata } from '@nestjs/common';
|
||||||
|
import { Query, Resolver } from '@nestjs/graphql';
|
||||||
|
import { Test, TestingModuleBuilder } from '@nestjs/testing';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
|
|
||||||
import { TestingModule } from '@nestjs/testing';
|
import { AppModule, FunctionalityModules } from '../../src/app';
|
||||||
import { hashSync } from '@node-rs/argon2';
|
import { UserFeaturesInit1698652531198 } from '../../src/data/migrations/1698652531198-user-features-init';
|
||||||
import { PrismaClient, type User } from '@prisma/client';
|
import { GqlModule } from '../../src/graphql.module';
|
||||||
|
|
||||||
import { RevertCommand, RunCommand } from '../../src/data/commands/run';
|
async function flushDB(client: PrismaClient) {
|
||||||
|
|
||||||
export async function flushDB() {
|
|
||||||
const client = new PrismaClient();
|
|
||||||
await client.$connect();
|
|
||||||
const result: { tablename: string }[] =
|
const result: { tablename: string }[] =
|
||||||
await client.$queryRaw`SELECT tablename
|
await client.$queryRaw`SELECT tablename
|
||||||
FROM pg_catalog.pg_tables
|
FROM pg_catalog.pg_tables
|
||||||
@@ -22,41 +22,99 @@ export async function flushDB() {
|
|||||||
.filter(name => !name.includes('migrations'))
|
.filter(name => !name.includes('migrations'))
|
||||||
.join(', ')}`
|
.join(', ')}`
|
||||||
);
|
);
|
||||||
|
|
||||||
await client.$disconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FakePrisma {
|
async function initFeatureConfigs(db: PrismaClient) {
|
||||||
fakeUser: User = {
|
await UserFeaturesInit1698652531198.up(db);
|
||||||
id: randomUUID(),
|
}
|
||||||
name: 'Alex Yang',
|
|
||||||
avatarUrl: '',
|
|
||||||
email: 'alex.yang@example.org',
|
|
||||||
password: hashSync('123456'),
|
|
||||||
emailVerified: new Date(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
get user() {
|
export async function initTestingDB(db: PrismaClient) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
await flushDB(db);
|
||||||
const prisma = this;
|
await initFeatureConfigs(db);
|
||||||
return {
|
}
|
||||||
async findFirst() {
|
|
||||||
return prisma.fakeUser;
|
interface TestingModuleMeatdata extends ModuleMetadata {
|
||||||
},
|
tapModule?(m: TestingModuleBuilder): void;
|
||||||
async findUnique() {
|
tapApp?(app: INestApplication): void;
|
||||||
return this.findFirst();
|
}
|
||||||
},
|
|
||||||
async update() {
|
function dedupeModules(modules: NonNullable<ModuleMetadata['imports']>) {
|
||||||
return this.findFirst();
|
const map = new Map();
|
||||||
},
|
|
||||||
};
|
modules.forEach(m => {
|
||||||
|
if ('module' in m) {
|
||||||
|
map.set(m.module, m);
|
||||||
|
} else {
|
||||||
|
map.set(m, m);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(map.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resolver(() => String)
|
||||||
|
class MockResolver {
|
||||||
|
@Query(() => String)
|
||||||
|
hello() {
|
||||||
|
return 'hello world';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initFeatureConfigs(module: TestingModule) {
|
export async function createTestingModule(
|
||||||
const run = module.get(RunCommand);
|
moduleDef: TestingModuleMeatdata = {}
|
||||||
const revert = module.get(RevertCommand);
|
) {
|
||||||
await Promise.allSettled([revert.run(['UserFeaturesInit1698652531198'])]);
|
// setting up
|
||||||
await run.runOne('UserFeaturesInit1698652531198');
|
let imports = moduleDef.imports ?? [];
|
||||||
|
imports =
|
||||||
|
imports[0] === AppModule
|
||||||
|
? [AppModule]
|
||||||
|
: dedupeModules([...FunctionalityModules, GqlModule, ...imports]);
|
||||||
|
|
||||||
|
const builder = Test.createTestingModule({
|
||||||
|
imports,
|
||||||
|
providers: [MockResolver, ...(moduleDef.providers ?? [])],
|
||||||
|
controllers: moduleDef.controllers,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (moduleDef.tapModule) {
|
||||||
|
moduleDef.tapModule(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const m = await builder.compile();
|
||||||
|
|
||||||
|
const prisma = m.get(PrismaClient);
|
||||||
|
if (prisma instanceof PrismaClient) {
|
||||||
|
await flushDB(prisma);
|
||||||
|
await initFeatureConfigs(prisma);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createTestingApp(moduleDef: TestingModuleMeatdata = {}) {
|
||||||
|
const m = await createTestingModule(moduleDef);
|
||||||
|
|
||||||
|
const app = m.createNestApplication({
|
||||||
|
cors: true,
|
||||||
|
bodyParser: true,
|
||||||
|
rawBody: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
graphqlUploadExpress({
|
||||||
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
|
maxFiles: 5,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (moduleDef.tapApp) {
|
||||||
|
moduleDef.tapApp(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
await app.init();
|
||||||
|
|
||||||
|
return {
|
||||||
|
module: m,
|
||||||
|
app,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
import { AppModule } from '../src/app';
|
import { AppModule } from '../src/app';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
|
||||||
import { QuotaService, QuotaType } from '../src/modules/quota';
|
import { QuotaService, QuotaType } from '../src/modules/quota';
|
||||||
import {
|
import {
|
||||||
checkBlobSize,
|
checkBlobSize,
|
||||||
collectAllBlobSizes,
|
collectAllBlobSizes,
|
||||||
|
createTestingApp,
|
||||||
createWorkspace,
|
createWorkspace,
|
||||||
getWorkspaceBlobsSize,
|
getWorkspaceBlobsSize,
|
||||||
initFeatureConfigs,
|
|
||||||
listBlobs,
|
listBlobs,
|
||||||
setBlob,
|
setBlob,
|
||||||
signUp,
|
signUp,
|
||||||
@@ -22,36 +18,13 @@ import {
|
|||||||
let app: INestApplication;
|
let app: INestApplication;
|
||||||
let quota: QuotaService;
|
let quota: QuotaService;
|
||||||
|
|
||||||
const client = new PrismaClient();
|
|
||||||
|
|
||||||
// cleanup database before each test
|
|
||||||
test.beforeEach(async () => {
|
test.beforeEach(async () => {
|
||||||
await client.$connect();
|
const { app: testApp } = await createTestingApp({
|
||||||
await client.user.deleteMany({});
|
|
||||||
await client.snapshot.deleteMany({});
|
|
||||||
await client.update.deleteMany({});
|
|
||||||
await client.workspace.deleteMany({});
|
|
||||||
await client.$disconnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
const module = await Test.createTestingModule({
|
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
providers: [RevertCommand, RunCommand],
|
});
|
||||||
}).compile();
|
|
||||||
app = module.createNestApplication();
|
|
||||||
app.use(
|
|
||||||
graphqlUploadExpress({
|
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
|
||||||
maxFiles: 5,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
quota = module.get(QuotaService);
|
|
||||||
|
|
||||||
// init features
|
app = testApp;
|
||||||
await initFeatureConfigs(module);
|
quota = app.get(QuotaService);
|
||||||
|
|
||||||
await app.init();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async () => {
|
test.afterEach.always(async () => {
|
||||||
|
|||||||
@@ -3,20 +3,18 @@ import {
|
|||||||
getLatestMailMessage,
|
getLatestMailMessage,
|
||||||
} from '@affine-test/kit/utils/cloud';
|
} from '@affine-test/kit/utils/cloud';
|
||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|
||||||
|
|
||||||
import { AppModule } from '../src/app';
|
import { AppModule } from '../src/app';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
|
||||||
import { MailService } from '../src/modules/auth/mailer';
|
import { MailService } from '../src/modules/auth/mailer';
|
||||||
import { AuthService } from '../src/modules/auth/service';
|
import { AuthService } from '../src/modules/auth/service';
|
||||||
|
import { PrismaService } from '../src/prisma';
|
||||||
import {
|
import {
|
||||||
acceptInviteById,
|
acceptInviteById,
|
||||||
|
createTestingApp,
|
||||||
createWorkspace,
|
createWorkspace,
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
initFeatureConfigs,
|
|
||||||
inviteUser,
|
inviteUser,
|
||||||
leaveWorkspace,
|
leaveWorkspace,
|
||||||
revokeUser,
|
revokeUser,
|
||||||
@@ -31,36 +29,13 @@ const test = ava as TestFn<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const client = new PrismaClient();
|
const { app } = await createTestingApp({
|
||||||
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],
|
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.app = app;
|
||||||
t.context.auth = auth;
|
t.context.client = app.get(PrismaService);
|
||||||
t.context.mail = mail;
|
t.context.auth = app.get(AuthService);
|
||||||
|
t.context.mail = app.get(MailService);
|
||||||
// init features
|
|
||||||
await initFeatureConfigs(module);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import type { INestApplication } from '@nestjs/common';
|
import type { INestApplication } from '@nestjs/common';
|
||||||
import { Test } from '@nestjs/testing';
|
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
import ava, { type TestFn } from 'ava';
|
import ava, { type TestFn } from 'ava';
|
||||||
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
|
|
||||||
import { AppModule } from '../src/app';
|
import { AppModule } from '../src/app';
|
||||||
import { RevertCommand, RunCommand } from '../src/data/commands/run';
|
import { PrismaService } from '../src/prisma';
|
||||||
import {
|
import {
|
||||||
acceptInviteById,
|
acceptInviteById,
|
||||||
|
createTestingApp,
|
||||||
createWorkspace,
|
createWorkspace,
|
||||||
currentUser,
|
currentUser,
|
||||||
getPublicWorkspace,
|
getPublicWorkspace,
|
||||||
getWorkspacePublicPages,
|
getWorkspacePublicPages,
|
||||||
initFeatureConfigs,
|
|
||||||
inviteUser,
|
inviteUser,
|
||||||
publishPage,
|
publishPage,
|
||||||
revokePublicPage,
|
revokePublicPage,
|
||||||
@@ -27,30 +25,12 @@ const test = ava as TestFn<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
test.beforeEach(async t => {
|
test.beforeEach(async t => {
|
||||||
const client = new PrismaClient();
|
const { app } = await createTestingApp({
|
||||||
await client.$connect();
|
|
||||||
await client.user.deleteMany({});
|
|
||||||
await client.update.deleteMany({});
|
|
||||||
await client.snapshot.deleteMany({});
|
|
||||||
await client.workspace.deleteMany({});
|
|
||||||
await client.$disconnect();
|
|
||||||
const module = await Test.createTestingModule({
|
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
providers: [RevertCommand, RunCommand],
|
});
|
||||||
}).compile();
|
|
||||||
const app = module.createNestApplication();
|
|
||||||
app.use(
|
|
||||||
graphqlUploadExpress({
|
|
||||||
maxFileSize: 10 * 1024 * 1024,
|
|
||||||
maxFiles: 5,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
await app.init();
|
|
||||||
t.context.client = client;
|
|
||||||
t.context.app = app;
|
|
||||||
|
|
||||||
// init features
|
t.context.client = app.get(PrismaService);
|
||||||
await initFeatureConfigs(module);
|
t.context.app = app;
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach.always(async t => {
|
test.afterEach.always(async t => {
|
||||||
|
|||||||
Reference in New Issue
Block a user