Skip to content

E2E: "Remaining Amount" column header disappears after enabling "Effective Amount" (invoices list, Issue #1876 test) #1920

Description

@steilerDev

BUG: "Remaining Amount" column header disappears after enabling "Effective Amount" (Issue #1876 E2E test)

Severity: Minor
Component: Frontend UI — Invoices list DataTable column preferences (useColumnPreferences)
Found in: e2e/tests/invoices/invoices.spec.ts:841"Effective Amount" column (Issue #1876) › Toggling "Effective Amount" shows a deposit/refund-aware value distinct from "Remaining Amount" @responsive (desktop project)

Steps to Reproduce

  1. As an authenticated user, navigate to /invoices on desktop viewport (≥1024px).
  2. Reset the table.invoices.columns preference (DELETE /api/users/me/preferences/table.invoices.columns) so both "Remaining Amount" and "Effective Amount" start hidden (both are defaultVisible: false).
  3. Open the column settings gear and enable "Remaining Amount" (checkbox click, then close popover with Escape).
  4. Re-open the column settings gear and enable "Effective Amount" the same way.
  5. Assert both columnheader "Effective Amount" and "Remaining Amount" are visible — this assertion passes.
  6. Immediately read the "Remaining Amount" column's cell value for a known invoice row.

Expected Behavior

"Remaining Amount" stays visible and its cell value is readable after having just been confirmed visible in step 5.

Actual Behavior

The "Remaining Amount" header is no longer found among visible table headers a moment later — Error: Column "Remaining Amount" not found among visible table headers (thrown from a toPass({ timeout: 3_000 }) retry loop, so this isn't a one-frame race; the header stays gone for the full 3s window). This has reproduced deterministically on every single CI run since it was introduced — 9 consecutive beta-targeted PRs (#1880, #1883, #1885, #1887, #1894, #1902, #1903, #1909, #1916), always in E2E Tests (Shard 5/16), always the same test, same error, ~4 minute runtime, both the initial attempt and the automatic retry. The two PRs immediately prior (#1855, #1858) had this shard passing, so the regression window is exactly PR #1880 (feat/1876-deposit-refunds), which is also where this test and the "Effective Amount" column were introduced.

Because E2E Gates is non-blocking on beta (only required on main-targeted PRs), this has been silently merging red for weeks without being caught.

Environment

  • Browser: Chromium (desktop project, 1440px viewport per CI config)
  • Viewport: desktop
  • Docker: yes, CI-built image (testcontainers)

Evidence

CI log excerpt (PR #1916, run 30675997438, job 91303406982):

✘ 96 [desktop] › tests/invoices/invoices.spec.ts:841:3 › "Effective Amount" column (Issue #1876) › Toggling "Effective Amount" shows a deposit/refund-aware value distinct from "Remaining Amount" @responsive (5.9s)
✘ 101 [desktop] › ... (retry #1) (6.2s)
Error: Column "Remaining Amount" not found among visible table headers
- Timeout 3000ms exceeded while waiting on the predicate
> 398 |     }).toPass({ timeout: 3_000 });
1 failed

Same shard/test/error also present in runs for PRs #1880 (90597079671), #1883 (90646967242, note: PR #1883 additionally had 3 other unrelated shard failures that day — 11/16, 15/16, 6/16 — those look like independent flakes, not this issue), #1885 (90682391864), #1887 (90773257757), #1894 (90887939821), #1902 (91115031204), #1903 (91134593031), #1909 (91175477994).

Notes

Likely root cause area: client/src/hooks/useColumnPreferences.ts. The hook's own local toggleColumn/savePreferences functional-setState logic looks race-free for two back-to-back toggles in the same component instance (each savePreferences(updated, columnOrder) call captures the full accumulated visibleColumns set, and the shared debounce ref just re-schedules to the latest call). Test failure timing (assertion at "both headers visible" passes, then the very next statement — reading "Remaining Amount"'s cell — fails to even find the header) points instead at the debounced upsert() (fires 500ms after the last toggle) racing against the "load preferences on mount" useEffect ([preferences, preferenceKey] deps) — i.e. once the debounced save lands and the preferences array from usePreferences() is refetched/updated, that load effect re-runs and may re-hydrate visibleColumns from a preferences payload that doesn't yet (or no longer) reflects both toggles, dropping "Remaining Amount" back to hidden. Recommend the frontend/backend agents trace usePreferences()'s upsert/refetch sequencing and whether the server-persisted table.invoices.columns value actually contains both keys at the moment the effect re-fires. This is unrelated to the #1895/#1896/#1918 claim/deposit-scope work in the current branch — filed here per E2E process because it was discovered during prior-failure triage and has never been fixed since introduction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions