Fix flaky quick_action_suggestions frame-guard spec

What does this MR do and why?

Fixes a flaky frontend spec that broke master: spec/frontend/editor/quick_action_suggestions_spec.js"recordFrequentCommandUsage › guards against double increment in the same frame".

Root cause

The guard test set global.performance = { now: () => 100 } to make the frame-bucket dedup deterministic. That assignment is a silent no-op: in the jsdom test environment global === window, but performance is a getter-only accessor property (no setter), so assigning to it is ignored.

As a result, the production code (app/assets/javascripts/editor/quick_action_suggestions.js) kept reading the real, advancing window.performance.now(). The guard de-duplicates writes that land in the same Math.floor(now / 16) (~60fps) frame bucket. When two back-to-back calls happened to straddle a 16ms bucket boundary — which occurs intermittently under CI contention — the guard key differed between the two calls, dedup never fired, and saveStorageValue ran twice instead of once. Hence the intermittent Expected: 1 / Received: 2.

Fix

Spy on performance.now (jest.spyOn(performance, 'now').mockReturnValue(100)) instead of reassigning the getter-only property. This pins the bucket to a constant so the two calls can never straddle a boundary. This is a test-only change; production timing behavior is unchanged. The manual save/restore of originalPerformance is removed since jest.restoreAllMocks() handles the spy.

Steps to reproduce the failure (before this fix)

With the original (broken) mock left in place, force the real clock the production code reads to cross a 16ms bucket boundary between the two calls:

it('guards against double increment in the same frame', () => {
  // floor(100/16)=6, floor(117/16)=7 -> different frame buckets
  jest.spyOn(performance, 'now').mockReturnValueOnce(100).mockReturnValueOnce(117);
  recordFrequentCommandUsage('alpha');
  recordFrequentCommandUsage('alpha');
  expect(LocalStorage.saveStorageValue).toHaveBeenCalledTimes(1);
});

Running yarn jest spec/frontend/editor/quick_action_suggestions_spec.js then fails deterministically with the exact master-broken signature:

✕ guards against double increment in the same frame
  Expected number of calls: 1
  Received number of calls: 2

This proves (a) the original global.performance assignment does not prevent the double write, and (b) crossing a frame bucket boundary reliably produces two writes. With this MR's fix the bucket is constant, so the suite passes deterministically (verified locally over repeated runs).

References

How to set up and validate locally

yarn jest spec/frontend/editor/quick_action_suggestions_spec.js

All 5 tests pass.

Merge request reports

Loading