CP_AUTOMATION/documentation/ui-team-requirements/FINAL_COMPLETE_DATA_TESTID_REQUIREMENTS.md
2025-12-12 19:54:54 +05:30

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:

  1. Never reuse the same data-testid value for two different DOM nodes
  2. Always use double underscore (__) to separate scope and dynamic parts
  3. Always use lowercase snake_case (no camelCase, no kebab-case)
  4. Always include data-testid on interactive elements (buttons, inputs, links)
  5. Always include data-testid on 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_start
  • completed
  • retake_available
  • abandoned
  • prerequisites_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 IMPLEMENTED
  • domain_card__{domainId}__action (action button) - ⚠️ MISSING
  • domains_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.id directly, 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:

  1. All static attributes are present and correctly named
  2. All dynamic attributes use correct template literal syntax
  3. All interactive elements (buttons, inputs, links) have test-ids
  4. All modal containers have test-ids on both overlay and content
  5. All question types have test-ids on containers and inputs
  6. No duplicate test-ids exist in the DOM
  7. 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

  1. Open Browser DevTools → Elements tab
  2. Navigate to each page (Assessments, Domains, Domain Assessment)
  3. Search for data-testid in Elements tab
  4. Verify all required attributes are present
  5. Check dynamic patterns by inspecting multiple questions/cards

📝 IMPLEMENTATION PRIORITY

Priority 1 (Critical - Required for Basic Automation):

  1. Assessment cards action buttons
  2. Domain cards action buttons
  3. Domain assessment page container
  4. Question shell containers
  5. All question type inputs (multiple choice, true/false, rating, open-ended, matrix)
  6. Navigation buttons (prev, next, submit)
  7. Domain feedback modal inputs
  8. Final feedback modal inputs

Priority 2 (Important - Required for Complete Automation):

  1. ⚠️ Instructions modal
  2. ⚠️ Submit confirmation modal
  3. ⚠️ Guidance modal
  4. ⚠️ Success modal
  5. ⚠️ Question navigator buttons

Priority 3 (Nice to Have - Enhanced Testing):

  1. ⚠️ Progress indicators
  2. ⚠️ Timer displays
  3. ⚠️ 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:

  1. All Priority 1 attributes are implemented and verified
  2. All Priority 2 attributes are implemented and verified
  3. All dynamic patterns generate correct test-ids
  4. No duplicate test-ids exist in the DOM
  5. All test-ids follow the naming convention
  6. Verification script passes without errors
  7. Manual inspection confirms all attributes are present

📞 SUPPORT & QUESTIONS

For questions or clarifications about this document:

  1. Review the examples in Section 7 (Reference Examples)
  2. Check the naming convention in Section 2 (Naming Convention)
  3. Verify against existing implementations (login, profile editor)
  4. 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!