Mirror of https://github.com/improsocial/impro An extensible Bluesky client for web impro.social
5

Configure Feed

Select the types of activity you want to include in your feed.

Improve flaky unit tests

Grace Kind (Jul 16, 2026, 2:45 PM -0500) e51b090c 48429388

+14 -5
+4 -5
tests/unit/specs/components/post-composer.test.js
··· 1 1 import { describe, it, beforeEach, afterEach } from "node:test"; 2 2 import assert from "node:assert/strict"; 3 + import { waitFor } from "../../testHelpers.js"; 3 4 import "/js/components/post-composer.js"; 4 5 5 6 describe("post-composer", () => { ··· 548 549 connectElement(element); 549 550 const event = makePasteEvent([makeImageFile()]); 550 551 element.handlePaste(event); 551 - await new Promise((resolve) => setTimeout(resolve, 10)); 552 + await waitFor(() => element.state.$selectedImages.get().length === 1); 552 553 const selectedImages = element.state.$selectedImages.get(); 553 - assert.deepEqual(selectedImages.length, 1); 554 554 assert(selectedImages[0].dataUrl.startsWith("data:image/png")); 555 555 assert(event.defaultPrevented); 556 556 }); ··· 569 569 makeImageFile("c.png"), 570 570 ]); 571 571 element.handlePaste(event); 572 - await new Promise((resolve) => setTimeout(resolve, 10)); 573 - assert.deepEqual(element.state.$selectedImages.get().length, 4); 572 + await waitFor(() => element.state.$selectedImages.get().length === 4); 574 573 }); 575 574 576 575 it("does not add pasted images when a video is already selected", async () => { ··· 579 578 element.state.$selectedVideo.set({ file: {}, status: "done" }); 580 579 const event = makePasteEvent([makeImageFile()]); 581 580 element.handlePaste(event); 582 - await new Promise((resolve) => setTimeout(resolve, 10)); 581 + await new Promise((resolve) => setTimeout(resolve, 20)); 583 582 assert.deepEqual(element.state.$selectedImages.get().length, 0); 584 583 assert(event.defaultPrevented); 585 584 });
+10
tests/unit/testHelpers.js
··· 42 42 globalThis.window = originalWindow; 43 43 } 44 44 45 + export async function waitFor(predicate, { timeout = 2000 } = {}) { 46 + const deadline = Number(process.hrtime.bigint() / 1_000_000n) + timeout; 47 + while (!predicate()) { 48 + if (Number(process.hrtime.bigint() / 1_000_000n) > deadline) { 49 + throw new Error("waitFor timed out"); 50 + } 51 + await new Promise((resolve) => setTimeout(resolve, 5)); 52 + } 53 + } 54 + 45 55 // A callable fetch replacement. Assign to globalThis.fetch, register routes 46 56 // with __intercept(matcher, handler), and inspect captured requests on `calls`. 47 57 // Matchers are strings (matched by URL prefix) or regex (matched with .test).