Skip to content

Commit

Permalink
refactor: improve the tests for all use cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Aliheym committed Oct 2, 2023
1 parent eebcf2d commit 82fd676
Show file tree
Hide file tree
Showing 20 changed files with 708 additions and 617 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
"fix:lint": "npm run check:lint --fix",
"fix": "npm run fix:lint && npm run fix:format",
"build": "npm run clean && tsc -p tsconfig.json",
"setup-test-db": "npm run teardown-test-db; docker-compose -f tests/docker-compose.yaml up -d && sleep 3",
"teardown-test-db": "docker-compose -f tests/docker-compose.yaml down --remove-orphans -v",
"test": "npm run setup-test-db && jest --runInBand"
"setup-test-db": "npm run teardown-test-db; docker compose -f tests/docker-compose.yaml up -d --wait",
"teardown-test-db": "docker compose -f tests/docker-compose.yaml down --remove-orphans -v",
"test": "npm run setup-test-db && jest"
},
"dependencies": {
"@types/cls-hooked": "^4.3.3",
Expand Down
125 changes: 0 additions & 125 deletions tests/custom-repos.test.ts

This file was deleted.

23 changes: 22 additions & 1 deletion tests/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
version: '3.9'

services:
postgres:
postgres-simple:
image: postgres:alpine
ports:
- '5435:5432'
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: test
healthcheck:
test: ["CMD-SHELL", "pg_isready", "-d", "test", "-U", "postgres"]
interval: 1s
timeout: 5s
retries: 10
start_period: 3s

postgres-nest:
image: postgres:alpine
ports:
- '5436:5432'
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: test
healthcheck:
test: ["CMD-SHELL", "pg_isready", "-d", "test", "-U", "postgres"]
interval: 1s
timeout: 5s
retries: 10
start_period: 3s
7 changes: 7 additions & 0 deletions tests/entities/Counter.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity('counters')
export class Counter {
@PrimaryGeneratedColumn()
value: number;
}
13 changes: 0 additions & 13 deletions tests/entities/Post.entity.ts

This file was deleted.

15 changes: 15 additions & 0 deletions tests/entities/User.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';

@Entity('users')
export class User {
@PrimaryColumn()
name: string;

@Column({ type: 'integer' })
money: number;

constructor(name: string, money: number) {
this.name = name;
this.money = money;
}
}
125 changes: 35 additions & 90 deletions tests/nest.test.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import {
initializeTransactionalContext,
addTransactionalDataSource,
Propagation,
runInTransaction,
runOnTransactionCommit,
runOnTransactionComplete,
runOnTransactionRollback,
} from '../src';
import { Post } from './entities/Post.entity';
import { NestPostReaderService } from './services/nest-post-reader.service';
import { NestPostWriterService } from './services/nest-post-writer.service';

async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

import { User } from './entities/User.entity';
import { UserReaderService } from './services/user-reader.service';
import { UserWriterService } from './services/user-writer.service';

import { initializeTransactionalContext, addTransactionalDataSource } from '../src';

describe('Integration with Nest.js', () => {
let app: TestingModule;

let readerService: NestPostReaderService;
let writerService: NestPostWriterService;
let readerService: UserReaderService;
let writerService: UserWriterService;

let dataSource: DataSource;

Expand All @@ -36,10 +26,11 @@ describe('Integration with Nest.js', () => {
return {
type: 'postgres',
host: 'localhost',
port: 5435,
port: 5436,
username: 'postgres',
password: 'postgres',
entities: [Post],
database: 'test',
entities: [User],
synchronize: true,
logging: false,
};
Expand All @@ -53,100 +44,54 @@ describe('Integration with Nest.js', () => {
},
}),

TypeOrmModule.forFeature([Post]),
TypeOrmModule.forFeature([User]),
],
providers: [NestPostReaderService, NestPostWriterService],
providers: [UserReaderService, UserWriterService],
exports: [],
}).compile();

readerService = app.get<NestPostReaderService>(NestPostReaderService);
writerService = app.get<NestPostWriterService>(NestPostWriterService);
readerService = app.get<UserReaderService>(UserReaderService);
writerService = app.get<UserWriterService>(UserWriterService);

dataSource = app.get(DataSource);

await dataSource.createEntityManager().clear(Post);
await dataSource.createEntityManager().clear(User);
});

afterEach(async () => {
await dataSource.createEntityManager().clear(Post);
await dataSource.createEntityManager().clear(User);
});

afterAll(async () => {
await app.close();
});

it('should create a post using service', async () => {
const message = 'NestJS - A successful post';

const [writtenPost, readPost] = await runInTransaction(async () => {
const writtenPost = await writerService.createPost(message);
const readPost = await readerService.getPostByMessage(message);
it('should create a user using service if transaction was completed successfully', async () => {
const name = 'John Doe';
const onTransactionCompleteSpy = jest.fn();

return [writtenPost, readPost];
});

expect(writtenPost.id).toBeGreaterThan(0);
expect(readPost.id).toBe(writtenPost.id);
});
const writtenPost = await writerService.createUser(name, onTransactionCompleteSpy);
expect(writtenPost.name).toBe(name);

it('should fail to create a post using service', async () => {
const message = 'NestJS - A unsuccessful post';
const readPost = await readerService.findUserByName(name);
expect(readPost?.name).toBe(name);

const promise = runInTransaction(async () => {
const writtenPost = await writerService.createPost(message, true);
const readPost = await readerService.getPostByMessage(message);

return [writtenPost, readPost];
});

expect(promise).rejects.toThrowError();

const readPost = await readerService.getPostByMessage(message);
expect(readPost).toBeNull();
expect(onTransactionCompleteSpy).toBeCalledTimes(1);
expect(onTransactionCompleteSpy).toBeCalledWith(true);
});

it('should create new transaction for "REQUIRES_NEW" propagation', async () => {
const message = 'NestJS - A successful post';
it('should fail to create a user using service if error was thrown', async () => {
const name = 'John Doe';
const onTransactionCompleteSpy = jest.fn();

const [writtenPost, readPost, secondReadPost] = await runInTransaction(async () => {
const writtenPost = await writerService.createPost(message);
expect(() =>
writerService.createUserAndThrow(name, onTransactionCompleteSpy),
).rejects.toThrowError();

const readPost = await runInTransaction(
() => {
return readerService.getPostByMessage(message);
},
{ propagation: Propagation.REQUIRES_NEW },
);

const secondReadPost = await readerService.getPostByMessage(message);

return [writtenPost, readPost, secondReadPost];
});

expect(writtenPost.id).toBeGreaterThan(0);
expect(secondReadPost.id).toBe(writtenPost.id);
const readPost = await readerService.findUserByName(name);
expect(readPost).toBeNull();
});

it('should call transaction hooks', async () => {
const message = 'NestJS - A successful post';

const onTransactionCommit = jest.fn();
const onTransactionRollback = jest.fn();
const onTransactionComplete = jest.fn();

await runInTransaction(async () => {
await writerService.createPost(message);

runOnTransactionCommit(onTransactionCommit);
runOnTransactionRollback(onTransactionRollback);
runOnTransactionComplete(onTransactionComplete);
});

await sleep(100);

expect(onTransactionCommit).toBeCalledTimes(1);
expect(onTransactionRollback).toBeCalledTimes(0);
expect(onTransactionComplete).toBeCalledTimes(1);
expect(onTransactionCompleteSpy).toBeCalledTimes(1);
expect(onTransactionCompleteSpy).toBeCalledWith(false);
});
});
Loading

0 comments on commit 82fd676

Please sign in to comment.