test: add mock db test

This commit is contained in:
Innei
2022-01-14 15:36:17 +08:00
parent f4e0f713d2
commit 12a2da7d3c
11 changed files with 280 additions and 45 deletions

View File

@@ -1,30 +1,26 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { pathsToModuleNameMapper } = require('ts-jest/utils')
const { pathsToModuleNameMapper } = require('ts-jest')
// In the following statement, replace `./tsconfig` with the path to your `tsconfig` file
// which contains the path mapping (ie the `compilerOptions.paths` option):
const { compilerOptions } = require('./tsconfig.json')
const { cd, $, chalk } = require('zx')
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: '.',
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
},
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
extensionsToTreatAsEsm: ['.ts'],
preset: 'ts-jest/presets/default-esm',
preset: 'ts-jest',
testEnvironment: 'node',
globals: {
'ts-jest': {
useESM: true,
},
isDev: process.env.NODE_ENV === 'development',
$,
chalk,
cd,
},
setupFiles: ['./test-setup.js'],
moduleNameMapper: {
...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),

View File

@@ -150,6 +150,7 @@
"jest": "27.4.7",
"lint-staged": "12.1.7",
"mockingoose": "2.15.2",
"mongodb-memory-server": "8.1.0",
"prettier": "2.5.1",
"rimraf": "3.0.2",
"run-script-webpack-plugin": "0.0.11",

130
pnpm-lock.yaml generated
View File

