Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-core-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
strategy:
fail-fast: false
matrix:
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,b1m,c1m,d1m,e1m,f1m]
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,b1m,c1m,d1m,e1m,f1m,h1m]
steps:
- uses: actions/checkout@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-core-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
strategy:
fail-fast: false
matrix:
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,b1m,c1m,d1m,e1m,f1m]
test: [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,b1m,c1m,d1m,e1m,f1m,h1m]
steps:
- uses: actions/checkout@v3
with:
Expand Down
2,778 changes: 2,778 additions & 0 deletions eform-client/playwright/e2e/plugins/time-planning-pn/h1m/420_SDK.sql

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { test, expect, Page } from '@playwright/test';
import { LoginPage } from '../../../Page objects/Login.page';

/**
* h1m variant of `h/dashboard-edit-a.spec.ts`: the paid-out-flex decimal
* round-trip suite, exercised under the `UseOneMinuteIntervals = true` code
* path. The shard's `post-migration.sql` flips the flag on every active
* assigned site, so the legacy in-spec setup from `h/` runs against the
* `minutesGap = 1` timepicker context.
*
* Why no shift-filling here (deviation from b1m / c1m / d1m / e1m):
*
* The legacy `h/` shard saves successfully WITHOUT filling any shift
* inputs — `#paidOutFlex` is a numeric field on the workday-entity
* dialog and the shift validators only fire when start/stop values are
* PRESENT (empty = no error, saveButton stays enabled). An earlier
* iteration of h1m tried to apply the multishift-shape pattern and
* timed out on `[data-testid="plannedStartOfShift3"]` because shifts
* 3-5 are gated behind `thirdShiftActive / fourthShiftActive /
* fifthShiftActive` per-site flags that the post-migration patch
* doesn't touch (only `UseOneMinuteIntervals` is flipped). The b1m
* spec activates those flags via a `#firstColumn3` settings-dialog
* dance — but h's flow goes through `#cell0_0` (a different dialog),
* so the b1m setup doesn't transplant cleanly. Rather than recreating
* the multi-shift activation dance for a spec that has nothing to do
* with shift inputs, h1m mirrors the legacy `h/` spec's empty-shift
* approach and gets its flag-on coverage incidentally (the flag is
* active on the assigned site for the whole session).
*
* Display assertion note: `#paidOutFlex` is a NUMERIC input — its
* `toHaveValue` assertions stay as `'1.2'`, `'0'` etc. (no `HH:mm:ss`
* formatting) since the field has nothing to do with time-of-day.
*
* Stateful test ordering: the legacy `h/` spec has the same cross-test
* dependency — test N reads back the value test N-1 saved. h1m preserves
* that order exactly. If a single test fails the chain breaks; that's
* intentional and matches `h/`.
*
* Defensive timing additions over the legacy `h/` spec — informed by the
* (reverted) g1m shard where the same `#workingHoursSite + 'ac ad'`
* filter pattern caused a "element detached from DOM" hang on the cell
* click. h1m waits for the spinner AND a 500ms settle after the site
* filter applies, then gates the dialog open on `#paidOutFlex` becoming
* visible. `#saveButton` is asserted `toBeEnabled` before the click —
* never `force: true`.
*/

async function waitForSpinner(page: Page) {
if (await page.locator('.overlay-spinner').count() > 0) {
await page.locator('.overlay-spinner').waitFor({ state: 'hidden', timeout: 30000 });
}
}

test.describe('Dashboard edit values (h1m, flag-on, paid-out-flex)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:4200');
await new LoginPage(page).login();
await page.locator('mat-nested-tree-node').filter({ hasText: 'Timeregistrering' }).click();

const indexUpdatePromise = page.waitForResponse(
r => r.url().includes('/api/time-planning-pn/plannings/index') && r.request().method() === 'POST'
);

await page.locator('mat-tree-node').filter({ hasText: 'Dashboard' }).click();
await indexUpdatePromise;
await waitForSpinner(page);

await page.locator('#workingHoursSite').click();
await page.locator('.ng-option').filter({ hasText: 'ac ad' }).click();
// Wait for site-filter re-index to finish before opening the cell — the
// legacy h spec races a 500ms timeout here, but the (reverted) g1m
// shard showed that the site-filter trigger detaches the cell row mid-
// click on flag-on. Wait for the spinner before reaching for #cell0_0.
await waitForSpinner(page);
await page.waitForTimeout(500);
Comment on lines +69 to +75

await page.locator('#cell0_0').click();
// Dialog open is async — gate on `#paidOutFlex` becoming visible.
await expect(page.locator('#paidOutFlex')).toBeVisible({ timeout: 10000 });
});

test('should set paid out flex value', async ({ page }) => {
await page.locator('#paidOutFlex').clear();
await page.locator('#paidOutFlex').fill('1.2');
});

test('should accepts decimal values with dot', async ({ page }) => {
await expect(page.locator('#paidOutFlex')).toHaveValue('1.2');
await page.locator('#paidOutFlex').clear();
await page.locator('#paidOutFlex').fill('1,2');
});

test('should accepts decimal values with comma', async ({ page }) => {
await expect(page.locator('#paidOutFlex')).toHaveValue('1.2');
await page.locator('#paidOutFlex').clear();
await page.locator('#paidOutFlex').fill('1,2');
});

test('should accepts whole numbers', async ({ page }) => {
Comment on lines +87 to +99
await expect(page.locator('#paidOutFlex')).toHaveValue('1.2');
await page.locator('#paidOutFlex').clear();
await page.locator('#paidOutFlex').fill('0');
});

test.afterEach(async ({ page }) => {
// Wait for saveButton to be enabled BEFORE clicking — never `force: true`.
await expect(page.locator('#saveButton')).toBeEnabled({ timeout: 10000 });
const savePromise = page.waitForResponse(
r => r.url().includes('/api/time-planning-pn/plannings/') && r.request().method() === 'PUT'
);
await page.locator('#saveButton').click();
await savePromise;
await page.waitForTimeout(1000);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- Post-migration patch for the f1m variant shard.
--
-- The base seed (`420_eform-angular-time-planning-plugin.sql`) is an old EF
-- baseline dump that pre-dates the `UseOneMinuteIntervals` column on
-- `AssignedSites`. The column is added at runtime by base-package migration
-- `20250226060341_Adding3MoreShifts` (executed by `Database.Migrate()` at
-- plugin startup) with default value 0.
--
-- This patch flips the flag on for every active assigned site so the f1m
-- shard exercises the flag-on rendering / form / picker code paths. The
Comment on lines +1 to +10
-- workflow runs this AFTER `Wait for app` (which gates on migrations being
-- complete) and BEFORE the matrix Playwright invocation.
UPDATE AssignedSites SET UseOneMinuteIntervals = 1 WHERE WorkflowState = 'created';
Loading