fix(yucca sdk): tsconfig for api tests (#706)

fix(yucca sdk): tsconfig for api
test: update lint issues in tests
This commit is contained in:
Paul Makles
2026-09-23 12:17:28 +01:00
committed by GitHub
parent 5efc3664a4
commit c473a911c4
10 changed files with 48 additions and 26 deletions
+1
View File
@@ -50,6 +50,7 @@ export default typescriptEslint.config([
'unicorn/import-style': 'off',
'unicorn/prefer-structured-clone': 'off',
'unicorn/no-for-loop': 'off',
'unicorn/no-useless-undefined': ['error', { checkArguments: false }],
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'require-await': 'off',
@@ -8,7 +8,7 @@ describe(ConfigRepository.name, () => {
selectFrom: jest.fn(() => ({
where: jest.fn(() => ({
select: jest.fn(() => ({
executeTakeFirst: jest.fn().mockResolvedValue(),
executeTakeFirst: jest.fn(),
})),
})),
})),
@@ -32,8 +32,8 @@ describe(ConfigRepository.name, () => {
});
it('falls back to global config and core count without placement', async () => {
const connections = jest.spyOn(yuccaWellKnown, 'getConnections').mockResolvedValue();
const packSize = jest.spyOn(yuccaWellKnown, 'getPackSizeMib').mockResolvedValue();
const connections = jest.spyOn(yuccaWellKnown, 'getConnections').mockResolvedValue(undefined);
const packSize = jest.spyOn(yuccaWellKnown, 'getPackSizeMib').mockResolvedValue(undefined);
const repository = new ConfigRepository(db as never, { statePath: '/state' }, LoggingRepository.create());
await expect(repository.getResticOptions({ siteCode: null, storageClusterCode: null })).resolves.toEqual({
@@ -7,6 +7,7 @@ import { BootstrapRepository } from 'src/repositories/bootstrap.repository';
import { ConfigRepository } from 'src/repositories/config.repository';
import { RepositoryRepository } from 'src/repositories/repository.repository';
import { RunHistoryRepository } from 'src/repositories/runHistory.repository';
import { type RunType } from 'src/schema/tables/runHistory.table';
import { BootstrapService } from 'src/services/bootstrap.service';
import { createTestingModule, TestContext, waitFor } from './testUtils';
@@ -15,7 +16,7 @@ const apiSubmitStructuredLog = submitStructuredLog as jest.Mock;
let ctx: TestContext;
const createInterruptedRun = async (type = TaskType.Backup) => {
const createInterruptedRun = async (type: RunType = TaskType.Backup) => {
const repositoryId = randomUUID();
const remoteId = `remote-${repositoryId}`;
@@ -31,6 +31,7 @@ describe('Database', () => {
const { schedule } = await scheduleService.createSchedule({
name: 'Snapshot Schedule',
paused: false,
cron: '0 0 * * *',
repositories: [repository.id],
});
@@ -43,6 +44,7 @@ describe('Database', () => {
await scheduleService.createSchedule({
name: 'Post-Snapshot Schedule',
paused: false,
cron: '0 6 * * *',
repositories: [],
});
@@ -4,7 +4,8 @@ import { RepositoryPathRepository } from 'src/repositories/repositoryPath.reposi
import { IntegrationsService } from 'src/services/integrations.service';
import { RepositoryService } from 'src/services/repository.service';
import { ScheduleService } from 'src/services/schedule.service';
import { createRemoteRepository, createTestingModule, TestContext } from './testUtils';
import { newImmichHooksMock } from './mocks';
import { createTestingModule, TestContext } from './testUtils';
let ctx: TestContext;
@@ -42,6 +43,7 @@ describe('Integrations', () => {
dataPath: '/data/immich',
dataFolders: ['upload', 'library'],
libraries: [],
hooks: newImmichHooksMock(),
},
});
@@ -79,6 +81,7 @@ describe('Integrations', () => {
{ id: 'lib-1', name: 'Photos', importPaths: ['/mnt/photos'], exclusionPatterns: [] },
{ id: 'lib-2', name: 'Videos', importPaths: ['/mnt/videos'], exclusionPatterns: [] },
],
hooks: newImmichHooksMock(),
},
});
@@ -119,6 +122,7 @@ describe('Integrations', () => {
dataPath: '/data/immich',
dataFolders: ['upload'],
libraries: [],
hooks: newImmichHooksMock(),
},
});
@@ -155,10 +159,7 @@ describe('Integrations', () => {
moduleConfig.update({ immichIntegration: undefined });
});
const hooks = {
getImmichDatabaseDumpConfig: jest.fn().mockResolvedValue({ enabled: true, keepLastAmount: 14 }),
configureImmichDatabaseDump: jest.fn(),
};
const hooks = newImmichHooksMock();
it('pauses and resumes the managed schedule', async () => {
const moduleConfig = ctx.module.get(ModuleConfigRepository);
const integrationsService = ctx.module.get(IntegrationsService);
@@ -170,7 +171,7 @@ describe('Integrations', () => {
dataPath: '/data/immich',
dataFolders: ['upload'],
libraries: [],
hooks: hooks as never,
hooks,
},
});
@@ -192,7 +193,8 @@ describe('Integrations', () => {
return schedules.find((entry) => entry.id === integration?.scheduleId);
};
expect((await getSchedule())?.paused).toBe(false);
const initialSchedule = await getSchedule();
expect(initialSchedule?.paused).toBe(false);
const status = await integrationsService.getImmichBackupStatus();
expect(status.databaseDump).toEqual({ enabled: true, keepLastAmount: 14 });
@@ -202,15 +204,18 @@ describe('Integrations', () => {
expect(status.databaseDumpWarningIgnored).toBe(false);
await integrationsService.ignoreImmichDatabaseDumpWarning();
expect((await integrationsService.getImmichBackupStatus()).databaseDumpWarningIgnored).toBe(true);
const ignoredStatus = await integrationsService.getImmichBackupStatus();
expect(ignoredStatus.databaseDumpWarningIgnored).toBe(true);
await integrationsService.configureImmichIntegration({ ...configuration, paused: true });
expect((await getSchedule())?.paused).toBe(true);
const pausedSchedule = await getSchedule();
expect(pausedSchedule?.paused).toBe(true);
await integrationsService.configureImmichIntegration({ ...configuration, paused: false });
expect((await getSchedule())?.paused).toBe(false);
const resumedSchedule = await getSchedule();
expect(resumedSchedule?.paused).toBe(false);
await immichRepository.delete();
moduleConfig.update({ immichIntegration: undefined });
@@ -1,3 +1,4 @@
import type { ImmichIntegration } from 'src/moduleConfig';
import type { ResticRepository } from 'src/repositories/restic.repository';
export type RepositoryInterface<T extends object> = Pick<T, keyof T>;
@@ -8,6 +9,7 @@ export const newResticRepositoryMock = (): jest.Mocked<RepositoryInterface<Resti
backup: jest.fn(),
restore: jest.fn(),
snapshots: jest.fn().mockResolvedValue([]),
snapshot: jest.fn(),
stats: jest.fn().mockResolvedValue({ total_size: 0, snapshots_count: 0 }),
forget: jest.fn(),
forgetByPolicy: jest.fn().mockResolvedValue([]),
@@ -17,3 +19,11 @@ export const newResticRepositoryMock = (): jest.Mocked<RepositoryInterface<Resti
unlockAll: jest.fn(),
};
};
export const newImmichHooksMock = (): jest.Mocked<ImmichIntegration['hooks']> => ({
createDatabaseBackup: jest.fn().mockResolvedValue('dump.sql.gz'),
cleanupDatabaseBackups: jest.fn(),
getImmichDatabaseDumpConfig: jest.fn().mockResolvedValue({ enabled: true, keepLastAmount: 14 }),
configureImmichDatabaseDump: jest.fn(),
enterMaintenanceRollback: jest.fn().mockResolvedValue({ jwt: 'jwt' }),
});
@@ -32,6 +32,7 @@ describe('Schedule', () => {
const { schedule } = await scheduleService.createSchedule({
name: 'Locked Schedule',
paused: false,
cron: '0 0 1 1 *',
repositories: [repository.id],
});
@@ -49,6 +50,7 @@ describe('Schedule', () => {
it('skips task creation when schedule has no repositories', async () => {
const { schedule } = await ctx.module.get(ScheduleService).createSchedule({
name: 'Empty Schedule',
paused: false,
cron: '0 0 1 1 *',
repositories: [],
});
@@ -85,6 +87,7 @@ describe('Schedule', () => {
const { schedule } = await scheduleService.createSchedule({
name: 'Multi Schedule',
paused: false,
cron: '0 0 1 1 *',
repositories: [repo1.id, repo2.id],
});
@@ -121,17 +124,11 @@ describe('Schedule', () => {
);
ctx.resticMock.backup.mockReset();
let callCount = 0;
ctx.resticMock.backup.mockImplementation(() => {
callCount++;
if (callCount === 1) {
return Promise.reject(new Error('Simulated backup failure'));
}
return Promise.resolve();
});
ctx.resticMock.backup.mockRejectedValueOnce(new Error('Simulated backup failure'));
const { schedule } = await scheduleService.createSchedule({
name: 'Resilient Schedule',
paused: false,
cron: '0 0 1 1 *',
repositories: [failRepo.id, successRepo.id],
});
@@ -140,7 +137,6 @@ describe('Schedule', () => {
await new Promise((resolve) => setTimeout(resolve, 300));
expect(callCount).toBe(2);
expect(ctx.resticMock.backup).toHaveBeenCalledTimes(2);
ctx.resticMock.backup.mockReset();
@@ -171,6 +167,7 @@ describe('Schedule', () => {
const { schedule } = await scheduleService.createSchedule({
name: 'Warn Schedule',
paused: false,
cron: '0 0 1 1 *',
repositories: [warnRepo.id],
});
@@ -200,6 +197,7 @@ describe('Schedule', () => {
const { schedule } = await scheduleService.createSchedule({
name: 'Ordering Schedule',
paused: false,
cron: '0 0 1 1 *',
repositories: [existing.id],
});
@@ -223,6 +221,7 @@ describe('Schedule', () => {
const { schedule } = await scheduleService.createSchedule({
name: 'Immich Schedule',
paused: false,
cron: '0 2 * * *',
repositories: [repository.id],
});
@@ -16,7 +16,7 @@ import { ModuleConfigProvider } from 'src/moduleConfig';
import { controllers, repositories, services } from 'src/orchestrationApi.module';
import { BackendRepository } from 'src/repositories/backend.repository';
import { ResticRepository } from 'src/repositories/restic.repository';
import { newResticRepositoryMock } from './mocks';
import { newResticRepositoryMock, RepositoryInterface } from './mocks';
type GatewayListener = (event: GatewayEvent) => void;
@@ -49,7 +49,7 @@ export interface TestContext {
gateway: EventsGateway;
events: TestEventBus;
database: InstanceType<typeof Database>;
resticMock: jest.Mocked<ResticRepository>;
resticMock: jest.Mocked<RepositoryInterface<ResticRepository>>;
backendId: string;
statePath: string;
backendPath: string;
@@ -1,4 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "src"
},
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
@@ -22,7 +22,8 @@
"noImplicitAny": true,
"strictBindCallApply": false,
"noFallthroughCasesInSwitch": false,
"rootDir": "src",
"baseUrl": ".",
"paths": { "src/*": ["src/*"] },
"outDir": "dist",
"types": ["@types/node", "@types/jest"]
},