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',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
providerType: 'caldav',
|
|
||||||
fastmailEmail: payload.fastmailEmail,
|
fastmailEmail: payload.fastmailEmail,
|
||||||
appPassword: payload.appPassword,
|
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 { 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 ──────────────────────────────────────────────────────────────────
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -176,3 +176,57 @@ describe('postSetupConfig — error rendering (BUG 2 regression)', () => {
|
|||||||
).resolves.toBeUndefined();
|
).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