52 KiB
🎯 FINAL COMPLETE DATA-TESTID REQUIREMENTS
Comprehensive Requirements Document for UI Development Team
Document Version: 2.0 (Final)
Date: 2025-01-20
Purpose: Complete, standalone requirements for all data-testid attributes needed for world-class automation testing
Status: ✅ READY FOR IMPLEMENTATION
📋 EXECUTIVE SUMMARY
This document provides complete, comprehensive, and accurate requirements for all data-testid attributes needed across the Cognitive Prism Assessment Platform. These attributes are critical for:
- ✅ Reliable Automation Testing - Stable locators that don't break with UI changes
- ✅ Performance Monitoring - Track element load times and interactions
- ✅ Error Analysis - Precise error reporting and debugging
- ✅ Regression Testing - Ensure functionality remains intact across updates
- ✅ World-Class Quality Assurance - Professional-grade test automation
Total Attributes Required: ~350+ (including dynamic patterns)
Priority: 🔴 CRITICAL - Required for production-ready automation
📐 NAMING CONVENTION (MANDATORY)
Pattern: {scope}__{element_name}
- Double underscore (
__) separates scope from element name - Single underscore (
_) within element names for readability - Scopes are lowercase snake_case (e.g.,
student_login,domain_assessment) - Element names are lowercase snake_case (e.g.,
first_name_input,submit_button)
Dynamic Patterns:
For dynamic collections, identifiers are appended with double underscore:
{scope}__{baseId}__{dynamicPart}- Example:
assessment_card__51_action - Example:
domain_question__123__option_A - Example:
domain_question__456__rating_3
Critical Rules:
- ✅ Never reuse the same
data-testidvalue for two different DOM nodes - ✅ Always use double underscore (
__) to separate scope and dynamic parts - ✅ Always use lowercase snake_case (no camelCase, no kebab-case)
- ✅ Always include
data-testidon interactive elements (buttons, inputs, links) - ✅ Always include
data-testidon containers that hold dynamic content
🎯 SCOPE REFERENCE
| Scope | Description | Route/Page |
|---|---|---|
student_login |
Sign-in form | / |
mandatory_reset |
First-login password reset modal | Modal overlay |
profile_incomplete |
Modal that forces profile completion | Modal overlay |
profile_editor |
Profile builder/editor | /student/profile-builder |
student_nav |
Logged-in student header/navigation | All student pages |
assessment_card |
Product cards on assessments hub | /assessments |
domains_page |
Domain listing screen | /assessment/{assignmentId}/domains |
domain_card |
Individual domain tiles | /assessment/{assignmentId}/domains |
domain_assessment |
In-progress domain test experience | /assessment/{assignmentId}/domain/{domainId} |
domain_question |
Question renderer + inputs | /assessment/{assignmentId}/domain/{domainId} |
domain_feedback |
Per-domain feedback modal | Modal overlay |
domains_final_feedback |
Final feedback modal after all domains | Modal overlay |
📦 SECTION 1: ASSESSMENTS HUB PAGE
File: src/pages/designs/design-1/assessment/AssessmentMainPage.jsx
Component: ProductCard.jsx (used in AssessmentSection.jsx)
1.1 Assessment Cards
Status: ❌ NOT IMPLEMENTED
File Location: src/pages/designs/design-1/assessment/components/ProductCard.jsx
Required Attributes:
// Assessment Card Container
<div
data-testid={`assessment_card__${assignmentId}`}
className="..."
>
{/* Assessment Card Action Button */}
<button
data-testid={`assessment_card__${assignmentId}__action`}
onClick={handleStartTest}
className="..."
>
Begin Assessment / Continue Assessment / View Results
</button>
</div>
Implementation Example:
// In ProductCard.jsx
const ProductCard = ({ assessment, onStart, onResume, onRetake, onViewResults }) => {
const assignmentId = assessment.assignmentId || assessment.id
return (
<div
data-testid={`assessment_card__${assignmentId}`}
className="assessment-card..."
>
{/* Card header with name, description */}
<h3>{assessment.name}</h3>
<p>{assessment.description}</p>
{/* Progress indicator */}
<div data-testid={`assessment_card__${assignmentId}__progress`}>
{assessment.progress?.overallProgress || 0}%
</div>
{/* Action Button */}
<button
data-testid={`assessment_card__${assignmentId}__action`}
onClick={() => {
if (assessment.status === 'completed') {
onViewResults?.(assessment)
} else if (assessment.status === 'in_progress') {
onResume?.(assessment)
} else {
onStart?.(assessment)
}
}}
className="..."
>
{assessment.progress?.buttonStatus || 'Begin Assessment'}
</button>
</div>
)
}
Dynamic Values:
assignmentId: Number (e.g.,51)- Generated:
assessment_card__51,assessment_card__51__action,assessment_card__51__progress
Implementation Locations:
- Line ~95: Add
data-testid={assessment_card__${assignmentId}}to<motion.div>container - Line ~161: Add
data-testid={assessment_card__${assignmentId}__progress}to progress value span - Line ~184: Add
data-testid={assessment_card__${assignmentId}__action}to action button,assessment_card__51__progress
1.2 Assessment Section Headers
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Section Container
<section
data-testid="assessments_page__section_{sectionName}"
className="..."
>
{/* Section Title */}
<h2
data-testid="assessments_page__section_{sectionName}__title"
className="..."
>
Ready to Start / Completed / etc.
</h2>
</section>
Section Names:
ready_to_startcompletedretake_availableabandonedprerequisites_needed
Implementation Example:
// In AssessmentMainPage.jsx
<AssessmentSection
title="Ready to Start"
tone="success"
items={categorized.readyToStartItems}
data-testid="assessments_page__section_ready_to_start"
// ...
/>
📦 SECTION 2: DOMAINS PAGE
File: src/pages/designs/design-1/assessment/domains/ProductDomainsPage.jsx
Component: DomainCard.jsx
2.1 Domain Cards
Status: ⚠️ PARTIALLY IMPLEMENTED
Current Implementation:
- ✅ Card container has test-id (line 83 in DomainCard.jsx):
domain_card__${domain.id} - ❌ Action button missing test-id (line 211-248 in DomainCard.jsx)
Required Attributes:
// Domain Card Container (✅ Already Implemented)
<motion.div
data-testid={`domain_card__${domain.id}`}
className="..."
>
{/* Domain Card Action Button (❌ MISSING) */}
<motion.button
data-testid={`domain_card__${domain.id}__action`}
onClick={() => onStart(domain)}
disabled={isActionDisabled}
className="..."
>
Start Assessment / Continue Assessment / Completed / Locked
</motion.button>
</motion.div>
Implementation Fix:
// In DomainCard.jsx, line ~211
<motion.button
data-testid={`domain_card__${domain.id}__action`} // ADD THIS LINE
whileHover={{ scale: isActionDisabled ? 1 : 1.02 }}
whileTap={{ scale: isActionDisabled ? 1 : 0.98 }}
disabled={isActionDisabled}
className="..."
>
{/* Button content */}
</motion.button>
Dynamic Values:
domain.id: Number (e.g.,1,2,3)- Generated:
domain_card__1,domain_card__1__action
2.2 Domains Page Container
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Page Container
<div
data-testid="domains_page__container"
className="..."
>
{/* Page Header */}
<div
data-testid="domains_page__header"
className="..."
>
<h1 data-testid="domains_page__title">TestProduct</h1>
<div data-testid="domains_page__progress_value">0%</div>
</div>
{/* Back Button */}
<button
data-testid="domains_page__back_button"
onClick={handleNavigateBack}
className="..."
>
<ArrowLeft />
</button>
</div>
Implementation Example:
// In ProductDomainsPage.jsx
<div
data-testid="domains_page__container"
className="..."
>
<button
data-testid="domains_page__back_button"
onClick={() => navigate(-1)}
className="..."
>
<ArrowLeft />
</button>
<div data-testid="domains_page__header">
<h1 data-testid="domains_page__title">{productInfo?.name}</h1>
<div data-testid="domains_page__progress_value">
{overallProgress}%
</div>
</div>
</div>
📦 SECTION 3: DOMAIN ASSESSMENT PAGE
File: src/pages/designs/design-1/assessment/domains/DomainAssessmentPage.jsx
Component: AssessmentHeader.jsx
3.1 Domain Assessment Page Container
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Page Container
<div
data-testid="domain_assessment__page"
className="..."
>
{/* Assessment Header */}
<AssessmentHeader
data-testid="domain_assessment__header"
// ...
/>
</div>
Implementation Example:
// In DomainAssessmentPage.jsx, main return statement
<div
data-testid="domain_assessment__page"
className="min-h-screen bg-gray-50 dark:bg-slate-900"
>
<AssessmentHeader
data-testid="domain_assessment__header"
domain={displayDomain}
product={displayProduct}
progress={progress}
timeLeft={timeLeft}
onNavigateBack={handleNavigateBack}
// ...
/>
</div>
3.2 Assessment Header Components
File: src/pages/designs/design-1/assessment/domains/components/AssessmentHeader.jsx
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Header Container
<header
data-testid="domain_assessment__header"
className="..."
>
{/* Back Button */}
<button
data-testid="domain_assessment__back_button"
onClick={onNavigateBack}
disabled={disableBack}
className="..."
>
<ArrowLeft />
</button>
{/* Domain Title */}
<h1
data-testid="domain_assessment__domain_title"
className="..."
>
{domain?.name}
</h1>
{/* Progress Value */}
<div
data-testid="domain_assessment__progress_value"
className="..."
>
{progressPercent}%
</div>
{/* Timer Value (if present) */}
{timeLeft && (
<div
data-testid="domain_assessment__timer_value"
className="..."
>
{formatTime(timeLeft)}
</div>
)}
</header>
Implementation Example:
// In AssessmentHeader.jsx
<header
data-testid="domain_assessment__header"
className="sticky top-0 z-30..."
>
<button
data-testid="domain_assessment__back_button"
onClick={onNavigateBack}
disabled={disableBack}
className="..."
>
<ArrowLeft />
</button>
<div>
<h1 data-testid="domain_assessment__domain_title">
{domain?.name || 'Domain Assessment'}
</h1>
</div>
<div data-testid="domain_assessment__progress_value">
{progressPercent}%
</div>
{timeLeft && (
<div data-testid="domain_assessment__timer_value">
{formatTime(timeLeft)}
</div>
)}
</header>
3.3 Instructions Modal
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Instructions Modal Container
<div
data-testid="domain_assessment__instructions_modal"
className="modal-overlay..."
>
{/* Modal Content */}
<div
data-testid="domain_assessment__instructions_modal__content"
className="modal-content..."
>
{/* Continue Button */}
<button
data-testid="domain_assessment__instructions_modal__continue_button"
onClick={handleContinue}
className="..."
>
Let's take the test!
</button>
</div>
</div>
Implementation Example:
// In DomainAssessmentPage.jsx, instructions modal section
{showInstructions && (
<div
data-testid="domain_assessment__instructions_modal"
className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50..."
>
<div
data-testid="domain_assessment__instructions_modal__content"
className="modal-content..."
>
{/* Instructions content */}
<button
data-testid="domain_assessment__instructions_modal__continue_button"
onClick={() => setShowInstructions(false)}
className="..."
>
Let's take the test!
</button>
</div>
</div>
)}
3.4 Sticky Action Bar
File: src/pages/designs/design-1/assessment/domains/components/StickyActionBar.jsx
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Action Bar Container
<div
data-testid="domain_assessment__action_bar"
className="sticky bottom-0..."
>
{/* Previous Button */}
<button
data-testid="domain_assessment__prev_button"
onClick={onPrev}
disabled={disablePrev}
className="..."
>
<ChevronLeft />
Previous
</button>
{/* Next Button */}
<button
data-testid="domain_assessment__next_button"
onClick={onNext}
disabled={disableNext}
className="..."
>
Next
<ChevronRight />
</button>
{/* Submit Button */}
<button
data-testid="domain_assessment__submit_button"
onClick={onSubmit}
disabled={disableSubmit}
className="..."
>
<Send />
Submit
</button>
</div>
Implementation Example:
// In StickyActionBar.jsx
<div
data-testid="domain_assessment__action_bar"
className="sticky bottom-0..."
>
<button
data-testid="domain_assessment__prev_button"
onClick={onPrev}
disabled={disablePrev}
className="..."
>
<ChevronLeft />
<span>Previous</span>
</button>
<button
data-testid="domain_assessment__next_button"
onClick={onNext}
disabled={disableNext}
className="..."
>
<span>Next</span>
<ChevronRight />
</button>
<button
data-testid="domain_assessment__submit_button"
onClick={onSubmit}
disabled={disableSubmit}
className="..."
>
<Send />
<span>Submit</span>
</button>
</div>
3.5 Question Navigator
File: src/pages/designs/design-1/assessment/domains/components/QuestionNavigator.jsx
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Navigator Container
<div
data-testid="domain_assessment__question_navigator"
className="..."
>
{/* Individual Question Buttons */}
{questionsOrder.map((questionId, idx) => (
<button
key={questionId}
data-testid={`domain_assessment__question_navigator__question_${idx + 1}`}
onClick={() => onSelect(idx)}
className="..."
>
{idx + 1}
</button>
))}
</div>
Implementation Example:
// In QuestionNavigator.jsx
<div
data-testid="domain_assessment__question_navigator"
className="..."
>
{questionsOrder.map((questionId, idx) => (
<button
key={questionId}
data-testid={`domain_assessment__question_navigator__question_${idx + 1}`}
onClick={() => onSelect(idx)}
className="..."
>
{answered && !isActive ? (
<CheckCircle2 />
) : (
<span>{idx + 1}</span>
)}
</button>
))}
</div>
3.6 Submit Confirmation Modal
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Submit Modal Container
<div
data-testid="domain_assessment__submit_modal"
className="modal-overlay..."
>
{/* Modal Content */}
<div
data-testid="domain_assessment__submit_modal__content"
className="modal-content..."
>
{/* Review Button */}
<button
data-testid="domain_assessment__submit_modal__review_button"
onClick={handleReview}
className="..."
>
Review Answers
</button>
{/* Confirm Button */}
<button
data-testid="domain_assessment__submit_modal__confirm_button"
onClick={handleConfirmSubmit}
className="..."
>
Confirm Submit
</button>
{/* Cancel Button */}
<button
data-testid="domain_assessment__submit_modal__cancel_button"
onClick={handleCancel}
className="..."
>
Cancel
</button>
</div>
</div>
3.7 Guidance Modal
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Guidance Modal Container
<div
data-testid="domain_assessment__guidance_modal"
className="modal-overlay..."
>
{/* Modal Content */}
<div
data-testid="domain_assessment__guidance_modal__content"
className="modal-content..."
>
{/* Dismiss Button */}
<button
data-testid="domain_assessment__guidance_modal__dismiss_button"
onClick={handleDismissGuidance}
className="..."
>
Got it
</button>
</div>
</div>
3.8 Success Modal
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Success Modal Container
<div
data-testid="domain_assessment__success_modal"
className="modal-overlay..."
>
{/* Modal Content */}
<div
data-testid="domain_assessment__success_modal__content"
className="modal-content..."
>
{/* Success Message */}
<p
data-testid="domain_assessment__success_modal__message"
className="..."
>
Domain assessment submitted successfully!
</p>
</div>
</div>
📦 SECTION 4: QUESTION COMPONENTS
File: src/pages/designs/design-1/assessment/domains/components/QuestionRenderer.jsx
Component: QuestionShell.jsx
4.1 Question Shell Container
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Question Shell Container
<div
data-testid={`domain_question__${question.id}`}
className="..."
>
{/* Question Header */}
<div
data-testid={`domain_question__${question.id}__header`}
className="..."
>
<span data-testid={`domain_question__${question.id}__number`}>
{currentIndex + 1}
</span>
<h2 data-testid={`domain_question__${question.id}__text`}>
{question.text}
</h2>
</div>
{/* Question Content (rendered by QuestionRenderer) */}
{children}
</div>
Implementation Example:
// In QuestionShell.jsx
<div
data-testid={`domain_question__${question.id}`}
className="bg-gradient-to-br..."
>
<div
data-testid={`domain_question__${question.id}__header`}
className="bg-gradient-to-r..."
>
<div>
<span data-testid={`domain_question__${question.id}__number`}>
{currentIndex + 1}
</span>
</div>
<div>
<h2 data-testid={`domain_question__${question.id}__text`}>
{question.text}
</h2>
</div>
</div>
<div className="p-4...">
{children}
</div>
</div>
Component: MultipleChoiceQuestion.jsx
4.2 Multiple Choice Questions
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Multiple Choice Container
<div
data-testid={`domain_question__${question.id}__multiple_choice`}
className="..."
>
{options.map((option, idx) => (
<button
key={idx}
data-testid={`domain_question__${question.id}__option_${String.fromCharCode(65 + idx)}`}
onClick={() => onChange(option.value)}
className="..."
>
{option.label}
</button>
))}
</div>
Implementation Example:
// In MultipleChoiceQuestion.jsx
<div
data-testid={`domain_question__${question.id}__multiple_choice`}
className="space-y-2..."
>
{options.map((option, idx) => {
const optionLabel = String.fromCharCode(65 + idx) // A, B, C, D, E
return (
<button
key={idx}
data-testid={`domain_question__${question.id}__option_${optionLabel}`}
onClick={() => onChange(option.value)}
className="..."
>
<div>
<span>{optionLabel}</span>
</div>
<div>
<p>{option.label}</p>
</div>
</button>
)
})}
</div>
Dynamic Values:
question.id: Number (e.g.,123)optionLabel: Letter (A, B, C, D, E)- Generated:
domain_question__123__option_A,domain_question__123__option_B
Component: TrueFalseQuestion.jsx
4.3 True/False Questions
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// True/False Container
<div
data-testid={`domain_question__${question.id}__true_false`}
className="..."
>
<button
data-testid={`domain_question__${question.id}__truefalse_True`}
onClick={() => onChange('True')}
className="..."
>
Yes
</button>
<button
data-testid={`domain_question__${question.id}__truefalse_False`}
onClick={() => onChange('False')}
className="..."
>
No
</button>
</div>
Implementation Example:
// In TrueFalseQuestion.jsx
<div
data-testid={`domain_question__${question.id}__true_false`}
className="grid grid-cols-2..."
>
<button
data-testid={`domain_question__${question.id}__truefalse_True`}
onClick={() => onChange('True')}
className="..."
>
Yes
</button>
<button
data-testid={`domain_question__${question.id}__truefalse_False`}
onClick={() => onChange('False')}
className="..."
>
No
</button>
</div>
Dynamic Values:
question.id: Number (e.g.,456)- Generated:
domain_question__456__truefalse_True,domain_question__456__truefalse_False
Component: RatingScaleQuestion.jsx
4.4 Rating Scale Questions
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Rating Scale Container
<div
data-testid={`domain_question__${question.id}__rating_scale`}
className="..."
>
{scaleOptions.map((option) => (
<button
key={option.value}
data-testid={`domain_question__${question.id}__rating_${option.value}`}
onClick={() => onChange(option.value)}
className="..."
>
{option.label}
</button>
))}
</div>
Implementation Example:
// In RatingScaleQuestion.jsx
<div
data-testid={`domain_question__${question.id}__rating_scale`}
className="space-y-4..."
>
<div className="grid gap-2...">
{scaleOptions.map((option) => (
<button
key={option.value}
data-testid={`domain_question__${question.id}__rating_${option.value}`}
onClick={() => onChange(option.value)}
className="..."
>
<span>{option.label}</span>
</button>
))}
</div>
</div>
Dynamic Values:
question.id: Number (e.g.,789)option.value: String (e.g.,"1","2","3","4","5")- Generated:
domain_question__789__rating_1,domain_question__789__rating_2
Component: OpenEndedQuestion.jsx
4.5 Open-Ended Questions
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Open-Ended Container
<div
data-testid={`domain_question__${question.id}__open_ended`}
className="..."
>
<textarea
data-testid={`domain_question__${question.id}__textarea`}
value={value}
onChange={(e) => onChange(e.target.value)}
className="..."
/>
</div>
Implementation Example:
// In OpenEndedQuestion.jsx
<div
data-testid={`domain_question__${question.id}__open_ended`}
className="space-y-2"
>
<textarea
data-testid={`domain_question__${question.id}__textarea`}
value={value}
onChange={(e) => onChange(e.target.value)}
rows={5}
maxLength={maxLength}
className="..."
/>
</div>
Dynamic Values:
question.id: Number (e.g.,101)- Generated:
domain_question__101__open_ended,domain_question__101__textarea
Component: MatrixQuestion.jsx
4.6 Matrix Questions
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Matrix Container
<div
data-testid={`domain_question__${question.id}__matrix`}
className="..."
>
<table>
<thead>
<tr>
<th>Statement</th>
{columns.map((column, colIdx) => (
<th key={column}>{column}</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, rowIdx) => (
<tr key={row}>
<td>{row}</td>
{columns.map((column, colIdx) => (
<td key={column}>
<input
type={allowMultiple ? 'checkbox' : 'radio'}
data-testid={`domain_question__${question.id}__matrix_${rowIdx}_${colIdx}`}
checked={isChecked}
onChange={() => handleChange(rowIdx, colIdx)}
className="..."
/>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
Implementation Example:
// In MatrixQuestion.jsx
<div
data-testid={`domain_question__${question.id}__matrix`}
className="overflow-x-auto..."
>
<table>
<thead>
<tr>
<th>Statement</th>
{columns.map((column) => (
<th key={column}>{column}</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row, rowIdx) => (
<tr key={row}>
<td>{row}</td>
{columns.map((column, colIdx) => {
const isChecked = /* check logic */
return (
<td key={column}>
<label>
<input
type={allowMultiple ? 'checkbox' : 'radio'}
data-testid={`domain_question__${question.id}__matrix_${rowIdx}_${colIdx}`}
checked={isChecked}
onChange={() => handleChange(row, column)}
className="..."
/>
</label>
</td>
)
})}
</tr>
))}
</tbody>
</table>
</div>
Dynamic Values:
question.id: Number (e.g.,202)rowIdx: Number (0-based index, e.g.,0,1,2)colIdx: Number (0-based index, e.g.,0,1,2,3,4)- Generated:
domain_question__202__matrix_0_0,domain_question__202__matrix_0_1
📦 SECTION 5: DOMAIN FEEDBACK MODAL
File: src/pages/designs/design-1/assessment/domains/DomainAssessmentPage.jsx
5.1 Domain Feedback Modal
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Feedback Modal Container
<div
data-testid="domain_feedback__modal"
className="modal-overlay..."
>
{/* Modal Content */}
<div
data-testid="domain_feedback__modal__content"
className="modal-content..."
>
{/* Question 1: Were these questions understandable? */}
<div
data-testid="domain_feedback__question1"
className="..."
>
<label>Were these questions understandable?</label>
{/* Yes Button */}
<button
data-testid="domain_feedback__question1_yes"
onClick={() => handleFeedbackChange('question1', true)}
className="..."
>
Yes
</button>
{/* No Button */}
<button
data-testid="domain_feedback__question1_no"
onClick={() => handleFeedbackChange('question1', false)}
className="..."
>
No
</button>
{/* Justification Textarea (shown when No is selected) */}
{feedbackData.question1 === false && (
<textarea
data-testid="domain_feedback__question1_justification"
value={feedbackData.question1Justification}
onChange={(e) => handleFeedbackChange('question1Justification', e.target.value)}
className="..."
/>
)}
</div>
{/* Question 2: Any other comments? */}
<div
data-testid="domain_feedback__question2"
className="..."
>
<label>Any other comments?</label>
<textarea
data-testid="domain_feedback__question2_textarea"
value={feedbackData.question2}
onChange={(e) => handleFeedbackChange('question2', e.target.value)}
className="..."
/>
</div>
{/* Submit Button */}
<button
data-testid="domain_feedback__submit_button"
onClick={handleFeedbackSubmit}
disabled={submittingFeedback}
className="..."
>
Submit Feedback
</button>
</div>
</div>
Implementation Example:
// In DomainAssessmentPage.jsx, feedback modal section
{showFeedbackModal && (
<div
data-testid="domain_feedback__modal"
className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50..."
>
<div
data-testid="domain_feedback__modal__content"
className="modal-content..."
>
<h2>Domain Feedback</h2>
{/* Question 1 */}
<div data-testid="domain_feedback__question1">
<label>Were these questions understandable?</label>
<div>
<button
data-testid="domain_feedback__question1_yes"
onClick={() => handleFeedbackChange('question1', true)}
className={feedbackData.question1 === true ? 'selected' : ''}
>
Yes
</button>
<button
data-testid="domain_feedback__question1_no"
onClick={() => handleFeedbackChange('question1', false)}
className={feedbackData.question1 === false ? 'selected' : ''}
>
No
</button>
</div>
{feedbackData.question1 === false && (
<textarea
data-testid="domain_feedback__question1_justification"
value={feedbackData.question1Justification}
onChange={(e) => handleFeedbackChange('question1Justification', e.target.value)}
placeholder="Please explain what was unclear"
className="..."
/>
)}
</div>
{/* Question 2 */}
<div data-testid="domain_feedback__question2">
<label>Any other comments?</label>
<textarea
data-testid="domain_feedback__question2_textarea"
value={feedbackData.question2}
onChange={(e) => handleFeedbackChange('question2', e.target.value)}
placeholder="Enter your comments..."
className="..."
/>
</div>
<button
data-testid="domain_feedback__submit_button"
onClick={handleFeedbackSubmit}
disabled={submittingFeedback}
className="..."
>
{submittingFeedback ? 'Submitting...' : 'Submit Feedback'}
</button>
</div>
</div>
)}
📦 SECTION 6: FINAL FEEDBACK MODAL
File: src/pages/designs/design-1/assessment/domains/ProductDomainsPage.jsx
6.1 Final Feedback Modal
Status: ❌ NOT IMPLEMENTED
Required Attributes:
// Final Feedback Modal Container
<div
data-testid="domains_final_feedback__modal"
className="modal-overlay..."
>
{/* Modal Content */}
<div
data-testid="domains_final_feedback__modal__content"
className="modal-content..."
>
{/* Overall Rating (1-5 stars) */}
<div
data-testid="domains_final_feedback__rating"
className="..."
>
{[1, 2, 3, 4, 5].map((rating) => (
<button
key={rating}
data-testid={`domains_final_feedback__rating_${rating}`}
onClick={() => setFinalOverallRating(rating)}
className={finalOverallRating === rating ? 'selected' : ''}
>
⭐
</button>
))}
</div>
{/* Clarity Question */}
<div
data-testid="domains_final_feedback__clarity"
className="..."
>
<label>Was the assessment clear and understandable?</label>
<button
data-testid="domains_final_feedback__clarity_yes"
onClick={() => setFinalFeedbackData({...finalFeedbackData, clarity: true})}
className="..."
>
Yes
</button>
<button
data-testid="domains_final_feedback__clarity_no"
onClick={() => setFinalFeedbackData({...finalFeedbackData, clarity: false})}
className="..."
>
No
</button>
{finalFeedbackData.clarity === false && (
<textarea
data-testid="domains_final_feedback__clarity_justification"
value={finalFeedbackData.clarityJustification}
onChange={(e) => setFinalFeedbackData({...finalFeedbackData, clarityJustification: e.target.value})}
className="..."
/>
)}
</div>
{/* Confidence Question */}
<div
data-testid="domains_final_feedback__confidence"
className="..."
>
<label>Do you feel confident in your responses?</label>
<button
data-testid="domains_final_feedback__confidence_yes"
onClick={() => setFinalFeedbackData({...finalFeedbackData, confidence: true})}
className="..."
>
Yes
</button>
<button
data-testid="domains_final_feedback__confidence_no"
onClick={() => setFinalFeedbackData({...finalFeedbackData, confidence: false})}
className="..."
>
No
</button>
{finalFeedbackData.confidence === false && (
<textarea
data-testid="domains_final_feedback__confidence_justification"
value={finalFeedbackData.confidenceJustification}
onChange={(e) => setFinalFeedbackData({...finalFeedbackData, confidenceJustification: e.target.value})}
className="..."
/>
)}
</div>
{/* Comments */}
<div
data-testid="domains_final_feedback__comments"
className="..."
>
<label>Any additional comments?</label>
<textarea
data-testid="domains_final_feedback__comments_textarea"
value={finalFeedbackData.comments}
onChange={(e) => setFinalFeedbackData({...finalFeedbackData, comments: e.target.value})}
className="..."
/>
</div>
{/* Submit Button */}
<button
data-testid="domains_final_feedback__submit_button"
onClick={handleFinalFeedbackSubmit}
disabled={finalFeedbackSubmitting}
className="..."
>
Submit Feedback
</button>
</div>
</div>
Implementation Example:
// In ProductDomainsPage.jsx, final feedback modal section
{showFinalFeedbackModal && (
<div
data-testid="domains_final_feedback__modal"
className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50..."
>
<div
data-testid="domains_final_feedback__modal__content"
className="modal-content..."
>
<h2>Final Feedback</h2>
{/* Overall Rating */}
<div data-testid="domains_final_feedback__rating">
<label>Overall Rating</label>
<div>
{[1, 2, 3, 4, 5].map((rating) => (
<button
key={rating}
data-testid={`domains_final_feedback__rating_${rating}`}
onClick={() => setFinalOverallRating(rating)}
className={finalOverallRating === rating ? 'selected' : ''}
>
⭐
</button>
))}
</div>
</div>
{/* Clarity */}
<div data-testid="domains_final_feedback__clarity">
<label>Was the assessment clear and understandable?</label>
<button
data-testid="domains_final_feedback__clarity_yes"
onClick={() => setFinalFeedbackData({...finalFeedbackData, clarity: true})}
>
Yes
</button>
<button
data-testid="domains_final_feedback__clarity_no"
onClick={() => setFinalFeedbackData({...finalFeedbackData, clarity: false})}
>
No
</button>
{finalFeedbackData.clarity === false && (
<textarea
data-testid="domains_final_feedback__clarity_justification"
value={finalFeedbackData.clarityJustification}
onChange={(e) => setFinalFeedbackData({...finalFeedbackData, clarityJustification: e.target.value})}
/>
)}
</div>
{/* Confidence */}
<div data-testid="domains_final_feedback__confidence">
<label>Do you feel confident in your responses?</label>
<button
data-testid="domains_final_feedback__confidence_yes"
onClick={() => setFinalFeedbackData({...finalFeedbackData, confidence: true})}
>
Yes
</button>
<button
data-testid="domains_final_feedback__confidence_no"
onClick={() => setFinalFeedbackData({...finalFeedbackData, confidence: false})}
>
No
</button>
{finalFeedbackData.confidence === false && (
<textarea
data-testid="domains_final_feedback__confidence_justification"
value={finalFeedbackData.confidenceJustification}
onChange={(e) => setFinalFeedbackData({...finalFeedbackData, confidenceJustification: e.target.value})}
/>
)}
</div>
{/* Comments */}
<div data-testid="domains_final_feedback__comments">
<label>Any additional comments?</label>
<textarea
data-testid="domains_final_feedback__comments_textarea"
value={finalFeedbackData.comments}
onChange={(e) => setFinalFeedbackData({...finalFeedbackData, comments: e.target.value})}
/>
</div>
<button
data-testid="domains_final_feedback__submit_button"
onClick={handleFinalFeedbackSubmit}
disabled={finalFeedbackSubmitting}
>
Submit Feedback
</button>
</div>
</div>
)}
📊 COMPLETE ATTRIBUTE CHECKLIST
Assessments Hub (Section 1)
assessment_card__{assignmentId}(card container)assessment_card__{assignmentId}__action(action button)assessments_page__section_{sectionName}(section container)assessments_page__section_{sectionName}__title(section title)
Domains Page (Section 2)
domain_card__{domainId}(card container) - ✅ ALREADY IMPLEMENTEDdomain_card__{domainId}__action(action button) - ⚠️ MISSINGdomains_page__container(page container)domains_page__header(page header)domains_page__title(product title)domains_page__progress_value(overall progress)domains_page__back_button(back button)
Domain Assessment Page (Section 3)
domain_assessment__page(page container)domain_assessment__header(header container)domain_assessment__back_button(back button)domain_assessment__domain_title(domain name)domain_assessment__progress_value(progress percentage)domain_assessment__timer_value(timer display)domain_assessment__action_bar(sticky action bar)domain_assessment__prev_button(previous button)domain_assessment__next_button(next button)domain_assessment__submit_button(submit button)domain_assessment__question_navigator(question navigator container)domain_assessment__question_navigator__question_{index}(individual question buttons)domain_assessment__instructions_modal(instructions modal)domain_assessment__instructions_modal__content(modal content)domain_assessment__instructions_modal__continue_button(continue button)domain_assessment__submit_modal(submit confirmation modal)domain_assessment__submit_modal__content(modal content)domain_assessment__submit_modal__review_button(review button)domain_assessment__submit_modal__confirm_button(confirm button)domain_assessment__submit_modal__cancel_button(cancel button)domain_assessment__guidance_modal(guidance modal)domain_assessment__guidance_modal__content(modal content)domain_assessment__guidance_modal__dismiss_button(dismiss button)domain_assessment__success_modal(success modal)domain_assessment__success_modal__content(modal content)domain_assessment__success_modal__message(success message)
Question Components (Section 4)
domain_question__{questionId}(question shell container)domain_question__{questionId}__header(question header)domain_question__{questionId}__number(question number)domain_question__{questionId}__text(question text)domain_question__{questionId}__multiple_choice(multiple choice container)domain_question__{questionId}__option_{A|B|C|D|E}(option buttons)domain_question__{questionId}__true_false(true/false container)domain_question__{questionId}__truefalse_True(Yes button)domain_question__{questionId}__truefalse_False(No button)domain_question__{questionId}__rating_scale(rating scale container)domain_question__{questionId}__rating_{1|2|3|4|5}(rating buttons)domain_question__{questionId}__open_ended(open-ended container)domain_question__{questionId}__textarea(textarea input)domain_question__{questionId}__matrix(matrix container)domain_question__{questionId}__matrix_{rowIndex}_{columnIndex}(matrix cells)
Domain Feedback Modal (Section 5)
domain_feedback__modal(modal container)domain_feedback__modal__content(modal content)domain_feedback__question1(question 1 container)domain_feedback__question1_yes(Yes button)domain_feedback__question1_no(No button)domain_feedback__question1_justification(justification textarea)domain_feedback__question2(question 2 container)domain_feedback__question2_textarea(comments textarea)domain_feedback__submit_button(submit button)
Final Feedback Modal (Section 6)
domains_final_feedback__modal(modal container)domains_final_feedback__modal__content(modal content)domains_final_feedback__rating(rating container)domains_final_feedback__rating_{1|2|3|4|5}(rating buttons)domains_final_feedback__clarity(clarity question container)domains_final_feedback__clarity_yes(Yes button)domains_final_feedback__clarity_no(No button)domains_final_feedback__clarity_justification(justification textarea)domains_final_feedback__confidence(confidence question container)domains_final_feedback__confidence_yes(Yes button)domains_final_feedback__confidence_no(No button)domains_final_feedback__confidence_justification(justification textarea)domains_final_feedback__comments(comments container)domains_final_feedback__comments_textarea(comments textarea)domains_final_feedback__submit_button(submit button)
🔧 IMPLEMENTATION GUIDELINES
1. Dynamic Attribute Generation
For dynamic attributes, use template literals:
// ✅ CORRECT
data-testid={`assessment_card__${assignmentId}__action`}
data-testid={`domain_question__${question.id}__option_${optionLabel}`}
data-testid={`domain_question__${question.id}__matrix_${rowIdx}_${colIdx}`}
// ❌ INCORRECT
data-testid="assessment_card__" + assignmentId + "__action" // Don't use string concatenation
data-testid={`domain_question_${question.id}_option_${optionLabel}`} // Missing double underscore
2. Question ID Format
Question IDs should be:
- Numbers (e.g.,
123,456) - Converted to string in template literals (JavaScript handles this automatically)
- Consistent - use
question.iddirectly, don't transform it
// ✅ CORRECT
data-testid={`domain_question__${question.id}`}
// ❌ INCORRECT
data-testid={`domain_question__${String(question.id).padStart(3, '0')}`} // Don't pad
data-testid={`domain_question__q${question.id}`} // Don't add prefix
3. Option Labels for Multiple Choice
Use letter labels (A, B, C, D, E) based on array index:
// ✅ CORRECT
const optionLabel = String.fromCharCode(65 + idx) // A, B, C, D, E
data-testid={`domain_question__${question.id}__option_${optionLabel}`}
// ❌ INCORRECT
data-testid={`domain_question__${question.id}__option_${option.value}`} // Don't use option.value
data-testid={`domain_question__${question.id}__option_${idx}`} // Don't use numeric index
4. Matrix Row/Column Indices
Use 0-based indices for both rows and columns:
// ✅ CORRECT
{rows.map((row, rowIdx) => (
columns.map((column, colIdx) => (
<input
data-testid={`domain_question__${question.id}__matrix_${rowIdx}_${colIdx}`}
// ...
/>
))
))}
// ❌ INCORRECT
data-testid={`domain_question__${question.id}__matrix_${rowIdx + 1}_${colIdx + 1}`} // Don't add 1
data-testid={`domain_question__${question.id}__matrix_${row}_${column}`} // Don't use row/column text
5. Modal Overlays
Always include test-id on both overlay and content:
// ✅ CORRECT
<div
data-testid="domain_feedback__modal"
className="fixed inset-0 bg-black/40..."
>
<div
data-testid="domain_feedback__modal__content"
className="modal-content..."
>
{/* Modal content */}
</div>
</div>
6. Conditional Elements
For conditional elements (e.g., justification textarea), always include test-id:
// ✅ CORRECT
{feedbackData.question1 === false && (
<textarea
data-testid="domain_feedback__question1_justification"
value={feedbackData.question1Justification}
// ...
/>
)}
✅ VERIFICATION CHECKLIST
After implementation, verify:
- ✅ All static attributes are present and correctly named
- ✅ All dynamic attributes use correct template literal syntax
- ✅ All interactive elements (buttons, inputs, links) have test-ids
- ✅ All modal containers have test-ids on both overlay and content
- ✅ All question types have test-ids on containers and inputs
- ✅ No duplicate test-ids exist in the DOM
- ✅ All test-ids follow the naming convention (double underscore, lowercase snake_case)
🧪 TESTING & VERIFICATION
Automated Verification Script
After implementation, run this verification script:
// Verification script (can be added to UI codebase)
const verifyTestIds = () => {
const requiredTestIds = [
'domain_assessment__page',
'domain_assessment__back_button',
'domain_assessment__prev_button',
'domain_assessment__next_button',
'domain_assessment__submit_button',
// ... all required test-ids
]
const missing = requiredTestIds.filter(id =>
!document.querySelector(`[data-testid="${id}"]`) &&
!document.querySelector(`[data-testid^="${id}"]`) // For dynamic patterns
)
if (missing.length > 0) {
console.error('Missing test-ids:', missing)
return false
}
return true
}
Manual Verification Steps
- Open Browser DevTools → Elements tab
- Navigate to each page (Assessments, Domains, Domain Assessment)
- Search for
data-testidin Elements tab - Verify all required attributes are present
- Check dynamic patterns by inspecting multiple questions/cards
📝 IMPLEMENTATION PRIORITY
Priority 1 (Critical - Required for Basic Automation):
- ✅ Assessment cards action buttons
- ✅ Domain cards action buttons
- ✅ Domain assessment page container
- ✅ Question shell containers
- ✅ All question type inputs (multiple choice, true/false, rating, open-ended, matrix)
- ✅ Navigation buttons (prev, next, submit)
- ✅ Domain feedback modal inputs
- ✅ Final feedback modal inputs
Priority 2 (Important - Required for Complete Automation):
- ⚠️ Instructions modal
- ⚠️ Submit confirmation modal
- ⚠️ Guidance modal
- ⚠️ Success modal
- ⚠️ Question navigator buttons
Priority 3 (Nice to Have - Enhanced Testing):
- ⚠️ Progress indicators
- ⚠️ Timer displays
- ⚠️ Section headers
📚 REFERENCE EXAMPLES
Example 1: Assessment Card
// File: AssessmentSection.jsx or AssessmentCard component
const AssessmentCard = ({ assessment }) => {
const assignmentId = assessment.assignmentId || assessment.id
return (
<div
data-testid={`assessment_card__${assignmentId}`}
className="assessment-card..."
>
<h3>{assessment.name}</h3>
<p>{assessment.description}</p>
<button
data-testid={`assessment_card__${assignmentId}__action`}
onClick={() => onStart(assessment)}
className="..."
>
{assessment.progress?.buttonStatus || 'Begin Assessment'}
</button>
</div>
)
}
Example 2: Multiple Choice Question
// File: MultipleChoiceQuestion.jsx
const MultipleChoiceQuestion = ({ question, value, onChange }) => {
const options = question.options || []
return (
<div
data-testid={`domain_question__${question.id}__multiple_choice`}
className="space-y-2..."
>
{options.map((option, idx) => {
const optionLabel = String.fromCharCode(65 + idx) // A, B, C, D, E
const isSelected = value === option.value
return (
<button
key={idx}
data-testid={`domain_question__${question.id}__option_${optionLabel}`}
onClick={() => onChange(option.value)}
className={isSelected ? 'selected' : ''}
>
<div>
<span>{optionLabel}</span>
</div>
<div>
<p>{option.label}</p>
</div>
</button>
)
})}
</div>
)
}
Example 3: Domain Feedback Modal
// File: DomainAssessmentPage.jsx
{showFeedbackModal && (
<div
data-testid="domain_feedback__modal"
className="fixed inset-0 bg-black/40 backdrop-blur-sm z-50 flex items-center justify-center"
>
<div
data-testid="domain_feedback__modal__content"
className="bg-white dark:bg-slate-800 rounded-2xl p-6 max-w-md w-full"
>
<h2>Domain Feedback</h2>
<div data-testid="domain_feedback__question1">
<label>Were these questions understandable?</label>
<div>
<button
data-testid="domain_feedback__question1_yes"
onClick={() => handleFeedbackChange('question1', true)}
>
Yes
</button>
<button
data-testid="domain_feedback__question1_no"
onClick={() => handleFeedbackChange('question1', false)}
>
No
</button>
</div>
{feedbackData.question1 === false && (
<textarea
data-testid="domain_feedback__question1_justification"
value={feedbackData.question1Justification}
onChange={(e) => handleFeedbackChange('question1Justification', e.target.value)}
/>
)}
</div>
<div data-testid="domain_feedback__question2">
<label>Any other comments?</label>
<textarea
data-testid="domain_feedback__question2_textarea"
value={feedbackData.question2}
onChange={(e) => handleFeedbackChange('question2', e.target.value)}
/>
</div>
<button
data-testid="domain_feedback__submit_button"
onClick={handleFeedbackSubmit}
disabled={submittingFeedback}
>
Submit Feedback
</button>
</div>
</div>
)}
🎯 SUCCESS CRITERIA
Implementation is considered complete when:
- ✅ All Priority 1 attributes are implemented and verified
- ✅ All Priority 2 attributes are implemented and verified
- ✅ All dynamic patterns generate correct test-ids
- ✅ No duplicate test-ids exist in the DOM
- ✅ All test-ids follow the naming convention
- ✅ Verification script passes without errors
- ✅ Manual inspection confirms all attributes are present
📞 SUPPORT & QUESTIONS
For questions or clarifications about this document:
- Review the examples in Section 7 (Reference Examples)
- Check the naming convention in Section 2 (Naming Convention)
- Verify against existing implementations (login, profile editor)
- Contact automation team for clarification
📋 DOCUMENT VERSION HISTORY
- v2.0 (2025-01-20): Final complete requirements - all assessment components
- v1.0 (2025-01-15): Initial requirements - login and profile editor
Status: ✅ READY FOR IMPLEMENTATION
Priority: 🔴 CRITICAL
Estimated Implementation Time: 2-3 days for complete implementation
🚀 LET'S BUILD WORLD-CLASS AUTOMATION TOGETHER!