- Implemented `getAppConfig` and `upsertAppConfig` functions in `config.ts` for managing application settings in the database. - Updated `mod.ts` to export the new configuration functions. - Refactored `ComicConfig.ts` to load and update comic watch paths using the new configuration functions. - Modified `comic_watcher.ts` to accept paths as parameters for creating watchers. - Created a new settings router in `settings.ts` for managing application settings via HTTP requests. - Integrated the settings router into the main server in `server.ts`. - Updated the settings management to use the new database-backed configuration. - Removed legacy configuration management code from `configRW.ts`. - Added integration tests for the settings router and error handling. - Updated `vitest` configuration for testing. - Cleaned up unused type definitions in `pnpm-lock.yaml`.
		
			
				
	
	
		
			102 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { beforeEach, describe, expect, it, vi, afterEach } from "vitest";
 | 
						|
import { Elysia } from "elysia";
 | 
						|
import { createDiffRouter } from "../src/diff/router.ts";
 | 
						|
import type { DiffManager } from "../src/diff/diff.ts";
 | 
						|
 | 
						|
const adminUser = { username: "admin", permission: [] as string[] };
 | 
						|
 | 
						|
const createTestApp = (diffManager: DiffManager) => {
 | 
						|
	const authPlugin = new Elysia({ name: "test-auth" })
 | 
						|
		.state("user", adminUser)
 | 
						|
		.derive(() => ({ user: adminUser }));
 | 
						|
 | 
						|
	return new Elysia({ name: "diff-test" })
 | 
						|
		.use(authPlugin)
 | 
						|
		.use(createDiffRouter(diffManager));
 | 
						|
};
 | 
						|
 | 
						|
describe("Diff router integration", () => {
 | 
						|
	let app: ReturnType<typeof createTestApp>
 | 
						|
	let diffManager: DiffManager;
 | 
						|
	let getAddedMock: ReturnType<typeof vi.fn>;
 | 
						|
	let commitMock: ReturnType<typeof vi.fn>;
 | 
						|
	let commitAllMock: ReturnType<typeof vi.fn>;
 | 
						|
 | 
						|
	beforeEach(() => {
 | 
						|
		getAddedMock = vi.fn(() => [
 | 
						|
			{
 | 
						|
				type: "comic",
 | 
						|
				value: [
 | 
						|
					{ path: "alpha.zip", type: "archive" },
 | 
						|
				],
 | 
						|
			},
 | 
						|
		]);
 | 
						|
		commitMock = vi.fn(async () => 101);
 | 
						|
		commitAllMock = vi.fn(async () => [201, 202]);
 | 
						|
 | 
						|
		diffManager = {
 | 
						|
			getAdded: getAddedMock,
 | 
						|
			commit: commitMock,
 | 
						|
			commitAll: commitAllMock,
 | 
						|
		} as unknown as DiffManager;
 | 
						|
 | 
						|
		app = createTestApp(diffManager);
 | 
						|
	});
 | 
						|
 | 
						|
	afterEach(async () => {
 | 
						|
		if (app?.server) {
 | 
						|
			await app.stop();
 | 
						|
		}
 | 
						|
		vi.clearAllMocks();
 | 
						|
	});
 | 
						|
 | 
						|
	it("GET /diff/list returns grouped pending items", async () => {
 | 
						|
		const response = await app.handle(new Request("http://localhost/diff/list"));
 | 
						|
		expect(response.status).toBe(200);
 | 
						|
 | 
						|
		const payload = await response.json();
 | 
						|
		expect(payload).toEqual([
 | 
						|
			{
 | 
						|
				type: "comic",
 | 
						|
				value: [
 | 
						|
					{ path: "alpha.zip", type: "archive" },
 | 
						|
				],
 | 
						|
			},
 | 
						|
		]);
 | 
						|
		expect(getAddedMock).toHaveBeenCalledTimes(1);
 | 
						|
	});
 | 
						|
 | 
						|
	it("POST /diff/commit commits each queued item", async () => {
 | 
						|
		const request = new Request("http://localhost/diff/commit", {
 | 
						|
			method: "POST",
 | 
						|
			headers: { "content-type": "application/json" },
 | 
						|
			body: JSON.stringify([
 | 
						|
				{ type: "comic", path: "alpha.zip" },
 | 
						|
			]),
 | 
						|
		});
 | 
						|
 | 
						|
		commitMock.mockResolvedValueOnce(555);
 | 
						|
 | 
						|
		const response = await app.handle(request);
 | 
						|
		expect(response.status).toBe(200);
 | 
						|
 | 
						|
		const payload = await response.json();
 | 
						|
		expect(payload).toEqual({ ok: true, docs: [555] });
 | 
						|
		expect(commitMock).toHaveBeenCalledWith("comic", "alpha.zip");
 | 
						|
	});
 | 
						|
 | 
						|
	it("POST /diff/commitall flushes all entries for the type", async () => {
 | 
						|
		const request = new Request("http://localhost/diff/commitall", {
 | 
						|
			method: "POST",
 | 
						|
			headers: { "content-type": "application/json" },
 | 
						|
			body: JSON.stringify({ type: "comic" }),
 | 
						|
		});
 | 
						|
 | 
						|
		const response = await app.handle(request);
 | 
						|
		expect(response.status).toBe(200);
 | 
						|
 | 
						|
		const payload = await response.json();
 | 
						|
		expect(payload).toEqual({ ok: true });
 | 
						|
		expect(commitAllMock).toHaveBeenCalledWith("comic");
 | 
						|
	});
 | 
						|
});
 |