Skip to content

Commit 44d4d13

Browse files
authored
Merge pull request #1553 from microting/feat/use-one-minute-intervals-phase-5-pr7-h1m
Phase 5 PR 7: h1m playwright variant + restore q to master matrix
2 parents e7361ef + b22595c commit 44d4d13

6 files changed

Lines changed: 3426 additions & 2 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
strategy:
8989
fail-fast: false
9090
matrix:
91-
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,b1m,c1m,d1m,e1m,f1m]
91+
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,b1m,c1m,d1m,e1m,f1m,h1m]
9292
steps:
9393
- uses: actions/checkout@v3
9494
with:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ jobs:
8181
strategy:
8282
fail-fast: false
8383
matrix:
84-
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,b1m,c1m,d1m,e1m,f1m]
84+
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,b1m,c1m,d1m,e1m,f1m,h1m]
8585
steps:
8686
- uses: actions/checkout@v3
8787
with:

eform-client/playwright/e2e/plugins/time-planning-pn/h1m/420_SDK.sql

Lines changed: 2778 additions & 0 deletions
Large diffs are not rendered by default.

eform-client/playwright/e2e/plugins/time-planning-pn/h1m/420_eform-angular-time-planning-plugin.sql

Lines changed: 518 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { test, expect, Page } from '@playwright/test';
2+
import { LoginPage } from '../../../Page objects/Login.page';
3+
4+
/**
5+
* h1m variant of `h/dashboard-edit-a.spec.ts`: the paid-out-flex decimal
6+
* round-trip suite, exercised under the `UseOneMinuteIntervals = true` code
7+
* path. The shard's `post-migration.sql` flips the flag on every active
8+
* assigned site, so the legacy in-spec setup from `h/` runs against the
9+
* `minutesGap = 1` timepicker context.
10+
*
11+
* Why no shift-filling here (deviation from b1m / c1m / d1m / e1m):
12+
*
13+
* The legacy `h/` shard saves successfully WITHOUT filling any shift
14+
* inputs — `#paidOutFlex` is a numeric field on the workday-entity
15+
* dialog and the shift validators only fire when start/stop values are
16+
* PRESENT (empty = no error, saveButton stays enabled). An earlier
17+
* iteration of h1m tried to apply the multishift-shape pattern and
18+
* timed out on `[data-testid="plannedStartOfShift3"]` because shifts
19+
* 3-5 are gated behind `thirdShiftActive / fourthShiftActive /
20+
* fifthShiftActive` per-site flags that the post-migration patch
21+
* doesn't touch (only `UseOneMinuteIntervals` is flipped). The b1m
22+
* spec activates those flags via a `#firstColumn3` settings-dialog
23+
* dance — but h's flow goes through `#cell0_0` (a different dialog),
24+
* so the b1m setup doesn't transplant cleanly. Rather than recreating
25+
* the multi-shift activation dance for a spec that has nothing to do
26+
* with shift inputs, h1m mirrors the legacy `h/` spec's empty-shift
27+
* approach and gets its flag-on coverage incidentally (the flag is
28+
* active on the assigned site for the whole session).
29+
*
30+
* Display assertion note: `#paidOutFlex` is a NUMERIC input — its
31+
* `toHaveValue` assertions stay as `'1.2'`, `'0'` etc. (no `HH:mm:ss`
32+
* formatting) since the field has nothing to do with time-of-day.
33+
*
34+
* Stateful test ordering: the legacy `h/` spec has the same cross-test
35+
* dependency — test N reads back the value test N-1 saved. h1m preserves
36+
* that order exactly. If a single test fails the chain breaks; that's
37+
* intentional and matches `h/`.
38+
*
39+
* Defensive timing additions over the legacy `h/` spec — informed by the
40+
* (reverted) g1m shard where the same `#workingHoursSite + 'ac ad'`
41+
* filter pattern caused a "element detached from DOM" hang on the cell
42+
* click. h1m waits for the spinner AND a 500ms settle after the site
43+
* filter applies, then gates the dialog open on `#paidOutFlex` becoming
44+
* visible. `#saveButton` is asserted `toBeEnabled` before the click —
45+
* never `force: true`.
46+
*/
47+
48+
async function waitForSpinner(page: Page) {
49+
if (await page.locator('.overlay-spinner').count() > 0) {
50+
await page.locator('.overlay-spinner').waitFor({ state: 'hidden', timeout: 30000 });
51+
}
52+
}
53+
54+
test.describe('Dashboard edit values (h1m, flag-on, paid-out-flex)', () => {
55+
test.beforeEach(async ({ page }) => {
56+
await page.goto('http://localhost:4200');
57+
await new LoginPage(page).login();
58+
await page.locator('mat-nested-tree-node').filter({ hasText: 'Timeregistrering' }).click();
59+
60+
const indexUpdatePromise = page.waitForResponse(
61+
r => r.url().includes('/api/time-planning-pn/plannings/index') && r.request().method() === 'POST'
62+
);
63+
64+
await page.locator('mat-tree-node').filter({ hasText: 'Dashboard' }).click();
65+
await indexUpdatePromise;
66+
await waitForSpinner(page);
67+
68+
await page.locator('#workingHoursSite').click();
69+
await page.locator('.ng-option').filter({ hasText: 'ac ad' }).click();
70+
// Wait for site-filter re-index to finish before opening the cell — the
71+
// legacy h spec races a 500ms timeout here, but the (reverted) g1m
72+
// shard showed that the site-filter trigger detaches the cell row mid-
73+
// click on flag-on. Wait for the spinner before reaching for #cell0_0.
74+
await waitForSpinner(page);
75+
await page.waitForTimeout(500);
76+
77+
await page.locator('#cell0_0').click();
78+
// Dialog open is async — gate on `#paidOutFlex` becoming visible.
79+
await expect(page.locator('#paidOutFlex')).toBeVisible({ timeout: 10000 });
80+
});
81+
82+
test('should set paid out flex value', async ({ page }) => {
83+
await page.locator('#paidOutFlex').clear();
84+
await page.locator('#paidOutFlex').fill('1.2');
85+
});
86+
87+
test('should accepts decimal values with dot', async ({ page }) => {
88+
await expect(page.locator('#paidOutFlex')).toHaveValue('1.2');
89+
await page.locator('#paidOutFlex').clear();
90+
await page.locator('#paidOutFlex').fill('1,2');
91+
});
92+
93+
test('should accepts decimal values with comma', async ({ page }) => {
94+
await expect(page.locator('#paidOutFlex')).toHaveValue('1.2');
95+
await page.locator('#paidOutFlex').clear();
96+
await page.locator('#paidOutFlex').fill('1,2');
97+
});
98+
99+
test('should accepts whole numbers', async ({ page }) => {
100+
await expect(page.locator('#paidOutFlex')).toHaveValue('1.2');
101+
await page.locator('#paidOutFlex').clear();
102+
await page.locator('#paidOutFlex').fill('0');
103+
});
104+
105+
test.afterEach(async ({ page }) => {
106+
// Wait for saveButton to be enabled BEFORE clicking — never `force: true`.
107+
await expect(page.locator('#saveButton')).toBeEnabled({ timeout: 10000 });
108+
const savePromise = page.waitForResponse(
109+
r => r.url().includes('/api/time-planning-pn/plannings/') && r.request().method() === 'PUT'
110+
);
111+
await page.locator('#saveButton').click();
112+
await savePromise;
113+
await page.waitForTimeout(1000);
114+
});
115+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- Post-migration patch for the f1m variant shard.
2+
--
3+
-- The base seed (`420_eform-angular-time-planning-plugin.sql`) is an old EF
4+
-- baseline dump that pre-dates the `UseOneMinuteIntervals` column on
5+
-- `AssignedSites`. The column is added at runtime by base-package migration
6+
-- `20250226060341_Adding3MoreShifts` (executed by `Database.Migrate()` at
7+
-- plugin startup) with default value 0.
8+
--
9+
-- This patch flips the flag on for every active assigned site so the f1m
10+
-- shard exercises the flag-on rendering / form / picker code paths. The
11+
-- workflow runs this AFTER `Wait for app` (which gates on migrations being
12+
-- complete) and BEFORE the matrix Playwright invocation.
13+
UPDATE AssignedSites SET UseOneMinuteIntervals = 1 WHERE WorkflowState = 'created';

0 commit comments

Comments
 (0)