Skip to content

Keep environment-agnostic global attachments and errors visible per environment (fixes #869) - #927

Open
d-braun wants to merge 3 commits into
allure-framework:mainfrom
d-braun:fix/869-global-attachments-per-environment
Open

d-braun wants to merge 3 commits into
allure-framework:mainfrom
d-braun:fix/869-global-attachments-per-environment

Conversation

@d-braun

@d-braun d-braun commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Context

Fixes #869.

Files declared via globalAttachments were only listed in the Global Attachments tab while the
environment picker was set to All. As soon as a single environment was selected, the tab showed
0 and rendered "No attachments information available" — even though such attachments aren't
environment-specific at all. In a multi-environment report that made them effectively unreachable,
because a single environment is exactly the view you work in while triaging one staging, language or
browser.

Cause

widgets/globals.json carries two views of the same data: the flat attachments list and the
per-environment attachmentsByEnv index. Global data which isn't bound to an environment is indexed
under the default environment by AllureStore (#indexGlobalAttachment / #indexGlobalError), so it
ends up in the default bucket. The frontend rendered only attachmentsByEnv[<selected env>] while
an environment was selected and therefore dropped the default bucket — the one bucket that applies
to every environment.

widgets/quality-gate.json has the same Record<envId, T[]> shape, results validated without an
environment go through the same store path, and ReportQualityGateResults had the same defect.

Solution

A shared selector, packages/web-awesome/src/utils/globals.ts, resolves the buckets to render:

  • no environment selected ("All") — every non-empty bucket, as before;
  • a single environment selected — the bucket of that environment plus the shared default
    bucket, because entries without an own environment are shared by all of them;
  • default selected — the shared bucket exactly once, no duplicates;
  • default declared as an environment in the report config — then the default bucket holds
    entries specific to that environment and nothing is shared. The environments widget can't tell
    that case apart on its own, because the default identity is always listed, so AllureStore now
    exposes configuredEnvironmentIds() and the awesome plugin marks declared identities in
    widgets/environments.json with configured: true. Reports without the flag behave as before.

Rendering: a lone default bucket in the All view renders as a plain list, everything else
renders as environment sections (the selected environment first, the shared one after it). While a
single environment is selected the section headers stay, they tell the shared bucket apart from the
entries of that environment.

Applied to:

  • ReportGlobalAttachments — the reported case;
  • ReportGlobalErrors — the same widget and the same defect, e.g. the stdout/stderr attachments
    and the "Test process has failed" error dispatched by allure run carry no environment and
    disappeared the same way;
  • ReportQualityGateResults — same defect, same widget shape. Side effect: with an environment
    selected the tab now renders section headers like the globals tabs do, instead of a bare list;
  • MainReport — the three tab counters count exactly what the tabs render.

The only change to the report data is the additive, optional configured flag on the identities in
widgets/environments.json; the AllureStore method is optional so third-party stores keep working.

Checklist

Unit tests cover the selector, both globals components, the quality gate component, the store
method, the generator and normalizeEnvironmentsWidget; e2e covers the shared quality gate bucket,
the header while an environment is selected and the declared-default case. Package suites of
web-awesome, core, core-api, web-commons, plugin-awesome and plugin-api pass;
yarn build, yarn lint and yarn format:check are clean.

@d-braun
d-braun force-pushed the fix/869-global-attachments-per-environment branch 4 times, most recently from 0873807 to 93b5b2e Compare September 8, 2026 10:08
@d-braun
d-braun force-pushed the fix/869-global-attachments-per-environment branch from c30386c to 48286eb Compare September 14, 2026 10:52
@todti

todti commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Nice diagnosis. I verified it against the store: #indexGlobalAttachment / #indexGlobalError (packages/core/src/store/store.ts:535-590) route globals without an environment through #resolveGlobalEnvironmentIdentity, which falls back to DEFAULT_ENVIRONMENT_IDENTITY, so the default bucket really is the shared one. The selector looks right, and the tab counters are safe: every global attachment is indexed into exactly one bucket, and generateGlobals filters the flat list and the index by the same written attachment set, so union(attachmentsByEnv) === attachments and the MainReport "All" counter is unchanged.

Three things I would like to see addressed.

1. The same defect is still live in the Quality Gate tab. See packages/web-awesome/src/components/ReportQualityGateResults/index.tsx:118-134.

qualityGateStore has the exact same Record<envId, T[]> shape, and a validation result dispatched without an environment goes through the same store path into the default bucket. So with environments: { "env-a": …, "env-b": … } and a globally failing rule, selecting env-a hits results[currentEnvironment.value] ?? [] on line 119, renders "No quality gate results", and MainReport/index.tsx:194 shows 0. That is exactly the #869 symptom.

It also makes the PR description inaccurate: it says the new behaviour "mirrors how quality gate results behave: filterable per environment, but global when they carry no environment", but Quality Gate has the bug too. After this PR, Global Errors and Quality Gate sit next to each other in the same header and disagree about shared entries.

globalEntriesByEnv and flatGlobalEntriesByEnv drop into ReportQualityGateResults and MainReport/index.tsx:193-196 unchanged. Could you include that here, or open a follow up issue and reword the description?

2. default is a configurable environment id, not a reserved bucket. See packages/web-awesome/src/utils/globals.ts:33.

normalizeEnvironmentDescriptorMap (packages/core/src/utils/environment.ts:78-122) validates ids but does not reserve default, so environments: { default: { matcher }, prod: { matcher } } is accepted and seeded as a real identity. In that config the default bucket holds genuinely environment specific entries, and sharedEntries leaks them into every other environment view plus its tab counter.

Suggestion: treat the default bucket as shared only when default is not one of the report's configured environments. The environment list is already available via the env store.

3. The section header disappears when only the shared bucket is rendered. See ReportGlobalAttachments/index.tsx:79-82 and ReportGlobalErrors/index.tsx:72-75.

The entries.length === 1 && entries[0][0] === DEFAULT_ENVIRONMENT branch now also fires while an environment is selected. Two consequences:

  • picker set to default in a multi environment report: the old code went through renderAttachmentSections([[currentEnvironment.value, …]]) and rendered the collapsible environment: "default" (N) header, now it is a bare list;
  • the selected environment has no own entries (the case the new e2e test in packages/e2e/test/allure-awesome/features/globals.test.ts asserts): the shared entries render unlabeled, so there is no hint that they are shared rather than specific to the selected environment.

Gating that branch on !currentEnvironment.value keeps the single default bucket rendering for the "All" view and keeps the header everywhere else.

@d-braun
d-braun force-pushed the fix/869-global-attachments-per-environment branch from 48286eb to 3b38c21 Compare September 15, 2026 11:11
…t and ensure visibility of environment-specific data across components and tests
…efault environment

Addresses the review on allure-framework#927:

* Quality Gate results use the same selector as global attachments and
  errors, so results dispatched without an environment stay visible while
  a single environment is selected; the tab counter counts the same set.
* The `default` bucket is only treated as shared when `default` isn't one
  of the report's configured environments. The environments widget can't
  tell that on its own, because the default identity is always listed, so
  the store exposes `configuredEnvironmentIds()` and the awesome plugin
  marks declared identities with `configured: true`.
* Section headers stay while a single environment is selected, they tell
  the shared bucket apart from the entries of that environment.
@d-braun

d-braun commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks @todti — all three addressed.

1. Quality Gate. Fixed here. ReportQualityGateResults and the tab counter now use the same globalEntriesByEnv / flatGlobalEntriesByEnv selector, so results without an environment stay visible next to those of the selected one. Side effect: with an environment selected, Quality Gate now renders section headers instead of a bare list, for consistency with point 3 — the should allow to switch between environments… e2e expectations were updated. The PR description no longer claims the globals "mirror" Quality Gate; it lists Quality Gate as a fixed component instead.

2. default as a configured id. Good catch, but the env store can't answer it: #addEnvironments seeds DEFAULT_ENVIRONMENT_IDENTITY whenever the list is empty (store.ts:361), so environments: { foo, bar } already yields [default, foo, bar] in environments.json — a declared default is indistinguishable there. It's now carried explicitly: AllureStore.configuredEnvironmentIds() (optional, third-party stores keep working), generateEnvirontmentsList marks declared identities with configured: true, and sharedEnvironmentId becomes null when default is declared. Backwards compatible; reports without the flag behave as before. This makes the "no changes to the report data model" statement in the description untrue, so that part is rewritten as well.

3. Section header. The plain-list branch is gated on !currentEnvironment.value, the header stays everywhere else, as suggested. The e2e case you pointed at asserts the header now.

Unit tests added for the selector, both globals components, Quality Gate, the store method, the generator and normalizeEnvironmentsWidget; e2e covers the shared Quality Gate bucket and the declared-default case.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Global attachments disappear when a single environment is selected

2 participants