From 1a67151e60197224e28b7dfff5fce25d641db637 Mon Sep 17 00:00:00 2001 From: beatz174-bit Date: Sun, 23 Nov 2025 13:20:18 +1000 Subject: [PATCH] Fix pick list item actions and add Playwright tests --- e2e/picklist.spec.ts | 37 ++++++++++++++++++++ package-lock.json | 64 ++++++++++++++++++++++++++++++++++ package.json | 4 ++- playwright.config.ts | 24 +++++++++++++ src/components/PickItemRow.tsx | 2 +- vite.config.ts | 2 ++ 6 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 e2e/picklist.spec.ts create mode 100644 playwright.config.ts diff --git a/e2e/picklist.spec.ts b/e2e/picklist.spec.ts new file mode 100644 index 0000000..c23f29c --- /dev/null +++ b/e2e/picklist.spec.ts @@ -0,0 +1,37 @@ +import { expect, test } from '@playwright/test'; + +const areaName = 'Drinks'; +const firstProduct = 'Mount Franklin 600ml'; +const secondProduct = 'Mars Bar'; + +test.describe('Active pick list', () => { + test('allows creating a pick list and adding products without crashing', async ({ page }) => { + await page.goto('/'); + + await expect(page.getByRole('heading', { name: 'StockFill' })).toBeVisible(); + await page.getByRole('link', { name: 'Create Pick List' }).click(); + await page.getByLabel('Area').click(); + await page.getByRole('option', { name: areaName }).first().click(); + await page.getByRole('button', { name: 'Save Pick List' }).click(); + + await expect(page.getByRole('heading', { name: `${areaName} List` })).toBeVisible(); + + const searchInput = page.getByPlaceholder('Search products'); + await searchInput.click(); + await searchInput.fill(firstProduct); + await page + .getByRole('option', { name: new RegExp(`${firstProduct} \\(${areaName}\\)`, 'i') }) + .first() + .click(); + + await expect(page.getByText(firstProduct).first()).toBeVisible(); + await expect(page.getByText(/Qty: 1 unit/i)).toBeVisible(); + + await searchInput.click(); + await searchInput.fill(secondProduct); + await page.getByRole('option', { name: new RegExp(secondProduct, 'i') }).first().click(); + + await expect(page.getByText(secondProduct).first()).toBeVisible(); + await expect(page.getByRole('button', { name: 'Save and Return' })).toBeEnabled(); + }); +}); diff --git a/package-lock.json b/package-lock.json index ee9c982..d976c79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "uuid": "^9.0.1" }, "devDependencies": { + "@playwright/test": "^1.50.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.1.0", "@testing-library/user-event": "^14.5.2", @@ -1669,6 +1670,22 @@ "dev": true, "license": "MIT" }, + "node_modules/@playwright/test": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -4856,6 +4873,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", diff --git a/package.json b/package.json index 372cf72..fb6f1a1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "build": "tsc && cp src/pwa/manifest.json public/manifest.json && cp src/pwa/service-worker.js public/service-worker.js && vite build", "preview": "vite preview", "lint": "eslint .", - "test": "vitest" + "test": "vitest", + "test:e2e": "playwright test" }, "dependencies": { "@emotion/react": "^11.13.0", @@ -28,6 +29,7 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.1.0", "@testing-library/user-event": "^14.5.2", + "@playwright/test": "^1.50.1", "@types/node": "^22.0.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..26093c9 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,24 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + retries: process.env.CI ? 2 : 0, + use: { + baseURL: 'http://127.0.0.1:4173', + headless: true, + trace: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + webServer: { + command: 'npm run dev -- --host --port 4173', + url: 'http://127.0.0.1:4173', + timeout: 120 * 1000, + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/src/components/PickItemRow.tsx b/src/components/PickItemRow.tsx index 6c01516..e96b608 100644 --- a/src/components/PickItemRow.tsx +++ b/src/components/PickItemRow.tsx @@ -1,4 +1,4 @@ -import { Add, Delete } from '@mui/icons-material'; +import { Add, Delete, Remove, SwapHoriz } from '@mui/icons-material'; import { Button, Checkbox, diff --git a/vite.config.ts b/vite.config.ts index 8bee3ae..98a0605 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,7 +10,9 @@ export default defineConfig({ outDir: 'dist', }, test: { + include: ['src/**/*.{test,spec}.{ts,tsx}'], environment: 'jsdom', setupFiles: './src/test/setup.ts', + exclude: ['e2e/**/*'], }, });