fix(12): satisfy CI fast-checks — lint unused vars, typed contract-test body, prettier
CI / changes (pull_request) Successful in 3s
CI / fast-checks (pull_request) Successful in 2m16s
CI / api (pull_request) Failing after 1m37s
CI / harness (pull_request) Failing after 1h3m45s
CI / security (pull_request) Failing after 11s
CI / gate (pull_request) Failing after 1s
CI / changes (pull_request) Successful in 3s
CI / fast-checks (pull_request) Successful in 2m16s
CI / api (pull_request) Failing after 1m37s
CI / harness (pull_request) Failing after 1h3m45s
CI / security (pull_request) Failing after 11s
CI / gate (pull_request) Failing after 1s
- Remove unused 'res'/'container' assignments (no-unused-vars) - setupClient.contract.test.ts: typed parseSentBody helper + non-async json mock (no-unsafe-*/require-await) - Prettier format 7 setup files Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f485b38324
commit
a193bc8236
@@ -636,7 +636,9 @@ export async function validateSetupDb(): Promise<void> {
|
||||
if (res.status === 423) throw new SetupAlreadyLockedError();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error('Cannot reach the database. Check DB_HOST, DB_PORT, DB_USER, DB_PASSWORD in your Docker environment and try again.');
|
||||
throw new Error(
|
||||
'Cannot reach the database. Check DB_HOST, DB_PORT, DB_USER, DB_PASSWORD in your Docker environment and try again.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +652,9 @@ export async function validateSetupOidc(): Promise<void> {
|
||||
if (res.status === 423) throw new SetupAlreadyLockedError();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error('OIDC discovery failed. Check the issuer URL and that Authelia is reachable from the server.');
|
||||
throw new Error(
|
||||
'OIDC discovery failed. Check the issuer URL and that Authelia is reachable from the server.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,7 +667,9 @@ export async function validateSetupVapid(): Promise<void> {
|
||||
if (res.status === 423) throw new SetupAlreadyLockedError();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error('VAPID validation failed. Check that your VAPID keys were generated with `npm run generate-secrets`.');
|
||||
throw new Error(
|
||||
'VAPID validation failed. Check that your VAPID keys were generated with `npm run generate-secrets`.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,7 +692,9 @@ export async function postSetupCredential(payload: SetupCredentialPayload): Prom
|
||||
if (res.status === 423) throw new SetupAlreadyLockedError();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Invalid password — CalDAV validation failed. Check the scope is 'Calendars & Contacts (CalDAV)' and try again.");
|
||||
throw new Error(
|
||||
"Invalid password — CalDAV validation failed. Check the scope is 'Calendars & Contacts (CalDAV)' and try again.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { postSetupConfig, postSetupCredential, type SetupConfigPayload, type SetupCredentialPayload } from './client.js';
|
||||
import {
|
||||
postSetupConfig,
|
||||
postSetupCredential,
|
||||
type SetupConfigPayload,
|
||||
type SetupCredentialPayload,
|
||||
} from './client.js';
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -28,11 +33,21 @@ function mockFetchResponse(body: unknown, status = 200): Response {
|
||||
return {
|
||||
ok: status >= 200 && status < 300,
|
||||
status,
|
||||
json: async () => body,
|
||||
clone: function () { return this as unknown as Response; },
|
||||
json: () => Promise.resolve(body),
|
||||
clone: function () {
|
||||
return this as unknown as Response;
|
||||
},
|
||||
} as unknown as Response;
|
||||
}
|
||||
|
||||
// Extract the JSON body sent on the first fetch call as a typed record, so the
|
||||
// strict typed-lint rules (no-unsafe-*) are satisfied without scattering casts.
|
||||
function parseSentBody(spy: ReturnType<typeof vi.fn>): Record<string, unknown> {
|
||||
const calls = spy.mock.calls as unknown as Array<[unknown, RequestInit]>;
|
||||
const init = calls[0][1];
|
||||
return JSON.parse(init.body as string) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
// Build a canonical camelCase payload using the contract type.
|
||||
// If SetupConfigPayload still has snake_case fields, TypeScript will error here
|
||||
// (the interface and this test agree on the camelCase contract).
|
||||
@@ -61,7 +76,7 @@ describe('postSetupConfig — payload contract (BUG 1 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupConfig(VALID_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).toHaveProperty('oidcIssuer', 'https://auth.example.com');
|
||||
expect(body).not.toHaveProperty('oidc_issuer');
|
||||
});
|
||||
@@ -70,7 +85,7 @@ describe('postSetupConfig — payload contract (BUG 1 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupConfig(VALID_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).toHaveProperty('oidcClientId', 'familysync');
|
||||
expect(body).not.toHaveProperty('oidc_client_id');
|
||||
});
|
||||
@@ -79,7 +94,7 @@ describe('postSetupConfig — payload contract (BUG 1 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupConfig(VALID_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).toHaveProperty('vapidPublicKey', 'BH_example_public_key');
|
||||
expect(body).not.toHaveProperty('vapid_public_key');
|
||||
});
|
||||
@@ -88,7 +103,7 @@ describe('postSetupConfig — payload contract (BUG 1 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupConfig(VALID_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).toHaveProperty('appExternalUrl', 'https://familysync.example.com');
|
||||
expect(body).not.toHaveProperty('app_url');
|
||||
});
|
||||
@@ -97,7 +112,7 @@ describe('postSetupConfig — payload contract (BUG 1 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupConfig(VALID_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(Object.keys(body).sort()).toEqual(
|
||||
['appExternalUrl', 'oidcClientId', 'oidcIssuer', 'vapidPublicKey'].sort(),
|
||||
);
|
||||
@@ -125,15 +140,17 @@ describe('postSetupConfig — error rendering (BUG 2 regression)', () => {
|
||||
error: {
|
||||
name: 'ZodError',
|
||||
issues: [
|
||||
{ code: 'invalid_string', message: 'oidcIssuer must be an https URL', path: ['oidcIssuer'] },
|
||||
{
|
||||
code: 'invalid_string',
|
||||
message: 'oidcIssuer must be an https URL',
|
||||
path: ['oidcIssuer'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(zodErrorBody, 400));
|
||||
|
||||
await expect(
|
||||
postSetupConfig(VALID_PAYLOAD),
|
||||
).rejects.toSatisfy((err: Error) => {
|
||||
await expect(postSetupConfig(VALID_PAYLOAD)).rejects.toSatisfy((err: Error) => {
|
||||
// The error message must NOT be "[object Object]"
|
||||
expect(err.message).not.toBe('[object Object]');
|
||||
// The error message must be a non-empty string
|
||||
@@ -149,31 +166,29 @@ describe('postSetupConfig — error rendering (BUG 2 regression)', () => {
|
||||
error: {
|
||||
name: 'ZodError',
|
||||
issues: [
|
||||
{ code: 'invalid_string', message: 'oidcIssuer must be an https URL', path: ['oidcIssuer'] },
|
||||
{
|
||||
code: 'invalid_string',
|
||||
message: 'oidcIssuer must be an https URL',
|
||||
path: ['oidcIssuer'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(zodErrorBody, 400));
|
||||
|
||||
await expect(
|
||||
postSetupConfig(VALID_PAYLOAD),
|
||||
).rejects.toThrow('oidcIssuer must be an https URL');
|
||||
await expect(postSetupConfig(VALID_PAYLOAD)).rejects.toThrow('oidcIssuer must be an https URL');
|
||||
});
|
||||
|
||||
it('throws a fallback status error when error body is empty', async () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse({}, 400));
|
||||
|
||||
await expect(
|
||||
postSetupConfig(VALID_PAYLOAD),
|
||||
).rejects.toThrow('400');
|
||||
await expect(postSetupConfig(VALID_PAYLOAD)).rejects.toThrow('400');
|
||||
});
|
||||
|
||||
it('returns void on 200 success', async () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
|
||||
await expect(
|
||||
postSetupConfig(VALID_PAYLOAD),
|
||||
).resolves.toBeUndefined();
|
||||
await expect(postSetupConfig(VALID_PAYLOAD)).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -202,7 +217,7 @@ describe('postSetupCredential — payload contract (CR-01 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(Object.keys(body).sort()).toEqual(['appPassword', 'fastmailEmail'].sort());
|
||||
});
|
||||
|
||||
@@ -210,7 +225,7 @@ describe('postSetupCredential — payload contract (CR-01 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).not.toHaveProperty('providerType');
|
||||
});
|
||||
|
||||
@@ -218,7 +233,7 @@ describe('postSetupCredential — payload contract (CR-01 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).toHaveProperty('fastmailEmail', 'user@fastmail.com');
|
||||
});
|
||||
|
||||
@@ -226,7 +241,7 @@ describe('postSetupCredential — payload contract (CR-01 regression)', () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
const body = parseSentBody(fetchSpy);
|
||||
expect(body).toHaveProperty('appPassword', 'secret-app-password');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user