Playwright start
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
---
|
||||
type: Task
|
||||
status: AI Gen TODO
|
||||
category: QA
|
||||
isAgentGenerated: "true"
|
||||
---
|
||||
|
||||
# Test: Blazor WASM Hydration Timing and State Reconciliation
|
||||
|
||||
## Description
|
||||
|
||||
Verify that the Blazor WASM client correctly reconciles state during hydration — the prerendered HTML should match the client-rendered output, and user interactions initiated **before** Blazor finishes loading should either be queued or gracefully ignored, not cause a crash or a stale render.
|
||||
|
||||
## Rationale
|
||||
|
||||
The app uses Blazor WASM with server-side prerendering. During the hydration gap (between `window.onload` and Blazor attaching its event handlers), the page shows static prerendered HTML. If a user (or test) interacts with a `<select>` or button during this gap, Blazor may:
|
||||
|
||||
- Lose the native-DOM change on re-render (the select value reverts).
|
||||
- Miss the event entirely (no handler is connected yet).
|
||||
- Throw a JS interop exception after hydration completes.
|
||||
|
||||
Our existing tests all navigate with `waitUntil: 'load'` and immediately start clicking. The `debug_initial_state.js` script revealed that Blazor components re-render asynchronously after load, destroying and recreating the DOM elements. This gap is a real source of flakiness.
|
||||
|
||||
## Playwright Feature
|
||||
|
||||
This test uses **`page.waitForResponse()`** to wait for a specific WASM resource (`dotnet.js` or `dotnet.wasm`) to confirm the .NET runtime has loaded, plus **`page.evaluate()` with polling** to detect when Blazor's component tree is fully hydrated.
|
||||
|
||||
### Approach
|
||||
|
||||
```js
|
||||
// Wait until the Blazor runtime signals it's ready
|
||||
await page.waitForResponse(response =>
|
||||
response.url().includes('dotnet.wasm') && response.status() === 200
|
||||
);
|
||||
|
||||
// OR poll for a Blazor-specific DOM signal
|
||||
await page.waitForFunction(() => {
|
||||
// Blazor sets the `_blazorCircuitId` or similar on the root element
|
||||
// Note: adjust the selector to match the app's actual signal
|
||||
return document.querySelector('select')?.classList.contains('blazor-hydrated')
|
||||
|| document.querySelector('.keyContainer > div') !== null;
|
||||
});
|
||||
```
|
||||
|
||||
### Test Cases
|
||||
|
||||
| Scenario | Interaction Timing | Expected Behavior |
|
||||
|---|---|---|
|
||||
| **Early select** | Select faction BEFORE dotnet.wasm loads | Select reverts on hydration, but WASM should apply the correct default filter |
|
||||
| **Early click** | Click "Clear Build Order" before Blazor ready | Click is ignored or queued; no crash |
|
||||
| **Early keyboard** | Press Q/W/E before key handler attached | Keys are ignored; no crash; no entity added |
|
||||
| **Mid-hydration** | Interact during component re-render (DOM destruction phase) | Interaction should be lost but never crash |
|
||||
| **Late interaction** | Wait for `dotnet.wasm` response, THEN interact | Should work correctly (this is the happy path that already passes) |
|
||||
|
||||
### Detecting Hydration Completion
|
||||
|
||||
Since Blazor WASM with prerendering doesn't emit a built-in "I'm done" event, the most reliable signal is:
|
||||
|
||||
```js
|
||||
await page.waitForFunction(() => {
|
||||
// Wait for at least one Blazor-triggered re-render by checking
|
||||
// the keyContainer has child divs with keyboard buttons
|
||||
const container = document.querySelector('.keyContainer');
|
||||
if (!container) return false;
|
||||
const buttons = container.querySelectorAll(':scope > div');
|
||||
return buttons.length === 19 || buttons.length > 10;
|
||||
});
|
||||
```
|
||||
|
||||
### What This Test Catches
|
||||
|
||||
- Race conditions between `page.goto('waitUntil: load')` and Blazor hydration.
|
||||
- DOM elements that are destroyed and re-created during hydration (stale locator references).
|
||||
- Test flakiness caused by Blazor's async initialization.
|
||||
- Missing error boundaries when JS interop calls fail during hydration.
|
||||
Reference in New Issue
Block a user