@@ -73,6 +73,7 @@ specifiers:
marked: 4.0.9
mkdirp: '*'
mockingoose: 2.15.2
mongodb-memory-server: 8.1.0
mongoose: '*'
mongoose-lean-id: 0.3.0
mongoose-lean-virtuals: 0.9.0
@@ -193,6 +194,7 @@ devDependencies:
jest: 27.4.7_ts-node@10.4.0
lint-staged: 12.1.7
mockingoose: 2.15.2_mongoose@6.1.6
mongodb-memory-server: 8.1.0
prettier: 2.5.1
rimraf: 3.0.2
run-script-webpack-plugin: 0.0.11
@@ -2116,6 +2118,10 @@ packages:
resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
dev: true
/@types/tmp/0.2.3:
resolution: {integrity: sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==}
dev: true
/@types/ua-parser-js/0.7.36:
resolution: {integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==}
dev: true
@@ -2877,6 +2883,12 @@ packages:
engines: {node: '>=8'}
dev: true
/async-mutex/0.3.2:
resolution: {integrity: sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==}
dependencies:
tslib: 2.3.1
dev: true
/async-retry/1.3.3:
resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==}
dependencies:
@@ -3130,6 +3142,10 @@ packages:
dependencies:
buffer: 5.7.1
/buffer-crc32/0.2.13:
resolution: {integrity: sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=}
dev: true
/buffer-equal-constant-time/1.0.1:
resolution: {integrity: sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=}
dev: false
@@ -3210,6 +3226,11 @@ packages:
resolution: {integrity: sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==}
engines: {node: '>=10'}
/camelcase/6.3.0:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
engines: {node: '>=10'}
dev: true
/caniuse-lite/1.0.30001279:
resolution: {integrity: sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ==}
dev: true
@@ -3424,6 +3445,10 @@ packages:
engines: {node: '>= 12'}
dev: true
/commondir/1.0.1:
resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=}
dev: true
/component-emitter/1.3.0:
resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
@@ -4457,6 +4482,12 @@ packages:
bser: 2.1.1
dev: true
/fd-slicer/1.1.0:
resolution: {integrity: sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=}
dependencies:
pend: 1.2.0
dev: true
/figures/3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
@@ -4487,6 +4518,15 @@ packages:
dependencies:
to-regex-range: 5.0.1
/find-cache-dir/3.3.2:
resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==}
engines: {node: '>=8'}
dependencies:
commondir: 1.0.1
make-dir: 3.1.0
pkg-dir: 4.2.0
dev: true
/find-my-way/4.5.1:
resolution: {integrity: sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==}
engines: {node: '>=10'}
@@ -4612,6 +4652,10 @@ packages:
resolution: {integrity: sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=}
dev: false
/fs-constants/1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: true
/fs-extra/10.0.0:
resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==}
engines: {node: '>=12'}
@@ -4693,6 +4737,11 @@ packages:
engines: {node: '>=8.0.0'}
dev: true
/get-port/5.1.1:
resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
engines: {node: '>=8'}
dev: true
/get-stream/5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
@@ -6302,6 +6351,12 @@ packages:
hasBin: true
dev: false
/md5-file/5.0.0:
resolution: {integrity: sha512-xbEFXCYVWrSx/gEKS1VPlg84h/4L20znVIulKw6kMfmBUAZNAnF00eczz9ICMl+/hjQGo5KSXRxbL/47X3rmMw==}
engines: {node: '>=10.13.0'}
hasBin: true
dev: true
/memfs/3.3.0:
resolution: {integrity: sha512-BEE62uMfKOavX3iG7GYX43QJ+hAeeWnwIAuJ/R6q96jaMtiLzhsxHJC8B1L7fK7Pt/vXDRwb3SG/yBpNGDPqzg==}
engines: {node: '>= 4.0.0'}
@@ -6429,6 +6484,41 @@ packages:
'@types/whatwg-url': 8.2.1
whatwg-url: 11.0.0
/mongodb-memory-server-core/8.1.0:
resolution: {integrity: sha512-U9NZc07OqiOOymrYn6g9yrAaB2VLp5RFUJ+vhjxcgrvZ/7tHQVX2OmhQfOlevzW1Pt1KvFhqe7ysioysPxQXYg==}
engines: {node: '>=12.22.0'}
dependencies:
'@types/tmp': 0.2.3
async-mutex: 0.3.2
camelcase: 6.3.0
debug: 4.3.3
find-cache-dir: 3.3.2
get-port: 5.1.1
https-proxy-agent: 5.0.0
md5-file: 5.0.0
mongodb: 4.2.2
new-find-package-json: 1.1.0
semver: 7.3.5
tar-stream: 2.2.0
tmp: 0.2.1
tslib: 2.3.1
uuid: 8.3.2
yauzl: 2.10.0
transitivePeerDependencies:
- supports-color
dev: true
/mongodb-memory-server/8.1.0:
resolution: {integrity: sha512-nV3bS2XxguZC/KUAgNyX/bYruxlW/xdwYKIcbq4VTWiSFdwXJAcn4gh1WVrlMcfRFOYF4Pyk/NrZeeuqpbM+Bw==}
engines: {node: '>=12.22.0'}
requiresBuild: true
dependencies:
mongodb-memory-server-core: 8.1.0
tslib: 2.3.1
transitivePeerDependencies:
- supports-color
dev: true
/mongodb/4.2.2:
resolution: {integrity: sha512-zt8rCTnTKyMQppyt63qMnrLM5dbADgUk18ORPF1XbtHLIYCyc9hattaYHi0pqMvNxDpgGgUofSVzS+UQErgTug==}
engines: {node: '>=12.9.0'}
@@ -6544,6 +6634,16 @@ packages:
reflect-metadata: 0.1.13
dev: false
/new-find-package-json/1.1.0:
resolution: {integrity: sha512-KOH3BNZcTKPzEkaJgG2iSUaurxKmefqRKmCOYH+8xqJytNIgjqU4J88BHfK+gy/UlEzlhccLyuJDJAcCgexSwA==}
engines: {node: '>=12.22.0'}
dependencies:
debug: 4.3.3
tslib: 2.3.1
transitivePeerDependencies:
- supports-color
dev: true
/no-case/2.3.2:
resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
dependencies:
@@ -6945,6 +7045,10 @@ packages:
resolution: {integrity: sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=}
dev: false
/pend/1.2.0:
resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=}
dev: true
/performance-now/2.1.0:
resolution: {integrity: sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=}
dev: false
@@ -7945,6 +8049,17 @@ packages:
engines: {node: '>=6'}
dev: true
/tar-stream/2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.0
dev: true
/tar/6.1.11:
resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
engines: {node: '>= 10'}
@@ -8084,6 +8199,13 @@ packages:
dependencies:
os-tmpdir: 1.0.2
/tmp/0.2.1:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
dependencies:
rimraf: 3.0.2
dev: true
/tmpl/1.0.5:
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
dev: true
@@ -8385,7 +8507,6 @@ packages:
/uuid/8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
dev: false
/v8-compile-cache/2.3.0:
resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
@@ -8800,6 +8921,13 @@ packages:
yargs-parser: 20.2.9
dev: true
/yauzl/2.10.0:
resolution: {integrity: sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=}
dependencies:
buffer-crc32: 0.2.13
fd-slicer: 1.1.0
dev: true
/yn/3.1.1:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
engines: {node: '>=6'}

View File

@@ -46,7 +46,7 @@ import { SnippetModule } from './modules/snippet/snippet.module'
import { ToolModule } from './modules/tool/tool.module'
import { UserModule } from './modules/user/user.module'
import { CacheModule } from './processors/cache/cache.module'
import { DbModule } from './processors/database/database.module'
import { DatabaseModule } from './processors/database/database.module'
import { GatewayModule } from './processors/gateway/gateway.module'
import { HelperModule } from './processors/helper/helper.module'
import { LoggerModule } from './processors/logger/logger.module'
@@ -65,7 +65,7 @@ mkdirs()
@Module({
imports: [
DbModule,
DatabaseModule,
CacheModule,
GraphQLModule.forRoot({

View File

@@ -82,8 +82,7 @@ export class SnippetController {
async update(@Param() param: MongoIdDto, @Body() body: SnippetModel) {
const { id } = param
await this.snippetService.update(id, body)
return await this.snippetService.getSnippetById(id)
return await this.snippetService.update(id, body)
}
@Delete('/:id')

View File

@@ -1,4 +1,8 @@
import { BadRequestException, Injectable } from '@nestjs/common'
import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common'
import { load } from 'js-yaml'
import { InjectModel } from 'nestjs-typegoose'
import { SnippetModel, SnippetType } from './snippet.model'
@@ -31,12 +35,7 @@ export class SnippetService {
await this.validateType(model)
delete model.created
await this.model.updateOne(
{
_id: id,
},
{ ...model },
)
return await this.model.findByIdAndUpdate(id, { ...model }, { new: true })
}
async delete(id: string) {
@@ -91,6 +90,9 @@ export class SnippetService {
}
async attachSnippet(model: SnippetModel) {
if (!model) {
throw new NotFoundException()
}
switch (model.type) {
case SnippetType.JSON: {
Reflect.set(model, 'data', JSON.parse(model.raw))

View File

@@ -45,4 +45,4 @@ const models = TypegooseModule.forFeature([
exports: [models, DatabaseService],
})
@Global()
export class DbModule {}
export class DatabaseModule {}

6
test-setup.js Normal file
View File

@@ -0,0 +1,6 @@
const { cd, $, chalk } = require('zx')
const globals = { $, chalk, cd, consola: console }
for (const key in globals) {
global[key] = globals[key]
}

View File

@@ -0,0 +1,45 @@
import { MongoMemoryServer } from 'mongodb-memory-server'
import mongoose from 'mongoose'
let mongod: MongoMemoryServer
/**
* Connect to mock memory db.
*/
const connect = async () => {
mongod = await MongoMemoryServer.create()
const uri = mongod.getUri()
await mongoose.connect(uri, {
autoIndex: true,
maxPoolSize: 10,
})
}
/**
* Close db connection
*/
const closeDatabase = async () => {
await mongoose.connection.dropDatabase()
await mongoose.connection.close()
await mongod.stop()
}
/**
* Delete db collections
*/
const clearDatabase = async () => {
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,
}

View File

@@ -77,29 +77,6 @@ describe.only('test /snippets', () => {
})
})
// test('POST /snippets, should return 201', async () => {
// mockingoose(model).toReturn(
// {
// ...mockPayload1,
// },
// 'create',
// )
// await app
// .inject({
// method: 'POST',
// url: '/snippets',
// payload: mockPayload1,
// })
// .then(async (res) => {
// const json = res.json()
// expect(res.statusCode).toBe(201)
// expect(json).toBeDefined()
// expect(json.name).toBe('Snippet_1')
// // set mockingoose
// })
// })
test('POST /snippets, re-create same of name should return 400', async () => {
await app
.inject({

View File

@@ -0,0 +1,81 @@
import { BadRequestException, NotFoundException } from '@nestjs/common'
import { Test } from '@nestjs/testing'
import { getModelForClass } from '@typegoose/typegoose'
import { getModelToken } from 'nestjs-typegoose'
import { dbHelper } from 'test/helper/db-mock.helper'
import { SnippetModel, SnippetType } from '~/modules/snippet/snippet.model'
import { SnippetService } from '~/modules/snippet/snippet.service'
describe.only('test Snippet Service', () => {
let service: SnippetService
beforeAll(async () => {
await dbHelper.connect()
const moduleRef = Test.createTestingModule({
providers: [
SnippetService,
{
provide: getModelToken('SnippetModel'),
useValue: getModelForClass(SnippetModel),
},
],
})
const app = await moduleRef.compile()
await app.init()
service = app.get(SnippetService)
})
afterAll(async () => {
await dbHelper.close()
})
const snippet = {
name: 'test',
raw: '{"foo": "bar"}',
type: SnippetType.JSON,
private: false,
reference: 'root',
}
let id = ''
it('should create one', async () => {
const res = await service.create(snippet)
expect(res).toMatchObject(snippet)
expect(res.id).toBeDefined()
id = res.id
})
it('should not allow duplicate create', async () => {
await expect(service.create(snippet)).rejects.toThrow(BadRequestException)
})
test('get only data snippet', async () => {
const res = await service.getSnippetByName(snippet.name, snippet.reference)
expect(res.name).toBe(snippet.name)
expect(res.data).toBeDefined()
})
test('get full snippet', async () => {
const res = await service.getSnippetById(id)
expect(res.name).toBe(snippet.name)
expect(res.data).toBeDefined()
})
test('modify', async () => {
const newSnippet = {
name: 'test',
raw: '{"foo": "b"}',
type: SnippetType.JSON,
private: true,
reference: 'root',
}
const res = await service.update(id, newSnippet)
expect(res.raw).toBe(newSnippet.raw)
})
test('delete', async () => {
await service.delete(id)
await expect(service.getSnippetById(id)).rejects.toThrow(NotFoundException)
})
})