/**
* Page Object Model for Response Components
*
* Abstracts interactions with different response components:
* - ResponseInputComponent (single questions)
* - MultipleChoiceResponseComponent
* - HypothesisResponseComponent
* - ChooseNextResponseComponent
*/
import { Page, Locator, expect } from '@playwright/test';
export class ResponseInputPage {
readonly page: Page;
readonly component: Locator;
readonly textarea: Locator;
readonly submitButton: Locator;
readonly clearButton: Locator;
readonly doneButton: Locator;
readonly drillDeeperButton: Locator;
readonly bailoutButtons: Locator;
readonly multipleChoiceBailout: Locator;
readonly hypothesisBailout: Locator;
readonly characterCount: Locator;
constructor(page: Page) {
this.page = page;
this.component = page.locator('app-response-input');
this.textarea = this.component.locator('textarea');
this.submitButton = this.component.locator('button:has-text("Send Response")');
this.clearButton = this.component.locator('button:has-text("Clear")');
this.doneButton = this.component.locator('.btn-icon.btn-done');
this.drillDeeperButton = this.component.locator('.btn-icon.btn-drill-deeper');
this.bailoutButtons = this.component.locator('.top-bail-out-buttons');
this.multipleChoiceBailout = this.bailoutButtons.locator('button:has-text("📝 Use Multiple Choice Instead")');
this.hypothesisBailout = this.bailoutButtons.locator('button:has-text("🔍 Use Hypothesis Challenge Instead")');
this.characterCount = this.component.locator('.char-count');
}
async isVisible(): Promise<boolean> {
return await this.component.isVisible();
}
async fillResponse(text: string): Promise<void> {
await this.textarea.fill(text);
}
async submit(): Promise<void> {
await this.submitButton.click();
}
async submitWithDone(): Promise<void> {
await this.doneButton.click();
}
async submitWithDrillDeeper(): Promise<void> {
await this.drillDeeperButton.click();
}
async clear(): Promise<void> {
await this.clearButton.click();
}
async clickMultipleChoiceBailout(): Promise<void> {
await this.multipleChoiceBailout.click();
}
async clickHypothesisBailout(): Promise<void> {
await this.hypothesisBailout.click();
}
async getCharacterCount(): Promise<string> {
return await this.characterCount.textContent() || '';
}
async submitWithKeyboard(): Promise<void> {
await this.textarea.press('Control+Enter');
}
}
export class MultipleChoiceResponsePage {
readonly page: Page;
readonly component: Locator;
readonly questions: Locator;
readonly submitButton: Locator;
readonly clearButton: Locator;
readonly doneButton: Locator;
readonly drillDeeperButton: Locator;
readonly bailoutButtons: Locator;
readonly openQuestionBailout: Locator;
readonly hypothesisBailout: Locator;
readonly selectionSummary: Locator;
constructor(page: Page) {
this.page = page;
this.component = page.locator('app-multiple-choice-response');
this.questions = this.component.locator('.question-card');
this.submitButton = this.component.locator('button:has-text("Submit Response")');
this.clearButton = this.component.locator('button:has-text("Clear All")');
this.doneButton = this.component.locator('.btn-icon.btn-done');
this.drillDeeperButton = this.component.locator('.btn-icon.btn-drill-deeper');
this.bailoutButtons = this.component.locator('.top-bail-out-buttons');
this.openQuestionBailout = this.bailoutButtons.locator('button:has-text("🤔 Use Open Question Instead")');
this.hypothesisBailout = this.bailoutButtons.locator('button:has-text("🔍 Use Hypothesis Challenge Instead")');
this.selectionSummary = this.component.locator('.selection-summary');
}
async isVisible(): Promise<boolean> {
return await this.component.isVisible();
}
async getQuestionCount(): Promise<number> {
return await this.questions.count();
}
async selectOption(questionIndex: number, optionIndex: number): Promise<void> {
const question = this.questions.nth(questionIndex);
const option = question.locator('.option-item').nth(optionIndex);
await option.locator('input[type="checkbox"]').check();
}
async addComment(questionIndex: number, optionIndex: number, comment: string): Promise<void> {
const question = this.questions.nth(questionIndex);
const option = question.locator('.option-item').nth(optionIndex);
// Open the comment section first
await option.locator('summary.comment-toggle').click();
const commentField = option.locator('.comment-input');
await commentField.fill(comment);
}
async submit(): Promise<void> {
await this.submitButton.click();
}
async submitWithDone(): Promise<void> {
await this.doneButton.click();
}
async submitWithDrillDeeper(): Promise<void> {
await this.drillDeeperButton.click();
}
async clickOpenQuestionBailout(): Promise<void> {
await this.openQuestionBailout.click();
}
async clickHypothesisBailout(): Promise<void> {
await this.hypothesisBailout.click();
}
async getSelectionSummary(): Promise<string> {
return await this.selectionSummary.textContent() || '';
}
}
export class HypothesisResponsePage {
readonly page: Page;
readonly component: Locator;
readonly hypotheses: Locator;
readonly submitButton: Locator;
readonly clearButton: Locator;
readonly doneButton: Locator;
readonly drillDeeperButton: Locator;
readonly bailoutButtons: Locator;
readonly openQuestionBailout: Locator;
readonly multipleChoiceBailout: Locator;
readonly wontAnswerChallenge: Locator;
constructor(page: Page) {
this.page = page;
this.component = page.locator('app-hypothesis-response');
this.hypotheses = this.component.locator('.hypothesis-card');
this.submitButton = this.component.locator('button:has-text("Submit Evaluation")');
this.clearButton = this.component.locator('button:has-text("Clear All")');
this.doneButton = this.component.locator('.btn-icon.btn-done');
this.drillDeeperButton = this.component.locator('.btn-icon.btn-drill-deeper');
this.bailoutButtons = this.component.locator('.top-bail-out-buttons');
this.openQuestionBailout = this.bailoutButtons.locator('button:has-text("🤔 Use Open Question Instead")');
this.multipleChoiceBailout = this.bailoutButtons.locator('button:has-text("📝 Use Multiple Choice Instead")');
this.wontAnswerChallenge = this.component.locator('.wont-answer-section');
}
async isVisible(): Promise<boolean> {
return await this.component.isVisible();
}
async getHypothesisCount(): Promise<number> {
return await this.hypotheses.count();
}
async setAgreementLevel(hypothesisIndex: number, level: number): Promise<void> {
const hypothesis = this.hypotheses.nth(hypothesisIndex);
const emojiButton = hypothesis.locator('.agreement-scale .agreement-button').nth(level);
await emojiButton.click();
}
async addHypothesisComment(hypothesisIndex: number, comment: string): Promise<void> {
const hypothesis = this.hypotheses.nth(hypothesisIndex);
// Open the comment section first
await hypothesis.locator('summary.comment-toggle').click();
const commentField = hypothesis.locator('.comment-input');
await commentField.fill(comment);
}
async setWontAnswerHypothesis(hypothesisIndex: number): Promise<void> {
const hypothesis = this.hypotheses.nth(hypothesisIndex);
const wontAnswerCheckbox = hypothesis.locator('.hypothesis-wont-answer input[type="checkbox"]');
await wontAnswerCheckbox.check();
}
async setWontAnswerChallenge(reason: string): Promise<void> {
const checkbox = this.wontAnswerChallenge.locator('input[type="checkbox"]');
await checkbox.check();
// Wait for the why section to appear, then find the textarea
const whySection = this.component.locator('.why-section');
await whySection.waitFor({ state: 'visible' });
const textarea = whySection.locator('.why-input');
await textarea.fill(reason);
}
async submit(): Promise<void> {
await this.submitButton.click();
}
async submitWithDone(): Promise<void> {
await this.doneButton.click();
}
async submitWithDrillDeeper(): Promise<void> {
await this.drillDeeperButton.click();
}
async clickOpenQuestionBailout(): Promise<void> {
await this.openQuestionBailout.click();
}
async clickMultipleChoiceBailout(): Promise<void> {
await this.multipleChoiceBailout.click();
}
}
export class ChooseNextResponsePage {
readonly page: Page;
readonly component: Locator;
readonly options: Locator;
readonly abortButton: Locator;
readonly newIdeasButton: Locator;
readonly selectedOption: Locator;
constructor(page: Page) {
this.page = page;
this.component = page.locator('app-choose-next-response');
this.options = this.component.locator('.option-card');
this.abortButton = this.component.locator('button:has-text("🛑 Abort")');
this.newIdeasButton = this.component.locator('button:has-text("💡 New Ideas")');
this.selectedOption = this.component.locator('.option-card.selected');
}
async isVisible(): Promise<boolean> {
return await this.component.isVisible();
}
async getOptionCount(): Promise<number> {
return await this.options.count();
}
async selectOption(optionIndex: number): Promise<void> {
const option = this.options.nth(optionIndex);
await option.click();
}
async clickAbort(): Promise<void> {
await this.abortButton.click();
}
async clickRequestNewIdeas(): Promise<void> {
await this.newIdeasButton.click();
}
async getSelectedOptionText(): Promise<string> {
const selectedCard = this.component.locator('.option-card.selected').first();
if (await selectedCard.isVisible()) {
const titleElement = selectedCard.locator('.option-title');
return await titleElement.textContent() || '';
}
return '';
}
async hasSelectedOption(): Promise<boolean> {
const selectedCards = this.component.locator('.option-card.selected');
return (await selectedCards.count()) > 0;
}
}