test: add note controller case (#939)
This commit is contained in:
@@ -13,3 +13,5 @@ packages/*/test
|
||||
packages/*/tests
|
||||
packages/*/esm
|
||||
packages/*/types
|
||||
|
||||
test/**/*.db.ts
|
||||
|
||||
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -6,6 +6,8 @@ on:
|
||||
- '**'
|
||||
tags:
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- test/**
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
|
||||
103
test/helper/create-e2e-app.ts
Normal file
103
test/helper/create-e2e-app.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { ModuleMetadata } from '@nestjs/common'
|
||||
import { APP_INTERCEPTOR } from '@nestjs/core'
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
import { BeAnObject, ReturnModelType } from '@typegoose/typegoose/lib/types'
|
||||
|
||||
import { HttpCacheInterceptor } from '~/common/interceptors/cache.interceptor'
|
||||
import { DbQueryInterceptor } from '~/common/interceptors/db-query.interceptor'
|
||||
import { JSONTransformInterceptor } from '~/common/interceptors/json-transform.interceptor'
|
||||
import { ResponseFilterInterceptor } from '~/common/interceptors/response-filter.interceptor'
|
||||
import { ResponseInterceptor } from '~/common/interceptors/response.interceptor'
|
||||
import { getModelToken } from '~/transformers/model.transformer'
|
||||
|
||||
import { dbHelper } from './db-mock.helper'
|
||||
import { redisHelper } from './redis-mock.helper'
|
||||
import { setupE2EApp } from './setup-e2e'
|
||||
|
||||
type ClassType = new (...args: any[]) => any
|
||||
|
||||
type ModelMap = Map<
|
||||
ClassType,
|
||||
{
|
||||
name: string
|
||||
token: string
|
||||
model: ReturnModelType<ClassType, BeAnObject>
|
||||
}
|
||||
>
|
||||
interface E2EAppMetaData {
|
||||
models?: ClassType[]
|
||||
pourData?: (modelMap: ModelMap) => Promise<void | (() => Promise<any>)>
|
||||
}
|
||||
|
||||
export const createE2EApp = (module: ModuleMetadata & E2EAppMetaData) => {
|
||||
const proxy: {
|
||||
app: NestFastifyApplication
|
||||
} = {} as any
|
||||
|
||||
let pourDataCleanup: (() => Promise<void>) | undefined
|
||||
|
||||
beforeAll(async () => {
|
||||
const { CacheService, token } = await redisHelper
|
||||
const { models, pourData, ...nestModule } = module
|
||||
nestModule.providers ||= []
|
||||
|
||||
nestModule.providers.push(
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: DbQueryInterceptor,
|
||||
},
|
||||
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: HttpCacheInterceptor, // 5
|
||||
},
|
||||
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: JSONTransformInterceptor, // 3
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: ResponseFilterInterceptor, // 2
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: ResponseInterceptor, // 1
|
||||
},
|
||||
)
|
||||
|
||||
nestModule.providers.push({ provide: token, useValue: CacheService })
|
||||
const modelMap = new Map() as ModelMap
|
||||
if (models) {
|
||||
models.forEach((model) => {
|
||||
const token = getModelToken(model.name)
|
||||
const modelInstance = dbHelper.getModel(model)
|
||||
nestModule.providers.push({
|
||||
provide: token,
|
||||
useValue: modelInstance,
|
||||
})
|
||||
modelMap.set(model, {
|
||||
name: model.name,
|
||||
token,
|
||||
model: modelInstance,
|
||||
})
|
||||
})
|
||||
}
|
||||
if (pourData) {
|
||||
const cleanup = await pourData(modelMap)
|
||||
// @ts-ignore
|
||||
pourDataCleanup = cleanup
|
||||
}
|
||||
const app = await setupE2EApp(nestModule)
|
||||
|
||||
proxy.app = app
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
if (pourDataCleanup) {
|
||||
return await pourDataCleanup()
|
||||
}
|
||||
})
|
||||
|
||||
return proxy
|
||||
}
|
||||
74
test/helper/db-mock.helper copy.ts
Normal file
74
test/helper/db-mock.helper copy.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { MongoMemoryServer } from 'mongodb-memory-server'
|
||||
import mongoose from 'mongoose'
|
||||
import { nanoid } from 'nanoid/async'
|
||||
|
||||
import { getModelForClass } from '@typegoose/typegoose'
|
||||
import {
|
||||
AnyParamConstructor,
|
||||
BeAnObject,
|
||||
IModelOptions,
|
||||
ReturnModelType,
|
||||
} from '@typegoose/typegoose/lib/types'
|
||||
|
||||
let mongod: MongoMemoryServer
|
||||
|
||||
const dbMap = new Map<string, typeof mongoose>()
|
||||
/**
|
||||
|
||||
* Connect to mock memory db.
|
||||
*/
|
||||
const connect = async () => {
|
||||
mongod = await MongoMemoryServer.create()
|
||||
const uri = mongod.getUri()
|
||||
|
||||
const mongooseInstance = await mongoose.connect(uri, {
|
||||
autoIndex: true,
|
||||
maxPoolSize: 10,
|
||||
})
|
||||
const id = await nanoid()
|
||||
dbMap.set(id, mongooseInstance)
|
||||
return id
|
||||
}
|
||||
|
||||
/**
|
||||
* Close db connection
|
||||
*/
|
||||
const closeDatabase = async (id: string) => {
|
||||
const mongoose = dbMap.get(id)
|
||||
if (!mongoose) {
|
||||
return
|
||||
}
|
||||
await mongoose.connection.dropDatabase()
|
||||
await mongoose.connection.close()
|
||||
dbMap.delete(id)
|
||||
if (dbMap.size === 0) await mongod.stop()
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete db collections
|
||||
*/
|
||||
const clearDatabase = async (id: string) => {
|
||||
const mongoose = dbMap.get(id)
|
||||
if (!mongoose) {
|
||||
return
|
||||
}
|
||||
const collections = mongoose.connection.collections
|
||||
|
||||
for (const key in collections) {
|
||||
const collection = collections[key]
|
||||
await collection.deleteMany({})
|
||||
}
|
||||
}
|
||||
|
||||
export const dbHelper = {
|
||||
connect,
|
||||
close: () => closeDatabase(),
|
||||
clear: () => clearDatabase(),
|
||||
|
||||
getModel<U extends AnyParamConstructor<any>, QueryHelpers = BeAnObject>(
|
||||
cl: U,
|
||||
options?: IModelOptions,
|
||||
): ReturnModelType<U, QueryHelpers> {
|
||||
return getModelForClass(cl, options)
|
||||
},
|
||||
}
|
||||
@@ -55,6 +55,10 @@ export const dbHelper = {
|
||||
cl: U,
|
||||
options?: IModelOptions,
|
||||
): ReturnModelType<U, QueryHelpers> {
|
||||
return getModelForClass(cl, options)
|
||||
return getModelForClass(cl, {
|
||||
existingMongoose: mongoose,
|
||||
existingConnection: mongoose.connection,
|
||||
...options,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
12
test/helper/defineProvider.ts
Normal file
12
test/helper/defineProvider.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface Provider<T = unknown> {
|
||||
provide: new (...args: any[]) => T
|
||||
useValue: Partial<T>
|
||||
}
|
||||
|
||||
export const defineProvider = <T>(provider: Provider<T>) => {
|
||||
return provider
|
||||
}
|
||||
|
||||
export const defineProviders = (providers: Provider[]) => {
|
||||
return providers
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { ValidationPipe } from '@nestjs/common'
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
import { TestingModule } from '@nestjs/testing'
|
||||
|
||||
import { fastifyApp } from '~/common/adapters/fastify.adapter'
|
||||
|
||||
export const setupE2EApp = async (module: TestingModule) => {
|
||||
const app = module.createNestApplication<NestFastifyApplication>(fastifyApp)
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
transform: true,
|
||||
whitelist: true,
|
||||
errorHttpStatusCode: 422,
|
||||
forbidUnknownValues: true,
|
||||
enableDebugMessages: isDev,
|
||||
stopAtFirstError: true,
|
||||
}),
|
||||
)
|
||||
|
||||
await app.init()
|
||||
await app.getHttpAdapter().getInstance().ready()
|
||||
return app
|
||||
}
|
||||
31
test/helper/setup-e2e.ts
Normal file
31
test/helper/setup-e2e.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ModuleMetadata, ValidationPipe } from '@nestjs/common'
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
import { Test, TestingModule } from '@nestjs/testing'
|
||||
|
||||
import { fastifyApp } from '~/common/adapters/fastify.adapter'
|
||||
|
||||
export const setupE2EApp = async (module: TestingModule | ModuleMetadata) => {
|
||||
let nextModule: TestingModule
|
||||
if (module instanceof TestingModule) {
|
||||
nextModule = module
|
||||
} else {
|
||||
nextModule = await Test.createTestingModule(module).compile()
|
||||
}
|
||||
|
||||
const app =
|
||||
nextModule.createNestApplication<NestFastifyApplication>(fastifyApp)
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
transform: true,
|
||||
whitelist: true,
|
||||
errorHttpStatusCode: 422,
|
||||
forbidUnknownValues: true,
|
||||
enableDebugMessages: isDev,
|
||||
stopAtFirstError: true,
|
||||
}),
|
||||
)
|
||||
|
||||
await app.init()
|
||||
await app.getHttpAdapter().getInstance().ready()
|
||||
return app
|
||||
}
|
||||
8
test/mock/modules/auth.mock.ts
Normal file
8
test/mock/modules/auth.mock.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineProvider } from 'test/helper/defineProvider'
|
||||
|
||||
import { AuthService } from '~/modules/auth/auth.service'
|
||||
|
||||
export const authProvider = defineProvider({
|
||||
useValue: {},
|
||||
provide: AuthService,
|
||||
})
|
||||
12
test/mock/modules/comment.mock.ts
Normal file
12
test/mock/modules/comment.mock.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { dbHelper } from 'test/helper/db-mock.helper'
|
||||
import { defineProvider } from 'test/helper/defineProvider'
|
||||
|
||||
import { CommentModel } from '~/modules/comment/comment.model'
|
||||
import { CommentService } from '~/modules/comment/comment.service'
|
||||
|
||||
export const commentProvider = defineProvider({
|
||||
provide: CommentService,
|
||||
useValue: {
|
||||
model: dbHelper.getModel(CommentModel) as any,
|
||||
},
|
||||
})
|
||||
20
test/mock/modules/config.mock.ts
Normal file
20
test/mock/modules/config.mock.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { defineProvider } from 'test/helper/defineProvider'
|
||||
|
||||
import { generateDefaultConfig } from '~/modules/configs/configs.default'
|
||||
import { ConfigsService } from '~/modules/configs/configs.service'
|
||||
|
||||
export const configProvider = defineProvider({
|
||||
provide: ConfigsService,
|
||||
useValue: {
|
||||
defaultConfig: generateDefaultConfig(),
|
||||
async get(key) {
|
||||
return this.defaultConfig[key]
|
||||
},
|
||||
async getConfig() {
|
||||
return this.defaultConfig
|
||||
},
|
||||
async waitForConfigReady() {
|
||||
return this.defaultConfig
|
||||
},
|
||||
},
|
||||
})
|
||||
20
test/mock/modules/gateway.mock.ts
Normal file
20
test/mock/modules/gateway.mock.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { defineProviders } from 'test/helper/defineProvider'
|
||||
|
||||
import { AdminEventsGateway } from '~/processors/gateway/admin/events.gateway'
|
||||
import { SystemEventsGateway } from '~/processors/gateway/system/events.gateway'
|
||||
import { WebEventsGateway } from '~/processors/gateway/web/events.gateway'
|
||||
|
||||
export const gatewayProviders = defineProviders([
|
||||
{
|
||||
provide: WebEventsGateway,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: AdminEventsGateway,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: SystemEventsGateway,
|
||||
useValue: {},
|
||||
},
|
||||
])
|
||||
18
test/mock/processors/counting.mock.ts
Normal file
18
test/mock/processors/counting.mock.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineProvider } from 'test/helper/defineProvider'
|
||||
|
||||
import { CountingService } from '~/processors/helper/helper.counting.service'
|
||||
|
||||
export const countingServiceProvider = defineProvider({
|
||||
useValue: {
|
||||
async updateLikeCount() {
|
||||
return true
|
||||
},
|
||||
async getThisRecordIsLiked() {
|
||||
return true
|
||||
},
|
||||
async updateReadCount() {
|
||||
return
|
||||
},
|
||||
},
|
||||
provide: CountingService,
|
||||
})
|
||||
12
test/mock/processors/text-macro.mock.ts
Normal file
12
test/mock/processors/text-macro.mock.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineProvider } from 'test/helper/defineProvider'
|
||||
|
||||
import { TextMacroService } from '~/processors/helper/helper.macro.service'
|
||||
|
||||
export const textMacroProvider = defineProvider({
|
||||
provide: TextMacroService,
|
||||
useValue: {
|
||||
async replaceTextMacro(text) {
|
||||
return text
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,7 +1,29 @@
|
||||
import { register } from '~/global/index.global'
|
||||
import { mkdirSync } from 'fs-extra'
|
||||
import { chalk } from 'zx'
|
||||
|
||||
import { Logger } from '@nestjs/common'
|
||||
|
||||
import {
|
||||
DATA_DIR,
|
||||
LOG_DIR,
|
||||
STATIC_FILE_DIR,
|
||||
TEMP_DIR,
|
||||
THEME_DIR,
|
||||
USER_ASSET_DIR,
|
||||
} from '~/constants/path.constant'
|
||||
|
||||
export async function setup() {
|
||||
await register()
|
||||
mkdirSync(DATA_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`数据目录已经建好:${DATA_DIR}`))
|
||||
mkdirSync(TEMP_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`临时目录已经建好:${TEMP_DIR}`))
|
||||
mkdirSync(LOG_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`日志目录已经建好:${LOG_DIR}`))
|
||||
mkdirSync(USER_ASSET_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`资源目录已经建好:${USER_ASSET_DIR}`))
|
||||
mkdirSync(STATIC_FILE_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`文件存放目录已经建好:${STATIC_FILE_DIR}`))
|
||||
mkdirSync(THEME_DIR, { recursive: true })
|
||||
}
|
||||
|
||||
export async function teardown() {}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import { beforeAll } from 'vitest'
|
||||
|
||||
import 'zx/globals'
|
||||
|
||||
import consola from 'consola'
|
||||
|
||||
beforeAll(async () => {
|
||||
await import('zx/globals')
|
||||
|
||||
global.isDev = true
|
||||
global.cwd = process.cwd()
|
||||
global.consola = consola
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
global.isDev = true
|
||||
global.cwd = process.cwd()
|
||||
global.consola = consola
|
||||
})
|
||||
37
test/setupFiles/lifecycle.ts
Normal file
37
test/setupFiles/lifecycle.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
// @ts-nocheck
|
||||
import { beforeAll } from 'vitest'
|
||||
|
||||
import 'zx/globals'
|
||||
|
||||
import consola from 'consola'
|
||||
import { dbHelper } from 'test/helper/db-mock.helper'
|
||||
import { redisHelper } from 'test/helper/redis-mock.helper'
|
||||
|
||||
import { registerJSONGlobal } from '~/global/json.global'
|
||||
|
||||
beforeAll(async () => {
|
||||
await import('zx/globals')
|
||||
|
||||
global.isDev = true
|
||||
global.cwd = process.cwd()
|
||||
global.consola = consola
|
||||
|
||||
registerJSONGlobal()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await dbHelper.clear()
|
||||
await dbHelper.close()
|
||||
await (await redisHelper).close()
|
||||
})
|
||||
|
||||
beforeAll(async () => {
|
||||
await dbHelper.connect()
|
||||
await redisHelper
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
global.isDev = true
|
||||
global.cwd = process.cwd()
|
||||
global.consola = consola
|
||||
})
|
||||
@@ -24,7 +24,6 @@ describe('AppController (e2e)', () => {
|
||||
})
|
||||
.overrideProvider(CacheService)
|
||||
.useValue({})
|
||||
|
||||
.compile()
|
||||
|
||||
app = moduleRef.createNestApplication<NestFastifyApplication>(fastifyApp)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { dbHelper } from 'test/helper/db-mock.helper'
|
||||
import { MockCacheService, redisHelper } from 'test/helper/redis-mock.helper'
|
||||
import { vi } from 'vitest'
|
||||
|
||||
@@ -20,11 +19,6 @@ describe('Test ConfigsService', () => {
|
||||
let service: ConfigsService
|
||||
|
||||
let redisService: MockCacheService
|
||||
afterAll(async () => {
|
||||
await dbHelper.clear()
|
||||
await dbHelper.close()
|
||||
await (await redisHelper).close()
|
||||
})
|
||||
|
||||
const optionModel = getModelForClass(OptionModel)
|
||||
const mockEmitFn = vi.fn()
|
||||
@@ -32,7 +26,6 @@ describe('Test ConfigsService', () => {
|
||||
const { CacheService: redisService$ } = await redisHelper
|
||||
|
||||
redisService = redisService$
|
||||
await dbHelper.connect()
|
||||
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
imports: [],
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`NoteController (e2e) > GET /latest 1`] = `
|
||||
{
|
||||
"data": {
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-20T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 20,
|
||||
"text": "Content 20",
|
||||
"title": "Note 20",
|
||||
"topic": null,
|
||||
},
|
||||
"next": {
|
||||
"nid": 19,
|
||||
"topic": null,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`NoteController (e2e) > GET /list/:id 1`] = `
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"created": "2023-01-17T11:01:57.851Z",
|
||||
"nid": 21,
|
||||
"title": "Note 2 (updated)",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"created": "2021-03-20T00:00:00.000Z",
|
||||
"nid": 20,
|
||||
"title": "Note 20",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"created": "2021-03-19T00:00:00.000Z",
|
||||
"nid": 19,
|
||||
"title": "Note 19",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"created": "2021-03-18T00:00:00.000Z",
|
||||
"nid": 18,
|
||||
"title": "Note 18",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"created": "2021-03-17T00:00:00.000Z",
|
||||
"nid": 17,
|
||||
"title": "Note 17",
|
||||
"topic": null,
|
||||
},
|
||||
],
|
||||
"size": 5,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-20T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 20,
|
||||
"text": "Content 20",
|
||||
"title": "Note 20",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-19T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 19,
|
||||
"text": "Content 19",
|
||||
"title": "Note 19",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-18T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 18,
|
||||
"text": "Content 18",
|
||||
"title": "Note 18",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-17T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 17,
|
||||
"text": "Content 17",
|
||||
"title": "Note 17",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-16T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 16,
|
||||
"text": "Content 16",
|
||||
"title": "Note 16",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-15T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 15,
|
||||
"text": "Content 15",
|
||||
"title": "Note 15",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-14T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 14,
|
||||
"text": "Content 14",
|
||||
"title": "Note 14",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-13T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 13,
|
||||
"text": "Content 13",
|
||||
"title": "Note 13",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-12T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 12,
|
||||
"text": "Content 12",
|
||||
"title": "Note 12",
|
||||
"topic": null,
|
||||
},
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-11T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 11,
|
||||
"text": "Content 11",
|
||||
"title": "Note 11",
|
||||
"topic": null,
|
||||
},
|
||||
],
|
||||
"pagination": {
|
||||
"current_page": 1,
|
||||
"has_next_page": true,
|
||||
"has_prev_page": false,
|
||||
"size": 10,
|
||||
"total": 20,
|
||||
"total_page": 2,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`NoteController (e2e) > Get patched note 1`] = `
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2023-01-17T11:01:57.851Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"modified": null,
|
||||
"mood": "happy",
|
||||
"music": [],
|
||||
"nid": 21,
|
||||
"text": "Content 2 (updated)",
|
||||
"title": "Note 2 (updated)",
|
||||
"topic": null,
|
||||
"weather": "sunny",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`NoteController (e2e) > POST /notes 1`] = `
|
||||
{
|
||||
"allow_comment": true,
|
||||
"comments_index": 0,
|
||||
"count": {
|
||||
"like": 0,
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2023-01-17T11:01:57.851Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"music": [],
|
||||
"nid": 21,
|
||||
"text": "Content 2",
|
||||
"title": "Note 2",
|
||||
}
|
||||
`;
|
||||
202
test/src/modules/note/note.controller.e2e-spec.ts
Normal file
202
test/src/modules/note/note.controller.e2e-spec.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import { createE2EApp } from 'test/helper/create-e2e-app'
|
||||
import { authProvider } from 'test/mock/modules/auth.mock'
|
||||
import { commentProvider } from 'test/mock/modules/comment.mock'
|
||||
import { configProvider } from 'test/mock/modules/config.mock'
|
||||
import { gatewayProviders } from 'test/mock/modules/gateway.mock'
|
||||
import { countingServiceProvider } from 'test/mock/processors/counting.mock'
|
||||
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter'
|
||||
import { ReturnModelType } from '@typegoose/typegoose'
|
||||
|
||||
import { OptionModel } from '~/modules/configs/configs.model'
|
||||
import { NoteController } from '~/modules/note/note.controller'
|
||||
import { NoteModel } from '~/modules/note/note.model'
|
||||
import { NoteService } from '~/modules/note/note.service'
|
||||
import { UserModel } from '~/modules/user/user.model'
|
||||
import { UserService } from '~/modules/user/user.service'
|
||||
import { CountingService } from '~/processors/helper/helper.counting.service'
|
||||
import { EventManagerService } from '~/processors/helper/helper.event.service'
|
||||
import { HttpService } from '~/processors/helper/helper.http.service'
|
||||
import { ImageService } from '~/processors/helper/helper.image.service'
|
||||
import { TextMacroService } from '~/processors/helper/helper.macro.service'
|
||||
import { SubPubBridgeService } from '~/processors/redis/subpub.service'
|
||||
|
||||
import MockDbData from './note.e2e-mock.db'
|
||||
|
||||
describe('NoteController (e2e)', () => {
|
||||
let model: ReturnModelType<typeof NoteModel>
|
||||
const proxy = createE2EApp({
|
||||
controllers: [NoteController],
|
||||
providers: [
|
||||
NoteService,
|
||||
ImageService,
|
||||
EventManagerService,
|
||||
commentProvider,
|
||||
|
||||
{
|
||||
provide: TextMacroService,
|
||||
useValue: {
|
||||
async replaceTextMacro(text) {
|
||||
return text
|
||||
},
|
||||
},
|
||||
},
|
||||
HttpService,
|
||||
configProvider,
|
||||
EventEmitter2,
|
||||
UserService,
|
||||
SubPubBridgeService,
|
||||
...gatewayProviders,
|
||||
authProvider,
|
||||
CountingService,
|
||||
countingServiceProvider,
|
||||
],
|
||||
imports: [],
|
||||
models: [NoteModel, OptionModel, UserModel],
|
||||
async pourData(modelMap) {
|
||||
// @ts-ignore
|
||||
const { model: _model } = modelMap.get(NoteModel) as {
|
||||
model: ReturnModelType<typeof NoteModel>
|
||||
}
|
||||
model = _model
|
||||
for await (const data of MockDbData) {
|
||||
await _model.create(data)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await model.deleteMany({})
|
||||
})
|
||||
|
||||
test('GET /notes', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/notes',
|
||||
})
|
||||
const data = res.json()
|
||||
expect(res.statusCode).toBe(200)
|
||||
|
||||
data.data.forEach((d) => {
|
||||
delete d.id
|
||||
delete d._id
|
||||
})
|
||||
expect(data).toMatchSnapshot()
|
||||
})
|
||||
|
||||
const createdNoteData: Partial<NoteModel> = {
|
||||
title: 'Note 2',
|
||||
text: 'Content 2',
|
||||
|
||||
allowComment: true,
|
||||
// use cutsom date
|
||||
created: new Date('2023-01-17T11:01:57.851Z'),
|
||||
}
|
||||
|
||||
test('POST /notes', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/notes',
|
||||
payload: createdNoteData,
|
||||
})
|
||||
|
||||
const data = res.json()
|
||||
expect(res.statusCode).toBe(201)
|
||||
createdNoteData.id = data.id
|
||||
createdNoteData.nid = data.nid
|
||||
delete data.id
|
||||
expect(data).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('PATCH /notes/:id', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'PATCH',
|
||||
url: `/notes/${createdNoteData.id}`,
|
||||
payload: {
|
||||
title: 'Note 2 (updated)',
|
||||
text: `Content 2 (updated)`,
|
||||
mood: 'happy',
|
||||
weather: 'sunny',
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(204)
|
||||
})
|
||||
|
||||
test('Get patched note', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: `/notes/${createdNoteData.id}`,
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(200)
|
||||
const data = res.json()
|
||||
delete data.id
|
||||
expect(data).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('GET /list/:id', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: `/notes/list/${createdNoteData.id}`,
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(200)
|
||||
const data = res.json()
|
||||
|
||||
data.data.forEach((note) => {
|
||||
delete note.id
|
||||
})
|
||||
|
||||
expect(data).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('DEL /notes/:id', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'DELETE',
|
||||
url: `/notes/${createdNoteData.id}`,
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(204)
|
||||
})
|
||||
|
||||
it('should got 404 when get deleted note', async () => {
|
||||
const { app } = proxy
|
||||
{
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: `/notes/${createdNoteData.id}`,
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(404)
|
||||
}
|
||||
{
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: `/notes/nid/${createdNoteData.nid}`,
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(404)
|
||||
}
|
||||
})
|
||||
|
||||
test('GET /latest', async () => {
|
||||
const { app } = proxy
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/notes/latest',
|
||||
})
|
||||
|
||||
expect(res.statusCode).toBe(200)
|
||||
const data = res.json()
|
||||
delete data.data.id
|
||||
delete data.next.id
|
||||
expect(data).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
15
test/src/modules/note/note.e2e-mock.db.ts
Normal file
15
test/src/modules/note/note.e2e-mock.db.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { NoteModel } from '~/modules/note/note.model'
|
||||
|
||||
export default Array.from({ length: 20 }).map((_, _i) => {
|
||||
const i = _i + 1
|
||||
return {
|
||||
title: 'Note ' + i,
|
||||
text: 'Content ' + i,
|
||||
created: new Date(`2021-03-${i.toFixed().padStart(2, '0')}T00:00:00.000Z`),
|
||||
modified: null,
|
||||
allowComment: true,
|
||||
|
||||
hide: false,
|
||||
commentsIndex: 0,
|
||||
}
|
||||
}) as NoteModel[]
|
||||
@@ -1,34 +1,15 @@
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
import { Test } from '@nestjs/testing'
|
||||
import { createE2EApp } from 'test/helper/create-e2e-app'
|
||||
import { configProvider } from 'test/mock/modules/config.mock'
|
||||
|
||||
import { fastifyApp } from '~/common/adapters/fastify.adapter'
|
||||
import { generateDefaultConfig } from '~/modules/configs/configs.default'
|
||||
import { ConfigsService } from '~/modules/configs/configs.service'
|
||||
import { BaseOptionController } from '~/modules/option/controllers/base.option.controller'
|
||||
|
||||
describe('OptionController (e2e)', () => {
|
||||
let app: NestFastifyApplication
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
const proxy = createE2EApp({
|
||||
controllers: [BaseOptionController],
|
||||
providers: [
|
||||
{
|
||||
provide: ConfigsService,
|
||||
useValue: {
|
||||
defaultConfig: generateDefaultConfig(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile()
|
||||
|
||||
app = moduleRef.createNestApplication<NestFastifyApplication>(fastifyApp)
|
||||
await app.init()
|
||||
await app.getHttpAdapter().getInstance().ready()
|
||||
providers: [configProvider],
|
||||
})
|
||||
|
||||
test('GET /config/jsonschema', () => {
|
||||
return app
|
||||
return proxy.app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/config/jsonschema',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { dbHelper } from 'test/helper/db-mock.helper'
|
||||
import mongoose from 'mongoose'
|
||||
import { redisHelper } from 'test/helper/redis-mock.helper'
|
||||
|
||||
import { Test } from '@nestjs/testing'
|
||||
@@ -17,9 +17,6 @@ describe('test serverless function service', () => {
|
||||
let service: ServerlessService
|
||||
|
||||
beforeAll(async () => {
|
||||
const connection = await dbHelper.connect()
|
||||
|
||||
await (await redisHelper).connect()
|
||||
const moduleRef = Test.createTestingModule({
|
||||
providers: [
|
||||
ServerlessService,
|
||||
@@ -32,15 +29,13 @@ describe('test serverless function service', () => {
|
||||
{
|
||||
provide: DatabaseService,
|
||||
useValue: {
|
||||
db: connection.connection.db,
|
||||
db: mongoose.connection.db,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
provide: getModelToken('SnippetModel'),
|
||||
useValue: getModelForClass(SnippetModel, {
|
||||
existingConnection: connection.connection,
|
||||
}),
|
||||
useValue: getModelForClass(SnippetModel),
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -50,12 +45,6 @@ describe('test serverless function service', () => {
|
||||
service = app.get(ServerlessService)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await dbHelper.clear()
|
||||
await dbHelper.close()
|
||||
;(await redisHelper).close()
|
||||
})
|
||||
|
||||
describe('run serverless function', () => {
|
||||
test('case-1', async () => {
|
||||
const model = new SnippetModel()
|
||||
|
||||
@@ -1,54 +1,21 @@
|
||||
import { dbHelper } from 'test/helper/db-mock.helper'
|
||||
import { MockCacheService, redisHelper } from 'test/helper/redis-mock.helper'
|
||||
import { setupE2EApp } from 'test/helper/register-app.helper'
|
||||
import { createE2EApp } from 'test/helper/create-e2e-app'
|
||||
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
import { Test } from '@nestjs/testing'
|
||||
import { getModelForClass } from '@typegoose/typegoose'
|
||||
|
||||
import { ServerlessService } from '~/modules/serverless/serverless.service'
|
||||
import { SnippetController } from '~/modules/snippet/snippet.controller'
|
||||
import { SnippetModel, SnippetType } from '~/modules/snippet/snippet.model'
|
||||
import { SnippetService } from '~/modules/snippet/snippet.service'
|
||||
import { DatabaseService } from '~/processors/database/database.service'
|
||||
import { CacheService } from '~/processors/redis/cache.service'
|
||||
import { getModelToken } from '~/transformers/model.transformer'
|
||||
|
||||
describe('test /snippets', () => {
|
||||
let app: NestFastifyApplication
|
||||
|
||||
beforeAll(async () => {
|
||||
await dbHelper.connect()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await dbHelper.clear()
|
||||
await dbHelper.close()
|
||||
})
|
||||
const model = getModelForClass(SnippetModel)
|
||||
|
||||
const mockPayload1: Partial<SnippetModel> = Object.freeze({
|
||||
name: 'Snippet_1',
|
||||
private: false,
|
||||
raw: JSON.stringify({ foo: 'bar' }),
|
||||
type: SnippetType.JSON,
|
||||
})
|
||||
let redisService: MockCacheService
|
||||
|
||||
afterAll(async () => {
|
||||
await (await redisHelper).close()
|
||||
})
|
||||
beforeAll(async () => {
|
||||
const { CacheService: redisService$ } = await redisHelper
|
||||
|
||||
redisService = redisService$
|
||||
|
||||
const ref = await Test.createTestingModule({
|
||||
const proxy = createE2EApp({
|
||||
controllers: [SnippetController],
|
||||
providers: [
|
||||
SnippetService,
|
||||
{ provide: DatabaseService, useValue: {} },
|
||||
{ provide: CacheService, useValue: redisService },
|
||||
|
||||
{
|
||||
provide: ServerlessService,
|
||||
useValue: {
|
||||
@@ -57,14 +24,19 @@ describe('test /snippets', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: getModelToken(SnippetModel.name),
|
||||
useValue: model,
|
||||
},
|
||||
],
|
||||
}).compile()
|
||||
models: [SnippetModel],
|
||||
})
|
||||
|
||||
app = await setupE2EApp(ref)
|
||||
const mockPayload1: Partial<SnippetModel> = Object.freeze({
|
||||
name: 'Snippet_1',
|
||||
private: false,
|
||||
raw: JSON.stringify({ foo: 'bar' }),
|
||||
type: SnippetType.JSON,
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
app = proxy.app
|
||||
})
|
||||
|
||||
test('POST /snippets, should 422 with wrong name', async () => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { dbHelper } from 'test/helper/db-mock.helper'
|
||||
import { redisHelper } from 'test/helper/redis-mock.helper'
|
||||
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common'
|
||||
@@ -14,12 +13,8 @@ import { getModelToken } from '~/transformers/model.transformer'
|
||||
|
||||
describe('test Snippet Service', () => {
|
||||
let service: SnippetService
|
||||
afterAll(async () => {
|
||||
await (await redisHelper).close()
|
||||
})
|
||||
beforeAll(async () => {
|
||||
await dbHelper.connect()
|
||||
|
||||
beforeAll(async () => {
|
||||
const redis = await redisHelper
|
||||
const moduleRef = Test.createTestingModule({
|
||||
providers: [
|
||||
@@ -40,10 +35,6 @@ describe('test Snippet Service', () => {
|
||||
service = app.get(SnippetService)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await dbHelper.close()
|
||||
})
|
||||
|
||||
const snippet = {
|
||||
name: 'test',
|
||||
raw: '{"foo": "bar"}',
|
||||
|
||||
@@ -14,13 +14,7 @@ import { getModelToken } from '~/transformers/model.transformer'
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: NestFastifyApplication
|
||||
|
||||
afterAll(async () => {
|
||||
await dbHelper.close()
|
||||
await (await redisHelper).close()
|
||||
})
|
||||
|
||||
beforeAll(async () => {
|
||||
await dbHelper.connect()
|
||||
const { CacheService, token } = await redisHelper
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
controllers: [UserController],
|
||||
|
||||
@@ -8,10 +8,6 @@ import { CacheService } from '~/processors/redis/cache.service'
|
||||
describe('test jwt service', () => {
|
||||
let service: JWTService
|
||||
|
||||
afterAll(async () => {
|
||||
await (await redisHelper).close()
|
||||
})
|
||||
|
||||
beforeAll(async () => {
|
||||
const { CacheService: MCacheService } = await redisHelper
|
||||
const moduleRef = Test.createTestingModule({
|
||||
|
||||
@@ -30,5 +30,12 @@
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./src/**/*.tsx",
|
||||
"./src/**/*.js",
|
||||
"./src/**/*.jsx",
|
||||
"./**/*.ts",
|
||||
],
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export default defineConfig({
|
||||
name: 'a-vitest-plugin-that-changes-config',
|
||||
config: () => ({
|
||||
test: {
|
||||
setupFiles: ['./setupFiles/add-something-to-global.ts'],
|
||||
setupFiles: ['./setupFiles/lifecycle.ts'],
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user