From 548cc12488559be4ec71e9e17090cceb54cb8370 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Sun, 26 Jul 2026 04:46:44 +0700 Subject: [PATCH] test(e2e): pin the provider create payload, including the fields that get dropped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The provider editor's whole write path had no oracle: createProvider, updateProvider, deleteProvider and the two test mutations were absent from every spec. The failure this guards is not hypothetical — the same class (a zero-ish agent field silently lost between the form and the wire) was found and fixed in the converter one round ago, with nothing left behind to keep it fixed. The cassette's defaults now carry `json: true`, `n: 1` and a real maxTokens, and the spec asserts the createProvider variables still hold them after the form round trip, plus that all thirteen agents are serialised rather than only the one the user touched. Dropping `n` from transformFormToGraphQL turns it red. Co-Authored-By: Claude Opus 4.8 --- .../e2e/mocks/cassettes/settings-providers.ts | 8 +-- frontend/e2e/specs/settings/providers.spec.ts | 50 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/frontend/e2e/mocks/cassettes/settings-providers.ts b/frontend/e2e/mocks/cassettes/settings-providers.ts index c8f7119e..b0724889 100644 --- a/frontend/e2e/mocks/cassettes/settings-providers.ts +++ b/frontend/e2e/mocks/cassettes/settings-providers.ts @@ -17,17 +17,19 @@ import { baseQueries, baseRest } from './base.ts'; const T = '2026-01-15T09:00:00Z'; +/** `n: 1` and `json: true` are the shipped simple_json defaults; they are pinned in the create payload + * because dropping exactly these on the way to the wire is a regression this repo has already had. */ const agentConfig = (model = 'e2e-model'): AgentConfigFragmentFragment => entity('AgentConfig', { extraBody: null, frequencyPenalty: null, - json: null, + json: true, maxLength: null, - maxTokens: null, + maxTokens: 4096, minLength: null, minP: null, model, - n: null, + n: 1, presencePenalty: null, price: null, reasoning: null, diff --git a/frontend/e2e/specs/settings/providers.spec.ts b/frontend/e2e/specs/settings/providers.spec.ts index 98760ea2..2f8023be 100644 --- a/frontend/e2e/specs/settings/providers.spec.ts +++ b/frontend/e2e/specs/settings/providers.spec.ts @@ -53,3 +53,53 @@ test.describe('settings providers create form', { tag: '@coverage' }, () => { expectCleanPage(pageErrorLog); }); }); + +test.describe('settings providers write path', { tag: '@coverage' }, () => { + const CREATED_NAME = 'E2E created provider'; + + test.use({ + cassette: populatedSettingsProvidersCassette({ + mutations: { + createProvider: [ + { + data: { createProvider: { __typename: 'ResultType', result: 'success' } } as never, + variables: { name: CREATED_NAME, type: 'anthropic' }, + }, + ], + }, + }), + }); + + // The create form is seeded from the type's defaults and then serialises the whole agents map back. + // Fields the user never touches are exactly the ones that get dropped on the way to the wire — this + // asserts the payload, because the UI looks identical either way. + test('create sends every agent field it was seeded with, zero-ish values included', async ({ + page, + pageErrorLog, + }) => { + await page.goto('/settings/providers/new?type=anthropic'); + + await expect(page.getByLabel('Name', { exact: true })).toBeVisible(); + await page.getByLabel('Name', { exact: true }).fill(CREATED_NAME); + + const request = page.waitForRequest( + (candidate) => + candidate.method() === 'POST' && candidate.postDataJSON()?.operationName === 'createProvider', + ); + + await page.getByRole('button', { exact: true, name: 'Create' }).click(); + + const { variables } = (await request).postDataJSON(); + + expect(variables.name).toBe(CREATED_NAME); + expect(variables.type).toBe('anthropic'); + expect(Object.keys(variables.agents), 'every agent is serialised, not just the edited one').toHaveLength(13); + expect(variables.agents.simpleJson).toMatchObject({ + json: true, + maxTokens: 4096, + model: 'e2e-anthropic-model', + n: 1, + }); + expectCleanPage(pageErrorLog); + }); +});