BlueSky & more on desktop lazurite.stormlightlabs.org/
tauri rust typescript bluesky appview atproto solid
2
fork

Configure Feed

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

at main 129 lines 4.6 kB view raw
1import { HashRouter, Route } from "@solidjs/router"; 2import { fireEvent, render, screen, waitFor } from "@solidjs/testing-library"; 3import { beforeEach, describe, expect, it, vi } from "vitest"; 4import { PostEngagementPanel } from "../PostEngagementPanel"; 5 6const getRecordBacklinksMock = vi.hoisted(() => vi.fn()); 7const moderateContentMock = vi.hoisted(() => vi.fn()); 8const postNavigationMock = vi.hoisted(() => ({ 9 backFromPost: vi.fn(), 10 buildPostHref: vi.fn(), 11 openPost: vi.fn(), 12 openPostEngagement: vi.fn(), 13 openPostScreen: vi.fn(), 14})); 15 16vi.mock("$/lib/api/diagnostics", () => ({ DiagnosticsController: { getRecordBacklinks: getRecordBacklinksMock } })); 17vi.mock("$/components/posts/hooks/usePostNavigation", () => ({ usePostNavigation: () => postNavigationMock })); 18vi.mock("$/lib/api/moderation", () => ({ ModerationController: { moderateContent: moderateContentMock } })); 19 20const POST_URI = "at://did:plc:alice/app.bsky.feed.post/123"; 21 22function renderPanel(hash = `#/post/${encodeURIComponent(POST_URI)}/engagement`) { 23 globalThis.location.hash = hash; 24 return render(() => ( 25 <HashRouter> 26 <Route path="/post/:encodedUri/engagement" component={() => <PostEngagementPanel uri={POST_URI} />} /> 27 </HashRouter> 28 )); 29} 30 31describe("PostEngagementPanel", () => { 32 beforeEach(() => { 33 vi.resetAllMocks(); 34 moderateContentMock.mockResolvedValue({ 35 alert: false, 36 blur: "none", 37 filter: false, 38 inform: false, 39 noOverride: false, 40 }); 41 getRecordBacklinksMock.mockResolvedValue({ 42 likes: { 43 cursor: null, 44 records: [{ 45 did: "did:plc:bob", 46 profile: { handle: "bob.test", displayName: "Bob" }, 47 uri: "at://did:plc:bob/app.bsky.feed.like/1", 48 }], 49 total: 1, 50 }, 51 quotes: { 52 cursor: null, 53 records: [{ 54 did: "did:plc:carol", 55 profile: { handle: "carol.test", displayName: "Carol" }, 56 uri: "at://did:plc:carol/app.bsky.feed.post/9", 57 value: { text: "This is a quoted post body." }, 58 }], 59 total: 1, 60 }, 61 replies: { cursor: null, records: [], total: 0 }, 62 reposts: { 63 cursor: null, 64 records: [{ 65 did: "did:plc:dana", 66 profile: { handle: "dana.test", displayName: "Dana" }, 67 uri: "at://did:plc:dana/app.bsky.feed.repost/3", 68 }], 69 total: 1, 70 }, 71 }); 72 }); 73 74 it("loads engagement and defaults to likes tab", async () => { 75 renderPanel(); 76 77 expect(await screen.findByText("Post Engagement")).toBeInTheDocument(); 78 expect(await screen.findByText("Bob")).toBeInTheDocument(); 79 expect(getRecordBacklinksMock).toHaveBeenCalledWith(POST_URI); 80 }); 81 82 it("opens quote posts from the quotes tab", async () => { 83 renderPanel(`#/post/${encodeURIComponent(POST_URI)}/engagement?tab=quotes`); 84 85 expect(await screen.findByText("This is a quoted post body.")).toBeInTheDocument(); 86 87 fireEvent.click(screen.getByRole("button", { name: /carol/i })); 88 89 expect(postNavigationMock.openPostScreen).toHaveBeenCalledWith("at://did:plc:carol/app.bsky.feed.post/9"); 90 }); 91 92 it("switches engagement tabs via query-state routing", async () => { 93 renderPanel(); 94 95 await screen.findByText("Bob"); 96 fireEvent.click(screen.getByRole("button", { name: /Reposts/i })); 97 98 await waitFor(() => expect(globalThis.location.hash).toContain("tab=reposts")); 99 expect(await screen.findByText("Dana")).toBeInTheDocument(); 100 }); 101 102 it("renders profile moderation badges for labeled engagement actors", async () => { 103 getRecordBacklinksMock.mockResolvedValueOnce({ 104 likes: { 105 cursor: null, 106 records: [{ 107 did: "did:plc:bob", 108 profile: { handle: "bob.test", displayName: "Bob", labels: [{ src: "did:plc:labeler", val: "sexual" }] }, 109 uri: "at://did:plc:bob/app.bsky.feed.like/1", 110 }], 111 total: 1, 112 }, 113 quotes: { cursor: null, records: [], total: 0 }, 114 replies: { cursor: null, records: [], total: 0 }, 115 reposts: { cursor: null, records: [], total: 0 }, 116 }); 117 moderateContentMock.mockImplementation(async (_labels, context: string) => { 118 if (context === "profileList") { 119 return { alert: true, blur: "none", filter: false, inform: false, noOverride: false }; 120 } 121 122 return { alert: false, blur: "none", filter: false, inform: false, noOverride: false }; 123 }); 124 125 renderPanel(); 126 expect(await screen.findByText("Bob")).toBeInTheDocument(); 127 expect(await screen.findByText("Alert")).toBeInTheDocument(); 128 }); 129});