Skip to content
Merged
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
e25e5f7
Multi subscriptions
prxt6529 Nov 7, 2025
43cf280
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 20, 2025
3499cf1
WIP
prxt6529 Nov 21, 2025
dc697c1
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 21, 2025
984b1c5
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 21, 2025
0b4314b
WIP
prxt6529 Nov 21, 2025
33f86b4
WIP
prxt6529 Nov 24, 2025
f3f40a9
WIP
prxt6529 Nov 25, 2025
a5566a5
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 25, 2025
ac33526
WIP
prxt6529 Nov 25, 2025
20e9031
WIP
prxt6529 Nov 25, 2025
1937477
WIP
prxt6529 Nov 27, 2025
0fc8f46
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 27, 2025
c25ff31
WIP
prxt6529 Nov 27, 2025
b4a87c3
WIP
prxt6529 Nov 27, 2025
3b9847c
WIP
prxt6529 Nov 27, 2025
df368ed
WIP
prxt6529 Nov 27, 2025
3ae4b2a
WIP
prxt6529 Nov 27, 2025
200b399
WIP
prxt6529 Nov 27, 2025
bf85cb3
WIP
prxt6529 Nov 27, 2025
e5a948e
WIP
prxt6529 Nov 27, 2025
58813da
WIP
prxt6529 Nov 27, 2025
072ddb5
WIP
prxt6529 Nov 27, 2025
921752d
WIP
prxt6529 Nov 27, 2025
b16ebdb
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 28, 2025
e16b661
WIP
prxt6529 Nov 28, 2025
d98e484
Fix tests
prxt6529 Nov 28, 2025
31ac263
Fix tests
prxt6529 Nov 28, 2025
0041787
WIP
prxt6529 Nov 28, 2025
2996a89
Merge branch 'main' into multi-subscriptions
prxt6529 Nov 28, 2025
793431d
WIP
prxt6529 Nov 28, 2025
1ff9764
WIP
prxt6529 Nov 28, 2025
ae71ab5
WIP
prxt6529 Nov 28, 2025
559e75e
WIP
prxt6529 Dec 1, 2025
b619826
Merge branch 'main' into multi-subscriptions
prxt6529 Dec 2, 2025
373afc6
WIP
prxt6529 Dec 2, 2025
d54e5ab
WIP Test fix Notifications Context
prxt6529 Dec 2, 2025
41f88e0
WIP
prxt6529 Dec 2, 2025
f32450c
WIP
prxt6529 Dec 2, 2025
b094fec
WIP
prxt6529 Dec 2, 2025
0329c08
WIP
prxt6529 Dec 2, 2025
243f9a3
WIP
prxt6529 Dec 2, 2025
4b6688e
WIP
prxt6529 Dec 2, 2025
b490f06
WIP
prxt6529 Dec 2, 2025
92e48ce
WIP
prxt6529 Dec 2, 2025
fa5f120
WIP
prxt6529 Dec 2, 2025
bdfe01d
WIP
prxt6529 Dec 2, 2025
a355ff2
WIP - Automatic airdrops
prxt6529 Dec 2, 2025
ac6d78e
WIP
prxt6529 Dec 2, 2025
9beff86
Sentry Issues
prxt6529 Dec 3, 2025
919494b
WIP
prxt6529 Dec 3, 2025
f6626bd
WIP
prxt6529 Dec 3, 2025
f418870
WIP
prxt6529 Dec 3, 2025
2ba928f
Merge branch 'main' into sentry-03-12-2
prxt6529 Dec 3, 2025
0fed907
WIP
prxt6529 Dec 3, 2025
496a9ee
WIP
prxt6529 Dec 3, 2025
0e7c424
WIP
prxt6529 Dec 3, 2025
98b4c98
WIP
prxt6529 Dec 3, 2025
e7fe42e
WIP
prxt6529 Dec 3, 2025
6de6b9a
WIP
prxt6529 Dec 3, 2025
5c12de9
wip
prxt6529 Dec 3, 2025
f3209e8
Merge branch 'sentry-03-12-2' into multi-subscriptions
prxt6529 Dec 3, 2025
9d9c4f0
WIP
prxt6529 Dec 3, 2025
8eaf3af
Trigger CI
prxt6529 Dec 3, 2025
6cd0418
Trigger CI
prxt6529 Dec 3, 2025
ed12adb
WIP
prxt6529 Dec 3, 2025
105d999
WIP
prxt6529 Dec 3, 2025
3d83e72
WIP
prxt6529 Dec 3, 2025
f3c8cf0
Merge branch 'sentry-03-12-2' into multi-subscriptions
prxt6529 Dec 3, 2025
3382396
Merge branch 'main' into multi-subscriptions
prxt6529 Dec 3, 2025
41026e7
Merge branch 'main' into multi-subscriptions
prxt6529 Dec 17, 2025
22aa93a
WIP
prxt6529 Dec 17, 2025
f8c0c78
WIP
prxt6529 Dec 17, 2025
130ccbc
WIP
prxt6529 Dec 18, 2025
2e3082c
WIP
prxt6529 Dec 18, 2025
c8084d3
WIP
prxt6529 Dec 18, 2025
c652e8f
WIP
prxt6529 Dec 18, 2025
2d184e1
Merge branch 'main' into multi-subscriptions
prxt6529 Dec 18, 2025
dce03cb
WIP
prxt6529 Dec 18, 2025
976b0f3
WIP
prxt6529 Dec 18, 2025
0fd4046
WIP
prxt6529 Dec 18, 2025
a77ca72
Merge branch 'main' into multi-subscriptions
prxt6529 Dec 18, 2025
c598f33
WIP - openapi models
prxt6529 Dec 19, 2025
b9ef283
WIP
prxt6529 Dec 19, 2025
eaa1bfb
WIP
prxt6529 Dec 19, 2025
102e26a
WIP
prxt6529 Dec 19, 2025
da6ca93
Merge branch 'main' into multi-subscriptions
prxt6529 Dec 19, 2025
407cc60
WIP
prxt6529 Dec 19, 2025
d42ca10
WIP
prxt6529 Dec 19, 2025
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 @@ -4,12 +4,10 @@ jest.mock("@/services/api/common-api", () => ({
commonApiPost: jest.fn(),
}));

