From 6fbd266d726ce0fa1c2a6a0af7c3d788c74a7117 Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 01:58:56 -0800 Subject: [PATCH 1/8] working vite test --- tests/.gitignore | 7 +++ tests/e2e/vite.spec.ts | 34 ++++++++++++++ tests/package-lock.json | 90 ++++++++++++++++++++++++++++++++++++++ tests/package.json | 13 ++++++ tests/playwright.config.ts | 35 +++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 tests/.gitignore create mode 100644 tests/e2e/vite.spec.ts create mode 100644 tests/package-lock.json create mode 100644 tests/package.json create mode 100644 tests/playwright.config.ts diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..c9b126c --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,7 @@ +# Dependencies +node_modules/ + +# Playwright +playwright-report/ +test-results/ +playwright/.cache/ diff --git a/tests/e2e/vite.spec.ts b/tests/e2e/vite.spec.ts new file mode 100644 index 0000000..5487e23 --- /dev/null +++ b/tests/e2e/vite.spec.ts @@ -0,0 +1,34 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Vite React Template', () => { + test('should load the app and display main content', async ({ page }) => { + await page.goto('/'); + + // Check that the page title is correct + await expect(page).toHaveTitle('vite'); + + // Check that the main heading is visible + await expect(page.getByRole('heading', { name: 'Vite + React' })).toBeVisible(); + + // Check that the Vite and React logos are present + await expect(page.getByAltText('Vite logo')).toBeVisible(); + await expect(page.getByAltText('React logo')).toBeVisible(); + }); + + test('should have working counter button', async ({ page }) => { + await page.goto('/'); + + // Find the counter button and verify initial state + const counterButton = page.getByRole('button', { name: /count is/i }); + await expect(counterButton).toBeVisible(); + await expect(counterButton).toHaveText('count is 0'); + + // Click the button and verify the count increments + await counterButton.click(); + await expect(counterButton).toHaveText('count is 1'); + + // Click again to verify continued functionality + await counterButton.click(); + await expect(counterButton).toHaveText('count is 2'); + }); +}); diff --git a/tests/package-lock.json b/tests/package-lock.json new file mode 100644 index 0000000..dc835a0 --- /dev/null +++ b/tests/package-lock.json @@ -0,0 +1,90 @@ +{ + "name": "powerappscodeapps-tests", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "powerappscodeapps-tests", + "version": "0.0.0", + "devDependencies": { + "@playwright/test": "^1.40.0", + "@types/node": "^24.10.9" + } + }, + "node_modules/@playwright/test": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz", + "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", + "dev": true, + "dependencies": { + "playwright": "1.57.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "24.10.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", + "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "dev": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "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": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz", + "integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==", + "dev": true, + "dependencies": { + "playwright-core": "1.57.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz", + "integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true + } + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 0000000..9582aec --- /dev/null +++ b/tests/package.json @@ -0,0 +1,13 @@ +{ + "name": "powerappscodeapps-tests", + "private": true, + "version": "0.0.0", + "scripts": { + "test:vite": "playwright test --project=vite", + "test:all": "playwright test" + }, + "devDependencies": { + "@playwright/test": "^1.40.0", + "@types/node": "^24.10.9" + } +} diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts new file mode 100644 index 0000000..9ff1b24 --- /dev/null +++ b/tests/playwright.config.ts @@ -0,0 +1,35 @@ +import { defineConfig, devices } from '@playwright/test'; +import path from 'path'; + +const isCI = !!process.env.CI; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: isCI, + retries: isCI ? 2 : 0, + workers: isCI ? 1 : undefined, + reporter: isCI ? 'github' : 'html', + use: { + trace: 'on-first-retry', + }, + projects: [ + { + name: 'vite', + testMatch: 'vite.spec.ts', + use: { + ...devices['Desktop Chrome'], + baseURL: isCI ? 'http://localhost:4173' : 'http://localhost:5173', + }, + }, + ], + webServer: [ + { + name: 'vite-template', + command: isCI ? 'npm run build && npm run preview' : 'npm run dev', + cwd: path.resolve(__dirname, '../templates/vite'), + url: isCI ? 'http://localhost:4173' : 'http://localhost:5173', + reuseExistingServer: !isCI, + }, + ], +}); From f726e47808e2e21d3aa48eaa270d44e1f901f854 Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:07:26 -0800 Subject: [PATCH 2/8] add starter template test --- templates/starter/package-lock.json | 14 ---------- tests/e2e/starter.spec.ts | 42 +++++++++++++++++++++++++++++ tests/package.json | 1 + tests/playwright.config.ts | 21 ++++++++++++--- 4 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 tests/e2e/starter.spec.ts diff --git a/templates/starter/package-lock.json b/templates/starter/package-lock.json index 167efeb..8903b59 100644 --- a/templates/starter/package-lock.json +++ b/templates/starter/package-lock.json @@ -85,7 +85,6 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2700,7 +2699,6 @@ "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2711,7 +2709,6 @@ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -2722,7 +2719,6 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2773,7 +2769,6 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -3026,7 +3021,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3157,7 +3151,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -3604,7 +3597,6 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4779,7 +4771,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -4810,7 +4801,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -5253,7 +5243,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -5322,7 +5311,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5473,7 +5461,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -5565,7 +5552,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, diff --git a/tests/e2e/starter.spec.ts b/tests/e2e/starter.spec.ts new file mode 100644 index 0000000..d88d16c --- /dev/null +++ b/tests/e2e/starter.spec.ts @@ -0,0 +1,42 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Starter Template', () => { + test('should load the app and display main content', async ({ page }) => { + await page.goto('/'); + + // Check that the page title is correct + await expect(page).toHaveTitle('Power Apps'); + + // Check that the main heading is visible + await expect(page.getByRole('heading', { name: 'Power + Code' })).toBeVisible(); + + // Check that the Power Apps and React logos are present + await expect(page.getByAltText('Power Apps logo')).toBeVisible(); + await expect(page.getByAltText('React logo')).toBeVisible(); + }); + + test('should have working counter button', async ({ page }) => { + await page.goto('/'); + + // Find the counter button and verify initial state + const counterButton = page.getByRole('button', { name: /count is/i }); + await expect(counterButton).toBeVisible(); + await expect(counterButton).toHaveText('count is 0'); + + // Click the button and verify the count increments + await counterButton.click(); + await expect(counterButton).toHaveText('count is 1'); + + // Click again to verify continued functionality + await counterButton.click(); + await expect(counterButton).toHaveText('count is 2'); + }); + + test('should have theme toggle', async ({ page }) => { + await page.goto('/'); + + // Check that the theme toggle button exists + const themeToggle = page.getByRole('button', { name: /toggle theme/i }); + await expect(themeToggle).toBeVisible(); + }); +}); diff --git a/tests/package.json b/tests/package.json index 9582aec..450f9c9 100644 --- a/tests/package.json +++ b/tests/package.json @@ -4,6 +4,7 @@ "version": "0.0.0", "scripts": { "test:vite": "playwright test --project=vite", + "test:starter": "playwright test --project=starter", "test:all": "playwright test" }, "devDependencies": { diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index 9ff1b24..89fc970 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -19,16 +19,31 @@ export default defineConfig({ testMatch: 'vite.spec.ts', use: { ...devices['Desktop Chrome'], - baseURL: isCI ? 'http://localhost:4173' : 'http://localhost:5173', + baseURL: 'http://localhost:4173', + }, + }, + { + name: 'starter', + testMatch: 'starter.spec.ts', + use: { + ...devices['Desktop Chrome'], + baseURL: 'http://localhost:4174', }, }, ], webServer: [ { name: 'vite-template', - command: isCI ? 'npm run build && npm run preview' : 'npm run dev', + command: 'npm run build && npm run preview -- --port 4173', cwd: path.resolve(__dirname, '../templates/vite'), - url: isCI ? 'http://localhost:4173' : 'http://localhost:5173', + url: 'http://localhost:4173', + reuseExistingServer: !isCI, + }, + { + name: 'starter-template', + command: 'npm run build && npm run preview -- --port 4174', + cwd: path.resolve(__dirname, '../templates/starter'), + url: 'http://localhost:4174', reuseExistingServer: !isCI, }, ], From fd8d0c4df1951974a83be3b959aca1948b5c0bc4 Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:09:13 -0800 Subject: [PATCH 3/8] add GH action --- .github/workflows/test-templates.yml | 48 ++++++++++++++++++++++++++++ tests/package.json | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test-templates.yml diff --git a/.github/workflows/test-templates.yml b/.github/workflows/test-templates.yml new file mode 100644 index 0000000..66529ee --- /dev/null +++ b/.github/workflows/test-templates.yml @@ -0,0 +1,48 @@ +name: Template Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install dependencies (tests) + working-directory: tests + run: npm ci + + - name: Install dependencies (vite template) + working-directory: templates/vite + run: npm ci + + - name: Install dependencies (starter template) + working-directory: templates/starter + run: npm ci + + - name: Install Playwright browsers + working-directory: tests + run: npx playwright install --with-deps chromium + + - name: Run Playwright tests + working-directory: tests + run: npm run test:all + env: + CI: true + + - name: Upload Playwright report + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: tests/playwright-report/ + retention-days: 30 diff --git a/tests/package.json b/tests/package.json index 450f9c9..767eb56 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,7 +1,7 @@ { "name": "powerappscodeapps-tests", "private": true, - "version": "0.0.0", + "version": "0.1.0", "scripts": { "test:vite": "playwright test --project=vite", "test:starter": "playwright test --project=starter", From 1b95e7192832a5af8d26fcfea622dc87be28f447 Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:14:29 -0800 Subject: [PATCH 4/8] restore package-lock in starter template --- templates/starter/package-lock.json | 83 +++++------------------------ 1 file changed, 12 insertions(+), 71 deletions(-) diff --git a/templates/starter/package-lock.json b/templates/starter/package-lock.json index dff4468..fed4149 100644 --- a/templates/starter/package-lock.json +++ b/templates/starter/package-lock.json @@ -86,6 +86,7 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -2911,6 +2912,7 @@ "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2921,6 +2923,7 @@ "integrity": "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2931,6 +2934,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2980,6 +2984,7 @@ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/types": "8.53.1", @@ -3231,6 +3236,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3348,6 +3354,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3798,6 +3805,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4874,6 +4882,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -4904,6 +4913,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -5292,48 +5302,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -5382,6 +5350,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5532,6 +5501,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -5601,35 +5571,6 @@ } } }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", From c2d58734ff5ff44987fc1c9c987b0f7d820f7dae Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:15:42 -0800 Subject: [PATCH 5/8] change npm ci to npm install for templates --- .github/workflows/test-templates.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-templates.yml b/.github/workflows/test-templates.yml index 66529ee..072a32b 100644 --- a/.github/workflows/test-templates.yml +++ b/.github/workflows/test-templates.yml @@ -23,11 +23,11 @@ jobs: - name: Install dependencies (vite template) working-directory: templates/vite - run: npm ci + run: npm install - name: Install dependencies (starter template) working-directory: templates/starter - run: npm ci + run: npm install - name: Install Playwright browsers working-directory: tests From cb752b0822a031d49a0936fde651c496c6e04b0a Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:25:22 -0800 Subject: [PATCH 6/8] seperate actions --- .github/workflows/test-starter-template.yml | 19 +++++++++++++++ .../{test-templates.yml => test-template.yml} | 24 +++++++++---------- .github/workflows/test-vite-template.yml | 19 +++++++++++++++ tests/playwright.config.ts | 2 +- 4 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/test-starter-template.yml rename .github/workflows/{test-templates.yml => test-template.yml} (65%) create mode 100644 .github/workflows/test-vite-template.yml diff --git a/.github/workflows/test-starter-template.yml b/.github/workflows/test-starter-template.yml new file mode 100644 index 0000000..ccef48a --- /dev/null +++ b/.github/workflows/test-starter-template.yml @@ -0,0 +1,19 @@ +name: Test Starter Template + +on: + push: + branches: [main] + paths: + - 'templates/starter/**' + - 'tests/**' + pull_request: + branches: [main] + paths: + - 'templates/starter/**' + - 'tests/**' + +jobs: + test: + uses: ./.github/workflows/test-template.yml + with: + template: starter diff --git a/.github/workflows/test-templates.yml b/.github/workflows/test-template.yml similarity index 65% rename from .github/workflows/test-templates.yml rename to .github/workflows/test-template.yml index 072a32b..002ff7f 100644 --- a/.github/workflows/test-templates.yml +++ b/.github/workflows/test-template.yml @@ -1,10 +1,12 @@ -name: Template Tests +name: Test Template on: - push: - branches: [main] - pull_request: - branches: [main] + workflow_call: + inputs: + template: + required: true + type: string + description: 'Template name (e.g., vite, starter)' jobs: test: @@ -21,12 +23,8 @@ jobs: working-directory: tests run: npm ci - - name: Install dependencies (vite template) - working-directory: templates/vite - run: npm install - - - name: Install dependencies (starter template) - working-directory: templates/starter + - name: Install dependencies (template) + working-directory: templates/${{ inputs.template }} run: npm install - name: Install Playwright browsers @@ -35,7 +33,7 @@ jobs: - name: Run Playwright tests working-directory: tests - run: npm run test:all + run: npm run test:${{ inputs.template }} env: CI: true @@ -43,6 +41,6 @@ jobs: uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} with: - name: playwright-report + name: playwright-report-${{ inputs.template }}-template path: tests/playwright-report/ retention-days: 30 diff --git a/.github/workflows/test-vite-template.yml b/.github/workflows/test-vite-template.yml new file mode 100644 index 0000000..f6aefa4 --- /dev/null +++ b/.github/workflows/test-vite-template.yml @@ -0,0 +1,19 @@ +name: Test Vite Template + +on: + push: + branches: [main] + paths: + - 'templates/vite/**' + - 'tests/**' + pull_request: + branches: [main] + paths: + - 'templates/vite/**' + - 'tests/**' + +jobs: + test: + uses: ./.github/workflows/test-template.yml + with: + template: vite diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index 89fc970..b0117df 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -9,7 +9,7 @@ export default defineConfig({ forbidOnly: isCI, retries: isCI ? 2 : 0, workers: isCI ? 1 : undefined, - reporter: isCI ? 'github' : 'html', + reporter: isCI ? [['github'], ['html', { open: 'never' }]] : 'html', use: { trace: 'on-first-retry', }, From 3be5b0658f68dbfbef6131f8423fdc75188274c3 Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:38:11 -0800 Subject: [PATCH 7/8] fix --- .github/workflows/test-template.yml | 18 ++++++++ tests/playwright.config.ts | 64 ++++++++++++++++------------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/.github/workflows/test-template.yml b/.github/workflows/test-template.yml index 002ff7f..71640dd 100644 --- a/.github/workflows/test-template.yml +++ b/.github/workflows/test-template.yml @@ -27,15 +27,33 @@ jobs: working-directory: templates/${{ inputs.template }} run: npm install + - name: Get Playwright version + id: playwright-version + working-directory: tests + run: echo "version=$(npm ls @playwright/test --json | jq -r '.dependencies["@playwright/test"].version')" >> $GITHUB_OUTPUT + + - name: Cache Playwright browsers + uses: actions/cache@v4 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: playwright-${{ steps.playwright-version.outputs.version }} + - name: Install Playwright browsers + if: steps.playwright-cache.outputs.cache-hit != 'true' working-directory: tests run: npx playwright install --with-deps chromium + - name: Install Playwright system dependencies + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: npx playwright install-deps chromium + - name: Run Playwright tests working-directory: tests run: npm run test:${{ inputs.template }} env: CI: true + TEMPLATE: ${{ inputs.template }} - name: Upload Playwright report uses: actions/upload-artifact@v4 diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index b0117df..713c94a 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -1,50 +1,56 @@ -import { defineConfig, devices } from '@playwright/test'; -import path from 'path'; +import { defineConfig, devices } from "@playwright/test"; +import path from "path"; const isCI = !!process.env.CI; +if (!process.env.TEMPLATE) { + throw new Error("TEMPLATE environment variable is not set to template."); +} +const template = process.env.TEMPLATE as "vite" | "starter"; // Set to 'vite' or 'starter' to run only one + +const webServers = { + vite: { + name: "vite-template", + command: "npm run build && npm run preview -- --port 4173", + cwd: path.resolve(__dirname, "../templates/vite"), + url: "http://localhost:4173", + reuseExistingServer: !isCI, + }, + starter: { + name: "starter-template", + command: "npm run build && npm run preview -- --port 4174", + cwd: path.resolve(__dirname, "../templates/starter"), + url: "http://localhost:4174", + reuseExistingServer: !isCI, + }, +}; export default defineConfig({ - testDir: './e2e', + testDir: "./e2e", fullyParallel: true, forbidOnly: isCI, retries: isCI ? 2 : 0, workers: isCI ? 1 : undefined, - reporter: isCI ? [['github'], ['html', { open: 'never' }]] : 'html', + reporter: isCI ? [["github"], ["html", { open: "never" }]] : "html", use: { - trace: 'on-first-retry', + trace: "on-first-retry", }, projects: [ { - name: 'vite', - testMatch: 'vite.spec.ts', + name: "vite", + testMatch: "vite.spec.ts", use: { - ...devices['Desktop Chrome'], - baseURL: 'http://localhost:4173', + ...devices["Desktop Chrome"], + baseURL: "http://localhost:4173", }, }, { - name: 'starter', - testMatch: 'starter.spec.ts', + name: "starter", + testMatch: "starter.spec.ts", use: { - ...devices['Desktop Chrome'], - baseURL: 'http://localhost:4174', + ...devices["Desktop Chrome"], + baseURL: "http://localhost:4174", }, }, ], - webServer: [ - { - name: 'vite-template', - command: 'npm run build && npm run preview -- --port 4173', - cwd: path.resolve(__dirname, '../templates/vite'), - url: 'http://localhost:4173', - reuseExistingServer: !isCI, - }, - { - name: 'starter-template', - command: 'npm run build && npm run preview -- --port 4174', - cwd: path.resolve(__dirname, '../templates/starter'), - url: 'http://localhost:4174', - reuseExistingServer: !isCI, - }, - ], + webServer: webServers[template], }); From 5f86cbd5efee3130fbd760a3fda5d89924fe1c69 Mon Sep 17 00:00:00 2001 From: Chamu-Rajasekera Date: Fri, 23 Jan 2026 02:53:01 -0800 Subject: [PATCH 8/8] tweaks --- .github/workflows/test-starter-template.yml | 2 +- .github/workflows/test-template.yml | 6 +-- .github/workflows/test-vite-template.yml | 2 +- tests/package.json | 4 +- tests/playwright.config.ts | 45 ++++++++++----------- 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test-starter-template.yml b/.github/workflows/test-starter-template.yml index ccef48a..963515c 100644 --- a/.github/workflows/test-starter-template.yml +++ b/.github/workflows/test-starter-template.yml @@ -13,7 +13,7 @@ on: - 'tests/**' jobs: - test: + test-starter-template: uses: ./.github/workflows/test-template.yml with: template: starter diff --git a/.github/workflows/test-template.yml b/.github/workflows/test-template.yml index 71640dd..bb2a21c 100644 --- a/.github/workflows/test-template.yml +++ b/.github/workflows/test-template.yml @@ -1,4 +1,4 @@ -name: Test Template +name: Test Template(s) on: workflow_call: @@ -50,7 +50,7 @@ jobs: - name: Run Playwright tests working-directory: tests - run: npm run test:${{ inputs.template }} + run: npm run test env: CI: true TEMPLATE: ${{ inputs.template }} @@ -60,5 +60,5 @@ jobs: if: ${{ !cancelled() }} with: name: playwright-report-${{ inputs.template }}-template - path: tests/playwright-report/ + path: tests/playwright-report/index.html retention-days: 30 diff --git a/.github/workflows/test-vite-template.yml b/.github/workflows/test-vite-template.yml index f6aefa4..b398eed 100644 --- a/.github/workflows/test-vite-template.yml +++ b/.github/workflows/test-vite-template.yml @@ -13,7 +13,7 @@ on: - 'tests/**' jobs: - test: + test-vite-template: uses: ./.github/workflows/test-template.yml with: template: vite diff --git a/tests/package.json b/tests/package.json index 767eb56..03add6a 100644 --- a/tests/package.json +++ b/tests/package.json @@ -3,9 +3,7 @@ "private": true, "version": "0.1.0", "scripts": { - "test:vite": "playwright test --project=vite", - "test:starter": "playwright test --project=starter", - "test:all": "playwright test" + "test": "playwright test" }, "devDependencies": { "@playwright/test": "^1.40.0", diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index 713c94a..995e02b 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -2,10 +2,7 @@ import { defineConfig, devices } from "@playwright/test"; import path from "path"; const isCI = !!process.env.CI; -if (!process.env.TEMPLATE) { - throw new Error("TEMPLATE environment variable is not set to template."); -} -const template = process.env.TEMPLATE as "vite" | "starter"; // Set to 'vite' or 'starter' to run only one +const template: "vite" | "starter" = process.env.TEMPLATE; // Set to 'vite' or 'starter' to run only one const webServers = { vite: { @@ -24,6 +21,25 @@ const webServers = { }, }; +const projects = { + vite: { + name: "vite", + testMatch: "vite.spec.ts", + use: { + ...devices["Desktop Chrome"], + baseURL: "http://localhost:4173", + }, + }, + starter: { + name: "starter", + testMatch: "starter.spec.ts", + use: { + ...devices["Desktop Chrome"], + baseURL: "http://localhost:4174", + }, + }, +}; + export default defineConfig({ testDir: "./e2e", fullyParallel: true, @@ -34,23 +50,6 @@ export default defineConfig({ use: { trace: "on-first-retry", }, - projects: [ - { - name: "vite", - testMatch: "vite.spec.ts", - use: { - ...devices["Desktop Chrome"], - baseURL: "http://localhost:4173", - }, - }, - { - name: "starter", - testMatch: "starter.spec.ts", - use: { - ...devices["Desktop Chrome"], - baseURL: "http://localhost:4174", - }, - }, - ], - webServer: webServers[template], + projects: projects[template] ? [projects[template]] : Object.values(projects), + webServer: webServers[template] ?? Object.values(webServers), });