From 317beafd3dca6f12f41dbf5ba1bfe524f9d8589f Mon Sep 17 00:00:00 2001 From: Bryan Lundberg Date: Tue, 23 Apr 2024 19:12:27 -0600 Subject: [PATCH] test: add some (e2e) cases (#296) * test: initial (e2e) implementation * test: add some test for settings * change description --- .gitignore | 4 +++ package-lock.json | 60 +++++++++++++++++++++++++++++++ package.json | 1 + playwright.config.ts | 77 +++++++++++++++++++++++++++++++++++++++ tests/test-1.spec.ts | 14 ++++++++ tests/test-2.spec.ts | 12 +++++++ tests/test-3.spec.ts | 11 ++++++ tests/test-4.spec.ts | 14 ++++++++ tests/test-5.spec.ts | 85 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 278 insertions(+) create mode 100644 playwright.config.ts create mode 100644 tests/test-1.spec.ts create mode 100644 tests/test-2.spec.ts create mode 100644 tests/test-3.spec.ts create mode 100644 tests/test-4.spec.ts create mode 100644 tests/test-5.spec.ts diff --git a/.gitignore b/.gitignore index 8f322f0d..402acb45 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,7 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/package-lock.json b/package-lock.json index 2f4c78fc..ac2399fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "zustand": "4.4.1" }, "devDependencies": { + "@playwright/test": "^1.43.1", "@types/uuid": "9.0.3" } }, @@ -417,6 +418,21 @@ "node": ">= 8" } }, + "node_modules/@playwright/test": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz", + "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==", + "dev": true, + "dependencies": { + "playwright": "1.43.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.4.0.tgz", @@ -3648,6 +3664,50 @@ "node": ">= 6" } }, + "node_modules/playwright": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", + "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==", + "dev": true, + "dependencies": { + "playwright-core": "1.43.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.43.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz", + "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", diff --git a/package.json b/package.json index 26d3ac59..285165e4 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "zustand": "4.4.1" }, "devDependencies": { + "@playwright/test": "^1.43.1", "@types/uuid": "9.0.3" } } diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000..301801ee --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,77 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/tests/test-1.spec.ts b/tests/test-1.spec.ts new file mode 100644 index 00000000..6385264c --- /dev/null +++ b/tests/test-1.spec.ts @@ -0,0 +1,14 @@ +import { test, expect } from "@playwright/test"; + +test("should navigate to all pages", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await expect(page.getByText("Choose a cube to load a")).toBeVisible(); + await expect(page.getByRole("list")).toBeVisible(); + await page.getByRole("link").nth(1).click(); + await page.getByRole("link").nth(2).click(); + await expect(page.getByText("Solves")).toBeVisible(); + await page.getByRole("link").nth(3).click(); + await expect(page.getByText("Metrics")).toBeVisible(); + await page.getByRole("link").nth(3).click(); + await expect(page.getByText("Cubes", { exact: true })).toBeVisible(); +}); diff --git a/tests/test-2.spec.ts b/tests/test-2.spec.ts new file mode 100644 index 00000000..dbfa9c4b --- /dev/null +++ b/tests/test-2.spec.ts @@ -0,0 +1,12 @@ +import { test, expect } from "@playwright/test"; + +test("should create a cube from home-page", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await page.getByRole("button", { name: "Select" }).click(); + await expect(page.getByText("Favorites")).toBeVisible(); + await page.getByRole("link", { name: "Add cube" }).click(); + await page.getByPlaceholder("Brand | Model | Version |").click(); + await page.getByPlaceholder("Brand | Model | Version |").fill("test"); + await page.getByRole("button", { name: "Create" }).click(); + await expect(page.getByText("test")).toBeVisible(); +}); diff --git a/tests/test-3.spec.ts b/tests/test-3.spec.ts new file mode 100644 index 00000000..75ec96bc --- /dev/null +++ b/tests/test-3.spec.ts @@ -0,0 +1,11 @@ +import { test, expect } from "@playwright/test"; + +test("Should create a cube from cubes-page", async ({ page }) => { + await page.goto("http://localhost:3000/cubes"); + await expect(page.getByText("Cubes", { exact: true })).toBeVisible(); + await page.getByRole("button").click(); + await page.getByPlaceholder("Brand | Model | Version |").fill("test"); + await page.getByRole("img", { name: "3x3", exact: true }).click(); + await page.getByRole("button", { name: "Create" }).click(); + await expect(page.getByText("test")).toBeVisible(); +}); diff --git a/tests/test-4.spec.ts b/tests/test-4.spec.ts new file mode 100644 index 00000000..ce591240 --- /dev/null +++ b/tests/test-4.spec.ts @@ -0,0 +1,14 @@ +import { test, expect } from "@playwright/test"; + +test("Should create and delete a cube", async ({ page }) => { + await page.goto("http://localhost:3000/cubes"); + await page.getByRole("button").click(); + await page.getByPlaceholder("Brand | Model | Version |").click(); + await page.getByPlaceholder("Brand | Model | Version |").fill("test"); + await page.getByRole("button", { name: "Create" }).click(); + await expect(page.getByText("test")).toBeVisible(); + await page.getByRole("button").nth(2).click(); + await page.getByRole("button", { name: "Delete" }).click(); + await page.getByRole("button", { name: "Confirm" }).click(); + await expect(page.getByText("No cubes for display.")).toBeVisible(); +}); diff --git a/tests/test-5.spec.ts b/tests/test-5.spec.ts new file mode 100644 index 00000000..63993886 --- /dev/null +++ b/tests/test-5.spec.ts @@ -0,0 +1,85 @@ +import { test, expect } from "@playwright/test"; + +test.describe("Should try all settings", () => { + test("Should change language", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await expect(page.getByText("Choose a cube to load a")).toBeVisible(); + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await expect(page.getByText("Language")).toBeVisible(); + await page.getByRole("combobox").selectOption("es"); + await expect(page.getByText("Idioma")).toBeVisible(); + await page.getByRole("combobox").selectOption("en"); + await expect(page.getByText("Language")).toBeVisible(); + }); + + test("Should hide scramble image", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await expect(page.getByText("Choose a cube to load a")).toBeVisible(); + + await expect(page.locator("twisty-player")).toBeVisible(); + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await page.getByRole("switch", { name: "Scramble image" }).click(); + await page.locator(".sm\\:grow").click(); + await expect(page.locator("twisty-player")).toHaveCount(0); + + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await page.getByRole("switch", { name: "Scramble image" }).click(); + await page.locator(".sm\\:grow").click(); + await expect(page.locator("twisty-player")).toBeVisible(); + }); + + test("Should toggle display timer stats", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await expect(page.getByText("Choose a cube to load a")).toBeVisible(); + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await page.locator(".sm\\:grow").click(); + await expect(page.getByText("Deviation:")).toBeVisible(); + await expect(page.getByText("Ao5: --")).toBeVisible(); + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await page.getByRole("switch", { name: "Session stats" }).click(); + await page.locator(".sm\\:grow").click(); + await expect(page.getByText("Deviation:")).toHaveCount(0); + await expect(page.getByText("Ao5: --")).toHaveCount(0); + }); + + test("Should toggle manual mode", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await expect(page.getByText("Choose a cube to load a")).toBeVisible(); + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await page.getByRole("switch", { name: "Manual mode" }).click(); + await page.locator(".sm\\:grow").click(); + await expect(page.getByPlaceholder("...")).toBeVisible(); + await page + .locator("div") + .filter({ hasText: /^SelectChoose a cube to load a scramble\.$/ }) + .getByRole("link") + .click(); + await page.getByRole("switch", { name: "Manual mode" }).click(); + await page.locator(".sm\\:grow").click(); + await expect(page.getByPlaceholder("...")).toHaveCount(0); + }); +});