/**
* Multiple Choice Flow E2E Tests
*
* Tests the complete flow for multiple choice requests including:
* - Question display with options
* - Option selection and deselection
* - Comment fields and validation
* - Priority handling and visual indicators
* - Bulk selection features
* - Completion status buttons
* - Tool redirect functionality
*/
import { test, expect } from '@playwright/test';
import { RequestHandlerPage } from '../support/page-objects/request-handler.page';
import { MultipleChoiceResponsePage } from '../support/page-objects/response-components.page';
import { ServerManager, TEST_PORTS, getAvailablePort } from '../support/test-utils/server-manager';
import { createMultipleChoiceRequest, generateLargeMultipleChoiceRequest, TEST_SCENARIOS } from '../support/test-utils/test-data';
import {
mockBrowserNotifications,
waitForSSEConnection,
waitForNetworkRequest,
logTestStep,
fillAndVerify,
randomString
} from '../support/test-utils/helpers';
test.describe('Multiple Choice Flow', () => {
let serverManager: ServerManager;
let requestHandler: RequestHandlerPage;
let multipleChoice: MultipleChoiceResponsePage;
test.beforeEach(async ({ page }) => {
await mockBrowserNotifications(page);
const availablePort = await getAvailablePort(TEST_PORTS.MULTIPLE_CHOICE);
serverManager = new ServerManager({
port: availablePort,
debug: true
});
logTestStep('Starting MCP server', { port: availablePort });
await serverManager.start();
requestHandler = new RequestHandlerPage(page);
multipleChoice = new MultipleChoiceResponsePage(page);
await requestHandler.goto(availablePort);
await requestHandler.waitForLoad();
await waitForSSEConnection(page);
await requestHandler.waitForConnection();
});
test.afterEach(async () => {
if (serverManager) {
await serverManager.stop();
}
});
test('should display multiple choice request correctly', async ({ page }) => {
logTestStep('Testing multiple choice display');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
// Wait for request to appear in UI
await expect(requestHandler.currentRequest).toBeVisible();
// Verify request type is detected correctly
const requestType = await requestHandler.getCurrentRequestType();
expect(requestType).toBe('multiple-choice');
// Verify multiple choice component is visible
await expect(multipleChoice.component).toBeVisible();
// Check question count
const questionCount = await multipleChoice.getQuestionCount();
expect(questionCount).toBeGreaterThan(0);
// Verify submit button is present
await expect(multipleChoice.submitButton).toBeVisible();
logTestStep('Multiple choice displayed correctly', { questionCount });
});
test('should handle single option selection', async ({ page }) => {
logTestStep('Testing single option selection');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Select an option from the first question
await multipleChoice.selectOption(0, 0);
// Verify selection is reflected in UI
const firstQuestion = multipleChoice.questions.nth(0);
const firstOption = firstQuestion.locator('.option-item').nth(0);
await expect(firstOption.locator('input[type="checkbox"]')).toBeChecked();
logTestStep('Single option selection verified');
});
test('should handle multiple option selection', async ({ page }) => {
logTestStep('Testing multiple option selection');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Select multiple options from the first question (which allows multiple)
await multipleChoice.selectOption(0, 0);
await multipleChoice.selectOption(0, 1);
await multipleChoice.selectOption(0, 2);
// Verify all selections
const firstQuestion = multipleChoice.questions.nth(0);
for (let i = 0; i < 3; i++) {
const option = firstQuestion.locator('.option-item').nth(i);
await expect(option.locator('input[type="checkbox"]')).toBeChecked();
}
logTestStep('Multiple option selection verified');
});
test('should handle comment fields', async ({ page }) => {
logTestStep('Testing comment fields');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Select an option first, then add comment to it
await multipleChoice.selectOption(0, 0); // Select first option of first question
const commentText = 'This is my reasoning for the selection';
await multipleChoice.addComment(0, 0, commentText); // Add comment to first option
// Verify comment was added to the selected option
const firstQuestion = multipleChoice.questions.nth(0);
const firstOption = firstQuestion.locator('.option-item').nth(0);
const commentField = firstOption.locator('.comment-input');
await expect(commentField).toHaveValue(commentText);
logTestStep('Comment fields verified');
});
test('should handle priority indicators', async ({ page }) => {
logTestStep('Testing priority indicators');
const testRequest = TEST_SCENARIOS.URGENT_PRIORITY;
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Look for priority indicators (usually arrows or styling)
const firstQuestion = multipleChoice.questions.nth(0);
const priorityIndicator = firstQuestion.locator('.priority-indicator, .priority-arrow, [class*="priority"]');
// Should have some priority indicator element
const hasIndicator = await priorityIndicator.count() > 0;
if (hasIndicator) {
await expect(priorityIndicator.first()).toBeVisible();
}
logTestStep('Priority indicators verified', { hasIndicator });
});
test('should submit multiple choice response', async ({ page }) => {
logTestStep('Testing multiple choice response submission');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Make selections
await multipleChoice.selectOption(0, 0);
await multipleChoice.selectOption(0, 1);
await multipleChoice.selectOption(1, 2);
// Add comments to the selected options
await multipleChoice.addComment(0, 1, 'Backend languages are important'); // Comment on option 1 of question 0
await multipleChoice.addComment(1, 2, 'PostgreSQL is reliable'); // Comment on option 2 of question 1
// Submit response
const responsePromise = waitForNetworkRequest(page, '/mcp/response');
await multipleChoice.submit();
await responsePromise;
// Request should be cleared after submission
await expect(requestHandler.currentRequest).toBeHidden();
await expect(requestHandler.waitingMessage).toBeVisible();
logTestStep('Multiple choice response submitted successfully');
});
test('should handle completion status buttons', async ({ page }) => {
logTestStep('Testing completion status buttons');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Make a selection
await multipleChoice.selectOption(0, 0);
// Test "Done" button
const doneResponsePromise = waitForNetworkRequest(page, '/mcp/response');
await multipleChoice.submitWithDone();
await doneResponsePromise;
logTestStep('Done button functionality verified');
// Test "Drill Deeper" button with new request
const drillRequest = createMultipleChoiceRequest({
question: 'Follow-up multiple choice questions'
});
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: drillRequest
});
await expect(multipleChoice.component).toBeVisible({ timeout: 20000 });
// Wait for options to be fully interactive (especially important for WebKit)
const secondOption = multipleChoice.questions.nth(0).locator('.option-item').nth(1);
await expect(secondOption).toBeVisible();
await expect(secondOption.locator('input[type="checkbox"]')).toBeVisible();
await multipleChoice.selectOption(0, 1);
const drillResponsePromise = waitForNetworkRequest(page, '/mcp/response');
await multipleChoice.submitWithDrillDeeper();
await drillResponsePromise;
logTestStep('Drill deeper button functionality verified');
});
test('should handle tool redirect functionality', async ({ page }) => {
logTestStep('Testing tool redirect functionality');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Test redirect to open question
const openQuestionRedirectPromise = waitForNetworkRequest(page, '/mcp/response');
await multipleChoice.clickOpenQuestionBailout();
await openQuestionRedirectPromise;
// Should clear current request and show waiting state
await expect(requestHandler.currentRequest).toBeHidden();
logTestStep('Open question redirect verified');
// Test redirect to hypothesis challenge
const hypothesisRequest = createMultipleChoiceRequest({
question: 'Another multiple choice for hypothesis testing'
});
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: hypothesisRequest
});
await expect(multipleChoice.component).toBeVisible();
const hypothesisRedirectPromise = waitForNetworkRequest(page, '/mcp/response');
await multipleChoice.clickHypothesisBailout();
await hypothesisRedirectPromise;
logTestStep('Hypothesis challenge redirect verified');
});
test('should handle selection summary', async ({ page }) => {
logTestStep('Testing selection summary');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Make some selections
await multipleChoice.selectOption(0, 0);
await multipleChoice.selectOption(0, 1);
await multipleChoice.selectOption(1, 0);
// Check if selection summary is updated
try {
const summary = await multipleChoice.getSelectionSummary();
expect(summary.length).toBeGreaterThan(0);
logTestStep('Selection summary verified', { summary });
} catch {
logTestStep('Selection summary not present (acceptable)');
}
});
test('should handle large number of questions', async ({ page }) => {
logTestStep('Testing large multiple choice sets');
const largeRequest = generateLargeMultipleChoiceRequest(15);
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: largeRequest
});
await expect(multipleChoice.component).toBeVisible();
// Verify all questions are displayed
const questionCount = await multipleChoice.getQuestionCount();
expect(questionCount).toBe(15);
// Make selections across multiple questions
for (let i = 0; i < 5; i++) {
await multipleChoice.selectOption(i, 0);
}
// Should still be able to submit
await expect(multipleChoice.submitButton).toBeEnabled();
logTestStep('Large multiple choice set handled correctly', { questionCount });
});
test('should handle form validation', async ({ page }) => {
logTestStep('Testing form validation');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Try to submit without selections (should be allowed but might show warning)
await expect(multipleChoice.submitButton).toBeEnabled();
// Make a selection and verify submit is still enabled
await multipleChoice.selectOption(0, 0);
await expect(multipleChoice.submitButton).toBeEnabled();
logTestStep('Form validation verified');
});
test('should handle question with single vs multiple selection', async ({ page }) => {
logTestStep('Testing single vs multiple selection behavior');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// First question allows multiple selections
await multipleChoice.selectOption(0, 0);
await multipleChoice.selectOption(0, 1);
// Verify both are selected
const firstQuestion = multipleChoice.questions.nth(0);
await expect(firstQuestion.locator('.option-item').nth(0).locator('input')).toBeChecked();
await expect(firstQuestion.locator('.option-item').nth(1).locator('input')).toBeChecked();
// Second question typically allows single selection only
await multipleChoice.selectOption(1, 0);
await multipleChoice.selectOption(1, 1); // This might deselect the first
logTestStep('Single vs multiple selection behavior verified');
});
test('should handle responsive design for questions', async ({ page }) => {
logTestStep('Testing responsive design for multiple choice');
const testRequest = createMultipleChoiceRequest();
await page.request.post(`${serverManager.getServerUrl()}/mcp/simulate-request`, {
data: testRequest
});
await expect(multipleChoice.component).toBeVisible();
// Test mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
await expect(multipleChoice.component).toBeVisible();
await expect(multipleChoice.questions.first()).toBeVisible();
// Test desktop viewport
await page.setViewportSize({ width: 1200, height: 800 });
await expect(multipleChoice.component).toBeVisible();
await expect(multipleChoice.questions.first()).toBeVisible();
logTestStep('Responsive design verified');
});
});