139 lines
3.3 KiB
TypeScript
139 lines
3.3 KiB
TypeScript
import type { ObjectLiteral } from 'typeorm';
|
|
import type { ConfigService } from '@nestjs/config';
|
|
import type { Mock, Mocked } from 'vitest';
|
|
|
|
/**
|
|
* Mock DataSource for services that use @InjectDataSource() with raw SQL.
|
|
* Follows ISP: separate from repository mocks.
|
|
*/
|
|
export interface MockDataSource {
|
|
query: Mock;
|
|
getRepository: Mock;
|
|
createQueryRunner: Mock;
|
|
}
|
|
|
|
/**
|
|
* Creates a mock DataSource for services using raw SQL queries.
|
|
* The query mock resolves to empty arrays by default.
|
|
* Override per-test with mockDataSource.query.mockResolvedValueOnce(...)
|
|
*/
|
|
export function createMockDataSource(): MockDataSource {
|
|
return {
|
|
query: vi.fn().mockResolvedValue([]),
|
|
getRepository: vi.fn(),
|
|
createQueryRunner: vi.fn(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Mock repository type for services using @InjectRepository().
|
|
*/
|
|
export interface MockRepository<_T extends ObjectLiteral = ObjectLiteral> {
|
|
find: Mock;
|
|
findOne: Mock;
|
|
findOneBy: Mock;
|
|
save: Mock;
|
|
create: Mock;
|
|
update: Mock;
|
|
delete: Mock;
|
|
remove: Mock;
|
|
count: Mock;
|
|
createQueryBuilder: Mock;
|
|
queryBuilder: MockQueryBuilder;
|
|
}
|
|
|
|
/**
|
|
* Creates a mock TypeORM repository with chainable query builder.
|
|
*/
|
|
export function createMockRepository<T extends ObjectLiteral>(): MockRepository<T> {
|
|
const queryBuilder = createMockQueryBuilder();
|
|
|
|
return {
|
|
find: vi.fn(),
|
|
findOne: vi.fn(),
|
|
findOneBy: vi.fn(),
|
|
save: vi.fn(),
|
|
create: vi.fn(),
|
|
update: vi.fn(),
|
|
delete: vi.fn(),
|
|
remove: vi.fn(),
|
|
count: vi.fn(),
|
|
createQueryBuilder: vi.fn().mockReturnValue(queryBuilder),
|
|
queryBuilder,
|
|
};
|
|
}
|
|
|
|
export interface MockQueryBuilder {
|
|
select: Mock;
|
|
addSelect: Mock;
|
|
where: Mock;
|
|
andWhere: Mock;
|
|
orWhere: Mock;
|
|
groupBy: Mock;
|
|
addGroupBy: Mock;
|
|
orderBy: Mock;
|
|
limit: Mock;
|
|
offset: Mock;
|
|
getRawOne: Mock;
|
|
getRawMany: Mock;
|
|
getOne: Mock;
|
|
getMany: Mock;
|
|
getCount: Mock;
|
|
leftJoin: Mock;
|
|
innerJoin: Mock;
|
|
}
|
|
|
|
/**
|
|
* Creates a mock SelectQueryBuilder with chainable methods.
|
|
*/
|
|
export function createMockQueryBuilder(): MockQueryBuilder {
|
|
const builder: MockQueryBuilder = {
|
|
select: vi.fn(),
|
|
addSelect: vi.fn(),
|
|
where: vi.fn(),
|
|
andWhere: vi.fn(),
|
|
orWhere: vi.fn(),
|
|
groupBy: vi.fn(),
|
|
addGroupBy: vi.fn(),
|
|
orderBy: vi.fn(),
|
|
limit: vi.fn(),
|
|
offset: vi.fn(),
|
|
getRawOne: vi.fn().mockResolvedValue(null),
|
|
getRawMany: vi.fn().mockResolvedValue([]),
|
|
getOne: vi.fn().mockResolvedValue(null),
|
|
getMany: vi.fn().mockResolvedValue([]),
|
|
getCount: vi.fn().mockResolvedValue(0),
|
|
leftJoin: vi.fn(),
|
|
innerJoin: vi.fn(),
|
|
};
|
|
|
|
// Make chainable methods return builder
|
|
const chainable = [
|
|
'select', 'addSelect', 'where', 'andWhere', 'orWhere',
|
|
'groupBy', 'addGroupBy', 'orderBy', 'limit', 'offset',
|
|
'leftJoin', 'innerJoin',
|
|
] as const;
|
|
|
|
for (const method of chainable) {
|
|
builder[method].mockReturnValue(builder);
|
|
}
|
|
|
|
return builder;
|
|
}
|
|
|
|
/**
|
|
* Creates a mock ConfigService with configurable return values.
|
|
*/
|
|
export function createMockConfigService(
|
|
config: Record<string, string | undefined> = {},
|
|
): Mocked<ConfigService> {
|
|
return {
|
|
get: vi.fn((key: string) => config[key]),
|
|
getOrThrow: vi.fn((key: string) => {
|
|
if (config[key] === undefined) {
|
|
throw new Error(`Config key ${key} not found`);
|
|
}
|
|
return config[key];
|
|
}),
|
|
} as unknown as Mocked<ConfigService>;
|
|
}
|