allure-framework / allure-framework/allure3
allure watch: live update reloads the whole page, freezing the open test result on a stale attempt and losing scroll position
- Dominant language
- HTML
- Stars
- 401
- Forks
- 58
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 34
Description
## What happened?
`allure watch`'s live update does a full page reload on every change. `injectLiveReloadScript` (`packages/static-server/src/utils.ts`) injects a script that listens on `/__live_reload` (Server-Sent Events) and calls `window.location.reload()` on every message, unconditionally.
This has two consequences.
A test result page open during a run gets pinned to a stale attempt, with no way to reach the current one. The test result route is keyed by the result's own id (`md5(uuid)`, computed in `packages/core/src/store/convert.ts`), which identifies one specific attempt, not "the current attempt of this test." A full-page reload preserves the URL (and so the id in it), so re-opening the same page just re-renders the same, now-stale attempt. Worse, `RetrySubstore.retriesByTr` (`packages/core/src/store/retrySubstore.ts`) returns an empty list when called on a result that is itself a retry (`isRetry: true`), so the stale page's own "Retries" tab has nothing to point at the newer attempt either — there is no way to navigate forward from it.
Every live update also resets the page's scroll position, since the update is a full page navigation rather than a data refetch. The more frequently results arrive, the less usable an open page is while a run is in progress — reading through a long step tree gets interrupted on every update.
## How can we reproduce it?
The stale-attempt part is verifiable without a browser: generate a report from two result files that share a test case but have different `uuid`s (two distinct attempts of the same test), and inspect the older attempt's own generated JSON.
```bash
mkdir allure-retry-nav-repro && cd allure-retry-nav-repro
npm init -y
npm install allure
mkdir allure-results
```
`write-results.mjs` — two distinct attempts of the same test, an older failure and a newer pass:
```js
import { randomUUID } from "node:crypto";
import { writeFileSync } from "node:fs";
const now = Date.now();
const base = {
name: "a flaky-ish test",
fullName: "a flaky-ish test",
stage: "finished",
steps: [],
attachments: [],
parameters: [],
labels: [],
links: [],
};
const first = { ...base, uuid: randomUUID(), status: "failed", start: now, stop: now + 1 };
const second = { ...base, uuid: randomUUID(), status: "passed", start: now + 1000, stop: now + 1001 };
writeFileSync(`allure-results/${first.uuid}-result.json`, JSON.stringify(first, null, 2));
writeFileSync(`allure-results/${second.uuid}-result.json`, JSON.stringify(second, null, 2));
console.log("older attempt store id:", require("node:crypto").createHash("md5").update(first.uuid).digest("hex"));
```
```bash
node write-results.mjs
npx allure awesome --output .report allure-results
cat .report/data/test-results/.json
```
Actual output (trimmed to the relevant fields):
```json
{ "isRetry": true, "retries": [] }
```
The older attempt's own data has nothing pointing at the newer one. A page opened at this id — which is exactly what happens if it was the current attempt when the page was first loaded and a live update later reloads it — has no data-level way to reach the current attempt.
For the scroll-loss half: run `allure watch --port `, open a test with a long step tree, scroll down into it, then write a new result file into the watched directory. The page reloads and the scroll position resets to the top — this follows directly from `injectLiveReloadScript` calling `window.location.reload()` unconditionally (quoted above), independent of which page is open.
## What did you expect?
The older attempt's `retries` should list the newer one, so a page pinned to a stale attempt has something to navigate to. And live updates should not reset an open page's scroll position.
## Environment
- Allure 3 version: 3.16.0 (also the latest version on npm at the time of writing; confirmed with `npm view allure version`)
- Node.js version: v26.7.0
- Package manager and version: npm 11.x (bundled with the Node.js version above)
- OS: macOS, arm64
## Additional context
I searched for existing issues describing this and didn't find one that matches this mechanism. #38 ("Remove test result navigation for retries", closed via #50) sounds related by title, but that closed PR is from January 2025 and touches a component tree (`packages/web-awesome/src/components/app/TestResult/...`) that no longer exists in the current codebase — I don't think it reflects a still-current decision, but flagging it in case there's history I'm missing.
I have a fix that addresses both without changing the route model: `RetrySubstore.retriesByTr` returns sibling attempts symmetrically (so a retry-side result also gets a pointer to the canonical one), and `injectLiveReloadScript` calls an optional `window.__allureLiveReload` hook (falling back to the existing full reload) that `web-awesome` uses to refetch just the open test result in place instead of reloading the page. Happy to open a PR.
Contributor guide
Research direction
Start with injectLiveReloadScript in packages/static-server/src/utils.ts, then trace retry data through packages/core/src/store/retrySubstore.ts and result IDs in packages/core/src/store/convert.ts. Reproduce the two-attempt case and the scroll reset with allure watch. Done means stale attempts expose the newer retry and live updates refresh an open result without resetting its scroll position.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- full-stack
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100