fix(12): CR-01 remove extraneous providerType from postSetupCredential wire body
The server's credentialSchema does not declare providerType; it was being silently stripped by Zod. Remove it from the request body and add a contract test suite asserting the exact wire keys sent, mirroring the existing BUG-1 tests for postSetupConfig. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ef3e9810a9
commit
066b69f2be
@@ -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