mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 08:21:39 -06:00
test(server): speed up slow unit tests
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
import { BadRequestException, ConflictException, ForbiddenException, ServiceUnavailableException, UnauthorizedException } from '@nestjs/common';
|
||||
|
||||
vi.mock('bcryptjs', () => ({
|
||||
hash: vi.fn((value: string) => Promise.resolve(`mock-hash:${value}`)),
|
||||
compare: vi.fn((plain: string, hashed: string) => Promise.resolve(hashed === `mock-hash:${plain}`)),
|
||||
}));
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
function makeDb(overrides?: Record<string, unknown>) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ForbiddenException, NotFoundException } from '@nestjs/common';
|
||||
import { ForbiddenException, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { MetadataCandidate, MetadataProviderKey } from '@projectx/types';
|
||||
import type { Mocked } from 'vitest';
|
||||
import { firstValueFrom, toArray } from 'rxjs';
|
||||
@@ -39,6 +39,11 @@ describe('MetadataFetchService', () => {
|
||||
let service: MetadataFetchService;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.spyOn(Logger.prototype, 'log').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'warn').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'debug').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined);
|
||||
|
||||
registry = {
|
||||
all: vi.fn(),
|
||||
select: vi.fn(),
|
||||
|
||||
@@ -164,6 +164,8 @@ describe('GoodreadsProvider', () => {
|
||||
});
|
||||
|
||||
it('should use slug-based scoring in extractBookIds', async () => {
|
||||
const BETWEEN_REQUESTS_MS = 600;
|
||||
vi.useFakeTimers();
|
||||
const searchHtml = `
|
||||
<a href="/book/show/1.The_Great_Gatsby?from_srp=true">B1</a>
|
||||
<a href="/book/show/2.Something_Else?from_srp=true">B2</a>
|
||||
@@ -179,7 +181,14 @@ describe('GoodreadsProvider', () => {
|
||||
.mockResolvedValueOnce({ ok: true, text: () => Promise.resolve(searchHtml) })
|
||||
.mockResolvedValue({ ok: true, text: () => Promise.resolve(bookHtml) });
|
||||
|
||||
await provider.search({ title: 'The Great Gatsby' });
|
||||
const searchPromise = provider.search({ title: 'The Great Gatsby' });
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
await vi.advanceTimersByTimeAsync(BETWEEN_REQUESTS_MS);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
await vi.advanceTimersByTimeAsync(BETWEEN_REQUESTS_MS);
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
await searchPromise;
|
||||
expect(global.fetch).toHaveBeenCalledTimes(4); // 1 search + 3 book lookups
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import * as fetchWithThrottleModule from '../../fetch-with-throttle';
|
||||
import { HardcoverClient } from './hardcover.client';
|
||||
@@ -8,9 +8,14 @@ vi.mock('../../fetch-with-throttle', () => ({
|
||||
}));
|
||||
|
||||
describe('HardcoverClient', () => {
|
||||
const client = new HardcoverClient();
|
||||
let client: HardcoverClient;
|
||||
const apiKey = 'test-api-key';
|
||||
|
||||
beforeEach(() => {
|
||||
client = new HardcoverClient();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('passes the apiKey directly to the Authorization header', async () => {
|
||||
const mockFetch = vi.mocked(fetchWithThrottleModule.fetchWithThrottle);
|
||||
mockFetch.mockResolvedValue({
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { ConflictException, ForbiddenException, NotFoundException } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
vi.mock('bcryptjs', () => ({
|
||||
hash: vi.fn((value: string) => Promise.resolve(`mock-hash:${value}`)),
|
||||
compare: vi.fn((plain: string, hashed: string) => Promise.resolve(hashed === `mock-hash:${plain}`)),
|
||||
}));
|
||||
|
||||
import { DB } from '../../../db';
|
||||
import { OpdsUserService } from '../opds-user.service';
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FileEventProcessorService } from './file-event-processor.service';
|
||||
import type { Mocked, MockedFunction } from 'vitest';
|
||||
import { ScannerRepository } from './scanner.repository';
|
||||
import { Logger } from '@nestjs/common';
|
||||
|
||||
vi.mock('fs/promises', () => ({
|
||||
stat: vi.fn(),
|
||||
@@ -69,6 +70,10 @@ function makeFileStat(overrides: Partial<{ ino: number; size: number; mtime: Dat
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.spyOn(Logger.prototype, 'log').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'warn').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'debug').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined);
|
||||
mockRepo.markBooksAsMissing.mockResolvedValue(undefined);
|
||||
mockRepo.markBooksAsPresent.mockResolvedValue(undefined);
|
||||
mockRepo.createBookFile.mockResolvedValue({} as any);
|
||||
|
||||
@@ -4,16 +4,27 @@ import { tmpdir } from 'os';
|
||||
|
||||
import { findBookCandidates, buildSingleBookCandidate } from './walk';
|
||||
|
||||
let suiteRoot: string;
|
||||
let root: string;
|
||||
let caseId = 0;
|
||||
|
||||
beforeAll(async () => {
|
||||
suiteRoot = await mkdtemp(join(tmpdir(), 'scanner-walk-suite-'));
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
root = await mkdtemp(join(tmpdir(), 'scanner-walk-'));
|
||||
root = join(suiteRoot, `case-${caseId++}`);
|
||||
await mkdir(root, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await rm(suiteRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
// Helpers
|
||||
async function dir(...parts: string[]): Promise<string> {
|
||||
const p = join(root, ...parts);
|
||||
|
||||
@@ -10,7 +10,7 @@ vi.mock('fs/promises', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
import { ConflictException, NotFoundException } from '@nestjs/common';
|
||||
import { ConflictException, Logger, NotFoundException } from '@nestjs/common';
|
||||
import type { MockedFunction } from 'vitest';
|
||||
import type { Dirent } from 'fs';
|
||||
import { readdir, stat } from 'fs/promises';
|
||||
@@ -152,6 +152,10 @@ function awaitScan(repo: ReturnType<typeof makeRepo>): Promise<void> {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.spyOn(Logger.prototype, 'log').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'warn').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'debug').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined);
|
||||
mockFindCandidates.mockResolvedValue([]);
|
||||
mockFindLooseCandidates.mockResolvedValue([]);
|
||||
mockBuildSingleCandidate.mockResolvedValue(null);
|
||||
|
||||
@@ -9,7 +9,7 @@ vi.mock('../metadata/lib/mobi-parser', () => ({ parseMobiFile: vi.fn() }));
|
||||
vi.mock('../metadata/lib/pdf-parser', () => ({ parsePdfFile: vi.fn() }));
|
||||
|
||||
import { access as fsAccess } from 'fs/promises';
|
||||
import { BadRequestException, ConflictException } from '@nestjs/common';
|
||||
import { BadRequestException, ConflictException, Logger } from '@nestjs/common';
|
||||
import { extractEpubMetadata } from '../metadata/lib/epub';
|
||||
|
||||
import { UploadService } from './upload.service';
|
||||
@@ -57,6 +57,10 @@ describe('UploadService', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.spyOn(Logger.prototype, 'log').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'warn').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'debug').mockImplementation(() => undefined);
|
||||
vi.spyOn(Logger.prototype, 'error').mockImplementation(() => undefined);
|
||||
service = new UploadService(db as any, appSettings as any, libraryService as any, validator as any, storage as any, processor as any);
|
||||
|
||||
validator.sanitizeFilename.mockReturnValue('book.epub');
|
||||
|
||||
Reference in New Issue
Block a user