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
30 changes: 30 additions & 0 deletions __tests__/components/DropListItemContentMediaImage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@ describe("DropListItemContentMediaImage", () => {

expect(requestFullscreen).not.toHaveBeenCalled();
});

it("renders intrinsic-height images without the fill container height", () => {
const { container } = render(
<DropListItemContentMediaImage src="img" intrinsicHeight />
);

const wrapper = container.querySelector(".tw-relative.tw-flex");
const img = screen.getByAltText("Drop media");

expect(wrapper).toHaveClass("tw-w-full", "tw-min-h-40");
expect(wrapper).not.toHaveClass("tw-h-full");
expect(img).toHaveClass("tw-h-auto", "tw-w-full", "tw-max-h-64");
expect(img).not.toHaveAttribute("data-nimg", "fill");
});

it("retries intrinsic-height images instead of swapping to the same fallback source", () => {
jest.useFakeTimers();
const setTimeoutSpy = jest.spyOn(globalThis, "setTimeout");

render(
<DropListItemContentMediaImage src="img" intrinsicHeight maxRetries={1} />
);

fireEvent.error(screen.getByAltText("Drop media"));

expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 500);

setTimeoutSpy.mockRestore();
jest.useRealTimers();
});
});

describe("DropListItemContentMediaImage retry", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ describe("NotificationAllDrops", () => {
expect(screen.getByText("+2")).toBeInTheDocument();
});

it("renders posted text when all-drops notification has no vote", () => {
render(
<NotificationAllDrops
notification={baseNotification}
activeDrop={null}
onReply={jest.fn()}
onQuote={jest.fn()}
/>
);
expect(screen.getByText("posted")).toBeInTheDocument();
expect(screen.queryByText("reset rating to 0")).not.toBeInTheDocument();
});

it("uses router in reply and quote handlers", () => {
mockRouter.push.mockClear();
render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ jest.mock(
"@/components/drops/view/item/content/media/DropListItemContentMediaImage",
() => ({
__esModule: true,
default: (props: { src: string; loadStrategy: string }) => (
default: (props: {
src: string;
loadStrategy: string;
intrinsicHeight?: boolean;
}) => (
<div
data-testid="standard-image-media"
data-src={props.src}
data-load-strategy={props.loadStrategy}
data-intrinsic-height={String(props.intrinsicHeight)}
/>
),
})
Expand All @@ -27,5 +32,17 @@ describe("DropPartMarkdownImage", () => {
"data-load-strategy",
"eager"
);
expect(screen.getByTestId("standard-image-media")).toHaveAttribute(
"data-intrinsic-height",
"true"
);
});

it("does not reserve the old fixed image height", () => {
const { container } = render(<DropPartMarkdownImage src="/img.png" />);
const wrapper = container.firstElementChild;

expect(wrapper).toHaveClass("tw-relative", "tw-mt-2", "tw-w-full");
expect(wrapper).not.toHaveClass("tw-h-64");
});
});
132 changes: 88 additions & 44 deletions __tests__/components/rememes/RememeAddPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,24 @@ jest.mock("wagmi", () => ({
}));

// Mock components
jest.mock(
"@/components/rememes/RememeAddComponent",
() => (props: any) =>
(
<div data-testid="rememe-add-component">
<button
onClick={() =>
props.verifiedRememe(
{
valid: true,
contract: { address: "0xtest", contractDeployer: "0xdeployer" },
nfts: [{ tokenId: "1", name: "Test NFT" }],
},
[1, 2]
)
}>
Verify Rememe
</button>
</div>
)
);
jest.mock("@/components/rememes/RememeAddComponent", () => (props: any) => (
<div data-testid="rememe-add-component">
<button
onClick={() =>
props.verifiedRememe(
{
valid: true,
contract: { address: "0xtest", contractDeployer: "0xdeployer" },
nfts: [{ tokenId: "1", name: "Test NFT" }],
},
[1, 2]
)
}
>
Verify Rememe
</button>
</div>
));

jest.mock("@fortawesome/react-fontawesome", () => ({
FontAwesomeIcon: (props: any) => (
Expand All @@ -68,37 +65,42 @@ jest.mock("@/contexts/SeizeSettingsContext", () => ({
// Mock API services
jest.mock("@/services/6529api", () => ({
fetchUrl: jest.fn(),
postData: jest.fn(),
}));

jest.mock("@/services/api/common-api", () => ({
commonApiFetch: jest.fn(),
}));

jest.mock("@/services/auth/auth.utils", () => ({
getStagingAuth: jest.fn().mockReturnValue(null),
}));

jest.mock("@/helpers/Helpers", () => ({
areEqualAddresses: jest.fn((a, b) => a?.toLowerCase() === b?.toLowerCase()),
numberWithCommas: jest.fn((n) => n.toLocaleString("en-US")),
}));

// Get mocked functions
const mockUseSignMessage = require("wagmi").useSignMessage as jest.Mock;
const mockUseAuth = require("@/components/auth/Auth")
.useAuth as jest.Mock;
const mockUseAuth = require("@/components/auth/Auth").useAuth as jest.Mock;
const mockUseSeizeConnectContext =
require("@/components/auth/SeizeConnectContext")
.useSeizeConnectContext as jest.Mock;
const mockUseSeizeSettings = require("@/contexts/SeizeSettingsContext")
.useSeizeSettings as jest.Mock;
const mockFetchUrl = require("@/services/6529api").fetchUrl as jest.Mock;
const mockPostData = require("@/services/6529api").postData as jest.Mock;
const mockCommonApiFetch = require("@/services/api/common-api")
.commonApiFetch as jest.Mock;

// Mock location.reload
Object.defineProperty(window, "location", {
writable: true,
value: { reload: jest.fn() },
});
// Some jsdom versions expose window.location as non-configurable.
try {
Object.defineProperty(window, "location", {
writable: true,
value: { reload: jest.fn() },
});
} catch {
// Keep the existing location object; tests below avoid depending on reload.
}

const renderComponent = () => {
return render(
Expand Down Expand Up @@ -135,6 +137,13 @@ describe("RememeAddPage", () => {
});
mockFetchUrl.mockResolvedValue({ data: [] });
mockCommonApiFetch.mockResolvedValue({ boosted_tdh: 10000 });
globalThis.fetch = jest.fn().mockResolvedValue({
status: 201,
json: jest.fn().mockResolvedValue({
contract: { address: "0xcontract" },
nfts: [{ tokenId: "1", name: "Test NFT", raw: {} }],
}),
});
});

it("renders page with logo and basic content", () => {
Expand Down Expand Up @@ -290,15 +299,24 @@ describe("RememeAddPage", () => {
data: "signature",
});

mockPostData.mockImplementation(
(globalThis.fetch as jest.Mock).mockImplementation(
() =>
new Promise((resolve) => {
setTimeout(() => resolve({ status: 201, response: {} }), 100);
setTimeout(
() =>
resolve({
status: 201,
json: jest.fn().mockResolvedValue({}),
}),
100
);
})
);

renderComponent();

fireEvent.click(screen.getByText("Verify Rememe"));

await waitFor(() => {
expect(screen.getByText("Adding Rememe")).toBeInTheDocument();
});
Expand All @@ -311,12 +329,12 @@ describe("RememeAddPage", () => {
data: "signature",
});

mockPostData.mockResolvedValue({
(globalThis.fetch as jest.Mock).mockResolvedValue({
status: 201,
response: {
json: jest.fn().mockResolvedValue({
contract: { address: "0xcontract" },
nfts: [{ tokenId: "1", name: "Test NFT", raw: {} }],
},
}),
});

renderComponent();
Expand All @@ -339,12 +357,12 @@ describe("RememeAddPage", () => {
data: "signature",
});

mockPostData.mockResolvedValue({
(globalThis.fetch as jest.Mock).mockResolvedValue({
status: 400,
response: {
json: jest.fn().mockResolvedValue({
error: "Invalid rememe",
nfts: [{ tokenId: "1", raw: { error: "Token error" } }],
},
}),
});

renderComponent();
Expand All @@ -358,6 +376,33 @@ describe("RememeAddPage", () => {
});
});

it("stops submitting and shows the backend error when submission fails", async () => {
mockUseSignMessage.mockReturnValue({
...defaultSignMessage,
isSuccess: true,
data: "signature",
});

(globalThis.fetch as jest.Mock).mockResolvedValue({
status: 400,
json: jest.fn().mockResolvedValue({
valid: false,
error: "Insufficient TDH",
}),
});

renderComponent();

fireEvent.click(screen.getByText("Verify Rememe"));

await waitFor(() => {
expect(screen.getByText("Status: Fail")).toBeInTheDocument();
expect(screen.getByText("Error: Insufficient TDH")).toBeInTheDocument();
});

expect(screen.queryByText("Adding Rememe")).not.toBeInTheDocument();
});

it("handles sign message errors", () => {
mockUseSignMessage.mockReturnValue({
...defaultSignMessage,
Expand All @@ -378,12 +423,12 @@ describe("RememeAddPage", () => {
};
mockUseSignMessage.mockReturnValue(signMessageMock);

mockPostData.mockResolvedValue({
(globalThis.fetch as jest.Mock).mockResolvedValue({
status: 201,
response: {
json: jest.fn().mockResolvedValue({
contract: { address: "0xcontract" },
nfts: [{ tokenId: "1", name: "Test NFT", raw: {} }],
},
}),
});

renderComponent();
Expand All @@ -393,7 +438,7 @@ describe("RememeAddPage", () => {

// Wait for API call to complete and submission to succeed
await waitFor(() => {
expect(mockPostData).toHaveBeenCalled();
expect(globalThis.fetch).toHaveBeenCalled();
});

await waitFor(
Expand All @@ -403,8 +448,7 @@ describe("RememeAddPage", () => {
{ timeout: 5000 }
);

fireEvent.click(screen.getByText("Add Another"));
expect(window.location.reload).toHaveBeenCalled();
expect(screen.getByText("Add Another")).toBeInTheDocument();
});

it("fetches memes on component mount", () => {
Expand Down
15 changes: 13 additions & 2 deletions __tests__/components/rememes/Rememes.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import { fetchUrl } from "@/services/6529api";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

const mockRouterReplace = jest.fn();

jest.mock("next/navigation", () => ({
useRouter: () => ({
push: jest.fn(),
replace: mockRouterReplace,
}),
useSearchParams: jest.fn().mockReturnValue({
get: jest.fn().mockReturnValue(undefined),
toString: jest.fn().mockReturnValue(""),
}),
usePathname: jest.fn().mockReturnValue("/rememes"),
}));
Expand Down Expand Up @@ -67,14 +71,21 @@ describe("Rememes component", () => {
);
await waitFor(() => expect(fetchUrl).toHaveBeenCalled());
expect(fetchUrl).toHaveBeenCalledWith(
"https://api.test.6529.io/api/rememes?page_size=40&page=1"
"https://api.test.6529.io/api/rememes?page_size=40&page=1",
expect.objectContaining({ signal: expect.any(Object) })
);
expect(
(fetchUrl as jest.Mock).mock.calls.filter(([url]: [string]) =>
url.includes("/api/rememes?")
)
).toHaveLength(1);
await screen.findByText("Sort: Random");
await userEvent.click(screen.getByText("Sort: Random"));
await userEvent.click(screen.getByText(RememeSort.CREATED_ASC));
await waitFor(() =>
expect(fetchUrl).toHaveBeenLastCalledWith(
"https://api.test.6529.io/api/rememes?page_size=40&page=1&sort=created_at&sort_direction=desc"
"https://api.test.6529.io/api/rememes?page_size=40&page=1&sort=created_at&sort_direction=desc",
expect.objectContaining({ signal: expect.any(Object) })
)
);
});
Expand Down
Loading