Skip to content

Commit 9a2c7b5

Browse files
committed
refactor(web): reuse archive controls for scope actions
2 parents 5d5fa41 + bc1b87f commit 9a2c7b5

3 files changed

Lines changed: 194 additions & 266 deletions

File tree

‎apps/web/src/components/settings/SettingsPanels.archive.browser.test.tsx‎

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { EnvironmentId, OrchestrationV2ArchivedShellSnapshot } from "@t3tools/contracts";
2+
import * as Cause from "effect/Cause";
23
import * as DateTime from "effect/DateTime";
34
import * as Schema from "effect/Schema";
45
import { AsyncResult } from "effect/reactivity";
@@ -107,9 +108,6 @@ const snapshot = Schema.decodeUnknownSync(OrchestrationV2ArchivedShellSnapshot)(
107108
itemCount: 0,
108109
visibleItemCount: 0,
109110
archivedAt: DateTime.makeUnsafe(now),
110-
settledOverride: null,
111-
settledAt: null,
112-
deletedAt: null,
113111
})),
114112
});
115113

@@ -242,3 +240,38 @@ it("releases the lock and reports a failed bulk action", async () => {
242240
await act(async () => openContextMenu());
243241
expect(state.unarchiveThread).toHaveBeenCalledOnce();
244242
});
243+
244+
it.each([
245+
["Unarchive Thread 1", "unarchiveThread"],
246+
["Delete Thread 1", "confirmAndDeleteThread"],
247+
] as const)("keeps %s locked independently and recovers after failure", async (label, method) => {
248+
const pending = deferred<ReturnType<typeof AsyncResult.failure>>();
249+
state[method].mockReturnValueOnce(pending.promise);
250+
const button = container.querySelector<HTMLButtonElement>(`button[aria-label="${label}"]`)!;
251+
252+
await act(async () => button.click());
253+
await act(async () => {
254+
button.click();
255+
button
256+
.closest('[data-slot="settings-row"]')!
257+
.dispatchEvent(new MouseEvent("contextmenu", { bubbles: true }));
258+
container
259+
.querySelector<HTMLButtonElement>('button[aria-label="Archived thread actions for Project"]')!
260+
.click();
261+
});
262+
expect(state[method]).toHaveBeenCalledOnce();
263+
expect(state.showContextMenu).not.toHaveBeenCalled();
264+
expect(document.querySelector('[role="menu"]')).toBeNull();
265+
266+
await act(async () => openContextMenu());
267+
expect(state.showContextMenu).toHaveBeenCalledOnce();
268+
const calls = state[method].mock.calls.length;
269+
await act(async () =>
270+
pending.resolve(AsyncResult.failure(Cause.fail(new Error("Disconnected")))),
271+
);
272+
expect(state.toast).toHaveBeenCalledWith(
273+
expect.objectContaining({ description: "Disconnected" }),
274+
);
275+
await act(async () => button.click());
276+
expect(state[method]).toHaveBeenCalledTimes(calls + 1);
277+
});

0 commit comments

Comments
 (0)