From 63c19acfc3989fcab6eabe95f2e4c952c1587be6 Mon Sep 17 00:00:00 2001 From: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com> Date: Wed, 3 Sep 2025 20:45:19 +0700 Subject: [PATCH] test(e2e): mock quiz data in quiz-challenge.spec.ts (#62011) Co-authored-by: Oliver Eyton-Williams --- e2e/fixtures/quiz-fixture.json | 26 ++++++++++++++ e2e/quiz-challenge.spec.ts | 65 +++++++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 e2e/fixtures/quiz-fixture.json diff --git a/e2e/fixtures/quiz-fixture.json b/e2e/fixtures/quiz-fixture.json new file mode 100644 index 00000000000..b92324a0964 --- /dev/null +++ b/e2e/fixtures/quiz-fixture.json @@ -0,0 +1,26 @@ +[ + { + "questions": [ + { "distractors": ["Wrong 1", "Wrong 2", "
const x = 1;
"], "text": "Question 1", "answer": "
console.log('ok')
Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 2", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 3", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 4", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 5", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 6", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 7", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 8", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 9", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 10", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 11", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 12", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 13", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 14", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 15", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 16", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 17", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 18", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 19", "answer": "Correct answer" }, + { "distractors": ["Wrong 1", "Wrong 2", "Wrong 3"], "text": "Question 20", "answer": "Correct answer" } + ] + } +] diff --git a/e2e/quiz-challenge.spec.ts b/e2e/quiz-challenge.spec.ts index d7de49970c6..4d80744dcf4 100644 --- a/e2e/quiz-challenge.spec.ts +++ b/e2e/quiz-challenge.spec.ts @@ -1,8 +1,47 @@ +import fs from 'fs'; +import path from 'path'; import { test, expect } from '@playwright/test'; import { allowTrailingSlash } from './utils/url'; +interface QuizQuestion { + distractors: string[]; + text: string; + answer: string; +} + +interface Quiz { + questions: QuizQuestion[]; +} + +interface PageData { + result: { + data: { + challengeNode: { + challenge: { quizzes: Quiz[] }; + }; + }; + }; +} + test.describe('Quiz challenge', () => { test.beforeEach(async ({ page }) => { + const fixturePath = path.join(__dirname, 'fixtures', 'quiz-fixture.json'); + const fixture = JSON.parse(fs.readFileSync(fixturePath, 'utf8')) as Quiz[]; + + // Intercept Gatsby page-data and inject a deterministic quiz fixture + await page.route('**/page-data/**/page-data.json', async route => { + const response = await route.fetch(); + const body = await response.text(); + + const pageData = JSON.parse(body) as PageData; + pageData.result.data.challengeNode.challenge.quizzes = fixture; + + await route.fulfill({ + contentType: 'application/json', + body: JSON.stringify(pageData) + }); + }); + await page.goto( '/learn/full-stack-developer/quiz-basic-html/quiz-basic-html' ); @@ -13,6 +52,18 @@ test.describe('Quiz challenge', () => { }) => { // Wait for the page content to render await expect(page.getByRole('radiogroup')).toHaveCount(20); + const radioGroups = await page.getByRole('radiogroup').all(); + + // The radio label contents are rendered with `PrismFormatted`. + // For accessibility we must ensure: + // - The formatted content is wrapped in a `span` + // - No ARIA role is added to `pre` elements + const firstGroup = radioGroups[0]; + const spanLabel = firstGroup.locator('span.quiz-answer-label'); + await expect(spanLabel).toHaveCount(4); + + const preWithRole = firstGroup.locator('pre[role]'); + await expect(preWithRole).toHaveCount(0); for (let i = 0; i < 15; i++) { const radioGroups = await page.getByRole('radiogroup').all(); @@ -41,10 +92,13 @@ test.describe('Quiz challenge', () => { // Answer 18 questions correctly. // This is enough to pass the quiz, and also allowing us to test the quiz passing criteria. for (let i = 0; i < radioGroups.length; i++) { + const group = radioGroups[i]; + const correct = group.getByRole('radio', { name: /Correct answer/i }); + const wrong = group.getByRole('radio', { name: /Wrong 1/i }); if (i <= 17) { - await radioGroups[i].locator("[role='radio'][data-value='4']").click(); + await correct.click(); } else { - await radioGroups[i].locator("[role='radio'][data-value='1']").click(); + await wrong.click(); } } @@ -105,10 +159,13 @@ test.describe('Quiz challenge', () => { // Answer only 10 questions correctly. for (let i = 0; i < radioGroups.length; i++) { + const group = radioGroups[i]; + const correct = group.getByRole('radio', { name: /Correct answer/i }); + const wrong = group.getByRole('radio', { name: /Wrong 1/i }); if (i <= 9) { - await radioGroups[i].locator("[role='radio'][data-value='4']").click(); + await correct.click(); } else { - await radioGroups[i].locator("[role='radio'][data-value='1']").click(); + await wrong.click(); } }