Files
Codeman/test/routes/session-routes-git-fetch-settings.test.ts
T
Codeman maintainer c04fa97f78 chore: replace the em-dashes this release added with plain punctuation
The merged PRs (mostly #714's git fetch) added about 120 em-dashes in
comments, docs, test names and three settings strings. Each one is now a
comma, colon, semicolon or parentheses. The English settings strings in
index.html and their i18n.js keys change together, and the zh-CN value
for the fetch interval uses full-width parentheses instead of a double
dash. The one left is the regex in constants.js that matches a dash
typed as a word, which is behaviour, not punctuation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 09:11:19 +01:00

105 lines
4.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* `POST /api/sessions/:id/git-fetch-settings` (session-routes.ts): the per-case half of the fetch interval
* (src/git-fetch-scheduler.ts): the case's own switch and its own interval. `null` on either half clears
* that half so the app-wide setting applies again, and a body that names one row leaves the other as it was,
* because the Session Options rows save on their own. Refused for remote and Docker cases, the same rule the
* Git panel and the scheduler use. app.inject(), no port.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import Fastify, { type FastifyInstance } from 'fastify';
import fastifyCookie from '@fastify/cookie';
import { createMockRouteContext, type MockRouteContext } from '../mocks/index.js';
import { installRouteErrorHandler } from '../../src/web/route-error-handler.js';
import { registerSessionRoutes } from '../../src/web/routes/session-routes.js';
interface Harness {
app: FastifyInstance;
ctx: MockRouteContext;
}
async function createHarness(): Promise<Harness> {
const app = Fastify({ logger: false });
await app.register(fastifyCookie);
const ctx = createMockRouteContext();
registerSessionRoutes(app, ctx);
installRouteErrorHandler(app);
await app.ready();
return { app, ctx };
}
describe('POST /api/sessions/:id/git-fetch-settings', () => {
let harness: Harness;
beforeEach(async () => {
harness = await createHarness();
});
afterEach(async () => {
await harness.app.close();
});
const post = (payload: unknown) =>
harness.app.inject({ method: 'POST', url: `/api/sessions/${harness.ctx._sessionId}/git-fetch-settings`, payload });
it('stores the case’s own choice, persists and broadcasts it', async () => {
const res = await post({ enabled: true, intervalSeconds: 120 });
expect(res.statusCode).toBe(200);
expect(JSON.parse(res.body).data.gitFetchSettings).toEqual({ enabled: true, intervalSeconds: 120 });
expect(harness.ctx._session.gitFetchEnabled).toBe(true);
expect(harness.ctx._session.gitFetchIntervalSeconds).toBe(120);
expect(harness.ctx.persistSessionState).toHaveBeenCalled();
});
it('answers `null` for a case that follows the app, which is what the Session Options row shows', async () => {
const data = JSON.parse((await post({})).body).data.gitFetchSettings;
expect(data).toEqual({ enabled: null, intervalSeconds: null });
});
it('clears the override on null so the app-wide setting applies again', async () => {
await post({ enabled: true, intervalSeconds: 120 });
const res = await post({ enabled: null, intervalSeconds: null });
expect(res.statusCode).toBe(200);
expect(harness.ctx._session.gitFetchEnabled).toBeUndefined();
expect(harness.ctx._session.gitFetchIntervalSeconds).toBeUndefined();
expect(JSON.parse(res.body).data.gitFetchSettings).toEqual({ enabled: null, intervalSeconds: null });
});
it('leaves the other half as it was when only one row was saved', async () => {
await post({ enabled: true });
expect(harness.ctx._session.gitFetchIntervalSeconds).toBeUndefined(); // still following the app on that half
const res = await post({ intervalSeconds: 90 });
expect(JSON.parse(res.body).data.gitFetchSettings).toEqual({ enabled: true, intervalSeconds: 90 });
});
it('rejects an interval outside the schema bounds, storing nothing, because that is what the scheduler acts on', async () => {
// `null` is NOT on this list: it is the schema's way of clearing the override, tested above.
for (const raw of [29, 3601, 12.5, '120', true]) {
const res = await post({ enabled: true, intervalSeconds: raw });
expect(res.statusCode, String(raw)).toBe(400);
}
expect(harness.ctx._session.gitFetchEnabled).toBeUndefined();
expect(harness.ctx.persistSessionState).not.toHaveBeenCalled();
});
it.each([
['remote', { host: 'h', user: 'u' }],
['docker', { container: 'c' }],
])('refuses a %s case, storing nothing', async (kind, value) => {
(harness.ctx._session as unknown as Record<string, unknown>)[kind] = value;
const res = await post({ enabled: true, intervalSeconds: 120 });
expect(JSON.parse(res.body)).toMatchObject({ success: false, errorCode: 'INVALID_INPUT' });
expect(harness.ctx._session.gitFetchEnabled).toBeUndefined();
expect(harness.ctx.persistSessionState).not.toHaveBeenCalled();
});
it('404s an unknown session, storing nothing', async () => {
const res = await harness.app.inject({
method: 'POST',
url: '/api/sessions/nope/git-fetch-settings',
payload: { enabled: true },
});
expect(res.statusCode).toBe(404);
expect(harness.ctx.persistSessionState).not.toHaveBeenCalled();
});
});