Skip to content

Commit

Permalink
test: add E2E quiz lesson seed and update test implementations for co…
Browse files Browse the repository at this point in the history
…urse enrollment and payment validation (#237)
  • Loading branch information
typeWolffo authored Nov 21, 2024
1 parent ca754ea commit 0fc305f
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 32 deletions.
64 changes: 64 additions & 0 deletions apps/api/src/e2e-data-seeds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,70 @@ export const e2eCourses: NiceCourseData[] = [
},
],
},
{
title: "E2E Testing Quiz",
description: "E2E Testing Quiz Description",
imageUrl: "https://placehold.co/600x400",
type: LESSON_TYPE.quiz.key,
state: STATUS.published.key,
isFree: true,
items: [
{
itemType: LESSON_ITEM_TYPE.question.key,
questionType: "single_choice",
questionBody: "E2E Testing Question",
state: "published",
questionAnswers: [
{
optionText: "E2E Testing Answer",
isCorrect: true,
position: 0,
},
],
},
{
itemType: LESSON_ITEM_TYPE.question.key,
questionType: "single_choice",
questionBody: "E2E Testing Question 2",
state: "published",
questionAnswers: [
{
optionText: "single true",
isCorrect: true,
position: 0,
},
{
optionText: "single false",
isCorrect: false,
position: 1,
},
],
},
{
itemType: LESSON_ITEM_TYPE.question.key,
questionType: "multiple_choice",
questionBody: "E2E Testing Question 3",
state: "published",
questionAnswers: [
{
optionText: "multiple true a",
isCorrect: true,
position: 0,
},
{
optionText: "multiple true b",
isCorrect: false,
position: 1,
},
{
optionText: "multiple false c",
isCorrect: false,
position: 2,
},
],
},
],
},
],
},
];
139 changes: 139 additions & 0 deletions apps/web/e2e/tests/course.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { expect, test, type Page } from "@playwright/test";

const TEST_COURSE = {
name: "For E2E Testing",
description: "E2E Testing Lesson Description",
} as const;

const PAYMENT_DATA = {
cardNumber: "4242424242424242",
cvc: "123",
expiryMonth: "10",
} as const;

const URL_PATTERNS = {
course:
/course\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
lesson:
/course\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}\/lesson\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
} as const;

const QUIZ_ANSWERS = [
{ name: "E2E Testing Answer", isCorrect: true },
{ name: "single false", isCorrect: false },
{ name: "multiple true a", isCorrect: true },
{ name: "multiple true b", isCorrect: true },
{ name: "multiple false c", isCorrect: false },
];

class CourseActions {
constructor(private readonly page: Page) {}

async searchCourse(): Promise<void> {
await this.page.getByPlaceholder("Search by title...").fill(TEST_COURSE.name);
await expect(this.page.getByRole("button", { name: "Clear All" })).toBeVisible();
}

async openCourse(): Promise<void> {
await this.page.getByRole("link", { name: TEST_COURSE.name }).click();
await expect(this.page).toHaveURL(URL_PATTERNS.course);
await this.verifyCourseContent();
}

private async verifyCourseContent(): Promise<void> {
await expect(this.page.getByText(TEST_COURSE.name)).toBeVisible();
await expect(this.page.getByText(TEST_COURSE.description)).toBeVisible();
}
}

class PaymentActions {
constructor(private readonly page: Page) {}

async fillPaymentForm(expiryYear: number): Promise<void> {
const stripeFrame = this.page.frameLocator('iframe[title="Secure payment input frame"]');
await stripeFrame.locator("#Field-numberInput").fill(PAYMENT_DATA.cardNumber);
await stripeFrame
.locator("#Field-expiryInput")
.fill(`${PAYMENT_DATA.expiryMonth}${expiryYear}`);
await stripeFrame.locator("#Field-cvcInput").fill(PAYMENT_DATA.cvc);
await expect(this.page.getByText(/Buy for/)).toBeVisible();
}

async completePurchase(): Promise<void> {
await this.page.getByRole("button", { name: /Buy for/ }).click();
}
}

class EnrollmentActions {
constructor(private readonly page: Page) {}

async enrollInCourse(): Promise<void> {
await this.page.getByRole("button", { name: "Enroll" }).click();
}

async unenrollFromCourse(): Promise<void> {
const unenrollButton = this.page.getByRole("button", { name: "Unenroll" });
await unenrollButton.waitFor({ state: "visible", timeout: 10000 });
await expect(unenrollButton).toBeVisible();
await unenrollButton.click();
await expect(this.page.getByRole("button", { name: /Enroll - / })).toBeVisible();
}
}

class QuizActions {
constructor(private readonly page: Page) {}

async solveQuiz(): Promise<void> {
await this.page.getByRole("heading", { name: "E2E Testing Quiz" }).click();
await expect(this.page).toHaveURL(URL_PATTERNS.lesson);

for (const answer of QUIZ_ANSWERS) {
await this.page.getByRole("button", { name: answer.name }).click();
}
}

async checkAndVerifyResults(): Promise<void> {
await this.page.getByRole("button", { name: "Check answers" }).click();
await expect(this.page.getByRole("dialog")).toBeVisible();
await expect(this.page.getByText(/Your Score: 33%/)).toBeVisible();
}

async resetQuiz(): Promise<void> {
await this.page.getByRole("button", { name: "Try Again" }).click();
await this.page.getByRole("button", { name: "Clear progress" }).click();
}
}

test.describe.serial("Course E2E", () => {
let courseActions: CourseActions;
let paymentActions: PaymentActions;
let enrollmentActions: EnrollmentActions;
let quizActions: QuizActions;

test.beforeEach(async ({ page }) => {
await page.goto("/");
courseActions = new CourseActions(page);
paymentActions = new PaymentActions(page);
enrollmentActions = new EnrollmentActions(page);
quizActions = new QuizActions(page);
await courseActions.searchCourse();
});

test("should find, open and enroll the paid course", async () => {
await courseActions.openCourse();
await enrollmentActions.enrollInCourse();
await paymentActions.fillPaymentForm(new Date().getFullYear() + 1);
await paymentActions.completePurchase();
await enrollmentActions.unenrollFromCourse();
});

test("should solve free quiz lesson", async ({ page }) => {
await courseActions.openCourse();

await quizActions.solveQuiz();
await quizActions.checkAndVerifyResults();
await quizActions.resetQuiz();

await page.goBack();
});
});
32 changes: 0 additions & 32 deletions apps/web/e2e/tests/get-course.spec.ts

This file was deleted.

0 comments on commit 0fc305f

Please sign in to comment.