Skip to content

Commit 1f055e8

Browse files
authored
Merge pull request #2024 from microting/feature/playwright-tests
feat: add Playwright e2e tests
2 parents bbb74dd + 0c25603 commit 1f055e8

18 files changed

+2558
-2
lines changed

.github/workflows/dotnet-core-master.yml

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,119 @@ jobs:
173173
- name: Build
174174
run: dotnet build eFormAPI/Plugins/ItemsPlanning.Pn/ItemsPlanning.Pn.sln
175175
- name: Unit Tests
176-
run: dotnet test --no-restore -c Release -v n eFormAPI/Plugins/ItemsPlanning.Pn/ItemsPlanning.Pn.Test/ItemsPlanning.Pn.Test.csproj
176+
run: dotnet test --no-restore -c Release -v n eFormAPI/Plugins/ItemsPlanning.Pn/ItemsPlanning.Pn.Test/ItemsPlanning.Pn.Test.csproj
177+
items-planning-playwright-test:
178+
needs: build
179+
runs-on: ubuntu-22.04
180+
continue-on-error: ${{ matrix.test == 'a' }}
181+
strategy:
182+
fail-fast: false
183+
matrix:
184+
test: [a,b,c]
185+
steps:
186+
- uses: actions/checkout@v3
187+
with:
188+
path: main
189+
- uses: actions/download-artifact@v4
190+
with:
191+
name: items-planning-container
192+
- run: docker load -i items-planning-container.tar
193+
- name: Create docker network
194+
run: docker network create --driver bridge --attachable data
195+
- name: Start MariaDB
196+
run: |
197+
docker pull mariadb:10.8
198+
docker run --name mariadbtest --network data -e MYSQL_ROOT_PASSWORD=secretpassword -p 3306:3306 -d mariadb:10.8
199+
- name: Start rabbitmq
200+
run: |
201+
docker pull rabbitmq:latest
202+
docker run -d --hostname my-rabbit --name some-rabbit --network data -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=password rabbitmq:latest
203+
- name: Sleep 15
204+
run: sleep 15
205+
- name: Start the newly build Docker container
206+
id: docker-run
207+
run: docker run --name my-container -p 4200:5000 --network data microtingas/frontend-container:latest "/ConnectionString=host=mariadbtest;Database=420_Angular;user=root;password=secretpassword;port=3306;Convert Zero Datetime = true;SslMode=none;" > docker_run_log 2>&1 &
208+
- name: Use Node.ts
209+
uses: actions/setup-node@v3
210+
with:
211+
node-version: 22
212+
- name: Extract branch name
213+
id: extract_branch
214+
run: echo "BRANCH=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_OUTPUT
215+
- name: 'Preparing Frontend checkout'
216+
uses: actions/checkout@v3
217+
with:
218+
repository: microting/eform-angular-frontend
219+
ref: ${{ steps.extract_branch.outputs.BRANCH }}
220+
path: eform-angular-frontend
221+
- name: Copy dependencies
222+
run: |
223+
cp -av main/eform-client/src/app/plugins/modules/items-planning-pn eform-angular-frontend/eform-client/src/app/plugins/modules/items-planning-pn
224+
mkdir -p eform-angular-frontend/eform-client/playwright/e2e/plugins/
225+
cp -av main/eform-client/playwright/e2e/plugins/items-planning-pn eform-angular-frontend/eform-client/playwright/e2e/plugins/items-planning-pn
226+
cp -av main/eform-client/playwright.config.ts eform-angular-frontend/eform-client/playwright.config.ts
227+
mkdir -p eform-angular-frontend/eform-client/cypress/e2e/plugins/
228+
cp -av main/eform-client/cypress/e2e/plugins/items-planning-pn eform-angular-frontend/eform-client/cypress/e2e/plugins/items-planning-pn
229+
cp -av main/eform-client/e2e/Assets eform-angular-frontend/eform-client/e2e/
230+
cd eform-angular-frontend/eform-client && ../../main/testinginstallpn.sh
231+
- name: yarn install
232+
run: cd eform-angular-frontend/eform-client && yarn install
233+
- name: Install Playwright browsers
234+
run: cd eform-angular-frontend/eform-client && npx playwright install --with-deps chromium
235+
- name: Pretest changes to work with Docker container
236+
run: sed -i 's/localhost/mariadbtest/g' eform-angular-frontend/eform-client/e2e/Constants/DatabaseConfigurationConstants.ts
237+
- name: DB Configuration
238+
uses: cypress-io/github-action@v4
239+
with:
240+
start: echo 'hi'
241+
wait-on: "http://localhost:4200"
242+
wait-on-timeout: 120
243+
browser: chrome
244+
record: false
245+
spec: cypress/e2e/db/*
246+
config-file: cypress.config.ts
247+
working-directory: eform-angular-frontend/eform-client
248+
command-prefix: "--"
249+
- name: Load DB dump
250+
if: matrix.test == 'a'
251+
run: |
252+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'update 420_Angular.EformPlugins set Status = 1'
253+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'drop database `420_SDK`'
254+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'create database `420_SDK`'
255+
docker exec -i mariadbtest mysql -u root --password=secretpassword 420_SDK < eform-angular-frontend/eform-client/cypress/e2e/plugins/items-planning-pn/a/420_sdk.sql
256+
- name: Change rabbitmq hostname
257+
if: ${{ matrix.test != 'a' }}
258+
run: docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'update 420_SDK.Settings set Value = "my-rabbit" where Name = "rabbitMqHost"'
259+
- name: Enable plugins
260+
if: ${{ matrix.test != 'a' }}
261+
run: |
262+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'update 420_Angular.EformPlugins set Status = 2'
263+
docker restart my-container
264+
sleep 15
265+
- name: Get standard output
266+
run: |
267+
docker logs my-container
268+
docker ps -a
269+
- name: Wait for app
270+
run: npx wait-on http://localhost:4200 --timeout 120000
271+
- name: Run Playwright test
272+
run: |
273+
cd eform-angular-frontend/eform-client
274+
npx playwright test playwright/e2e/plugins/items-planning-pn/${{matrix.test}}/
275+
- name: Stop the newly build Docker container
276+
run: docker stop my-container
277+
- name: Get standard output
278+
run: |
279+
docker logs my-container
280+
docker ps -a
281+
- name: The job has failed
282+
if: ${{ failure() }}
283+
run: |
284+
cat docker_run_log
285+
- name: Archive Playwright report
286+
if: ${{ failure() }}
287+
uses: actions/upload-artifact@v4
288+
with:
289+
name: playwright-report-${{matrix.test}}
290+
path: eform-angular-frontend/eform-client/playwright-report/
291+
retention-days: 2

.github/workflows/dotnet-core-pr.yml

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,116 @@ jobs:
167167
- name: Build
168168
run: dotnet build eFormAPI/Plugins/ItemsPlanning.Pn/ItemsPlanning.Pn.sln
169169
- name: Unit Tests
170-
run: dotnet test --no-restore -c Release -v n eFormAPI/Plugins/ItemsPlanning.Pn/ItemsPlanning.Pn.Test/ItemsPlanning.Pn.Test.csproj
170+
run: dotnet test --no-restore -c Release -v n eFormAPI/Plugins/ItemsPlanning.Pn/ItemsPlanning.Pn.Test/ItemsPlanning.Pn.Test.csproj
171+
items-planning-playwright-test:
172+
needs: build
173+
runs-on: ubuntu-22.04
174+
continue-on-error: ${{ matrix.test == 'a' }}
175+
strategy:
176+
fail-fast: false
177+
matrix:
178+
test: [a,b,c]
179+
steps:
180+
- uses: actions/checkout@v3
181+
with:
182+
path: main
183+
- uses: actions/download-artifact@v4
184+
with:
185+
name: items-planning-container
186+
- run: docker load -i items-planning-container.tar
187+
- name: Create docker network
188+
run: docker network create --driver bridge --attachable data
189+
- name: Start MariaDB
190+
run: |
191+
docker pull mariadb:10.8
192+
docker run --name mariadbtest --network data -e MYSQL_ROOT_PASSWORD=secretpassword -p 3306:3306 -d mariadb:10.8
193+
- name: Start rabbitmq
194+
run: |
195+
docker pull rabbitmq:latest
196+
docker run -d --hostname my-rabbit --name some-rabbit --network data -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=password rabbitmq:latest
197+
- name: Sleep 15
198+
run: sleep 15
199+
- name: Start the newly build Docker container
200+
id: docker-run
201+
run: docker run --name my-container -p 4200:5000 --network data microtingas/frontend-container:latest "/ConnectionString=host=mariadbtest;Database=420_Angular;user=root;password=secretpassword;port=3306;Convert Zero Datetime = true;SslMode=none;" > docker_run_log 2>&1 &
202+
- name: Use Node.ts
203+
uses: actions/setup-node@v3
204+
with:
205+
node-version: 22
206+
- name: 'Preparing Frontend checkout'
207+
uses: actions/checkout@v3
208+
with:
209+
repository: microting/eform-angular-frontend
210+
ref: stable
211+
path: eform-angular-frontend
212+
- name: Copy dependencies
213+
run: |
214+
cp -av main/eform-client/src/app/plugins/modules/items-planning-pn eform-angular-frontend/eform-client/src/app/plugins/modules/items-planning-pn
215+
mkdir -p eform-angular-frontend/eform-client/playwright/e2e/plugins/
216+
cp -av main/eform-client/playwright/e2e/plugins/items-planning-pn eform-angular-frontend/eform-client/playwright/e2e/plugins/items-planning-pn
217+
cp -av main/eform-client/playwright.config.ts eform-angular-frontend/eform-client/playwright.config.ts
218+
mkdir -p eform-angular-frontend/eform-client/cypress/e2e/plugins/
219+
cp -av main/eform-client/cypress/e2e/plugins/items-planning-pn eform-angular-frontend/eform-client/cypress/e2e/plugins/items-planning-pn
220+
cp -av main/eform-client/e2e/Assets eform-angular-frontend/eform-client/e2e/
221+
cd eform-angular-frontend/eform-client && ../../main/testinginstallpn.sh
222+
- name: yarn install
223+
run: cd eform-angular-frontend/eform-client && yarn install
224+
- name: Install Playwright browsers
225+
run: cd eform-angular-frontend/eform-client && npx playwright install --with-deps chromium
226+
- name: Pretest changes to work with Docker container
227+
run: sed -i 's/localhost/mariadbtest/g' eform-angular-frontend/eform-client/e2e/Constants/DatabaseConfigurationConstants.ts
228+
- name: DB Configuration
229+
uses: cypress-io/github-action@v4
230+
with:
231+
start: echo 'hi'
232+
wait-on: "http://localhost:4200"
233+
wait-on-timeout: 120
234+
browser: chrome
235+
record: false
236+
spec: cypress/e2e/db/*
237+
config-file: cypress.config.ts
238+
working-directory: eform-angular-frontend/eform-client
239+
command-prefix: "--"
240+
- name: Load DB dump
241+
if: matrix.test == 'a'
242+
run: |
243+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'update 420_Angular.EformPlugins set Status = 1'
244+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'drop database `420_SDK`'
245+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'create database `420_SDK`'
246+
docker exec -i mariadbtest mysql -u root --password=secretpassword 420_SDK < eform-angular-frontend/eform-client/cypress/e2e/plugins/items-planning-pn/a/420_sdk.sql
247+
- name: Change rabbitmq hostname
248+
if: ${{ matrix.test != 'a' }}
249+
run: docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'update 420_SDK.Settings set Value = "my-rabbit" where Name = "rabbitMqHost"'
250+
- name: Enable plugins
251+
if: ${{ matrix.test != 'a' }}
252+
run: |
253+
docker exec -i mariadbtest mysql -u root --password=secretpassword -e 'update 420_Angular.EformPlugins set Status = 2'
254+
docker restart my-container
255+
sleep 15
256+
- name: Get standard output
257+
run: |
258+
docker logs my-container
259+
docker ps -a
260+
- name: Wait for app
261+
run: npx wait-on http://localhost:4200 --timeout 120000
262+
- name: Run Playwright test
263+
run: |
264+
cd eform-angular-frontend/eform-client
265+
npx playwright test playwright/e2e/plugins/items-planning-pn/${{matrix.test}}/
266+
- name: Stop the newly build Docker container
267+
run: docker stop my-container
268+
- name: Get standard output
269+
run: |
270+
docker logs my-container
271+
docker ps -a
272+
- name: The job has failed
273+
if: ${{ failure() }}
274+
run: |
275+
cat docker_run_log
276+
- name: Archive Playwright report
277+
if: ${{ failure() }}
278+
uses: actions/upload-artifact@v4
279+
with:
280+
name: playwright-report-${{matrix.test}}
281+
path: eform-angular-frontend/eform-client/playwright-report/
282+
retention-days: 2
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Items Planning Playwright Migration — Implementation Plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task.
4+
5+
**Goal:** Migrate items-planning WDIO e2e tests to Playwright with CI jobs.
6+
7+
**Architecture:** 3 page objects + 8 test files across folders a/b/c. Uses shared Playwright page objects from eform-angular-frontend.
8+
9+
**Tech Stack:** Playwright Test, TypeScript, GitHub Actions
10+
11+
---
12+
13+
See spec at `docs/superpowers/specs/2026-04-04-items-planning-playwright-migration-design.md` for detailed conversion patterns.
14+
15+
Tasks:
16+
1. Create `playwright.config.ts`
17+
2. Port `ItemsPlanningPlanningPage.ts` (main page + PlanningRowObject + PlanningCreateUpdate)
18+
3. Port `ItemsPlanningModal.page.ts` (create/edit/delete modals)
19+
4. Port `ItemsPlanningPairingPage.ts` (pairing grid)
20+
5. Copy `PlanningsTestImport.data.ts` (pure data, no WDIO deps)
21+
6. Port folder `a/` test (plugin activation)
22+
7. Port folder `b/` tests (add, edit, delete)
23+
8. Port folder `c/` tests (sorting, multiple-delete, tags, import, pairing)
24+
9. Update master workflow
25+
10. Update PR workflow
26+
11. Create PR
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Items Planning Plugin — Playwright Migration Design Spec
2+
3+
## Goal
4+
5+
Migrate WDIO e2e tests in `eform-angular-items-planning-plugin` to Playwright, following patterns from `eform-angular-workflow-plugin` PR #1346. WDIO tests remain in place.
6+
7+
## Current State
8+
9+
- **10 WDIO test files** (+ 1 placeholder `assert-true.spec.ts`)
10+
- **4 WDIO page objects** in `eform-client/e2e/Page objects/ItemsPlanning/`
11+
- **CI uses matrix [a,b,c]** mapping to `wdio-headless-plugin-step2{a,b,c}.conf.ts`
12+
- Config `a` runs only `assert-true.spec.ts` (placeholder), `b` same, `c` runs tags/import/pairing/plugins-page
13+
- No Playwright files exist
14+
15+
## Target State
16+
17+
### New Files
18+
19+
```
20+
eform-client/playwright.config.ts
21+
eform-client/playwright/e2e/plugins/items-planning-pn/
22+
├── ItemsPlanningPlanningPage.ts
23+
├── ItemsPlanningModal.page.ts
24+
├── ItemsPlanningPairingPage.ts
25+
├── PlanningsTestImport.data.ts
26+
├── a/
27+
│ └── items-planning-settings.spec.ts # plugin activation
28+
├── b/
29+
│ ├── items-planning.add.spec.ts
30+
│ ├── items-planning.edit.spec.ts
31+
│ └── items-planning.delete.spec.ts
32+
└── c/
33+
├── items-planning.sorting.spec.ts
34+
├── items-planning.multiple-delete.spec.ts
35+
├── items-planning.tags.spec.ts
36+
├── items-planning.import.spec.ts
37+
└── items-planning.pairing.spec.ts
38+
```
39+
40+
### Modified Files
41+
42+
| File | Change |
43+
|------|--------|
44+
| `.github/workflows/dotnet-core-master.yml` | Add `items-planning-playwright-test` job |
45+
| `.github/workflows/dotnet-core-pr.yml` | Add `items-planning-playwright-test` job |
46+
47+
## Excluded Tests
48+
49+
- `items-planning.settings.spec.ts` — references missing `ItemsPlanningSettings.page`, not run in CI
50+
- `assert-true.spec.ts` — placeholder canary
51+
52+
## WDIO → Playwright Conversion Patterns
53+
54+
| WDIO | Playwright |
55+
|------|-----------|
56+
| `$('#id')` | `this.page.locator('#id')` |
57+
| `$$('sel')` | `this.page.locator('sel')` |
58+
| `element.getText()` | `locator.textContent()` + `.trim()` |
59+
| `element.getValue()` | `locator.inputValue()` |
60+
| `element.setValue(v)` | `locator.fill(v)` |
61+
| `element.addValue(v)` | `locator.pressSequentially(v)` |
62+
| `element.getProperty('checked')` | `locator.isChecked()` |
63+
| `element.getAttribute('style')` | `locator.getAttribute('style')` |
64+
| `element.waitForDisplayed()` | `locator.waitFor({state:'visible'})` |
65+
| `element.waitForDisplayed({reverse:true})` | `locator.waitFor({state:'hidden'})` |
66+
| `element.waitForClickable()` | `locator.waitFor({state:'visible'})` (Playwright auto-waits on click) |
67+
| `element.isClickable()` | `await locator.isVisible()` |
68+
| `element.isExisting()` | `await locator.count() > 0` |
69+
| `browser.pause(n)` | `page.waitForTimeout(n)` |
70+
| `browser.keys(['Return'])` | `page.keyboard.press('Enter')` |
71+
| `browser.keys(['Escape'])` | `page.keyboard.press('Escape')` |
72+
| `browser.uploadFile(path)` | `locator.setInputFiles(path)` |
73+
| `export default new Class()` | `export class Class { constructor(page: Page) {} }` |
74+
| `selectValueInNgSelector(element, value)` | `selectValueInNgSelector(page, '#selector', value)` |
75+
| `selectDateOnDatePicker(y,m,d)` | `selectDateOnNewDatePicker(page, y, m, d)` |
76+
| `customDaLocale` date format `P` | `format(date, 'dd.MM.yyyy')` (equivalent output) |
77+
78+
## Shared Dependencies from eform-angular-frontend
79+
80+
Page objects (already Playwright-ready):
81+
- `LoginPage`, `MyEformsPage`, `PluginPage`, `FoldersPage`, `DeviceUsersPage`, `TagsModalPage`
82+
83+
Helper functions:
84+
- `generateRandmString`, `getRandomInt`, `selectValueInNgSelector`, `selectDateOnNewDatePicker`, `testSorting`
85+
86+
Import paths from `plugins/items-planning-pn/`:
87+
- Shared page objects: `../../Page objects/X.page`
88+
- Helper functions: `../../helper-functions`
89+
- From test files in `a/`, `b/`, `c/`: `../../../Page objects/X.page`, `../../../helper-functions`
90+
- Plugin page objects from same plugin dir: `../ItemsPlanningPlanningPage`
91+
92+
## CI Job Design
93+
94+
New `items-planning-playwright-test` job:
95+
- `needs: build`, matrix `[a,b,c]`
96+
- Copies plugin source + Playwright tests + config into frontend
97+
- For matrix `a`: no plugin enable (activation test), loads DB dump from cypress path
98+
- For matrix `b`,`c`: enables plugin in DB, restarts container
99+
- Runs `npx playwright test playwright/e2e/plugins/items-planning-pn/${{matrix.test}}/`
100+
- Uploads Playwright report artifact on failure
101+
102+
## Assets
103+
104+
The import test requires `e2e/Assets/Skabelon Døvmark NEW.xlsx`. This needs to be copied to the frontend in CI. The Playwright test uses `page.setInputFiles()` instead of WDIO's `browser.uploadFile()`.

eform-client/playwright.config.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
export default defineConfig({
4+
testDir: './playwright/e2e',
5+
fullyParallel: false,
6+
workers: 1,
7+
timeout: 120_000,
8+
reporter: [['html', { open: 'never' }]],
9+
use: {
10+
baseURL: 'http://localhost:4200',
11+
viewport: { width: 1920, height: 1080 },
12+
video: 'retain-on-failure',
13+
screenshot: 'only-on-failure',
14+
trace: 'retain-on-failure',
15+
},
16+
projects: [
17+
{
18+
name: 'chromium',
19+
use: { ...devices['Desktop Chrome'] },
20+
},
21+
],
22+
});

0 commit comments

Comments
 (0)