Skip to content

fix(wizards): stop wizard error notices from flickering (NPPM-2733)#513

Merged
wil-gerken merged 7 commits into
releasefrom
hotfix/nppm-2733-wizard-error-flicker
Jul 9, 2026
Merged

fix(wizards): stop wizard error notices from flickering (NPPM-2733)#513
wil-gerken merged 7 commits into
releasefrom
hotfix/nppm-2733-wizard-error-flicker

Conversation

@wil-gerken

@wil-gerken wil-gerken commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

All Submissions:

Changes proposed in this Pull Request:

Wizard screens such as Connections and Advanced Settings could show an error notice that flickered rapidly on and off whenever one of the screen's API requests failed (a disconnected service, a 5xx, a timeout, or a 429). The flicker was a self-reinforcing render loop, not a real repeated error. This keeps a failed request visible as one steady error notice.

  • use-wizard-api-fetch.ts: keep fetch errors in local component state and stop syncing them through the shared wizard store. Also drops the store-error reads that this leaves dead, plus the now-unused useEffect import.
  • use-wizard-api-fetch.test.js: regression tests confirming a failed fetch surfaces locally and is never written into the shared store.

Reference: NPPM-2733

How to test the changes in this Pull Request:

Reproduce the problem (before this PR):

  1. Open Newspack → Settings → Connections.
  2. Make one card's API call fail. For example, use a service that is not connected so its status check errors, or block the request in DevTools.
  3. Hard-reload the page several times (Cmd/Ctrl + Shift + R). The loop is a race, so it does not trigger on every load. Within a few reloads, the error notice flickers rapidly on and off and the page's CPU usage spikes. One failed request drives thousands of re-renders.

Verify the fix:

  1. Repeat the same steps, hard-reloading several times.
  2. The error notice appears once and stays visible on every load, with no flicker and no CPU spike.

Verified on an isolated environment: before the fix, roughly 1,800 DOM mutations and 420 notice toggles per load; after the fix, 0 repeated DOM mutations and 0 notice toggles across repeated reloads, with the error still displaying correctly.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully run tests with your changes locally?

The JS unit tests run in CI. Local jest is currently blocked by a pnpm babel-jest resolution issue in the dev environment, so the tests were validated by inspection and left to CI rather than a local run. The fix itself was verified end-to-end in an isolated browser environment (the metrics under How to test).

Notes for reviewers. For this hook, request errors belong in local component state only; the shared @wordpress/data store holds cacheable, serializable response data. useWizardApiFetch kept the fetch error in both places and synced them with two effects; the store reducer deep-clones on every write, so useSelect re-renders each write and the two effects raced into a render loop (the flicker). It is a race, hence intermittent, which matches the sporadic Connections and Google-card reports (including that connecting Google made it go away). No other code reads the store's per-slug error, so removal is contained. One behavior note: two components on the same slug no longer share an error through the store (that sharing was the unreliable race being fixed).

Release risk: Low

Assessed via /release-risk.

Signal Score Evidence
Contract surface Low Internal frontend hook (src/wizards/hooks/); no cross-repo contract, no external consumers
Surface type Low Internal JS React hook; no public-method / REST / hook-signature change
Publisher exposure Low Admin wizard screens only (never the public frontend); behavior change only on a wizard fetch failure
Change shape Low +13/-16 in one production file; two regression tests added (~2.7x test:prod)

Tier: Low — no contract crossing, admin-only surface, tiny self-contained diff with added tests.

Key risk to guard: that errors still surface in the wizards (the fix must not silently swallow them). Verified before/after on an isolated environment (~1,800 DOM mutations and 420 notice-toggles per load → 0/0, error still displaying), plus the two regression tests pass locally and in CI. No feature flag; rollback is a revert of the single commit.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 2, 2026 21:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an intermittent render-loop in Newspack wizard screens (e.g., Connections / Advanced Settings) where a single failed request could cause the error notice to rapidly flicker and spike CPU usage. It does so by keeping request errors in local hook state rather than syncing them into the shared @wordpress/data wizard store, and adds a regression test to ensure errors are not written back into the store.

Changes:

  • Stop syncing fetch errors between useWizardApiFetch local state and the shared wizard store to avoid clone-on-write feedback loops.
  • Remove now-dead reads of cached/store error state when returning cached responses.
  • Add Jest coverage to ensure failed requests surface locally and do not write to the store’s error path.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.ts Removes store↔local error syncing to prevent flickering render loops; simplifies cached response handling.
plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.test.js Adds regression tests asserting errors remain local and are never synced into the shared store.

