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
107 changes: 90 additions & 17 deletions __tests__/components/home/LatestDropNextMintSubscribe.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ jest.mock("@tanstack/react-query", () => ({
useQuery: jest.fn(),
}));

jest.mock("@/components/cookies/CookieConsentContext", () => ({
useCookieConsent: () => ({ country: "US" }),
}));

jest.mock(
"@/components/user/subscriptions/MemeSubscriptionRow",
() =>
function MockMemeSubscriptionRow(props: any) {
return (
<div data-testid="meme-subscription-row">
token:{props.subscription.token_id} eligibility:{props.eligibilityCount}
token:{props.subscription.token_id} eligibility:
{props.eligibilityCount}
minting_today:{String(props.minting_today)} readonly:
{String(props.readonly)} variant:{props.variant ?? "default"} date:
{String(props.date)}
{String(props.readonly)} balance:{props.balanceLabel} variant:
{props.variant ?? "default"} date:{String(props.date)}
</div>
);
}
Expand Down Expand Up @@ -86,6 +91,9 @@ describe("LatestDropNextMintSubscribe", () => {
expect(screen.getByTestId("meme-subscription-row")).toHaveTextContent(
/readonly:false/
);
expect(screen.getByTestId("meme-subscription-row")).toHaveTextContent(
/balance:0/
);
Comment thread
prxt6529 marked this conversation as resolved.
expect(screen.getByTestId("meme-subscription-row")).toHaveTextContent(
/variant:compact/
);
Expand Down Expand Up @@ -124,27 +132,92 @@ describe("LatestDropNextMintSubscribe", () => {
);
});

it("does not render when there is no connected profile", () => {
const { container } = renderWithAuth(
<LatestDropNextMintSubscribe />,
{ connectedProfile: null }
it("falls back to zero balance for non-finite details", () => {
useQueryMock.mockImplementation(({ queryKey }) => {
if (queryKey[0] === "next-mint-subscription-details") {
return {
data: {
balance: Number.NaN,
subscription_eligibility_count: 3,
},
};
}

if (queryKey[0] === "next-mint-subscription-status") {
return {
data: {
subscribed: true,
eligibility: 2,
count: 1,
},
refetch: jest.fn(),
};
}

return {
data: null,
refetch: jest.fn(),
};
});

renderWithAuth(<LatestDropNextMintSubscribe />);

expect(screen.getByTestId("meme-subscription-row")).toHaveTextContent(
"balance:0"
);
});

it("does not render when there is no connected profile", () => {
const { container } = renderWithAuth(<LatestDropNextMintSubscribe />, {
connectedProfile: null,
});

expect(container).toBeEmptyDOMElement();
});

it("does not render during an active proxy session", () => {
const { container } = renderWithAuth(
<LatestDropNextMintSubscribe />,
{
activeProfileProxy: {
id: "proxy-1",
granted_to: {} as any,
created_at: Date.now(),
created_by: {} as any,
actions: [],
} as any,
const { container } = renderWithAuth(<LatestDropNextMintSubscribe />, {
activeProfileProxy: {
id: "proxy-1",
granted_to: {} as any,
created_at: Date.now(),
created_by: {} as any,
actions: [],
} as any,
});

expect(container).toBeEmptyDOMElement();
});

it("does not render in latest-drop mode when the profile is not subscribed", () => {
useQueryMock.mockImplementation(({ queryKey }) => {
if (queryKey[0] === "next-mint-subscription-details") {
return {
data: {
subscription_eligibility_count: 3,
},
};
}

if (queryKey[0] === "next-mint-subscription-status") {
return {
data: {
subscribed: false,
eligibility: 2,
count: 1,
},
refetch: jest.fn(),
};
}

return {
data: null,
refetch: jest.fn(),
};
});

const { container } = renderWithAuth(
<LatestDropNextMintSubscribe showOnlyWhenSubscribed readonly />
);

expect(container).toBeEmptyDOMElement();
Expand Down
6 changes: 6 additions & 0 deletions __tests__/components/home/NowMintingDetails.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ jest.mock("@/components/home/now-minting/NowMintingStatsGrid", () => ({
default: () => <div data-testid="stats-grid" />,
}));

jest.mock("@/components/home/now-minting/LatestDropNextMintSubscribe", () => ({
__esModule: true,
default: () => <div data-testid="subscribe-section" />,
}));

jest.mock("@/components/home/now-minting/NowMintingCountdown", () => ({
__esModule: true,
default: () => <div data-testid="countdown" />,
Expand Down Expand Up @@ -53,6 +58,7 @@ describe("NowMintingDetails", () => {
expect(screen.queryByText("Dimensions")).not.toBeInTheDocument();
expect(screen.getByText("Collection")).toBeInTheDocument();
expect(screen.getByText("Season")).toBeInTheDocument();
expect(screen.getByTestId("subscribe-section")).toBeInTheDocument();
});

it("renders file metadata rows when image metadata is present", () => {
Expand Down
149 changes: 149 additions & 0 deletions __tests__/components/user/subscriptions/MemeSubscriptionRow.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { renderWithAuth } from "@/__tests__/utils/testContexts";
import MemeSubscriptionRow from "@/components/user/subscriptions/MemeSubscriptionRow";
import { useQuery } from "@tanstack/react-query";
import { screen } from "@testing-library/react";

jest.mock("@tanstack/react-query", () => ({
useQuery: jest.fn(),
useQueryClient: () => ({
invalidateQueries: jest.fn(),
}),
}));

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

const useQueryMock = useQuery as jest.Mock;

describe("MemeSubscriptionRow", () => {
beforeEach(() => {
useQueryMock.mockImplementation(({ queryKey }) => {
if (queryKey[0] === "consolidation-final-subscription") {
return {
data: {
phase: "Phase 1",
phase_position: 4,
phase_subscriptions: 12,
airdrop_address: "0xabc123",
subscribed_count: 2,
},
};
}

return {
data: null,
};
});
});

afterEach(() => {
jest.clearAllMocks();
});

it("shows the subscribed compact view without toggle controls", () => {
renderWithAuth(
<MemeSubscriptionRow
profileKey="test-key"
title="The Memes"
subscription={
{
token_id: 478,
contract: "0x123",
subscribed: true,
subscribed_count: 2,
} as any
}
eligibilityCount={3}
readonly
refresh={jest.fn()}
minting_today={false}
first
date={null}
variant="compact"
balanceLabel="0.1"
subscribedView
/>
);

expect(screen.getByText("Subscribed")).toBeInTheDocument();
expect(screen.getByText("2 / 3")).toBeInTheDocument();
expect(
screen.queryByLabelText(/Toggle subscription for The Memes #478/)
).not.toBeInTheDocument();
expect(
screen.queryByLabelText(/Select subscription quantity for The Memes/)
).not.toBeInTheDocument();
expect(
screen.getByText(/Phase: Phase 1 - Subscription Position: 4 \/ 12/)
).toBeInTheDocument();
});

it("renders the compact balance label", () => {
renderWithAuth(
<MemeSubscriptionRow
profileKey="test-key"
title="The Memes"
subscription={
{
token_id: 478,
contract: "0x123",
subscribed: true,
subscribed_count: 2,
} as any
}
eligibilityCount={3}
readonly
refresh={jest.fn()}
minting_today={false}
first
date={null}
variant="compact"
balanceLabel="0.5"
subscribedView
/>
);

expect(screen.getByText("Balance")).toBeInTheDocument();
expect(screen.getByText("0.5")).toBeInTheDocument();
});

it("omits phase metadata when the final subscription is unavailable", () => {
useQueryMock.mockImplementation(({ queryKey }) => {
if (queryKey[0] === "consolidation-final-subscription") {
return { data: null };
}

return {
data: null,
};
});

renderWithAuth(
<MemeSubscriptionRow
profileKey="test-key"
title="The Memes"
subscription={
{
token_id: 478,
contract: "0x123",
subscribed: true,
subscribed_count: 2,
} as any
}
eligibilityCount={3}
readonly
refresh={jest.fn()}
minting_today={false}
first
date={null}
variant="compact"
balanceLabel="0.5"
subscribedView
/>
);

expect(screen.queryByText(/Phase:/)).not.toBeInTheDocument();
});
});
45 changes: 31 additions & 14 deletions components/home/now-minting/LatestDropNextMintSubscribe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ function getProfileKey(
);
}

export default function LatestDropNextMintSubscribe() {
export default function LatestDropNextMintSubscribe(
props: Readonly<{
showOnlyWhenSubscribed?: boolean;
readonly?: boolean;
}> = {}
) {
const { connectedProfile, activeProfileProxy } = useContext(AuthContext);
const { country } = useCookieConsent();
const { isIos } = useCapacitor();
Expand All @@ -53,17 +58,15 @@ export default function LatestDropNextMintSubscribe() {
enabled: !hideSubscriptions && !!profileKey,
});

const {
data: status,
refetch: refetchStatus,
} = useQuery<ApiUpcomingMemeSubscriptionStatus>({
queryKey: ["next-mint-subscription-status", profileKey, tokenId],
queryFn: async () =>
await commonApiFetch<ApiUpcomingMemeSubscriptionStatus>({
endpoint: `subscriptions/consolidation/upcoming-memes/${tokenId}/${profileKey}`,
}),
enabled: !hideSubscriptions && !!profileKey && hasTokenId,
});
const { data: status, refetch: refetchStatus } =
useQuery<ApiUpcomingMemeSubscriptionStatus>({
queryKey: ["next-mint-subscription-status", profileKey, tokenId],
queryFn: async () =>
await commonApiFetch<ApiUpcomingMemeSubscriptionStatus>({
endpoint: `subscriptions/consolidation/upcoming-memes/${tokenId}/${profileKey}`,
}),
enabled: !hideSubscriptions && !!profileKey && hasTokenId,
});

const subscription = useMemo<NFTSubscription | null>(() => {
if (!profileKey || !hasTokenId || !status) {
Expand All @@ -79,7 +82,20 @@ export default function LatestDropNextMintSubscribe() {
} as NFTSubscription;
}, [hasTokenId, profileKey, status, tokenId]);

if (hideSubscriptions || !profileKey || !subscription) {
const balanceLabel = useMemo(() => {
const balance = details?.balance ?? 0;
const safeBalance = Number.isFinite(balance) ? balance : 0;
return new Intl.NumberFormat(undefined, {
maximumFractionDigits: 6,
}).format(Math.round(safeBalance * 1_000_000) / 1_000_000);
}, [details?.balance]);

if (
hideSubscriptions ||
!profileKey ||
!subscription ||
(props.showOnlyWhenSubscribed && !subscription.subscribed)
) {
return null;
}

Expand All @@ -93,7 +109,8 @@ export default function LatestDropNextMintSubscribe() {
eligibilityCount={
details?.subscription_eligibility_count ?? status?.eligibility ?? 1
}
readonly={false}
balanceLabel={balanceLabel}
readonly={props.readonly ?? false}
refresh={() => {
refetchStatus();
}}
Expand Down
Loading
Loading