Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { render, screen } from "@testing-library/react";
import React from "react";

import { createSeizeHandlers } from "@/components/drops/view/part/dropPartMarkdown/handlers/seize";
import { parseSeizeDropLink } from "@/helpers/SeizeLinkParser";
import {
parseSeizeDropLink,
parseSeizeQuoteLink,
} from "@/helpers/SeizeLinkParser";

const mockDropItemChat = jest.fn(
({ href, dropId }: { href: string; dropId: string }) => (
Expand All @@ -13,6 +16,13 @@ const mockDropItemChat = jest.fn(
const mockRenderSeizeQuote = jest.fn(() => (
<div data-testid="seize-quote-content" />
));
const mockQuorumParticipationDropLinkPreview = jest.fn((props: any) => (
<div
data-testid="quorum-participation-preview"
data-drop-id={props.dropId}
data-serial-no={props.serialNo}
/>
));

jest.mock("@/helpers/SeizeLinkParser", () => ({
parseSeizeDropLink: jest.fn(),
Expand All @@ -26,20 +36,34 @@ jest.mock("@/components/waves/drops/DropItemChat", () => ({
default: (props: any) => mockDropItemChat(props),
}));

jest.mock(
"@/components/waves/quorum/QuorumParticipationDropLinkPreview",
() => ({
__esModule: true,
default: (props: any) => mockQuorumParticipationDropLinkPreview(props),
})
);

jest.mock("@/components/drops/view/part/dropPartMarkdown/renderers", () => ({
renderSeizeQuote: (...args: any[]) => mockRenderSeizeQuote(...args),
}));

const mockedParseSeizeDropLink = parseSeizeDropLink as jest.MockedFunction<
typeof parseSeizeDropLink
>;
const mockedParseSeizeQuoteLink = parseSeizeQuoteLink as jest.MockedFunction<
typeof parseSeizeQuoteLink
>;

const getDropHandler = (options?: {
const getHandlers = (options?: {
readonly onQuoteClick?: ((drop: any) => void) | undefined;
readonly currentDropId?: string | undefined;
readonly isMemesWaveById?:
| ((waveId: string | undefined | null) => boolean)
| undefined;
readonly isQuorumWaveById?:
| ((waveId: string | undefined | null) => boolean)
| undefined;
}) =>
createSeizeHandlers({
onQuoteClick: options?.onQuoteClick ?? jest.fn(),
Expand All @@ -49,11 +73,20 @@ const getDropHandler = (options?: {
embedDepth: 0,
maxEmbedDepth: 4,
isMemesWaveById: options?.isMemesWaveById,
})[3];
isQuorumWaveById: options?.isQuorumWaveById,
});

const getDropHandler = (options?: Parameters<typeof getHandlers>[0]) =>
getHandlers(options)[3]!;

const getQuoteHandler = (options?: Parameters<typeof getHandlers>[0]) =>
getHandlers(options)[0]!;

describe("createSeizeHandlers drop handler", () => {
beforeEach(() => {
jest.clearAllMocks();
mockedParseSeizeDropLink.mockReturnValue(null);
mockedParseSeizeQuoteLink.mockReturnValue(null);
});

it("keeps DropItemChat rendering for memes waves", () => {
Expand All @@ -77,6 +110,42 @@ describe("createSeizeHandlers drop handler", () => {
expect(mockRenderSeizeQuote).not.toHaveBeenCalled();
});

it("renders quorum participation preview for quorum drop links", () => {
const onQuoteClick = jest.fn();
mockedParseSeizeDropLink.mockReturnValue({
waveId: "quorum-wave-id",
dropId: "drop-1",
});
const handler = getDropHandler({
onQuoteClick,
isMemesWaveById: () => false,
isQuorumWaveById: (waveId) => waveId === "quorum-wave-id",
});

const href = "https://site.com/waves/quorum-wave-id?drop=drop-1";
const element = handler.render(href);
render(<>{element}</>);

expect(screen.getByTestId("quorum-participation-preview")).toHaveAttribute(
"data-drop-id",
"drop-1"
);
expect(mockQuorumParticipationDropLinkPreview).toHaveBeenCalledWith(
expect.objectContaining({
href,
waveId: "quorum-wave-id",
dropId: "drop-1",
onQuoteClick,
embedPath: [],
quotePath: [],
embedDepth: 1,
maxEmbedDepth: 4,
})
);
expect(mockRenderSeizeQuote).not.toHaveBeenCalled();
expect(mockDropItemChat).not.toHaveBeenCalled();
});

it("renders quote-style preview for non-memes waves", () => {
const onQuoteClick = jest.fn();
mockedParseSeizeDropLink.mockReturnValue({
Expand Down Expand Up @@ -143,4 +212,39 @@ describe("createSeizeHandlers drop handler", () => {
handler.render("https://site.com/waves/normal-wave-id?drop=drop-4")
).toThrow("Seize drop link matches current drop");
});

it("renders quorum participation preview for quorum serial links", () => {
const onQuoteClick = jest.fn();
mockedParseSeizeQuoteLink.mockReturnValue({
waveId: "quorum-wave-id",
serialNo: "7",
});
const handler = getQuoteHandler({
onQuoteClick,
isQuorumWaveById: (waveId) => waveId === "quorum-wave-id",
});

const href = "https://site.com/waves/quorum-wave-id?serialNo=7";
const element = handler.render(href);
render(<>{element}</>);

expect(screen.getByTestId("quorum-participation-preview")).toHaveAttribute(
"data-serial-no",
"7"
);
expect(mockQuorumParticipationDropLinkPreview).toHaveBeenCalledWith(
expect.objectContaining({
href,
waveId: "quorum-wave-id",
serialNo: "7",
onQuoteClick,
embedPath: [],
quotePath: ["quorum-wave-id:7"],
embedDepth: 1,
maxEmbedDepth: 4,
hideLink: true,
})
);
expect(mockRenderSeizeQuote).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import "@testing-library/jest-dom";
import { fireEvent, render } from "@testing-library/react";

const mockIsMemesWave = jest.fn();
const mockIsQuorumWave = jest.fn();

jest.mock("@/config/env", () => ({
publicEnv: {
BASE_ENDPOINT: "https://base",
},
}));
jest.mock("@/contexts/SeizeSettingsContext", () => ({
useSeizeSettings: () => ({ isMemesWave: mockIsMemesWave }),
useSeizeSettings: () => ({
isMemesWave: mockIsMemesWave,
isQuorumWave: mockIsQuorumWave,
}),
}));

const writeText = jest.fn().mockResolvedValue(undefined);
Expand All @@ -21,6 +25,7 @@ describe("WaveDropActionsCopyLink", () => {
beforeEach(() => {
jest.clearAllMocks();
mockIsMemesWave.mockReturnValue(false);
mockIsQuorumWave.mockReturnValue(false);
});

it("copies serial jump links for non-memes drops", () => {
Expand Down Expand Up @@ -49,6 +54,20 @@ describe("WaveDropActionsCopyLink", () => {
expect(writeText).toHaveBeenCalledWith("https://base/waves/w1?drop=d1");
});

it("copies canonical drop links for quorum participation drops", () => {
mockIsQuorumWave.mockReturnValue(true);

const drop: any = {
id: "d1",
wave: { id: "w1" },
serial_no: 5,
drop_type: ApiDropType.Participatory,
};
const { getByRole } = render(<WaveDropActionsCopyLink drop={drop} />);
fireEvent.click(getByRole("button"));
expect(writeText).toHaveBeenCalledWith("https://base/waves/w1?drop=d1");
});

it("disables button for temporary drop", () => {
const drop: any = { id: "temp-1", wave: { id: "w1" }, serial_no: 1 };
const { getByRole } = render(<WaveDropActionsCopyLink drop={drop} />);
Expand Down
44 changes: 43 additions & 1 deletion __tests__/components/waves/drops/WaveDropMobileMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

const mockIsMemesWave = jest.fn();
const mockIsQuorumWave = jest.fn();
const writeText = jest.fn().mockResolvedValue(undefined);
const addReactionMock = jest.fn((props: any) => (
<div
Expand All @@ -25,6 +26,9 @@ const mobileWrapperMock = jest.fn((props: any) =>
jest.mock("@/hooks/drops/useDropInteractionRules", () => ({
useDropInteractionRules: jest.fn(),
}));
jest.mock("@/hooks/drops/useCanShowDropCurationsAction", () => ({
useCanShowDropCurationsAction: jest.fn(() => false),
}));
jest.mock("@/components/waves/drops/WaveDropMobileMenuDelete", () => () => (
<div data-testid="delete" />
));
Expand Down Expand Up @@ -60,7 +64,10 @@ jest.mock(
);

jest.mock("@/contexts/SeizeSettingsContext", () => ({
useSeizeSettings: () => ({ isMemesWave: mockIsMemesWave }),
useSeizeSettings: () => ({
isMemesWave: mockIsMemesWave,
isQuorumWave: mockIsQuorumWave,
}),
}));
jest.mock("@/contexts/EmojiContext", () => ({
useEmoji: () => ({
Expand Down Expand Up @@ -90,6 +97,7 @@ beforeEach(() => {
addReactionMock.mockClear();
mobileWrapperMock.mockClear();
mockIsMemesWave.mockReturnValue(false);
mockIsQuorumWave.mockReturnValue(false);
mockedUseDropInteractionRules.mockReturnValue({
canShowVote: true,
canVote: true,
Expand Down Expand Up @@ -168,6 +176,40 @@ test("copies canonical drop links for memes submissions", async () => {
expect(writeText).toHaveBeenCalledWith("https://base/waves/w?drop=1");
});

test("copies canonical drop links for quorum participation drops", async () => {
mockIsQuorumWave.mockReturnValue(true);

const drop = {
id: "1",
serial_no: 1,
wave: { id: "w" },
drop_type: ApiDropType.Participatory,
author: { handle: "alice" },
} as any;
render(
<AuthContext.Provider
value={
{
connectedProfile: { handle: "alice" },
activeProfileProxy: null,
} as any
}
>
<WaveDropMobileMenu
drop={drop}
isOpen
showReplyAndQuote
longPressTriggered={false}
setOpen={jest.fn()}
onReply={jest.fn()}
onAddReaction={jest.fn()}
/>
</AuthContext.Provider>
);
await userEvent.click(screen.getByText("Copy link"));
expect(writeText).toHaveBeenCalledWith("https://base/waves/w?drop=1");
});

test("hides follow and clap when author and memes wave", () => {
mockIsMemesWave.mockReturnValue(true);

Expand Down
Loading
Loading