From c5dea52e69fd1c1c83c0c089d1c73692ed2b4fea Mon Sep 17 00:00:00 2001 From: Greg Johnston Date: Tue, 20 Aug 2024 13:38:22 -0400 Subject: [PATCH] chore: restore Playwright tests for counters example (#2864) --- examples/counters/.gitignore | 6 ++ examples/counters/Makefile.toml | 1 + examples/counters/e2e/.gitignore | 4 + examples/counters/e2e/package-lock.json | 83 ++++++++++++++++ examples/counters/e2e/package.json | 10 ++ examples/counters/e2e/playwright.config.ts | 77 +++++++++++++++ .../e2e/tests/add_1k_counters.spec.ts | 19 ++++ .../counters/e2e/tests/add_counter.spec.ts | 15 +++ .../counters/e2e/tests/clear_counters.spec.ts | 18 ++++ .../e2e/tests/decrement_count.spec.ts | 16 +++ .../counters/e2e/tests/enter_count.spec.ts | 30 ++++++ .../e2e/tests/fixtures/counters_page.ts | 98 +++++++++++++++++++ .../e2e/tests/increment_count.spec.ts | 16 +++ .../counters/e2e/tests/remove_counter.spec.ts | 17 ++++ .../counters/e2e/tests/view_counters.spec.ts | 19 ++++ examples/counters/index.html | 3 +- examples/counters/src/lib.rs | 5 +- examples/counters/tests/web.rs | 8 +- 18 files changed, 438 insertions(+), 7 deletions(-) create mode 100644 examples/counters/.gitignore create mode 100644 examples/counters/e2e/.gitignore create mode 100644 examples/counters/e2e/package-lock.json create mode 100644 examples/counters/e2e/package.json create mode 100644 examples/counters/e2e/playwright.config.ts create mode 100644 examples/counters/e2e/tests/add_1k_counters.spec.ts create mode 100644 examples/counters/e2e/tests/add_counter.spec.ts create mode 100644 examples/counters/e2e/tests/clear_counters.spec.ts create mode 100644 examples/counters/e2e/tests/decrement_count.spec.ts create mode 100644 examples/counters/e2e/tests/enter_count.spec.ts create mode 100644 examples/counters/e2e/tests/fixtures/counters_page.ts create mode 100644 examples/counters/e2e/tests/increment_count.spec.ts create mode 100644 examples/counters/e2e/tests/remove_counter.spec.ts create mode 100644 examples/counters/e2e/tests/view_counters.spec.ts diff --git a/examples/counters/.gitignore b/examples/counters/.gitignore new file mode 100644 index 000000000..d3fc9d0a8 --- /dev/null +++ b/examples/counters/.gitignore @@ -0,0 +1,6 @@ +# Support playwright testing +node_modules/ +test-results/ +end2end/playwright-report/ +playwright/.cache/ +pnpm-lock.yaml \ No newline at end of file diff --git a/examples/counters/Makefile.toml b/examples/counters/Makefile.toml index 7c753497b..a968d5f4e 100644 --- a/examples/counters/Makefile.toml +++ b/examples/counters/Makefile.toml @@ -2,4 +2,5 @@ extend = [ { path = "../cargo-make/main.toml" }, { path = "../cargo-make/wasm-test.toml" }, { path = "../cargo-make/trunk_server.toml" }, + { path = "../cargo-make/playwright-trunk-test.toml" }, ] diff --git a/examples/counters/e2e/.gitignore b/examples/counters/e2e/.gitignore new file mode 100644 index 000000000..75e854d8d --- /dev/null +++ b/examples/counters/e2e/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/examples/counters/e2e/package-lock.json b/examples/counters/e2e/package-lock.json new file mode 100644 index 000000000..c67e400e0 --- /dev/null +++ b/examples/counters/e2e/package-lock.json @@ -0,0 +1,83 @@ +{ + "name": "grip", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "grip", + "devDependencies": { + "@playwright/test": "^1.35.1" + } + }, + "node_modules/.pnpm/@playwright+test@1.33.0": { + "extraneous": true + }, + "node_modules/.pnpm/@types+node@20.2.1/node_modules/@types/node": { + "version": "20.2.1", + "extraneous": true, + "license": "MIT" + }, + "node_modules/.pnpm/playwright-core@1.33.0/node_modules/playwright-core": { + "version": "1.33.0", + "extraneous": true, + "license": "Apache-2.0", + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.35.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.35.1.tgz", + "integrity": "sha512-b5YoFe6J9exsMYg0pQAobNDR85T1nLumUYgUTtKm4d21iX2L7WqKq9dW8NGJ+2vX0etZd+Y7UeuqsxDXm9+5ZA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.35.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/@types/node": { + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", + "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", + "dev": true + }, + "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/playwright-core": { + "version": "1.35.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.35.1.tgz", + "integrity": "sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + } + } +} diff --git a/examples/counters/e2e/package.json b/examples/counters/e2e/package.json new file mode 100644 index 000000000..b55b650fd --- /dev/null +++ b/examples/counters/e2e/package.json @@ -0,0 +1,10 @@ +{ + "private": "true", + "scripts": {}, + "devDependencies": { + "@playwright/test": "^1.46.1" + }, + "dependencies": { + "pnpm": "^9.7.1" + } +} diff --git a/examples/counters/e2e/playwright.config.ts b/examples/counters/e2e/playwright.config.ts new file mode 100644 index 000000000..93b328ee0 --- /dev/null +++ b/examples/counters/e2e/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.DEV, + /* Retry on CI only */ + retries: process.env.DEV ? 0 : 10, + /* Opt out of parallel tests on CI. */ + workers: process.env.DEV ? 1 : 1, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: [["html", { open: "never" }], ["list"]], + /* 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:8080", + + /* 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: "cd ../ && trunk serve", + // url: "http://127.0.0.1:8080", + // reuseExistingServer: false, //!process.env.CI, + // }, +}); diff --git a/examples/counters/e2e/tests/add_1k_counters.spec.ts b/examples/counters/e2e/tests/add_1k_counters.spec.ts new file mode 100644 index 000000000..ee65dc8aa --- /dev/null +++ b/examples/counters/e2e/tests/add_1k_counters.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Add 1000 Counters", () => { + test("should increase the number of counters", async ({ page }) => { + const ui = new CountersPage(page); + + await Promise.all([ + await ui.goto(), + await ui.addOneThousandCountersButton.waitFor(), + ]); + + await ui.addOneThousandCounters(); + await ui.addOneThousandCounters(); + await ui.addOneThousandCounters(); + + await expect(ui.counters).toHaveText("3000"); + }); +}); diff --git a/examples/counters/e2e/tests/add_counter.spec.ts b/examples/counters/e2e/tests/add_counter.spec.ts new file mode 100644 index 000000000..ed24360ff --- /dev/null +++ b/examples/counters/e2e/tests/add_counter.spec.ts @@ -0,0 +1,15 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Add Counter", () => { + test("should increase the number of counters", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + + await ui.addCounter(); + await ui.addCounter(); + await ui.addCounter(); + + await expect(ui.counters).toHaveText("3"); + }); +}); diff --git a/examples/counters/e2e/tests/clear_counters.spec.ts b/examples/counters/e2e/tests/clear_counters.spec.ts new file mode 100644 index 000000000..29cdfe9aa --- /dev/null +++ b/examples/counters/e2e/tests/clear_counters.spec.ts @@ -0,0 +1,18 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Clear Counters", () => { + test("should reset the counts", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + + await ui.addCounter(); + await ui.addCounter(); + await ui.addCounter(); + + await ui.clearCounters(); + + await expect(ui.total).toHaveText("0"); + await expect(ui.counters).toHaveText("0"); + }); +}); diff --git a/examples/counters/e2e/tests/decrement_count.spec.ts b/examples/counters/e2e/tests/decrement_count.spec.ts new file mode 100644 index 000000000..9b4834e3e --- /dev/null +++ b/examples/counters/e2e/tests/decrement_count.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Decrement Count", () => { + test("should decrease the total count", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + await ui.addCounter(); + + await ui.decrementCount(); + await ui.decrementCount(); + await ui.decrementCount(); + + await expect(ui.total).toHaveText("-3"); + }); +}); diff --git a/examples/counters/e2e/tests/enter_count.spec.ts b/examples/counters/e2e/tests/enter_count.spec.ts new file mode 100644 index 000000000..98e625078 --- /dev/null +++ b/examples/counters/e2e/tests/enter_count.spec.ts @@ -0,0 +1,30 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Enter Count", () => { + test("should increase the total count", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + await ui.addCounter(); + + await ui.enterCount("5"); + + await expect(ui.total).toHaveText("5"); + await expect(ui.counters).toHaveText("1"); + }); + + test("should decrease the total count", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + await ui.addCounter(); + await ui.addCounter(); + await ui.addCounter(); + + await ui.enterCount("100"); + await ui.enterCount("100", 1); + await ui.enterCount("100", 2); + await ui.enterCount("50", 1); + + await expect(ui.total).toHaveText("250"); + }); +}); diff --git a/examples/counters/e2e/tests/fixtures/counters_page.ts b/examples/counters/e2e/tests/fixtures/counters_page.ts new file mode 100644 index 000000000..7b951de65 --- /dev/null +++ b/examples/counters/e2e/tests/fixtures/counters_page.ts @@ -0,0 +1,98 @@ +import { expect, Locator, Page } from "@playwright/test"; + +export class CountersPage { + readonly page: Page; + readonly addCounterButton: Locator; + readonly addOneThousandCountersButton: Locator; + readonly clearCountersButton: Locator; + + readonly incrementCountButton: Locator; + readonly counterInput: Locator; + readonly decrementCountButton: Locator; + readonly removeCountButton: Locator; + + readonly total: Locator; + readonly counters: Locator; + + constructor(page: Page) { + this.page = page; + + this.addCounterButton = page.locator("button", { hasText: "Add Counter" }); + + this.addOneThousandCountersButton = page.locator("button", { + hasText: "Add 1000 Counters", + }); + + this.clearCountersButton = page.locator("button", { + hasText: "Clear Counters", + }); + + this.decrementCountButton = page.locator("button", { + hasText: "-1", + }); + + this.incrementCountButton = page.locator("button", { + hasText: "+1", + }); + + this.removeCountButton = page.locator("button", { + hasText: "x", + }); + + this.total = page.getByTestId("total"); + + this.counters = page.getByTestId("counters"); + + this.counterInput = page.getByRole("textbox"); + } + + async goto() { + await this.page.goto("/"); + } + + async addCounter() { + await Promise.all([ + this.addCounterButton.waitFor(), + this.addCounterButton.click(), + ]); + } + + async addOneThousandCounters() { + this.addOneThousandCountersButton.click(); + } + + async decrementCount(index: number = 0) { + await Promise.all([ + this.decrementCountButton.nth(index).waitFor(), + this.decrementCountButton.nth(index).click(), + ]); + } + + async incrementCount(index: number = 0) { + await Promise.all([ + this.incrementCountButton.nth(index).waitFor(), + this.incrementCountButton.nth(index).click(), + ]); + } + + async clearCounters() { + await Promise.all([ + this.clearCountersButton.waitFor(), + this.clearCountersButton.click(), + ]); + } + + async enterCount(count: string, index: number = 0) { + await Promise.all([ + this.counterInput.nth(index).waitFor(), + this.counterInput.nth(index).fill(count), + ]); + } + + async removeCounter(index: number = 0) { + await Promise.all([ + this.removeCountButton.nth(index).waitFor(), + this.removeCountButton.nth(index).click(), + ]); + } +} diff --git a/examples/counters/e2e/tests/increment_count.spec.ts b/examples/counters/e2e/tests/increment_count.spec.ts new file mode 100644 index 000000000..15b490454 --- /dev/null +++ b/examples/counters/e2e/tests/increment_count.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Increment Count", () => { + test("should increase the total count", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + await ui.addCounter(); + + await ui.incrementCount(); + await ui.incrementCount(); + await ui.incrementCount(); + + await expect(ui.total).toHaveText("3"); + }); +}); diff --git a/examples/counters/e2e/tests/remove_counter.spec.ts b/examples/counters/e2e/tests/remove_counter.spec.ts new file mode 100644 index 000000000..7abffb088 --- /dev/null +++ b/examples/counters/e2e/tests/remove_counter.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("Remove Counter", () => { + test("should decrement the number of counters", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + + await ui.addCounter(); + await ui.addCounter(); + await ui.addCounter(); + + await ui.removeCounter(1); + + await expect(ui.counters).toHaveText("2"); + }); +}); diff --git a/examples/counters/e2e/tests/view_counters.spec.ts b/examples/counters/e2e/tests/view_counters.spec.ts new file mode 100644 index 000000000..3d014c6fa --- /dev/null +++ b/examples/counters/e2e/tests/view_counters.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./fixtures/counters_page"; + +test.describe("View Counters", () => { + test("should see the title", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + + await expect(page).toHaveTitle("Counters"); + }); + + test("should see the initial counts", async ({ page }) => { + const counters = new CountersPage(page); + await counters.goto(); + + await expect(counters.total).toHaveText("0"); + await expect(counters.counters).toHaveText("0"); + }); +}); diff --git a/examples/counters/index.html b/examples/counters/index.html index 5c37472ec..72206b0d0 100644 --- a/examples/counters/index.html +++ b/examples/counters/index.html @@ -2,6 +2,7 @@ + Counters - \ No newline at end of file + diff --git a/examples/counters/src/lib.rs b/examples/counters/src/lib.rs index e6be7e9c1..a29c051c7 100644 --- a/examples/counters/src/lib.rs +++ b/examples/counters/src/lib.rs @@ -44,12 +44,13 @@ pub fn Counters() -> impl IntoView {

"Total: " - + {move || { counters.get().iter().map(|(_, count)| count.get()).sum::().to_string() }} - " from " {move || counters.get().len().to_string()} + " from " + {move || counters.get().len().to_string()} " counters."