Skip to content

Commit 592db81

Browse files
tkirda-bisonclaude
andcommitted
refactor(test): drive preventBadQueries spec off onSearchComplete
The previous version scheduled three actions via wall-clock setTimeout (10/20/30 ms) and waited for `ajaxCount === 2` to resolve a Promise seeded inside `beforeEach`. Under load — particularly the fork-pool cold-start path on Windows — the timeouts bunched up or the resolver never fired, hitting the 10-second hook timeout. We saw the flake three times in one session. Rewrite the test to drive off the plugin's own `onSearchComplete` callback, which fires for every query attempt (ajax success, ajax failure, and bad-query short-circuit alike). Each action awaits the next `onSearchComplete` directly — no wall clock, no nested setTimeout chain, no race window. 5/5 consecutive local runs pass in ~50ms (was ~11s when passing, 10000+ ms when flaking). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ce18d0d commit 592db81

1 file changed

Lines changed: 44 additions & 37 deletions

File tree

test/autocomplete.test.js

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -314,50 +314,57 @@ describe("Autocomplete Async — cache key", () => {
314314
});
315315

316316
describe("Autocomplete Async — preventBadQueries", () => {
317-
let ajaxCount = 0;
317+
it("blocks queries that share a no-results prefix, until the guard is disabled", async () => {
318+
const input = $("<input />");
319+
const serviceUrl = "/autocomplete/prevent/ajax";
320+
let ajaxCount = 0;
318321

319-
beforeEach(async () => {
320-
await new Promise((resolve) => {
321-
const input = $("<input />");
322-
let instance;
323-
const serviceUrl = "/autocomplete/prevent/ajax";
322+
// Drive the test off the plugin's own `onSearchComplete` callback
323+
// instead of wall-clock setTimeouts. onSearchComplete fires for every
324+
// query attempt — ajax-succeeded, ajax-failed, AND bad-query-short-
325+
// circuit — so it's a single deterministic synchronisation point.
326+
const searchResolvers = [];
327+
const nextSearchComplete = () =>
328+
new Promise((resolve) => searchResolvers.push(resolve));
324329

325-
input.autocomplete({ serviceUrl });
330+
$.mockjax({
331+
url: serviceUrl,
332+
responseTime: 1,
333+
response: function () {
334+
ajaxCount += 1;
335+
this.responseText = JSON.stringify({ suggestions: [] });
336+
},
337+
});
326338

327-
$.mockjax({
328-
url: serviceUrl,
329-
responseTime: 1,
330-
response: function () {
331-
ajaxCount += 1;
332-
this.responseText = JSON.stringify({ suggestions: [] });
333-
if (ajaxCount === 2) {
334-
resolve();
335-
}
336-
},
337-
});
339+
input.autocomplete({
340+
serviceUrl,
341+
onSearchComplete: () => {
342+
const resolve = searchResolvers.shift();
343+
if (resolve) resolve();
344+
},
345+
});
346+
const instance = input.autocomplete();
338347

339-
setTimeout(() => {
340-
input.val("Jam");
341-
instance = input.autocomplete();
342-
instance.onValueChange();
343-
}, 10);
348+
// 1. "Jam" → ajax fires, empty response → "Jam" added to badQueries.
349+
const ack1 = nextSearchComplete();
350+
input.val("Jam");
351+
instance.onValueChange();
352+
await ack1;
344353

345-
setTimeout(() => {
346-
input.val("Jama");
347-
instance.onValueChange();
348-
}, 20);
354+
// 2. "Jama" starts with "Jam" → blocked by isBadQuery, no ajax;
355+
// onSearchComplete still fires synchronously with `[]`.
356+
const ack2 = nextSearchComplete();
357+
input.val("Jama");
358+
instance.onValueChange();
359+
await ack2;
349360

350-
setTimeout(() => {
351-
instance.setOptions({ preventBadQueries: false });
352-
input.val("Jamai");
353-
instance.onValueChange();
354-
}, 30);
355-
});
356-
});
361+
// 3. Disable the guard, type a fresh query → ajax fires again.
362+
const ack3 = nextSearchComplete();
363+
instance.setOptions({ preventBadQueries: false });
364+
input.val("Jamai");
365+
instance.onValueChange();
366+
await ack3;
357367

358-
it("Should prevent Ajax requests if previous query with matching root failed.", () => {
359-
// Ajax call should have been made twice (then short-circuited by the
360-
// bad-query guard until preventBadQueries was disabled).
361368
expect(ajaxCount).toBe(2);
362369
});
363370
});

0 commit comments

Comments
 (0)