Skip to content

Commit 4fe628b

Browse files
authored
merge(mongo-sample): merge mongo-sample branch to master
* fix(actions): update GitHub actions Actions are now 1-to-1 mapped for each application to run its own tests * feat(mongo): add test suite for mongo This suite covers a basic CRUD application for mongodb and NestJS Related to #3
1 parent b873c7f commit 4fe628b

22 files changed

+837
-18
lines changed

.github/workflows/nodejs.yml renamed to .github/workflows/complex.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
name: Node CI
1+
name: Complex Sample
22

3-
on:
3+
on:
44
pull_request:
5-
branches:
5+
branches:
66
- 'master'
77
push:
88

@@ -14,7 +14,6 @@ jobs:
1414
strategy:
1515
matrix:
1616
node-version: [10.x, 12.x]
17-
sample-name: [complex-sample, simple-sample, typeorm-sample, typeorm-graphql-sample]
1817

1918
steps:
2019
- uses: actions/checkout@v1
@@ -25,6 +24,6 @@ jobs:
2524
- name: npm install
2625
run: npm ci
2726
- name: npm test
28-
run: npm test -- ${{ matrix.sample-name }}
27+
run: npm test -- complex-sample
2928
env:
3029
CI: true

.github/workflows/mongo.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Mongo Sample
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- 'master'
7+
push:
8+
9+
jobs:
10+
test:
11+
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
node-version: [10.x, 12.x]
17+
18+
steps:
19+
- uses: actions/checkout@v1
20+
- name: Use Node.js ${{ matrix.node-version }}
21+
uses: actions/setup-node@v1
22+
with:
23+
node-version: ${{ matrix.node-version }}
24+
- name: npm install
25+
run: npm ci
26+
- name: npm test
27+
run: npm test -- mongo-sample
28+
env:
29+
CI: true

.github/workflows/simple.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Simple Sample
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- 'master'
7+
push:
8+
9+
jobs:
10+
test:
11+
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
node-version: [10.x, 12.x]
17+
18+
steps:
19+
- uses: actions/checkout@v1
20+
- name: Use Node.js ${{ matrix.node-version }}
21+
uses: actions/setup-node@v1
22+
with:
23+
node-version: ${{ matrix.node-version }}
24+
- name: npm install
25+
run: npm ci
26+
- name: npm test
27+
run: npm test -- simple-sample
28+
env:
29+
CI: true

.github/workflows/typeorm-graphql.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: TypeORM GraphQL Sample
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- 'master'
7+
push:
8+
9+
jobs:
10+
test:
11+
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
node-version: [10.x, 12.x]
17+
18+
steps:
19+
- uses: actions/checkout@v1
20+
- name: Use Node.js ${{ matrix.node-version }}
21+
uses: actions/setup-node@v1
22+
with:
23+
node-version: ${{ matrix.node-version }}
24+
- name: npm install
25+
run: npm ci
26+
- name: npm test
27+
run: npm test -- typeorm-graphql-sample
28+
env:
29+
CI: true

.github/workflows/typeorm.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: TypeORM Sample
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- 'master'
7+
push:
8+
9+
jobs:
10+
test:
11+
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
node-version: [10.x, 12.x]
17+
18+
steps:
19+
- uses: actions/checkout@v1
20+
- name: Use Node.js ${{ matrix.node-version }}
21+
uses: actions/setup-node@v1
22+
with:
23+
node-version: ${{ matrix.node-version }}
24+
- name: npm install
25+
run: npm ci
26+
- name: npm test
27+
run: npm test -- typeorm-sample
28+
env:
29+
CI: true

