@wopr-network/platform-ui-core 1.23.0 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -3,6 +3,18 @@ import userEvent from "@testing-library/user-event";
|
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import { CreateInstanceClient } from "../app/instances/new/create-instance-client";
|
|
5
5
|
|
|
6
|
+
vi.mock("next/navigation", () => ({
|
|
7
|
+
useRouter: vi.fn().mockReturnValue({
|
|
8
|
+
push: vi.fn(),
|
|
9
|
+
replace: vi.fn(),
|
|
10
|
+
prefetch: vi.fn(),
|
|
11
|
+
back: vi.fn(),
|
|
12
|
+
refresh: vi.fn(),
|
|
13
|
+
}),
|
|
14
|
+
usePathname: vi.fn().mockReturnValue("/instances/new"),
|
|
15
|
+
useSearchParams: vi.fn().mockReturnValue(new URLSearchParams()),
|
|
16
|
+
}));
|
|
17
|
+
|
|
6
18
|
vi.mock("@/lib/marketplace-data", () => ({
|
|
7
19
|
listMarketplacePlugins: vi.fn(),
|
|
8
20
|
}));
|
|
@@ -2,25 +2,19 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
2
2
|
|
|
3
3
|
vi.mock("@/lib/trpc", () => ({
|
|
4
4
|
trpcVanilla: {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
query: vi.fn().mockResolvedValue({
|
|
8
|
-
orgId: "org-1",
|
|
9
|
-
balanceCents: 5000,
|
|
10
|
-
dailyBurnCents: 100,
|
|
11
|
-
runwayDays: 50,
|
|
12
|
-
}),
|
|
13
|
-
},
|
|
14
|
-
orgMemberUsage: {
|
|
5
|
+
billing: {
|
|
6
|
+
creditsBalance: {
|
|
15
7
|
query: vi.fn().mockResolvedValue({
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
balance_credits: 5000,
|
|
9
|
+
daily_burn_credits: 100,
|
|
10
|
+
runway_days: 50,
|
|
19
11
|
}),
|
|
20
12
|
},
|
|
21
|
-
|
|
13
|
+
billingInfo: {
|
|
22
14
|
query: vi.fn().mockResolvedValue({ paymentMethods: [], invoices: [] }),
|
|
23
15
|
},
|
|
16
|
+
},
|
|
17
|
+
org: {
|
|
24
18
|
orgTopupCheckout: {
|
|
25
19
|
mutate: vi.fn().mockResolvedValue({
|
|
26
20
|
url: "https://checkout.stripe.com/test",
|
|
@@ -42,7 +36,7 @@ import {
|
|
|
42
36
|
} from "@/lib/org-billing-api";
|
|
43
37
|
|
|
44
38
|
describe("org-billing-api", () => {
|
|
45
|
-
it("getOrgCreditBalance converts
|
|
39
|
+
it("getOrgCreditBalance converts credits to dollars", async () => {
|
|
46
40
|
const result = await getOrgCreditBalance("org-1");
|
|
47
41
|
expect(result.balance).toBe(50);
|
|
48
42
|
expect(result.dailyBurn).toBe(1);
|
|
@@ -9,10 +9,11 @@ interface MockMutate {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
interface MockTrpcVanilla {
|
|
12
|
+
billing: {
|
|
13
|
+
creditsBalance: MockQuery;
|
|
14
|
+
billingInfo: MockQuery;
|
|
15
|
+
};
|
|
12
16
|
org: {
|
|
13
|
-
orgBillingBalance: MockQuery;
|
|
14
|
-
orgMemberUsage: MockQuery;
|
|
15
|
-
orgBillingInfo: MockQuery;
|
|
16
17
|
orgTopupCheckout: MockMutate;
|
|
17
18
|
orgRemovePaymentMethod: MockMutate;
|
|
18
19
|
};
|
|
@@ -20,10 +21,11 @@ interface MockTrpcVanilla {
|
|
|
20
21
|
|
|
21
22
|
vi.mock("@/lib/trpc", () => ({
|
|
22
23
|
trpcVanilla: {
|
|
24
|
+
billing: {
|
|
25
|
+
creditsBalance: { query: vi.fn() },
|
|
26
|
+
billingInfo: { query: vi.fn() },
|
|
27
|
+
},
|
|
23
28
|
org: {
|
|
24
|
-
orgBillingBalance: { query: vi.fn() },
|
|
25
|
-
orgMemberUsage: { query: vi.fn() },
|
|
26
|
-
orgBillingInfo: { query: vi.fn() },
|
|
27
29
|
orgTopupCheckout: { mutate: vi.fn() },
|
|
28
30
|
orgRemovePaymentMethod: { mutate: vi.fn() },
|
|
29
31
|
},
|
|
@@ -33,8 +35,8 @@ vi.mock("@/lib/trpc", () => ({
|
|
|
33
35
|
describe("org-billing-api null guards", () => {
|
|
34
36
|
it("getOrgCreditBalance handles empty response", async () => {
|
|
35
37
|
const { trpcVanilla } = await import("@/lib/trpc");
|
|
36
|
-
const {
|
|
37
|
-
|
|
38
|
+
const { billing } = trpcVanilla as unknown as MockTrpcVanilla;
|
|
39
|
+
billing.creditsBalance.query.mockResolvedValue({});
|
|
38
40
|
|
|
39
41
|
const { getOrgCreditBalance } = await import("@/lib/org-billing-api");
|
|
40
42
|
const result = await getOrgCreditBalance("org-1");
|
|
@@ -43,11 +45,7 @@ describe("org-billing-api null guards", () => {
|
|
|
43
45
|
expect(result.runway).toBeNull();
|
|
44
46
|
});
|
|
45
47
|
|
|
46
|
-
it("getOrgMemberUsage
|
|
47
|
-
const { trpcVanilla } = await import("@/lib/trpc");
|
|
48
|
-
const { org } = trpcVanilla as unknown as MockTrpcVanilla;
|
|
49
|
-
org.orgMemberUsage.query.mockResolvedValue({ orgId: "o", periodStart: "2026-01-01" });
|
|
50
|
-
|
|
48
|
+
it("getOrgMemberUsage returns stub with empty members", async () => {
|
|
51
49
|
const { getOrgMemberUsage } = await import("@/lib/org-billing-api");
|
|
52
50
|
const result = await getOrgMemberUsage("org-1");
|
|
53
51
|
expect(result.members).toEqual([]);
|
|
@@ -55,8 +53,8 @@ describe("org-billing-api null guards", () => {
|
|
|
55
53
|
|
|
56
54
|
it("getOrgBillingInfo handles empty response", async () => {
|
|
57
55
|
const { trpcVanilla } = await import("@/lib/trpc");
|
|
58
|
-
const {
|
|
59
|
-
|
|
56
|
+
const { billing } = trpcVanilla as unknown as MockTrpcVanilla;
|
|
57
|
+
billing.billingInfo.query.mockResolvedValue({});
|
|
60
58
|
|
|
61
59
|
const { getOrgBillingInfo } = await import("@/lib/org-billing-api");
|
|
62
60
|
const result = await getOrgBillingInfo("org-1");
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
mockOrgBillingInfoQuery,
|
|
4
|
+
mockCreditsBalanceQuery,
|
|
5
|
+
mockBillingInfoQuery,
|
|
7
6
|
mockOrgTopupCheckoutMutate,
|
|
8
7
|
mockOrgSetDefaultPaymentMethodMutate,
|
|
9
8
|
} = vi.hoisted(() => ({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
mockOrgBillingInfoQuery: vi.fn(),
|
|
9
|
+
mockCreditsBalanceQuery: vi.fn(),
|
|
10
|
+
mockBillingInfoQuery: vi.fn(),
|
|
13
11
|
mockOrgTopupCheckoutMutate: vi.fn(),
|
|
14
12
|
mockOrgSetDefaultPaymentMethodMutate: vi.fn(),
|
|
15
13
|
}));
|
|
16
14
|
|
|
17
15
|
vi.mock("@/lib/trpc", () => ({
|
|
18
16
|
trpcVanilla: {
|
|
17
|
+
billing: {
|
|
18
|
+
creditsBalance: { query: mockCreditsBalanceQuery },
|
|
19
|
+
billingInfo: { query: mockBillingInfoQuery },
|
|
20
|
+
},
|
|
19
21
|
org: {
|
|
20
|
-
orgBillingBalance: { query: mockOrgBillingBalanceQuery },
|
|
21
|
-
orgMemberUsage: { query: mockOrgMemberUsageQuery },
|
|
22
|
-
orgBillingInfo: { query: mockOrgBillingInfoQuery },
|
|
23
22
|
orgTopupCheckout: { mutate: mockOrgTopupCheckoutMutate },
|
|
24
23
|
orgSetDefaultPaymentMethod: { mutate: mockOrgSetDefaultPaymentMethodMutate },
|
|
25
24
|
},
|
|
@@ -38,11 +37,11 @@ import {
|
|
|
38
37
|
describe("getOrgCreditBalance", () => {
|
|
39
38
|
afterEach(() => vi.clearAllMocks());
|
|
40
39
|
|
|
41
|
-
it("converts
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
it("converts credits to dollars and returns balance", async () => {
|
|
41
|
+
mockCreditsBalanceQuery.mockResolvedValue({
|
|
42
|
+
balance_credits: 5000,
|
|
43
|
+
daily_burn_credits: 200,
|
|
44
|
+
runway_days: 25,
|
|
46
45
|
});
|
|
47
46
|
|
|
48
47
|
const result = await getOrgCreditBalance("org-1");
|
|
@@ -51,14 +50,29 @@ describe("getOrgCreditBalance", () => {
|
|
|
51
50
|
dailyBurn: 2,
|
|
52
51
|
runway: 25,
|
|
53
52
|
});
|
|
54
|
-
expect(
|
|
53
|
+
expect(mockCreditsBalanceQuery).toHaveBeenCalledWith({});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("falls back to legacy cents fields", async () => {
|
|
57
|
+
mockCreditsBalanceQuery.mockResolvedValue({
|
|
58
|
+
balance_cents: 3000,
|
|
59
|
+
daily_burn_cents: 100,
|
|
60
|
+
runway_days: 30,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const result = await getOrgCreditBalance("org-1");
|
|
64
|
+
expect(result).toEqual({
|
|
65
|
+
balance: 30,
|
|
66
|
+
dailyBurn: 1,
|
|
67
|
+
runway: 30,
|
|
68
|
+
});
|
|
55
69
|
});
|
|
56
70
|
|
|
57
71
|
it("defaults to zero balance when response fields are null", async () => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
mockCreditsBalanceQuery.mockResolvedValue({
|
|
73
|
+
balance_credits: null,
|
|
74
|
+
daily_burn_credits: null,
|
|
75
|
+
runway_days: null,
|
|
62
76
|
});
|
|
63
77
|
|
|
64
78
|
const result = await getOrgCreditBalance("org-1");
|
|
@@ -70,7 +84,7 @@ describe("getOrgCreditBalance", () => {
|
|
|
70
84
|
});
|
|
71
85
|
|
|
72
86
|
it("defaults to zero balance when response fields are undefined", async () => {
|
|
73
|
-
|
|
87
|
+
mockCreditsBalanceQuery.mockResolvedValue({});
|
|
74
88
|
|
|
75
89
|
const result = await getOrgCreditBalance("org-1");
|
|
76
90
|
expect(result).toEqual({
|
|
@@ -81,101 +95,17 @@ describe("getOrgCreditBalance", () => {
|
|
|
81
95
|
});
|
|
82
96
|
|
|
83
97
|
it("propagates tRPC errors", async () => {
|
|
84
|
-
|
|
98
|
+
mockCreditsBalanceQuery.mockRejectedValue(new Error("Forbidden"));
|
|
85
99
|
await expect(getOrgCreditBalance("org-1")).rejects.toThrow("Forbidden");
|
|
86
100
|
});
|
|
87
101
|
});
|
|
88
102
|
|
|
89
103
|
describe("getOrgMemberUsage", () => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
it("transforms member usage with cents-to-dollars conversion", async () => {
|
|
93
|
-
mockOrgMemberUsageQuery.mockResolvedValue({
|
|
94
|
-
orgId: "org-1",
|
|
95
|
-
periodStart: "2026-03-01",
|
|
96
|
-
members: [
|
|
97
|
-
{
|
|
98
|
-
memberId: "m-1",
|
|
99
|
-
name: "Alice",
|
|
100
|
-
email: "alice@test.com",
|
|
101
|
-
creditsConsumedCents: 1500,
|
|
102
|
-
lastActiveAt: "2026-03-02T10:00:00Z",
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
memberId: "m-2",
|
|
106
|
-
name: "Bob",
|
|
107
|
-
email: "bob@test.com",
|
|
108
|
-
creditsConsumedCents: 300,
|
|
109
|
-
lastActiveAt: null,
|
|
110
|
-
},
|
|
111
|
-
],
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
const result = await getOrgMemberUsage("org-1");
|
|
115
|
-
expect(result).toEqual({
|
|
116
|
-
orgId: "org-1",
|
|
117
|
-
periodStart: "2026-03-01",
|
|
118
|
-
members: [
|
|
119
|
-
{
|
|
120
|
-
memberId: "m-1",
|
|
121
|
-
name: "Alice",
|
|
122
|
-
email: "alice@test.com",
|
|
123
|
-
creditsConsumed: 15,
|
|
124
|
-
lastActiveAt: "2026-03-02T10:00:00Z",
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
memberId: "m-2",
|
|
128
|
-
name: "Bob",
|
|
129
|
-
email: "bob@test.com",
|
|
130
|
-
creditsConsumed: 3,
|
|
131
|
-
lastActiveAt: null,
|
|
132
|
-
},
|
|
133
|
-
],
|
|
134
|
-
});
|
|
135
|
-
expect(mockOrgMemberUsageQuery).toHaveBeenCalledWith({ orgId: "org-1" });
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("defaults member fields when properties are missing", async () => {
|
|
139
|
-
mockOrgMemberUsageQuery.mockResolvedValue({
|
|
140
|
-
orgId: "org-1",
|
|
141
|
-
periodStart: "2026-03-01",
|
|
142
|
-
members: [{}],
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
const result = await getOrgMemberUsage("org-1");
|
|
146
|
-
expect(result.members[0]).toEqual({
|
|
147
|
-
memberId: "",
|
|
148
|
-
name: "",
|
|
149
|
-
email: "",
|
|
150
|
-
creditsConsumed: 0,
|
|
151
|
-
lastActiveAt: null,
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("handles null members array", async () => {
|
|
156
|
-
mockOrgMemberUsageQuery.mockResolvedValue({
|
|
157
|
-
orgId: "org-1",
|
|
158
|
-
periodStart: "2026-03-01",
|
|
159
|
-
members: null,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const result = await getOrgMemberUsage("org-1");
|
|
163
|
-
expect(result.members).toEqual([]);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it("falls back orgId and periodStart when missing from response", async () => {
|
|
167
|
-
mockOrgMemberUsageQuery.mockResolvedValue({
|
|
168
|
-
members: [],
|
|
169
|
-
});
|
|
170
|
-
|
|
104
|
+
it("returns stub data with empty members array", async () => {
|
|
171
105
|
const result = await getOrgMemberUsage("org-1");
|
|
172
106
|
expect(result.orgId).toBe("org-1");
|
|
173
|
-
expect(result.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
it("propagates tRPC errors", async () => {
|
|
177
|
-
mockOrgMemberUsageQuery.mockRejectedValue(new Error("Server error"));
|
|
178
|
-
await expect(getOrgMemberUsage("org-1")).rejects.toThrow("Server error");
|
|
107
|
+
expect(result.members).toEqual([]);
|
|
108
|
+
expect(result.periodStart).toBeTruthy();
|
|
179
109
|
});
|
|
180
110
|
});
|
|
181
111
|
|
|
@@ -195,7 +125,7 @@ describe("getOrgBillingInfo", () => {
|
|
|
195
125
|
hostedLineItems: undefined,
|
|
196
126
|
},
|
|
197
127
|
];
|
|
198
|
-
|
|
128
|
+
mockBillingInfoQuery.mockResolvedValue({ paymentMethods, invoices });
|
|
199
129
|
|
|
200
130
|
const result = await getOrgBillingInfo("org-1");
|
|
201
131
|
expect(result).toEqual({
|
|
@@ -212,11 +142,11 @@ describe("getOrgBillingInfo", () => {
|
|
|
212
142
|
},
|
|
213
143
|
],
|
|
214
144
|
});
|
|
215
|
-
expect(
|
|
145
|
+
expect(mockBillingInfoQuery).toHaveBeenCalledWith({});
|
|
216
146
|
});
|
|
217
147
|
|
|
218
148
|
it("defaults to empty arrays when fields are null", async () => {
|
|
219
|
-
|
|
149
|
+
mockBillingInfoQuery.mockResolvedValue({
|
|
220
150
|
paymentMethods: null,
|
|
221
151
|
invoices: null,
|
|
222
152
|
});
|
|
@@ -226,15 +156,16 @@ describe("getOrgBillingInfo", () => {
|
|
|
226
156
|
});
|
|
227
157
|
|
|
228
158
|
it("defaults to empty arrays when fields are undefined", async () => {
|
|
229
|
-
|
|
159
|
+
mockBillingInfoQuery.mockResolvedValue({});
|
|
230
160
|
|
|
231
161
|
const result = await getOrgBillingInfo("org-1");
|
|
232
162
|
expect(result).toEqual({ paymentMethods: [], invoices: [] });
|
|
233
163
|
});
|
|
234
164
|
|
|
235
|
-
it("
|
|
236
|
-
|
|
237
|
-
await
|
|
165
|
+
it("returns defaults on tRPC error instead of throwing", async () => {
|
|
166
|
+
mockBillingInfoQuery.mockRejectedValue(new Error("Not found"));
|
|
167
|
+
const result = await getOrgBillingInfo("org-1");
|
|
168
|
+
expect(result).toEqual({ paymentMethods: [], invoices: [] });
|
|
238
169
|
});
|
|
239
170
|
});
|
|
240
171
|
|