Files
confidence-engine/tests/e2e/fixtures/investigation-scenarios.js
T

255 lines
8.6 KiB
JavaScript

/**
* Investigation scenarios — shared fixture data for all E2E Playwright tests.
*
* Each scenario defines:
* - name / centralStatement (the text entered into the scenario textarea)
* - mockMode (which mock mode to activate: "complete" | "error" | "" )
* - answerSequence [ { text, expectedHeadingAfterTurn } ]
* - expectedTerminalState (final card heading)
* - screenshots [ { label, expectedVisible } ]
*
* The test scripts drive the application through these scenarios using the
* Developer-details scenario selector (UI mock mode), or by setting env vars.
*/
/* ── Shared constants ─────────────────────────────────────── */
const BASE_SCENARIO_TEXT =
"Complaints increased by 35% while production increased by 40%.";
/* ── Scenario definitions ─────────────────────────────────── */
/**
* Multi-turn investigation with at least 2 turns.
* Uses the default sequential-turn mock (no special scenario flag).
*/
const happyPathComparison = {
name: "Happy path — multi-turn comparison",
centralStatement:
"Product A has a 4.2 star average rating while Product B averages 4.6 stars across 10,000+ reviews each.",
mockMode: "", // "" → sequential turns via default mock
turnCount: 3,
answerSequence: [
{
text: "Yes, both are standard 5-star scales.",
expectedHeadingAfterTurn: "Current investigation",
},
{
text: "The gap persists across verified purchase reviews.",
expectedHeadingAfterTurn: "Current investigation",
},
],
terminalState: null, // does not reach a terminal state (unknowns remain)
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "after-first-turn", afterAction: "after-answer-1" },
],
};
/**
* Complete investigation — all unknowns resolved.
* Uses the "complete" mock mode (jumps to terminal after start).
*/
const happyPathComplete = {
name: "Happy path — complete investigation",
centralStatement: BASE_SCENARIO_TEXT,
mockMode: "complete",
turnCount: 1, // start gives turn 0, first update → final state
answerSequence: [
{
text: "The complaint rate fell from 2.0 per 100 to 1.9 per 100 units.",
expectedHeadingAfterTurn: "Investigation complete",
},
],
terminalState: "Investigation complete",
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "terminal-state", afterAction: "after-answer-1" },
],
};
/**
* Evidence-limit state — unknowns remain but no next question.
*/
const evidenceLimit = {
name: "Evidence limit (stuck early)",
centralStatement:
"Should a mid-sized manufacturing company invest in automated quality inspection?",
mockMode: "", // single-turn default scenario
turnCount: 1,
answerSequence: [], // no answers needed — stuck after start
terminalState: "Current evidence limit reached",
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "terminal-state", afterAction: "after-start" },
],
};
/**
* Provider error — all calls return a structured provider error.
*/
const providerError = {
name: "Provider error",
centralStatement: BASE_SCENARIO_TEXT,
mockMode: "error",
turnCount: 0, // start call also errors
answerSequence: [],
terminalState: null,
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "terminal-state", afterAction: "after-start" },
],
};
/**
* Malformed response — the start produces a malformed shape.
* (We simulate this via error mode which skips all structured output.)
*/
const malformedResponse = {
name: "Malformed response",
centralStatement: BASE_SCENARIO_TEXT,
mockMode: "error", // reuses error mode for malformed path
turnCount: 0,
answerSequence: [],
terminalState: null,
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "terminal-state", afterAction: "after-start" },
],
};
/**
* Long investigation — market entry, 5 turns.
*/
const longInvestigation = {
name: "Long investigation — European market entry",
centralStatement:
"Should we enter the European market with our SaaS analytics platform?",
mockMode: "", // sequential turns from scenario data (long array)
turnCount: 5,
answerSequence: [
{ text: "The market is valued at approximately €8B and growing.", expectedHeadingAfterTurn: "Current investigation" },
{ text: "Our platform does not currently support EU data residency.", expectedHeadingAfterTurn: "Current investigation" },
{ text: "Achieving compliance would take 6 months and $500K engineering investment.", expectedHeadingAfterTurn: "Current investigation" },
{ text: "Our real-time collaboration feature has no direct European equivalent.", expectedHeadingAfterTurn: "Investigation complete", isLast: true },
],
terminalState: "Investigation complete",
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "mid-investigation", afterAction: "after-answer-2" },
{ label: "terminal-state", afterAction: "after-answer-4" },
],
};
/**
* Contradiction fixture — two opposing recommendations.
*/
const contradictionFixture = {
name: "Contradiction fixture",
centralStatement:
"Two consultants provided opposite recommendations about whether to outsource IT operations.",
mockMode: "",
turnCount: 2,
answerSequence: [
{ text: "Consultant A focused on cost over 2 years; Consultant B focused on quality over 5+ years.", expectedHeadingAfterTurn: "Current investigation" },
],
terminalState: null,
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "after-answer-1", afterAction: "after-answer-1" },
],
};
/**
* Diagnosis fixture — churn diagnosis.
*/
const diagnosisFixture = {
name: "Diagnosis fixture",
centralStatement:
"Customer churn increased from 2% to 5% monthly over the last quarter.",
mockMode: "",
turnCount: 1,
answerSequence: [],
terminalState: null,
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "terminal-state", afterAction: "after-start" },
],
};
/**
* Comparison fixture — product ratings with 3 turns.
*/
const comparisonFixture = {
name: "Comparison fixture",
centralStatement:
"Product A has a 4.2 star average rating while Product B averages 4.6 stars across 10,000+ reviews each.",
mockMode: "",
turnCount: 3,
answerSequence: [
{ text: "Both use the standard 5-star customer review scale.", expectedHeadingAfterTurn: "Current investigation" },
{ text: "Verified purchase gap remains approximately 0.3 stars.", expectedHeadingAfterTurn: "Current investigation" },
],
terminalState: null,
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "after-answer-1", afterAction: "after-answer-1" },
],
};
/**
* Prioritisation fixture — decision investigation.
*/
const prioritisationFixture = {
name: "Prioritisation fixture (team relocation)",
centralStatement:
"Should I relocate my engineering team from London to Manchester?",
mockMode: "",
turnCount: 2,
answerSequence: [
{ text: "Manchester has a growing tech ecosystem with 500+ roles posted monthly.", expectedHeadingAfterTurn: "Current investigation" },
],
terminalState: null,
screenshots: [
{ label: "initial-state", afterAction: "before-start" },
{ label: "after-answer-1", afterAction: "after-answer-1" },
],
};
/* ── Registry for dynamic test generation ─────────────────── */
export const INVESTIGATION_SCENARIOS = [
happyPathComparison,
happyPathComplete,
evidenceLimit,
providerError,
malformedResponse,
longInvestigation,
contradictionFixture,
diagnosisFixture,
comparisonFixture,
prioritisationFixture,
];
export const SCENARIO_LOOKUP = {};
INVESTIGATION_SCENARIOS.forEach((s) => {
SCENARIO_LOOKUP[s.name] = s;
});
/**
* Helper to get the answer text for a given turn index.
* Returns null if there is no answer for that turn.
*/
export function getAnswerForTurn(scenario, turnIndex) {
return scenario.answerSequence[turnIndex]?.text || null;
}
/**
* Return the list of screenshots in execution order.
*/
export function getScreenshotsOrdered(screenshotList) {
// Preserve insertion order from scenario definition
return screenshotList;
}
export default INVESTIGATION_SCENARIOS;