Comment thread plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.ts
Comment thread plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.ts
Comment thread plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.ts Outdated
@wil-gerken
wil-gerken force-pushed the hotfix/nppm-2733-wizard-error-flicker branch 2 times, most recently from 89699b6 to c81ee18 Compare July 2, 2026 22:37
@wil-gerken
wil-gerken requested a review from Copilot July 2, 2026 22:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.test.js Outdated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017LQQufEP5XCqi4susWmgnH
@wil-gerken
wil-gerken force-pushed the hotfix/nppm-2733-wizard-error-flicker branch from c81ee18 to f42351a Compare July 2, 2026 23:19
@wil-gerken
wil-gerken requested a review from Copilot July 2, 2026 23:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@wil-gerken
wil-gerken marked this pull request as ready for review July 3, 2026 04:42
@wil-gerken
wil-gerken requested a review from a team as a code owner July 3, 2026 04:42
@dkoo dkoo self-assigned this Jul 6, 2026

@dkoo dkoo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested manually and could no longer replicate the flickering (could easily replicate on main).

The core fix is correct and a clear net improvement — it removes a genuine self-reinforcing render loop (the dual local↔store error sync, where the store's deep-clone-on-write kept re-triggering useSelect) that spiked CPU on any failed wizard request. Keeping fetch errors in local component state rather than the serializable @wordpress/data store is the right architectural call, and it's well-contained: nothing reads getWizardData(slug).error, and the separate top-level state.error path is untouched.

One behavior change deserves an explicit decision before merge. Because errors are now local to each hook instance, a child modal that calls setError() and then closes itself (onFinally: closeModal) no longer surfaces its failure to the sibling list that renders the notice via errorMessage. Two concrete flows regress to no error feedback on a failed save:

  • Premium Newsletters → Advanced Settings: advanced-settings.tsx sets the error in onError and closes the modal in onFinally, while premium-newsletters-list.tsx renders the notice off its own errorMessage.
  • Audience → Content Gates → Gate priority: same shape (content-gates-priority.tsxcontent-gates.tsx).

Pre-PR these appeared (via the store bridge, albeit flickering); post-PR the parent's errorMessage never updates, so the notice never fires. That contradicts the PR's stated guarantee that errors must still surface. Simplest fix: have the modal onError handlers surface their own error directly (e.g. addNotice) instead of relying on the parent's errorMessage. If the team would rather ship the flicker fix now and follow up, that's reasonable too — just worth doing consciously.

Everything else is pre-existing hygiene (noted inline), not a regression from this change.

Notes on code outside this PR’s changed lines (can’t be posted inline, so collected here):

  • plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.test.jsNit: Coverage gap: no test exercises the new useEffect( () => setError( null ), [ slug ] ) slug-reset behavior (render with an error, re-render with a new slug, assert errorMessage clears). That effect was added specifically in response to prior review; a small test would lock it in. Optional for a hotfix.

Comment thread plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.ts
Comment thread plugins/newspack-plugin/src/wizards/hooks/use-wizard-api-fetch.ts Outdated

@dkoo dkoo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to update the review status, sorry!

@github-actions github-actions Bot added [Status] Needs Changes or Feedback Pull request needs changes or feedback and removed [Status] Needs Review labels Jul 7, 2026
wil-gerken and others added 3 commits July 7, 2026 13:30
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAPFBaB5WGKRDffLP9Cu2A
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAPFBaB5WGKRDffLP9Cu2A
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAPFBaB5WGKRDffLP9Cu2A

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAPFBaB5WGKRDffLP9Cu2A

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

@wil-gerken

Copy link
Copy Markdown
Contributor Author

Added a slug-reset test — it renders with an existing error, re-renders with a new slug, and asserts errorMessage clears. Fails before the fix, passes after.

@wil-gerken
wil-gerken requested a review from dkoo July 7, 2026 22:25
@wil-gerken wil-gerken added [Status] Needs Review and removed [Status] Needs Changes or Feedback Pull request needs changes or feedback labels Jul 7, 2026
@github-actions github-actions Bot added [Status] Approved Pull request has been approved and removed [Status] Needs Review labels Jul 9, 2026
@dkoo

dkoo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Thanks for addressing the feedback, @wil-gerken! This is good to go.

@wil-gerken
wil-gerken merged commit 3600da0 into release Jul 9, 2026
13 checks passed
@wil-gerken
wil-gerken deleted the hotfix/nppm-2733-wizard-error-flicker branch July 9, 2026 17:52
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Hey @wil-gerken, good job getting this PR merged! 🎉

Now, the needs-changelog label has been added to it.

Please check if this PR needs to be included in the "Upcoming Changes" and "Release Notes" doc. If it doesn't, simply remove the label.

If it does, please add an entry to our shared document, with screenshots and testing instructions if applicable, then remove the label.

Thank you! ❤️

matticbot pushed a commit that referenced this pull request Jul 9, 2026
## newspack [6.45.1](https://github.com/Automattic/newspack-workspace/compare/newspack@6.45.0...newspack@6.45.1) (2026-07-09)

### Bug Fixes

* **wizards:** stop wizard error notices from flickering (NPPM-2733) ([#513](#513)) ([3600da0](3600da0))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Status] Approved Pull request has been approved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants