Phase 12: Initial Setup Wizard #22
@@ -671,9 +671,9 @@ export async function postSetupCredential(payload: SetupCredentialPayload): Prom
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
providerType: 'caldav',
|
||||
fastmailEmail: payload.fastmailEmail,
|
||||
appPassword: payload.appPassword,
|
||||
// providerType omitted — not in credentialSchema; server hard-codes 'caldav'
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { postSetupConfig, type SetupConfigPayload } from './client.js';
|
||||
import { postSetupConfig, postSetupCredential, type SetupConfigPayload, type SetupCredentialPayload } from './client.js';
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -176,3 +176,57 @@ describe('postSetupConfig — error rendering (BUG 2 regression)', () => {
|
||||
).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
// ── CR-01: postSetupCredential wire body contract ─────────────────────────────
|
||||
// Guards that postSetupCredential sends exactly { fastmailEmail, appPassword }
|
||||
// matching the server's credentialSchema — no extra fields (e.g. providerType).
|
||||
|
||||
describe('postSetupCredential — payload contract (CR-01 regression)', () => {
|
||||
let fetchSpy: ReturnType<typeof vi.fn>;
|
||||
|
||||
const VALID_CREDENTIAL_PAYLOAD: SetupCredentialPayload = {
|
||||
fastmailEmail: 'user@fastmail.com',
|
||||
appPassword: 'secret-app-password',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
fetchSpy = vi.fn();
|
||||
vi.stubGlobal('fetch', fetchSpy);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('sends exactly the 2 canonical fields matching credentialSchema', async () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
expect(Object.keys(body).sort()).toEqual(['appPassword', 'fastmailEmail'].sort());
|
||||
});
|
||||
|
||||
it('does NOT send providerType (not in credentialSchema; server hard-codes caldav)', async () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
expect(body).not.toHaveProperty('providerType');
|
||||
});
|
||||
|
||||
it('sends fastmailEmail matching the payload value', async () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
expect(body).toHaveProperty('fastmailEmail', 'user@fastmail.com');
|
||||
});
|
||||
|
||||
it('sends appPassword matching the payload value', async () => {
|
||||
fetchSpy.mockResolvedValueOnce(mockFetchResponse(null, 200));
|
||||
await postSetupCredential(VALID_CREDENTIAL_PAYLOAD);
|
||||
|
||||
const body = JSON.parse(fetchSpy.mock.calls[0][1].body as string);
|
||||
expect(body).toHaveProperty('appPassword', 'secret-app-password');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user