From f5cfe4e8a2a2e8bf36c8cdbdc58201bb36810934 Mon Sep 17 00:00:00 2001 From: Joseph Cruz Date: Mon, 26 Jun 2023 21:11:09 -0400 Subject: [PATCH] test(counters_stable): add playwright tests (#1235) --- examples/cargo-make/common.toml | 2 +- examples/cargo-make/main.toml | 3 + examples/cargo-make/playwright-test.toml | 7 ++ examples/cargo-make/playwright.toml | 119 ++++++++++++++++++ examples/cargo-make/trunk_server.toml | 22 ++++ examples/counters_stable/.gitignore | 20 +++ examples/counters_stable/Makefile.toml | 6 +- examples/counters_stable/e2e/.gitignore | 4 + .../counters_stable/e2e/package-lock.json | 83 ++++++++++++ examples/counters_stable/e2e/package.json | 7 ++ .../counters_stable/e2e/playwright.config.ts | 77 ++++++++++++ .../e2e/tests/add_1k_counters.spec.ts | 23 ++++ .../e2e/tests/add_counter.spec.ts | 16 +++ .../e2e/tests/clear_counters.spec.ts | 18 +++ .../e2e/tests/counters_page.ts | 63 ++++++++++ .../e2e/tests/decrement_count.spec.ts | 17 +++ .../e2e/tests/increment_count.spec.ts | 17 +++ .../e2e/tests/view_counters.spec.ts | 19 +++ examples/counters_stable/index.html | 1 + examples/counters_stable/package.json | 11 ++ examples/counters_stable/src/main.rs | 8 +- 21 files changed, 537 insertions(+), 6 deletions(-) create mode 100644 examples/cargo-make/playwright-test.toml create mode 100644 examples/cargo-make/playwright.toml create mode 100644 examples/cargo-make/trunk_server.toml create mode 100644 examples/counters_stable/.gitignore create mode 100644 examples/counters_stable/e2e/.gitignore create mode 100644 examples/counters_stable/e2e/package-lock.json create mode 100644 examples/counters_stable/e2e/package.json create mode 100644 examples/counters_stable/e2e/playwright.config.ts create mode 100644 examples/counters_stable/e2e/tests/add_1k_counters.spec.ts create mode 100644 examples/counters_stable/e2e/tests/add_counter.spec.ts create mode 100644 examples/counters_stable/e2e/tests/clear_counters.spec.ts create mode 100644 examples/counters_stable/e2e/tests/counters_page.ts create mode 100644 examples/counters_stable/e2e/tests/decrement_count.spec.ts create mode 100644 examples/counters_stable/e2e/tests/increment_count.spec.ts create mode 100644 examples/counters_stable/e2e/tests/view_counters.spec.ts create mode 100644 examples/counters_stable/package.json diff --git a/examples/cargo-make/common.toml b/examples/cargo-make/common.toml index c75a3000e..9766a16b0 100644 --- a/examples/cargo-make/common.toml +++ b/examples/cargo-make/common.toml @@ -34,7 +34,7 @@ category = "Cleanup" script = ''' for pw_dir in $(find . -name playwright.config.ts | xargs dirname) do - rm -rf $pw_dir/playwright-report + rm -rf $pw_dir/playwright-report pw_dir/playwright pw_dir/test-results done ''' diff --git a/examples/cargo-make/main.toml b/examples/cargo-make/main.toml index 910cae261..da3c32c7a 100644 --- a/examples/cargo-make/main.toml +++ b/examples/cargo-make/main.toml @@ -1,5 +1,8 @@ extend = [{ path = "../cargo-make/common.toml" }] +[tasks.ci] +alias = "verify-flow" + [tasks.verify-flow] description = "Provides pre and post hooks for verify" dependencies = ["pre-verify", "verify", "post-verify"] diff --git a/examples/cargo-make/playwright-test.toml b/examples/cargo-make/playwright-test.toml new file mode 100644 index 000000000..694b2990b --- /dev/null +++ b/examples/cargo-make/playwright-test.toml @@ -0,0 +1,7 @@ +extend = [{ path = "../cargo-make/playwright.toml" }] + +[tasks.test-e2e] +dependencies = ["setup-node", "test-playwright-autostart"] + +[tasks.clean-all] +dependencies = ["clean-cargo", "clean-node_modules", "clean-playwright"] diff --git a/examples/cargo-make/playwright.toml b/examples/cargo-make/playwright.toml new file mode 100644 index 000000000..5085b8cba --- /dev/null +++ b/examples/cargo-make/playwright.toml @@ -0,0 +1,119 @@ +[tasks.clean-playwright] +description = "Delete playwright directories" +category = "Cleanup" +script = ''' +for pw_dir in $(find . -name playwright.config.ts | xargs dirname) +do + rm -rf $pw_dir/playwright-report pw_dir/playwright pw_dir/test-results +done +''' + +[tasks.test-playwright-autostart] +description = "Run playwright test with server autostart" +category = "Test" +command = "npm" +args = ["run", "e2e:auto-start"] + +[tasks.test-playwright] +description = "Run playwright test" +category = "Test" +script = ''' +BOLD="\e[1m" +GREEN="\e[0;32m" +RED="\e[0;31m" +RESET="\e[0m" + +project_dir=$CARGO_MAKE_WORKING_DIRECTORY + +# Discover commands +if command -v pnpm; then + PLAYWRIGHT_CMD=pnpm +elif command -v npm; then + PLAYWRIGHT_CMD=npx +else + echo "${RED}${BOLD}ERROR${RESET} - pnpm or npm is required by this task" + exit 1 +fi + +# Run playwright command +for pw_path in $(find . -name playwright.config.ts) +do + pw_dir=$(dirname $pw_path) + cd $pw_dir + ${PLAYWRIGHT_CMD} playwright test + cd $project_dir +done +''' + +[tasks.test-playwright-ui] +description = "Run playwright test --ui" +category = "Test" +script = ''' +BOLD="\e[1m" +GREEN="\e[0;32m" +RED="\e[0;31m" +RESET="\e[0m" + +project_dir=$CARGO_MAKE_WORKING_DIRECTORY + +# Discover commands +if command -v pnpm; then + PLAYWRIGHT_CMD=pnpm +elif command -v npm; then + PLAYWRIGHT_CMD=npx +else + echo "${RED}${BOLD}ERROR${RESET} - pnpm or npm is required by this task" + exit 1 +fi + +# Run playwright command +for pw_path in $(find . -name playwright.config.ts) +do + pw_dir=$(dirname $pw_path) + cd $pw_dir + ${PLAYWRIGHT_CMD} playwright test --ui + cd $project_dir +done +''' + +[tasks.test-playwright-report] +description = "Run playwright show-report" +category = "Test" +script = ''' +BOLD="\e[1m" +GREEN="\e[0;32m" +RED="\e[0;31m" +RESET="\e[0m" + +project_dir=$CARGO_MAKE_WORKING_DIRECTORY + +# Discover commands +if command -v pnpm; then + PLAYWRIGHT_CMD=pnpm +elif command -v npm; then + PLAYWRIGHT_CMD=npx +else + echo "${RED}${BOLD}ERROR${RESET} - pnpm or npm is required by this task" + exit 1 +fi + +# Run playwright command +for pw_path in $(find . -name playwright.config.ts) +do + pw_dir=$(dirname $pw_path) + cd $pw_dir + ${PLAYWRIGHT_CMD} playwright show-report + cd $project_dir +done +''' + +# ALIASES + +[tasks.pw] +dependencies = ["test-playwright"] + +[tasks.pw-ui] +dependencies = ["test-playwright-ui"] + +[tasks.pw-report] +dependencies = ["test-playwright-report"] diff --git a/examples/cargo-make/trunk_server.toml b/examples/cargo-make/trunk_server.toml new file mode 100644 index 000000000..09610e28e --- /dev/null +++ b/examples/cargo-make/trunk_server.toml @@ -0,0 +1,22 @@ +[tasks.build] +command = "trunk" +args = ["build"] + +[tasks.clean-trunk] +command = "trunk" +args = ["clean"] + +[tasks.start-trunk] +command = "trunk" +args = ["serve", "--open"] + +[tasks.stop-trunk] +script = ''' + pkill -f "cargo-make" + pkill -f "trunk" +''' + +# ALIASES + +[tasks.dev] +dependencies = ["start-trunk"] diff --git a/examples/counters_stable/.gitignore b/examples/counters_stable/.gitignore new file mode 100644 index 000000000..b77e2dda3 --- /dev/null +++ b/examples/counters_stable/.gitignore @@ -0,0 +1,20 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# Support playwright testing +node_modules/ +test-results/ +end2end/playwright-report/ +playwright/.cache/ +pnpm-lock.yaml + +# Support trunk +dist diff --git a/examples/counters_stable/Makefile.toml b/examples/counters_stable/Makefile.toml index 1705f0514..79bad3fb3 100644 --- a/examples/counters_stable/Makefile.toml +++ b/examples/counters_stable/Makefile.toml @@ -1,4 +1,8 @@ -extend = [{ path = "../cargo-make/main.toml" }] +extend = [ + { path = "../cargo-make/main.toml" }, + { path = "../cargo-make/trunk_server.toml" }, + { path = "../cargo-make/playwright-test.toml" }, +] [tasks.build] command = "cargo" diff --git a/examples/counters_stable/e2e/.gitignore b/examples/counters_stable/e2e/.gitignore new file mode 100644 index 000000000..75e854d8d --- /dev/null +++ b/examples/counters_stable/e2e/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/examples/counters_stable/e2e/package-lock.json b/examples/counters_stable/e2e/package-lock.json new file mode 100644 index 000000000..c67e400e0 --- /dev/null +++ b/examples/counters_stable/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_stable/e2e/package.json b/examples/counters_stable/e2e/package.json new file mode 100644 index 000000000..f7038d2bc --- /dev/null +++ b/examples/counters_stable/e2e/package.json @@ -0,0 +1,7 @@ +{ + "private": "true", + "scripts": {}, + "devDependencies": { + "@playwright/test": "^1.35.1" + } +} diff --git a/examples/counters_stable/e2e/playwright.config.ts b/examples/counters_stable/e2e/playwright.config.ts new file mode 100644 index 000000000..41c1635fc --- /dev/null +++ b/examples/counters_stable/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.CI, + /* Retry on CI only */ + retries: process.env.CI ? 10 : 10, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : 1, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: "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_stable/e2e/tests/add_1k_counters.spec.ts b/examples/counters_stable/e2e/tests/add_1k_counters.spec.ts new file mode 100644 index 000000000..4289ca9ce --- /dev/null +++ b/examples/counters_stable/e2e/tests/add_1k_counters.spec.ts @@ -0,0 +1,23 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./counters_page"; + +test.describe("Add 1000 Counters", () => { + test("should increment the total count by 1K", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + + // FIXME: Uncomment to make the test fail consistently + + await ui.addOneThousandCounters(); + // await expect(ui.total).toHaveText("0"); + // await expect(ui.counters).toHaveText("1000"); + + await ui.addOneThousandCounters(); + // await expect(ui.total).toHaveText("0"); + // await expect(ui.counters).toHaveText("2000"); + + await ui.addOneThousandCounters(); + await expect(ui.total).toHaveText("0"); + await expect(ui.counters).toHaveText("3000"); + }); +}); diff --git a/examples/counters_stable/e2e/tests/add_counter.spec.ts b/examples/counters_stable/e2e/tests/add_counter.spec.ts new file mode 100644 index 000000000..c0cf480d5 --- /dev/null +++ b/examples/counters_stable/e2e/tests/add_counter.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./counters_page"; + +test.describe("Add Counter", () => { + test("should increment the total count", async ({ page }) => { + const ui = new CountersPage(page); + await ui.goto(); + + await ui.addCounter(); + await ui.addCounter(); + await ui.addCounter(); + + await expect(ui.total).toHaveText("0"); + await expect(ui.counters).toHaveText("3"); + }); +}); diff --git a/examples/counters_stable/e2e/tests/clear_counters.spec.ts b/examples/counters_stable/e2e/tests/clear_counters.spec.ts new file mode 100644 index 000000000..288b352d2 --- /dev/null +++ b/examples/counters_stable/e2e/tests/clear_counters.spec.ts @@ -0,0 +1,18 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./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_stable/e2e/tests/counters_page.ts b/examples/counters_stable/e2e/tests/counters_page.ts new file mode 100644 index 000000000..bdbf65a13 --- /dev/null +++ b/examples/counters_stable/e2e/tests/counters_page.ts @@ -0,0 +1,63 @@ +import { expect, Locator, Page } from "@playwright/test"; + +export class CountersPage { + readonly page: Page; + readonly addCounterButton: Locator; + readonly addOneThousandCountersButton: Locator; + readonly clearCountersButton: Locator; + readonly decrementCountButton: Locator; + readonly incrementCountButton: 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.total = page.getByTestId("total"); + + this.counters = page.getByTestId("counters"); + } + + async goto() { + await this.page.goto("/"); + } + + async addCounter() { + this.addCounterButton.click(); + } + + async addOneThousandCounters() { + this.addOneThousandCountersButton.click(); + } + + async decrementCount() { + this.decrementCountButton.click(); + } + + async incrementCount() { + this.incrementCountButton.click(); + } + + async clearCounters() { + this.clearCountersButton.click(); + } +} diff --git a/examples/counters_stable/e2e/tests/decrement_count.spec.ts b/examples/counters_stable/e2e/tests/decrement_count.spec.ts new file mode 100644 index 000000000..a984a57d4 --- /dev/null +++ b/examples/counters_stable/e2e/tests/decrement_count.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./counters_page"; + +test.describe("Decrement Count", () => { + test("should decrement 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"); + await expect(ui.counters).toHaveText("1"); + }); +}); diff --git a/examples/counters_stable/e2e/tests/increment_count.spec.ts b/examples/counters_stable/e2e/tests/increment_count.spec.ts new file mode 100644 index 000000000..a41eed9cb --- /dev/null +++ b/examples/counters_stable/e2e/tests/increment_count.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./counters_page"; + +test.describe("Increment Count", () => { + test("should increment 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"); + await expect(ui.counters).toHaveText("1"); + }); +}); diff --git a/examples/counters_stable/e2e/tests/view_counters.spec.ts b/examples/counters_stable/e2e/tests/view_counters.spec.ts new file mode 100644 index 000000000..d4b051549 --- /dev/null +++ b/examples/counters_stable/e2e/tests/view_counters.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from "@playwright/test"; +import { CountersPage } from "./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 (Stable)"); + }); + + 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_stable/index.html b/examples/counters_stable/index.html index 5c37472ec..54d09ef46 100644 --- a/examples/counters_stable/index.html +++ b/examples/counters_stable/index.html @@ -1,6 +1,7 @@ + Counters (Stable) diff --git a/examples/counters_stable/package.json b/examples/counters_stable/package.json new file mode 100644 index 000000000..86d5d8868 --- /dev/null +++ b/examples/counters_stable/package.json @@ -0,0 +1,11 @@ +{ + "private": "true", + "scripts": { + "start-server": "trunk serve", + "e2e": "cargo make test-playwright", + "e2e:auto-start": "start-server-and-test start-server http://127.0.0.1:8080 e2e" + }, + "devDependencies": { + "start-server-and-test": "^1.15.4" + } +} diff --git a/examples/counters_stable/src/main.rs b/examples/counters_stable/src/main.rs index 2baf049fe..0a065955f 100644 --- a/examples/counters_stable/src/main.rs +++ b/examples/counters_stable/src/main.rs @@ -56,7 +56,7 @@ pub fn Counters(cx: Scope) -> impl IntoView {

"Total: " - {move || + {move || counters.get() .iter() .map(|(_, (count, _))| count.get()) @@ -64,7 +64,7 @@ pub fn Counters(cx: Scope) -> impl IntoView { .to_string() } " from " - {move || counters.with(|counters| counters.len()).to_string()} + {move || counters.with(|counters| counters.len()).to_string()} " counters."