Reputation: 578
NestJS provides a sample Transaction code on (https://docs.nestjs.com/techniques/database#transactions), and I now would like to create Unit test script against the code. Here are the some dependent files:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({type: 'text', name: 'first_name'})
firstName: string;
@Column({type: 'text', name: 'last_name'})
lastName: string;
@Column({name: 'is_active', default: true})
isActive: boolean;
}
@Injectable()
export class UsersService {
constructor(
private connection: Connection
) {}
async createMany(users: User[]): User[] {
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const user1 = await queryRunner.manager.save(users[0]);
await queryRunner.commitTransaction();
return [user1];
} catch (err) {
// since we have errors lets rollback the changes we made
await queryRunner.rollbackTransaction();
} finally {
// you need to release a queryRunner which was manually instantiated
await queryRunner.release();
}
}
}
Here is the unit test script. I am close to accomplish but still I am getting undefined
from await queryRunner.manager.save(users[0])
with the jest.spyOn
setup below:
describe('UsersService', () => {
let usersService: UsersService;
let connection: Connection;
class ConnectionMock {
createQueryRunner(mode?: "master" | "slave"): QueryRunner {
const qr = {
manager: {},
} as QueryRunner;
qr.manager;
Object.assign(qr.manager, {
save: jest.fn()
});
qr.connect = jest.fn();
qr.release = jest.fn();
qr.startTransaction = jest.fn();
qr.commitTransaction = jest.fn();
qr.rollbackTransaction = jest.fn();
qr.release = jest.fn();
return qr;
}
}
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService, {
provide: Connection,
useClass: ConnectionMock,
}],
}).compile();
usersService = module.get<UsersService>(UsersService);
connection = module.get<Connection>(Connection);
});
it('should be defined', () => {
expect(usersService).toBeDefined();
});
it('should return expected results after user create', async () => {
const user1: User = { id: 1, firstName: 'First', lastName: 'User', isActive: true };
const queryRunner = connection.createQueryRunner();
// I would like to make the following spyOn work
jest.spyOn(queryRunner.manager, 'save').mockResolvedValueOnce(user1);
expect(await appService.createMany([user1])).toEqual([user1]);
});
});
Upvotes: 1
Views: 8538
Reputation: 16127
connection.createQueryRunner();
will return difference instance of QueryRunner
.
This mean queryRunner
of const queryRunner = connection.createQueryRunner();
will not reference to queryRunner
in const queryRunner = this.connection.createQueryRunner();
of createMany
function.
Then your mock jest.spyOn(queryRunner.manager, 'save').mockResolvedValueOnce(user1);
does not make sense.
Keep it simple, make QueryRunner
as a "global" variable, then binding it to ConnectionMock
, this mean we will have the same "variable" when we call createQueryRunner
.
Updated beforeEach
content, ConnectionMock
class.
describe('UsersService', () => {
let usersService: UsersService;
let connection: Connection;
const qr = {
manager: {},
} as QueryRunner;
class ConnectionMock {
createQueryRunner(mode?: "master" | "slave"): QueryRunner {
return qr;
}
}
beforeEach(async () => {
// reset qr mocked function
Object.assign(qr.manager, {
save: jest.fn()
});
qr.connect = jest.fn();
qr.release = jest.fn();
qr.startTransaction = jest.fn();
qr.commitTransaction = jest.fn();
qr.rollbackTransaction = jest.fn();
qr.release = jest.fn();
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService, {
provide: Connection,
useClass: ConnectionMock,
}],
}).compile();
usersService = module.get<UsersService>(UsersService);
connection = module.get<Connection>(Connection);
});
it('should be defined', () => {
expect(usersService).toBeDefined();
});
it('should return expected results after user create', async () => {
const user1: User = { id: 1, firstName: 'First', lastName: 'User', isActive: true };
const queryRunner = connection.createQueryRunner();
// I would like to make the following spyOn work
jest.spyOn(queryRunner.manager, 'save').mockResolvedValueOnce(user1);
expect(await appService. createMany([user1])).toEqual([user1]);
});
});
Upvotes: 2