mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-08-24 20:16:30 +00:00
test(e2e): fill the provider cassettes with the shape the backend emits
The settings-providers cassettes left nine of eleven default configs null and every model catalog empty. Verified against the live backend that this is a shape it never sends: gemini/deepseek/ollama all return a non-null default and a populated model catalog even with zero keys configured. The empty catalogs made the create-form's model-dropdown seeding path structurally unreachable — no spec could reach it. Give every type a default config and a two-entry catalog, and add a spec that picks a type and opens an agent's model dropdown: it asserts a catalog-only model appears there. That option is gone when the catalog is empty, so the spec fails on the old backend-impossible shape — the coverage that was missing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b4f50ba3f0
commit
0d4232a1d5
@@ -3,6 +3,7 @@ import type { ResultOf } from '@graphql-typed-document-node/core';
|
||||
import type {
|
||||
AgentConfigFragmentFragment,
|
||||
AgentsConfigFragmentFragment,
|
||||
ModelConfigFragmentFragment,
|
||||
ProviderConfigFragmentFragment,
|
||||
SettingsProvidersDocument,
|
||||
} from '@/graphql/types';
|
||||
@@ -66,21 +67,48 @@ const defaultConfig = (type: ProviderType): ProviderConfigFragmentFragment =>
|
||||
updatedAt: T,
|
||||
});
|
||||
|
||||
const modelConfig = (name: string): ModelConfigFragmentFragment =>
|
||||
entity('ModelConfig', { name, price: null, reasoning: null, thinking: null });
|
||||
|
||||
// The backend fills a default config AND a model catalog for EVERY type, keyed or not (verified live:
|
||||
// gemini/deepseek/ollama all return a non-null default and a populated catalog with zero keys). A
|
||||
// cassette leaving them null/[] encodes a wire state the resolver never emits and leaves the
|
||||
// create-form's model-dropdown seeding path structurally unreachable.
|
||||
const allDefaults = () =>
|
||||
entity('DefaultProvidersConfig', {
|
||||
anthropic: defaultConfig(ProviderType.Anthropic),
|
||||
bedrock: defaultConfig(ProviderType.Bedrock),
|
||||
custom: defaultConfig(ProviderType.Custom),
|
||||
deepseek: defaultConfig(ProviderType.Deepseek),
|
||||
gemini: defaultConfig(ProviderType.Gemini),
|
||||
glm: defaultConfig(ProviderType.Glm),
|
||||
kimi: defaultConfig(ProviderType.Kimi),
|
||||
minimax: defaultConfig(ProviderType.Minimax),
|
||||
ollama: defaultConfig(ProviderType.Ollama),
|
||||
openai: defaultConfig(ProviderType.Openai),
|
||||
qwen: defaultConfig(ProviderType.Qwen),
|
||||
});
|
||||
|
||||
const catalog = (type: ProviderType) => [modelConfig(`e2e-${type}-model`), modelConfig(`e2e-${type}-model-mini`)];
|
||||
|
||||
const allModels = () =>
|
||||
entity('ProvidersModelsList', {
|
||||
anthropic: catalog(ProviderType.Anthropic),
|
||||
bedrock: catalog(ProviderType.Bedrock),
|
||||
custom: catalog(ProviderType.Custom),
|
||||
deepseek: catalog(ProviderType.Deepseek),
|
||||
gemini: catalog(ProviderType.Gemini),
|
||||
glm: catalog(ProviderType.Glm),
|
||||
kimi: catalog(ProviderType.Kimi),
|
||||
minimax: catalog(ProviderType.Minimax),
|
||||
ollama: catalog(ProviderType.Ollama),
|
||||
openai: catalog(ProviderType.Openai),
|
||||
qwen: catalog(ProviderType.Qwen),
|
||||
});
|
||||
|
||||
const noProviders: ResultOf<typeof SettingsProvidersDocument> = {
|
||||
settingsProviders: entity('ProvidersConfig', {
|
||||
default: entity('DefaultProvidersConfig', {
|
||||
anthropic: defaultConfig(ProviderType.Anthropic),
|
||||
bedrock: null,
|
||||
custom: null,
|
||||
deepseek: null,
|
||||
gemini: null,
|
||||
glm: null,
|
||||
kimi: null,
|
||||
minimax: null,
|
||||
ollama: null,
|
||||
openai: defaultConfig(ProviderType.Openai),
|
||||
qwen: null,
|
||||
}),
|
||||
default: allDefaults(),
|
||||
enabled: entity('ProvidersReadinessStatus', {
|
||||
anthropic: false,
|
||||
bedrock: false,
|
||||
@@ -94,19 +122,7 @@ const noProviders: ResultOf<typeof SettingsProvidersDocument> = {
|
||||
openai: false,
|
||||
qwen: false,
|
||||
}),
|
||||
models: entity('ProvidersModelsList', {
|
||||
anthropic: [],
|
||||
bedrock: [],
|
||||
custom: [],
|
||||
deepseek: [],
|
||||
gemini: [],
|
||||
glm: [],
|
||||
kimi: [],
|
||||
minimax: [],
|
||||
ollama: [],
|
||||
openai: [],
|
||||
qwen: [],
|
||||
}),
|
||||
models: allModels(),
|
||||
userDefined: [],
|
||||
}),
|
||||
};
|
||||
@@ -125,19 +141,7 @@ export const settingsProvidersCassette = (override: Cassette = {}): Cassette =>
|
||||
|
||||
const populatedProviders: ResultOf<typeof SettingsProvidersDocument> = {
|
||||
settingsProviders: entity('ProvidersConfig', {
|
||||
default: entity('DefaultProvidersConfig', {
|
||||
anthropic: defaultConfig(ProviderType.Anthropic),
|
||||
bedrock: null,
|
||||
custom: null,
|
||||
deepseek: null,
|
||||
gemini: null,
|
||||
glm: null,
|
||||
kimi: null,
|
||||
minimax: null,
|
||||
ollama: null,
|
||||
openai: defaultConfig(ProviderType.Openai),
|
||||
qwen: null,
|
||||
}),
|
||||
default: allDefaults(),
|
||||
enabled: entity('ProvidersReadinessStatus', {
|
||||
anthropic: true,
|
||||
bedrock: false,
|
||||
@@ -151,19 +155,7 @@ const populatedProviders: ResultOf<typeof SettingsProvidersDocument> = {
|
||||
openai: true,
|
||||
qwen: false,
|
||||
}),
|
||||
models: entity('ProvidersModelsList', {
|
||||
anthropic: [],
|
||||
bedrock: [],
|
||||
custom: [],
|
||||
deepseek: [],
|
||||
gemini: [],
|
||||
glm: [],
|
||||
kimi: [],
|
||||
minimax: [],
|
||||
ollama: [],
|
||||
openai: [],
|
||||
qwen: [],
|
||||
}),
|
||||
models: allModels(),
|
||||
userDefined: [
|
||||
entity('ProviderConfig', {
|
||||
agents: agentsConfig(),
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { expect, test } from '../../fixtures/test.ts';
|
||||
import { expectCleanPage } from '../../helpers/errors.ts';
|
||||
import { settingsProvidersCassette } from '../../mocks/cassettes/settings-providers.ts';
|
||||
import {
|
||||
populatedSettingsProvidersCassette,
|
||||
settingsProvidersCassette,
|
||||
} from '../../mocks/cassettes/settings-providers.ts';
|
||||
|
||||
test.describe('settings providers', { tag: '@coverage' }, () => {
|
||||
test.use({ cassette: settingsProvidersCassette() });
|
||||
@@ -27,3 +30,26 @@ test.describe('settings providers', { tag: '@coverage' }, () => {
|
||||
expectCleanPage(pageErrorLog);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('settings providers create form', { tag: '@coverage' }, () => {
|
||||
// Needs a cassette where the type is enabled: the create form bounces `?type=` for a disabled
|
||||
// one, so the empty seed would just redirect to the list.
|
||||
test.use({ cassette: populatedSettingsProvidersCassette() });
|
||||
|
||||
// A selected type seeds each agent's model from that type's catalog. The catalog must carry the
|
||||
// shape the backend actually emits (a non-empty model list for every type, keyed or not); an
|
||||
// empty catalog makes this whole path unreachable and any assertion on it vacuous. `?type=` is
|
||||
// the URL the type picker produces, driven directly to avoid the dirty-form navigation blocker.
|
||||
test('seeds the agent model from the selected type catalog', async ({ page, pageErrorLog }) => {
|
||||
await page.goto('/settings/providers/new?type=anthropic');
|
||||
|
||||
await page.getByRole('button', { name: /^Adviser/ }).click();
|
||||
await page.getByRole('button', { name: 'Open model list' }).first().click();
|
||||
|
||||
// A catalog-only model (not the seeded agent default), so it can only appear if the type's
|
||||
// model list reached the dropdown — the path an empty catalog leaves unreachable.
|
||||
await expect(page.getByRole('option', { name: 'e2e-anthropic-model-mini' })).toBeVisible();
|
||||
|
||||
expectCleanPage(pageErrorLog);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user