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 229 lines 8.7 kB view raw
1import { AppTestProviders } from "$/test/providers"; 2import { fireEvent, render, screen, waitFor } from "@solidjs/testing-library"; 3import { beforeEach, describe, expect, it, vi } from "vitest"; 4import { DiagnosticsPanel } from "../DiagnosticsPanel"; 5 6const getAccountListsMock = vi.hoisted(() => vi.fn()); 7const getAccountLabelsMock = vi.hoisted(() => vi.fn()); 8const getAccountBlockedByMock = vi.hoisted(() => vi.fn()); 9const getAccountBlockingMock = vi.hoisted(() => vi.fn()); 10const getAccountStarterPacksMock = vi.hoisted(() => vi.fn()); 11const getRecordBacklinksMock = vi.hoisted(() => vi.fn()); 12const moderateContentMock = vi.hoisted(() => vi.fn()); 13 14vi.mock( 15 "$/lib/api/diagnostics", 16 () => ({ 17 DiagnosticsController: { 18 getAccountBlockedBy: getAccountBlockedByMock, 19 getAccountBlocking: getAccountBlockingMock, 20 getAccountLabels: getAccountLabelsMock, 21 getAccountLists: getAccountListsMock, 22 getAccountStarterPacks: getAccountStarterPacksMock, 23 getRecordBacklinks: getRecordBacklinksMock, 24 }, 25 }), 26); 27vi.mock("$/lib/api/moderation", () => ({ ModerationController: { moderateContent: moderateContentMock } })); 28 29function renderPanel(recordUri?: string) { 30 render(() => ( 31 <AppTestProviders session={{ activeDid: "did:plc:test", activeHandle: "test.bsky.social" }}> 32 <DiagnosticsPanel did="did:plc:test" onClose={vi.fn()} recordUri={recordUri ?? null} /> 33 </AppTestProviders> 34 )); 35} 36 37describe("DiagnosticsPanel", () => { 38 beforeEach(() => { 39 getAccountListsMock.mockReset(); 40 getAccountLabelsMock.mockReset(); 41 getAccountBlockedByMock.mockReset(); 42 getAccountBlockingMock.mockReset(); 43 getAccountStarterPacksMock.mockReset(); 44 getRecordBacklinksMock.mockReset(); 45 moderateContentMock.mockReset(); 46 moderateContentMock.mockResolvedValue({ 47 alert: false, 48 blur: "none", 49 filter: false, 50 inform: false, 51 noOverride: false, 52 }); 53 54 getAccountListsMock.mockResolvedValue({ 55 lists: [{ 56 description: "Builders and product people.", 57 memberCount: 12, 58 purpose: "app.bsky.graph.defs#curatelist", 59 title: "Builders", 60 creator: { handle: "mira.test" }, 61 }, { 62 description: "Moderation boundary set.", 63 listItemCount: 5, 64 purpose: "app.bsky.graph.defs#modlist", 65 title: "Safety", 66 creator: { handle: "safety.test" }, 67 }], 68 total: 2, 69 truncated: false, 70 }); 71 getAccountLabelsMock.mockResolvedValue({ 72 labels: [{ src: "did:plc:labeler", val: "!hide" }], 73 sourceProfiles: { "did:plc:labeler": { displayName: "Safety Service", handle: "safety.service" } }, 74 cursor: null, 75 }); 76 getAccountBlockedByMock.mockResolvedValue({ 77 cursor: null, 78 items: [{ availability: "available", did: "did:plc:blocker", profile: { handle: "blocker.test" } }], 79 total: 1, 80 }); 81 getAccountBlockingMock.mockResolvedValue({ 82 cursor: null, 83 items: [{ availability: "available", subjectDid: "did:plc:boundary", profile: { handle: "boundary.test" } }], 84 }); 85 getAccountStarterPacksMock.mockResolvedValue({ 86 starterPacks: [{ 87 creator: { handle: "packer.test" }, 88 description: "Starter pack desc.", 89 listItemCount: 8, 90 title: "Newcomers", 91 }], 92 total: 1, 93 truncated: false, 94 }); 95 getRecordBacklinksMock.mockResolvedValue({ 96 likes: { cursor: null, records: [], total: 0 }, 97 quotes: { cursor: null, records: [], total: 0 }, 98 replies: { cursor: null, records: [], total: 0 }, 99 reposts: { cursor: null, records: [], total: 0 }, 100 }); 101 }); 102 103 it("renders the tab shell and switches tabs with keys", async () => { 104 renderPanel(); 105 106 expect(await screen.findByText("Social Diagnostics")).toBeInTheDocument(); 107 expect(screen.getByRole("button", { name: "Lists" })).toHaveAttribute("aria-pressed", "true"); 108 109 fireEvent.keyDown(document, { key: "2" }); 110 expect(screen.getByRole("button", { name: "Labels" })).toBeInTheDocument(); 111 fireEvent.keyDown(document, { key: "Escape" }); 112 }); 113 114 it("groups lists and shows neutral labels", async () => { 115 renderPanel(); 116 117 fireEvent.click(await screen.findByRole("button", { name: "Lists" })); 118 expect(screen.getAllByText("Curation").length).toBeGreaterThan(0); 119 expect(screen.getByText("Builders")).toBeInTheDocument(); 120 expect(screen.getAllByText("Moderation").length).toBeGreaterThan(0); 121 }); 122 123 it("shows blocks and starter packs with progressive disclosure", async () => { 124 renderPanel(); 125 126 fireEvent.click(await screen.findByRole("button", { name: "Blocks" })); 127 expect(await screen.findByText("Boundaries around you")).toBeInTheDocument(); 128 expect(screen.getByRole("button", { name: /show details/i })).toBeInTheDocument(); 129 130 fireEvent.click(screen.getByRole("button", { name: /show details/i })); 131 await waitFor(() => expect(screen.getAllByText("blocker.test").length).toBeGreaterThan(0)); 132 133 fireEvent.click(screen.getByRole("button", { name: "Starter Packs" })); 134 expect(await screen.findByText("Newcomers")).toBeInTheDocument(); 135 expect(screen.getByText("8 members")).toBeInTheDocument(); 136 }); 137 138 it("renders unavailable block rows without breaking the section", async () => { 139 getAccountBlockedByMock.mockResolvedValueOnce({ 140 cursor: null, 141 items: [{ 142 availability: "unavailable", 143 did: "did:plc:missing", 144 unavailableMessage: "This profile is unavailable right now.", 145 }], 146 total: 1, 147 }); 148 149 renderPanel(); 150 151 fireEvent.click(await screen.findByRole("button", { name: "Blocks" })); 152 fireEvent.click(screen.getByRole("button", { name: /show details/i })); 153 154 const missing = await screen.findAllByText("did:plc:missing"); 155 expect(missing.length).toBeGreaterThan(0); 156 expect(screen.getByText("This profile is unavailable right now.")).toBeInTheDocument(); 157 }); 158 159 it("renders moderation badges for labeled block-list profiles", async () => { 160 getAccountBlockedByMock.mockResolvedValueOnce({ 161 cursor: null, 162 items: [{ 163 availability: "available", 164 did: "did:plc:blocker", 165 profile: { handle: "blocker.test", labels: [{ src: "did:plc:labeler", val: "sexual" }] }, 166 }], 167 total: 1, 168 }); 169 moderateContentMock.mockImplementation(async (_labels, context: string) => { 170 if (context === "profileList") { 171 return { alert: true, blur: "none", filter: false, inform: false, noOverride: false }; 172 } 173 174 return { alert: false, blur: "none", filter: false, inform: false, noOverride: false }; 175 }); 176 177 renderPanel(); 178 179 fireEvent.click(await screen.findByRole("button", { name: "Blocks" })); 180 fireEvent.click(screen.getByRole("button", { name: /show details/i })); 181 182 expect(await screen.findByText("blocker.test")).toBeInTheDocument(); 183 expect(await screen.findByText("Alert")).toBeInTheDocument(); 184 }); 185 186 it("explains backlinks when no record URI is selected", async () => { 187 renderPanel(); 188 189 fireEvent.click(await screen.findByRole("button", { name: "Backlinks" })); 190 191 expect(await screen.findByText(/Backlinks are record-specific engagement context/i)).toBeInTheDocument(); 192 expect(screen.getByText(/Open a post or record to inspect the public references pointing at it/i)) 193 .toBeInTheDocument(); 194 }); 195 196 it("renders moderation badges for labeled backlink profiles", async () => { 197 getRecordBacklinksMock.mockResolvedValueOnce({ 198 likes: { 199 cursor: null, 200 records: [{ 201 collection: "app.bsky.feed.like", 202 did: "did:plc:fan", 203 profile: { handle: "fan.test", labels: [{ src: "did:plc:labeler", val: "sexual" }] }, 204 rkey: "1", 205 uri: "at://did:plc:fan/app.bsky.feed.like/1", 206 }], 207 total: 1, 208 }, 209 quotes: { cursor: null, records: [], total: 0 }, 210 replies: { cursor: null, records: [], total: 0 }, 211 reposts: { cursor: null, records: [], total: 0 }, 212 }); 213 moderateContentMock.mockImplementation(async (_labels, context: string) => { 214 if (context === "profileList") { 215 return { alert: true, blur: "none", filter: false, inform: false, noOverride: false }; 216 } 217 218 return { alert: false, blur: "none", filter: false, inform: false, noOverride: false }; 219 }); 220 221 renderPanel("at://did:plc:test/app.bsky.feed.post/123"); 222 223 fireEvent.click(await screen.findByRole("button", { name: "Backlinks" })); 224 fireEvent.click(await screen.findByRole("button", { name: /likes/i })); 225 226 expect(await screen.findByText("fan.test")).toBeInTheDocument(); 227 expect(await screen.findByText("Alert")).toBeInTheDocument(); 228 }); 229});