import {
download,
isSubscriptionsAdmin,
SubscriptionConfirm,
} from "@/components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription";
import * as ReviewDistributionPlanTableSubscriptionModule from "@/components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription";
import { ApiIdentity } from "@/generated/models/ApiIdentity";
const { download, isSubscriptionsAdmin, SubscriptionConfirm } =
ReviewDistributionPlanTableSubscriptionModule;

jest.mock("react-bootstrap", () => ({
__esModule: true,
Expand Down Expand Up @@ -59,7 +57,18 @@ describe("ReviewDistributionPlanTableSubscription utilities", () => {
});
});

import { render, screen } from "@testing-library/react";
import { AuthContext } from "@/components/auth/Auth";
import { DistributionPlanToolContext } from "@/components/distribution-plan-tool/DistributionPlanToolContext";
import { ReviewDistributionPlanTableItemType } from "@/components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTable";
import { PUBLIC_SUBSCRIPTIONS_PHASE_ID } from "@/components/distribution-plan-tool/review-distribution-plan/table/constants";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
const { SubscriptionLinks } = ReviewDistributionPlanTableSubscriptionModule;

jest.mock("@/components/distribution-plan-tool/common/CircleLoader", () => ({
__esModule: true,
default: () => <div data-testid="circle-loader">Loading...</div>,
}));

test("SubscriptionConfirm extracts token id from plan name", () => {
render(
Expand All @@ -74,3 +83,218 @@ test("SubscriptionConfirm extracts token id from plan name", () => {
const input = screen.getByRole("spinbutton") as HTMLInputElement;
expect(input.value).toBe("123");
});

test("SubscriptionConfirm displays token id as text when confirmedTokenId is provided", () => {
render(
<SubscriptionConfirm
title="t"
plan={{ id: "1", name: "Meme 123 drop" } as any}
show={true}
handleClose={jest.fn()}
confirmedTokenId="456"
onConfirm={jest.fn()}
/>
);
expect(screen.queryByRole("spinbutton")).not.toBeInTheDocument();
expect(screen.getByText("456")).toBeInTheDocument();
});

test("SubscriptionConfirm shows input when confirmedTokenId is not provided", () => {
render(
<SubscriptionConfirm
title="t"
plan={{ id: "1", name: "Meme 123 drop" } as any}
show={true}
handleClose={jest.fn()}
onConfirm={jest.fn()}
/>
);
const input = screen.getByRole("spinbutton") as HTMLInputElement;
expect(input).toBeInTheDocument();
expect(input.value).toBe("123");
});

describe("SubscriptionLinks", () => {
const mockSetToast = jest.fn();
const mockAuthCtx = {
connectedProfile: {
wallets: [{ wallet: "0x0187C9a182736ba18b44eE8134eE438374cf87DC" }],
},
setToast: mockSetToast,
};

const mockPlan = { id: "plan1", name: "Meme 123 drop" } as any;
const mockDistCtx = {
confirmedTokenId: null,
} as any;

beforeEach(() => {
jest.clearAllMocks();
mockFetch.mockResolvedValue({
airdrops: [],
airdrops_unconsolidated: [],
allowlists: [],
});
const mockURL = {
createObjectURL: jest.fn(() => "blob:mock-url"),
revokeObjectURL: jest.fn(),
};
globalThis.URL = mockURL as any;
});
Comment thread
prxt6529 marked this conversation as resolved.

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

it("renders Public Subscriptions button for public phase", () => {
const publicPhase = {
id: "phase1",
name: "public",
type: ReviewDistributionPlanTableItemType.PHASE,
phaseId: PUBLIC_SUBSCRIPTIONS_PHASE_ID,
} as any;

render(
<DistributionPlanToolContext.Provider value={mockDistCtx}>
<AuthContext.Provider value={mockAuthCtx as any}>
<SubscriptionLinks plan={mockPlan} phase={publicPhase} />
</AuthContext.Provider>
</DistributionPlanToolContext.Provider>
);

expect(screen.getByText("Public Subscriptions")).toBeInTheDocument();
});

it("shows confirm modal when Public Subscriptions button is clicked", async () => {
const user = userEvent.setup();
const publicPhase = {
id: "phase1",
name: "public",
type: ReviewDistributionPlanTableItemType.PHASE,
phaseId: PUBLIC_SUBSCRIPTIONS_PHASE_ID,
} as any;

render(
<DistributionPlanToolContext.Provider value={mockDistCtx}>
<AuthContext.Provider value={mockAuthCtx as any}>
<SubscriptionLinks plan={mockPlan} phase={publicPhase} />
</AuthContext.Provider>
</DistributionPlanToolContext.Provider>
);

await user.click(screen.getByText("Public Subscriptions"));

await waitFor(() => {
expect(
screen.getByText("Confirm Download Public Subscriptions Info")
).toBeInTheDocument();
});
});

it("calls download and shows toast when Public Subscriptions is confirmed", async () => {
const user = userEvent.setup();

jest
.spyOn(
ReviewDistributionPlanTableSubscriptionModule,
"isSubscriptionsAdmin"
)
.mockReturnValue(true);
jest
.spyOn(ReviewDistributionPlanTableSubscriptionModule, "download")
.mockResolvedValue({
success: true,
message: "Download successful",
});

const publicPhase = {
id: "phase1",
name: "public",
type: ReviewDistributionPlanTableItemType.PHASE,
phaseId: PUBLIC_SUBSCRIPTIONS_PHASE_ID,
} as any;

render(
<DistributionPlanToolContext.Provider value={mockDistCtx}>
<AuthContext.Provider value={mockAuthCtx as any}>
<SubscriptionLinks plan={mockPlan} phase={publicPhase} />
</AuthContext.Provider>
</DistributionPlanToolContext.Provider>
);

await user.click(screen.getByText("Public Subscriptions"));

await waitFor(() => {
expect(
screen.getByText("Confirm Download Public Subscriptions Info")
).toBeInTheDocument();
});

await user.click(screen.getByText("Looks good"));

await waitFor(() => {
expect(mockSetToast).toHaveBeenCalledWith({
type: "success",
message: "Download successful",
});
});
Comment thread
prxt6529 marked this conversation as resolved.
});

it("does not render for non-admin users", () => {
const nonAdminCtx = {
connectedProfile: {
wallets: [{ wallet: "0x123" }],
},
setToast: jest.fn(),
};

const publicPhase = {
id: "phase1",
name: "public",
type: ReviewDistributionPlanTableItemType.PHASE,
phaseId: PUBLIC_SUBSCRIPTIONS_PHASE_ID,
} as any;

const { container } = render(
<DistributionPlanToolContext.Provider value={mockDistCtx}>
<AuthContext.Provider value={nonAdminCtx as any}>
<SubscriptionLinks plan={mockPlan} phase={publicPhase} />
</AuthContext.Provider>
</DistributionPlanToolContext.Provider>
);

expect(container.innerHTML).toBe("");
});

it("displays token id as text when confirmedTokenId is provided in context", async () => {
const user = userEvent.setup();
const distCtxWithTokenId = {
confirmedTokenId: "789",
} as any;
const publicPhase = {
id: "phase1",
name: "public",
type: ReviewDistributionPlanTableItemType.PHASE,
phaseId: PUBLIC_SUBSCRIPTIONS_PHASE_ID,
} as any;

render(
<DistributionPlanToolContext.Provider value={distCtxWithTokenId}>
<AuthContext.Provider value={mockAuthCtx as any}>
<SubscriptionLinks plan={mockPlan} phase={publicPhase} />
</AuthContext.Provider>
</DistributionPlanToolContext.Provider>
);

await user.click(screen.getByText("Public Subscriptions"));

await waitFor(() => {
expect(
screen.getByText("Confirm Download Public Subscriptions Info")
).toBeInTheDocument();
});

expect(screen.queryByRole("spinbutton")).not.toBeInTheDocument();
expect(screen.getByText("789")).toBeInTheDocument();
});
});
Loading