Contributing.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ Or run tests in watch mode:
2727
npm run test:watch
2828
```
2929

30-
To update Jest snapshots:
31-
32-
```bash
33-
npm run test:jest -- -u
34-
```
35-
3630
**Don’t forget to add tests and update documentation for your changes.**
3731

3832
**Please update npm lock file (`package-lock.json`) if you add or update dependencies.**

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This is not necessarily the Nest canonical way to test an application, nor is it
1919
1. `git clone https://github.com/jmcdo29/testing-nestjs.git`
2020
2. `cd testing-nestjs/<folderName>`
2121
3. `npm install` OR `yarn add`
22-
4. `npm run test` OR `npm run test:e2e` OR `yarn test` OR `yarn test:e2e`
22+
4. `npm run test` OR `yarn test`
2323

2424
## Contributing
2525

apps/mongo-sample/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<p align="center">
2+
<img src="./testCoverage.png"/>
3+
</p>
4+
5+
# Mongo Sample
6+
7+
Welcome to the example of using MongoDB with Nest and running tests! My _second favorite_ topic! I decided to go with a very simple CRUD application for a single database object, but if there is enough of a demand I will extend this out to a larger repository with more objects and options. Not much else to say other than I hope this is found as helpful to the community!
8+
9+
## Side Note
10+
11+
For this application, I have added a side package called `@golevelup/nestjs-testing` (name subject to change) to help with mocking Repository objects without needing to create the entire mock on your own. I did run into a few issues with the library this time around, namely matching mocks to mocks, so that's something I'll need to work on updating in the future. In the meantime, enjoy the tests!

apps/mongo-sample/src/app.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Module } from '@nestjs/common';
2+
import { MongooseModule } from '@nestjs/mongoose';
23
import { AppController } from './app.controller';
34
import { AppService } from './app.service';
5+
import { CatModule } from './cat/cat.module';
46

