Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add E2E quiz lesson seed and update test implementations for course enrollment and payment validation #237

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.