BlueSky & more on desktop
lazurite.stormlightlabs.org/
tauri
rust
typescript
bluesky
appview
atproto
solid
1import { createRoot } from "solid-js";
2import { beforeEach, describe, expect, it, vi } from "vitest";
3import { usePostNavigation } from "../hooks/usePostNavigation";
4
5const navigateMock = vi.hoisted(() => vi.fn());
6const threadOverlayMock = vi.hoisted(() => ({
7 buildThreadHref: vi.fn((uri: string | null) => (uri ? `/timeline?thread=${encodeURIComponent(uri)}` : "/timeline")),
8 closeThread: vi.fn(),
9 drawerEnabled: vi.fn(() => true),
10 openThread: vi.fn(),
11 threadUri: vi.fn(() => null),
12}));
13
14vi.mock("@solidjs/router", () => ({ useNavigate: () => navigateMock }));
15vi.mock("../hooks/useThreadOverlayNavigation", () => ({ useThreadOverlayNavigation: () => threadOverlayMock }));
16
17describe("usePostNavigation", () => {
18 beforeEach(() => {
19 navigateMock.mockReset();
20 threadOverlayMock.buildThreadHref.mockClear();
21 threadOverlayMock.openThread.mockClear();
22 });
23
24 it("opens posts with thread overlay context", () => {
25 createRoot((dispose) => {
26 const navigation = usePostNavigation();
27 void navigation.openPost("at://did:plc:alice/app.bsky.feed.post/1");
28 dispose();
29 });
30
31 expect(threadOverlayMock.openThread).toHaveBeenCalledWith("at://did:plc:alice/app.bsky.feed.post/1");
32 expect(navigateMock).not.toHaveBeenCalled();
33 });
34
35 it("opens full-screen post routes explicitly", () => {
36 createRoot((dispose) => {
37 const navigation = usePostNavigation();
38 void navigation.openPostScreen("at://did:plc:alice/app.bsky.feed.post/2");
39 dispose();
40 });
41
42 expect(navigateMock).toHaveBeenCalledWith("/post/at%3A%2F%2Fdid%3Aplc%3Aalice%2Fapp.bsky.feed.post%2F2");
43 });
44
45 it("builds and opens post engagement routes", () => {
46 createRoot((dispose) => {
47 const navigation = usePostNavigation();
48 void navigation.openPostEngagement("at://did:plc:alice/app.bsky.feed.post/3", "quotes");
49 dispose();
50 });
51
52 expect(navigateMock).toHaveBeenCalledWith(
53 "/post/at%3A%2F%2Fdid%3Aplc%3Aalice%2Fapp.bsky.feed.post%2F3/engagement?tab=quotes",
54 );
55 });
56
57 it("delegates href building to thread overlay routing", () => {
58 createRoot((dispose) => {
59 const navigation = usePostNavigation();
60 navigation.buildPostHref("at://did:plc:alice/app.bsky.feed.post/4");
61 dispose();
62 });
63
64 expect(threadOverlayMock.buildThreadHref).toHaveBeenCalledWith("at://did:plc:alice/app.bsky.feed.post/4");
65 });
66});