57
@Module({
6-
imports: [],
8+
imports: [MongooseModule.forRoot(process.env.MONGODB_URI), CatModule],
79
controllers: [AppController],
810
providers: [AppService],
911
})
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import { createMock, DeepMocked } from '@golevelup/nestjs-testing';
2+
import { Test, TestingModule } from '@nestjs/testing';
3+
import { CatController } from './cat.controller';
4+
import { CatDTO } from './cat.dto';
5+
import { CatService } from './cat.service';
6+
import { Cat } from './interfaces/cat.interface';
7+
8+
describe('Cat Controller', () => {
9+
let controller: CatController;
10+
let service: CatService;
11+
12+
beforeEach(async () => {
13+
const module: TestingModule = await Test.createTestingModule({
14+
controllers: [CatController],
15+
// If you've looked at the complex sample you'll notice that these functions
16+
// are a little bit more in depth using mock implementation
17+
// to give us a little bit more control and flexibility in our tests
18+
// this is not necessary, but can sometimes be helpful in a test scenario
19+
providers: [
20+
{
21+
provide: CatService,
22+
useValue: {
23+
getAll: jest
24+
.fn()
25+
.mockResolvedValue([
26+
{ name: 'Test Cat 1', breed: 'Test Breed 1', age: 4 },
27+
{ name: 'Test Cat 2', breed: 'Test Breed 2', age: 3 },
28+
{ name: 'Test Cat 3', breed: 'Test Breed 3', age: 2 },
29+
]),
30+
getOne: jest.fn().mockImplementation((id: string) =>
31+
Promise.resolve({
32+
name: 'Test Cat 1',
33+
breed: 'Test Breed 1',
34+
age: 4,
35+
_id: id,
36+
}),
37+
),
38+
getOneByName: jest
39+
.fn()
40+
.mockImplementation((name: string) =>
41+
Promise.resolve({ name, breed: 'Test Breed 1', age: 4 }),
42+
),
43+
insertOne: jest
44+
.fn()
45+
.mockImplementation((cat: CatDTO) =>
46+
Promise.resolve({ _id: 'a uuid', ...cat }),
47+
),
48+
updateOne: jest
49+
.fn()
50+
.mockImplementation((cat: CatDTO) =>
51+
Promise.resolve({ _id: 'a uuid', ...cat }),
52+
),
53+
deleteOne: jest.fn().mockResolvedValue({ deleted: true }),
54+
},
55+
},
56+
],
57+
}).compile();
58+
59+
controller = module.get<CatController>(CatController);
60+
service = module.get<CatService>(CatService);
61+
});
62+
63+
it('should be defined', () => {
64+
expect(controller).toBeDefined();
65+
});
66+
67+
describe('getCats', () => {
68+
it('should get an array of cats', () => {
69+
expect(controller.getCats()).resolves.toEqual([
70+
{
71+
name: 'Test Cat 1',
72+
breed: 'Test Breed 1',
73+
age: 4,
74+
},
75+
{
76+
name: 'Test Cat 2',
77+
breed: 'Test Breed 2',
78+
age: 3,
79+
},
80+
{
81+
name: 'Test Cat 3',
82+
breed: 'Test Breed 3',
83+
age: 2,
84+
},
85+
]);
86+
});
87+
});
88+
describe('getById', () => {
89+
it('should get a single cat', () => {
90+
expect(controller.getById('a strange id')).resolves.toEqual({
91+
name: 'Test Cat 1',
92+
breed: 'Test Breed 1',
93+
age: 4,
94+
_id: 'a strange id',
95+
});
96+
expect(controller.getById('a different id')).resolves.toEqual({
97+
name: 'Test Cat 1',
98+
breed: 'Test Breed 1',
99+
age: 4,
100+
_id: 'a different id',
101+
});
102+
});
103+
});
104+
describe('getByName', () => {
105+
it('should get a cat back', async () => {
106+
expect(controller.getByName('Ventus')).resolves.toEqual({
107+
name: 'Ventus',
108+
breed: 'Test Breed 1',
109+
age: 4,
110+
});
111+
// using the really cool @golevelup/nestjs-testing module's utility function here
112+
// otherwise we need to pass `as any` or we need to mock all 54+ attributes of Document
113+
const aquaMock = createMock<Cat>({
114+
name: 'Aqua',
115+
breed: 'Maine Coon',
116+
age: 5,
117+
});
118+
const getByNameSpy = jest
119+
.spyOn(service, 'getOneByName')
120+
.mockResolvedValueOnce(aquaMock);
121+
const getResponse = await controller.getByName('Aqua');
122+
expect(getResponse).toEqual(aquaMock);
123+
expect(getByNameSpy).toBeCalledWith('Aqua');
124+
});
125+
});
126+
describe('newCat', () => {
127+
it('should create a new cat', () => {
128+
const newCatDTO: CatDTO = {
129+
name: 'New Cat 1',
130+
breed: 'New Breed 1',
131+
age: 4,
132+
};
133+
expect(controller.newCat(newCatDTO)).resolves.toEqual({
134+
_id: 'a uuid',
135+
...newCatDTO,
136+
});
137+
});
138+
});
139+
describe('updateCat', () => {
140+
it('should update a new cat', () => {
141+
const newCatDTO: CatDTO = {
142+
name: 'New Cat 1',
143+
breed: 'New Breed 1',
144+
age: 4,
145+
};
146+
expect(controller.updateCat(newCatDTO)).resolves.toEqual({
147+
_id: 'a uuid',
148+
...newCatDTO,
149+
});
150+
});
151+
});
152+
describe('deleteCat', () => {
153+
it('should return that it deleted a cat', () => {
154+
expect(controller.deleteCat('a uuid that exists')).resolves.toEqual({
155+
deleted: true,
156+
});
157+
});
158+
it('should return that it did not delete a cat', () => {
159+
const deleteSpy = jest
160+
.spyOn(service, 'deleteOne')
161+
.mockResolvedValueOnce({ deleted: false });
162+
expect(
163+
controller.deleteCat('a uuid that does not exist'),
164+
).resolves.toEqual({ deleted: false });
165+
expect(deleteSpy).toBeCalledWith('a uuid that does not exist');
166+
});
167+
});
168+
});

0 commit comments

Comments
 (0)