Skip to content

Commit

Permalink
test: course settings e2e test (#394)
Browse files Browse the repository at this point in the history
* test: course settings e2e test

* fix: simplify page handling in createCourse e2e tests by passing page directly to tests
  • Loading branch information
typeWolffo authored Jan 22, 2025
1 parent 64d5bc2 commit 79d14a2
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ const CoursePricing = ({ courseId, priceInCents, currency }: CoursePricingProps)
<div className="mt-1.5">
<Input
type="radio"
name="isFree"
name="isPaid"
checked={isFree === false}
onChange={() => setValue("isFree", false)}
className="h-4 w-4 cursor-pointer p-1 pt-4"
id="isFree"
id="isPaid"
/>
</div>
<div>
<Label htmlFor="paid" className={"body-lg-md cursor-pointer text-neutral-950"}>
<Label htmlFor="isPaid" className={"body-lg-md cursor-pointer text-neutral-950"}>
<div className="body-lg-md mb-2 text-neutral-950">
{t("adminCourseView.pricing.paidCourseHeader")}
</div>
Expand Down Expand Up @@ -118,6 +118,7 @@ const CoursePricing = ({ courseId, priceInCents, currency }: CoursePricingProps)
"border-error-600": form.formState.errors.priceInCents,
},
)}
id="price"
aria-label={t("adminCourseView.pricing.field.price")}
/>
{form.formState.errors.priceInCents && (
Expand Down
11 changes: 9 additions & 2 deletions apps/web/e2e/auth.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import { test as setup } from "@playwright/test";
import { AuthFixture } from "./fixture/auth.fixture";

setup("authenticate", async ({ page }) => {
const authFixture = new AuthFixture(page);
await authFixture.login("[email protected]", "password");
const studentAuthFixture = new AuthFixture(page);
await studentAuthFixture.login("[email protected]", "password");

await page.context().storageState({
path: "e2e/.auth/user.json",
});

const adminAuthFixture = new AuthFixture(page);
await adminAuthFixture.login("[email protected]", "password");

await page.context().storageState({
path: "e2e/.auth/admin.json",
});
});
128 changes: 128 additions & 0 deletions apps/web/e2e/tests/admin/course-settings.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { expect, test, type Page } from "@playwright/test";

const TEST_COURSE = {
name: "For E2E Testing",
course_description: "DO NOT DELETE THIS COURSE.",
} as const;

const URL_PATTERNS = {
course:
/admin\/beta-courses\/[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;

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

async searchCourse(): Promise<void> {
await this.page.waitForSelector('a[href="/admin/courses"]', { state: "visible" });
await this.page.getByText("My Courses").click();
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("row", { name: TEST_COURSE.name }).click();
await this.page.waitForURL(URL_PATTERNS.course);
await expect(this.page).toHaveURL(URL_PATTERNS.course);
await this.verifyCourseContent();
}

private async verifyCourseContent(): Promise<void> {
await expect(this.page.getByRole("heading", { name: TEST_COURSE.name })).toBeVisible();
}
}

test.describe.serial("Course E2E", () => {
let courseActions: CourseActions;

test.beforeEach(async ({ page }) => {
await page.goto("/");
courseActions = new CourseActions(page);
await courseActions.searchCourse();
await courseActions.openCourse();
});

test("should change course price to free", async ({ page }) => {
await page.getByRole("tab", { name: "Pricing" }).click();
await page.getByText("Free").click();
await page.getByRole("button", { name: "Save" }).click();
await page.reload();

await expect(page.locator("#isFree")).toBeChecked();
});

test("should change course price to paid", async ({ page }) => {
await page.getByRole("tab", { name: "Pricing" }).click();
await page.getByText("Paid course").click();
await page.getByPlaceholder("Amount").fill("42069");
await page.getByRole("button", { name: "Save" }).click();
await page.reload();

await expect(page.locator("#isPaid")).toBeChecked();
await expect(page.getByPlaceholder("Amount")).toHaveValue("42,069.00");
});

test("should change course status to draft", async ({ page }) => {
await page.getByRole("tab", { name: "Status" }).click();
await page.getByText("Draft").click();
await page.getByRole("button", { name: "Save" }).click();
await page.reload();

await expect(page.locator("#draft")).toBeChecked();
});

test("should change course status to published", async ({ page }) => {
await page.getByRole("tab", { name: "Status" }).click();
await page.getByLabel("Published").click();
await page.getByRole("button", { name: "Save" }).click();
await page.reload();

await expect(page.locator("#published")).toBeChecked();
});

test("should change course title", async ({ page }) => {
await page.getByRole("tab", { name: "Settings" }).click();
await page.getByLabel("Course title").fill(`${TEST_COURSE.name} test`);

await page.getByRole("button", { name: "Save" }).click();
await page.reload();

await expect(
page.getByRole("heading", { name: `${TEST_COURSE.name} test`, level: 4 }),
).toBeVisible();
});

test("should change course description", async ({ page }) => {
await page.getByRole("tab", { name: "Settings" }).click();
await page.getByLabel("Description").fill(`${TEST_COURSE.course_description} test`);

await page.getByRole("button", { name: "Save" }).click();
await page.reload();

await expect(page.getByLabel("Description")).toHaveValue(
`${TEST_COURSE.course_description} test`,
);
});

test("should change course values to defults all at once", async ({ page }) => {
await page.getByRole("tab", { name: "Settings" }).click();
await page.getByLabel("Course title").fill(TEST_COURSE.name);
await page.getByLabel("Description").fill(TEST_COURSE.course_description);
await page.getByRole("button", { name: "Save" }).click();
await page.reload();
await expect(page.getByRole("heading", { name: TEST_COURSE.name, level: 4 })).toBeVisible();
await expect(page.getByLabel("Description")).toHaveValue(TEST_COURSE.course_description);

await page.getByRole("tab", { name: "Pricing" }).click();
await page.getByText("Free").click();
await page.getByRole("button", { name: "Save" }).click();
await page.reload();
await expect(page.locator("#isFree")).toBeChecked();

await page.getByRole("tab", { name: "Status" }).click();
await page.getByLabel("Published").click();
await page.getByRole("button", { name: "Save" }).click();
await page.reload();
await expect(page.locator("#published")).toBeChecked();
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { test, expect } from "@playwright/test";

import { AuthFixture } from "e2e/fixture/auth.fixture";

import type { Locator, Page } from "@playwright/test";

export class CreateCourseActions {
Expand Down Expand Up @@ -233,23 +231,13 @@ test.describe.serial("Course management", () => {
let newChapterId: string;
const expectedTitle = "CSS Fundamentals";
// Page have to be defined here to use it inside beforeAll, we need it to login as a Admin.
let page: Page;

test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
const authFixture = new AuthFixture(page);
await page.goto("/");
await authFixture.logout();
await page.waitForURL("/auth/login");
await authFixture.login("[email protected]", "password");
});

test.beforeEach(async () => {
test.beforeEach(async ({ page }) => {
await page.goto("/admin/courses");
createCourseActions = new CreateCourseActions(page);
});

test("should click cancel button and back to the course list", async () => {
test("should click cancel button and back to the course list", async ({ page }) => {
await createCourseActions.navigateToNewCoursePage(page);

await page.getByRole("button", { name: /cancel/i }).click();
Expand All @@ -259,7 +247,7 @@ test.describe.serial("Course management", () => {
expect(currentUrl).toMatch("/admin/courses");
});

test("should disable the proceed button when form is incomplete", async () => {
test("should disable the proceed button when form is incomplete", async ({ page }) => {
await createCourseActions.navigateToNewCoursePage(page);

const proceedButton = page.getByRole("button", { name: /proceed/i });
Expand All @@ -270,7 +258,7 @@ test.describe.serial("Course management", () => {
await expect(proceedButton).not.toBeDisabled();
});

test("should create a new course with chapter and lesson", async () => {
test("should create a new course with chapter and lesson", async ({ page }) => {
await createCourseActions.navigateToNewCoursePage(page);

await createCourseActions.fillCourseForm(page, expectedTitle);
Expand Down Expand Up @@ -415,7 +403,7 @@ test.describe.serial("Course management", () => {
await expect(quizLocator).toBeVisible();
});

test("should check if course occurs on course list", async () => {
test("should check if course occurs on course list", async ({ page }) => {
await createCourseActions.openCourse(newCourseId);

await createCourseActions.verifyCoursePage(page, newCourseId, expectedTitle);
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
15 changes: 13 additions & 2 deletions apps/web/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dotenv.config({ path: path.resolve(__dirname, ".env") });
const baseURL = process.env.CI ? "http://localhost:5173" : "https://app.lms.localhost";

const config: PlaywrightTestConfig = {
timeout: 120000,
testDir: "./e2e",
fullyParallel: true,
forbidOnly: !!process.env.CI,
Expand All @@ -40,7 +39,8 @@ const config: PlaywrightTestConfig = {
testMatch: /.*\.setup\.ts/,
},
{
name: "chromium",
name: "chromium-student",
testDir: "./e2e/tests/student",
dependencies: ["setup"],
use: {
...devices["Desktop Chrome"],
Expand All @@ -49,6 +49,17 @@ const config: PlaywrightTestConfig = {
},
testMatch: /.*\.(spec|test)\.ts$/,
},
{
name: "chromium-admin",
testDir: "./e2e/tests/admin",
dependencies: ["setup"],
use: {
...devices["Desktop Chrome"],
viewport: { width: 1920, height: 1080 },
storageState: "e2e/.auth/admin.json",
},
testMatch: /.*\.(spec|test)\.ts$/,
},
],
};

Expand Down

0 comments on commit 79d14a2

Please sign in to comment.