@lookiero/checkout 10.1.0 → 11.0.0
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/cypress/integration/checkout.spec.ts +0 -3
- package/dist/fake-dependencies/@lookiero/payments-front/index.d.ts +8 -7
- package/dist/fake-dependencies/@lookiero/payments-front/index.js +11 -3
- package/dist/index.d.ts +3 -3
- package/dist/src/ExpoRoot.js +17 -12
- package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.d.ts +1 -1
- package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.js +2 -0
- package/dist/src/infrastructure/projection/checkout/checkout.mock.d.ts +1 -0
- package/dist/src/infrastructure/projection/checkout/checkout.mock.js +3 -3
- package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.d.ts +1 -1
- package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.js +2 -1
- package/dist/src/infrastructure/tracking/tracking.d.ts +2 -2
- package/dist/src/infrastructure/tracking/useTrackCheckout.d.ts +10 -17
- package/dist/src/infrastructure/tracking/useTrackCheckout.js +27 -12
- package/dist/src/infrastructure/ui/Root.d.ts +6 -6
- package/dist/src/infrastructure/ui/Root.js +2 -3
- package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.d.ts +26 -0
- package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.js +127 -0
- package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.d.ts +3 -2
- package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.js +17 -26
- package/dist/src/infrastructure/ui/i18n/i18n.d.ts +1 -0
- package/dist/src/infrastructure/ui/i18n/i18n.js +1 -0
- package/dist/src/infrastructure/ui/routing/CheckoutMiddleware.js +1 -12
- package/dist/src/infrastructure/ui/routing/Routing.d.ts +5 -5
- package/dist/src/infrastructure/ui/routing/Routing.js +2 -10
- package/dist/src/infrastructure/ui/routing/routes.d.ts +0 -1
- package/dist/src/infrastructure/ui/routing/routes.js +0 -1
- package/dist/src/infrastructure/ui/views/App.js +5 -6
- package/dist/src/infrastructure/ui/views/checkout/Checkout.d.ts +7 -2
- package/dist/src/infrastructure/ui/views/checkout/Checkout.js +20 -9
- package/dist/src/infrastructure/ui/views/checkout/Checkout.style.d.ts +3 -0
- package/dist/src/infrastructure/ui/views/checkout/Checkout.style.js +3 -0
- package/dist/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.js +7 -7
- package/dist/src/projection/customer/customer.d.ts +2 -0
- package/dist/src/projection/order/order.d.ts +1 -1
- package/dist/src/projection/subscription/subscription.d.ts +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/fake-dependencies/@lookiero/payments-front/index.tsx +36 -8
- package/index.ts +10 -3
- package/package.json +3 -3
- package/src/ExpoRoot.tsx +43 -36
- package/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.ts +4 -1
- package/src/infrastructure/projection/checkout/checkout.mock.ts +8 -3
- package/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.ts +3 -2
- package/src/infrastructure/tracking/tracking.ts +2 -2
- package/src/infrastructure/tracking/useTrackCheckout.test.tsx +51 -24
- package/src/infrastructure/tracking/useTrackCheckout.ts +66 -56
- package/src/infrastructure/ui/Root.tsx +9 -9
- package/src/infrastructure/ui/components/templates/header/itemHeader/ItemHeader.tsx +1 -0
- package/src/infrastructure/ui/hooks/useCheckoutFlow.test.tsx +302 -0
- package/src/infrastructure/ui/hooks/useCheckoutFlow.tsx +203 -0
- package/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.ts +18 -60
- package/src/infrastructure/ui/i18n/i18n.ts +1 -0
- package/src/infrastructure/ui/routing/CheckoutMiddleware.test.tsx +0 -11
- package/src/infrastructure/ui/routing/CheckoutMiddleware.tsx +1 -15
- package/src/infrastructure/ui/routing/Routing.tsx +14 -25
- package/src/infrastructure/ui/routing/routes.ts +0 -1
- package/src/infrastructure/ui/views/App.tsx +5 -13
- package/src/infrastructure/ui/views/checkout/Checkout.style.ts +3 -0
- package/src/infrastructure/ui/views/checkout/Checkout.test.tsx +51 -43
- package/src/infrastructure/ui/views/checkout/Checkout.tsx +51 -13
- package/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.tsx +8 -8
- package/src/projection/customer/customer.ts +2 -0
- package/src/projection/order/order.ts +1 -1
- package/src/projection/subscription/subscription.ts +1 -1
- package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.d.ts +0 -27
- package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.js +0 -97
- package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.d.ts +0 -12
- package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.js +0 -88
- package/src/infrastructure/ui/hooks/useSubmitCheckout.test.ts +0 -297
- package/src/infrastructure/ui/hooks/useSubmitCheckout.ts +0 -169
- package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.test.tsx +0 -134
- package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.tsx +0 -124
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
import { act, renderHook, waitFor } from "@testing-library/react-native";
|
|
2
|
-
import { mock } from "jest-mock-extended";
|
|
3
|
-
import { RefObject } from "react";
|
|
4
|
-
import { CommandStatus } from "@lookiero/messaging-react";
|
|
5
|
-
import { PaymentFlowRef } from "@lookiero/payments-front";
|
|
6
|
-
import { ChargeStatus } from "@lookiero/payments-front/build/infrastructure/CheckoutAPI";
|
|
7
|
-
import { Logger } from "@lookiero/sty-psp-logging";
|
|
8
|
-
import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
|
|
9
|
-
import { CheckoutBookingProjection } from "../../../projection/checkoutBooking/checkoutBooking";
|
|
10
|
-
import { useSubmitCheckout } from "../../domain/checkout/react/useSubmitCheckout";
|
|
11
|
-
import { useBlockCheckoutBooking } from "../../domain/checkoutBooking/react/useBlockCheckoutBooking";
|
|
12
|
-
import { paymentFlowPayload as mockPaymentFlowPayload } from "../../projection/payment/paymentFlowPayload.mock";
|
|
13
|
-
import { useQueryBus } from "./useQueryBus";
|
|
14
|
-
import { useSubmitCheckout as sut } from "./useSubmitCheckout";
|
|
15
|
-
|
|
16
|
-
const checkoutId = "9c450400-0cd7-44a4-b0e3-e0002a9bf8df";
|
|
17
|
-
const checkoutBookingId = "07c996bb-a0b4-45f9-ae21-6bb9c784d12b";
|
|
18
|
-
const errorChargeStatuses = Object.values(ChargeStatus).filter((status) => status !== ChargeStatus.EXECUTED);
|
|
19
|
-
|
|
20
|
-
const logger = mock<Logger>();
|
|
21
|
-
|
|
22
|
-
jest.mock("@lookiero/sty-psp-notifications");
|
|
23
|
-
jest.mock("./useQueryBus");
|
|
24
|
-
jest.mock("../../domain/checkout/react/useSubmitCheckout");
|
|
25
|
-
jest.mock("../../domain/checkoutBooking/react/useBlockCheckoutBooking");
|
|
26
|
-
|
|
27
|
-
describe("useSubmitCheckout custom hook", () => {
|
|
28
|
-
test("returns success as the status right after calling 'submitCheckout'", async () => {
|
|
29
|
-
const mockBlockCheckoutBooking = jest.fn();
|
|
30
|
-
const mockSubmitCheckout = jest.fn();
|
|
31
|
-
const mockCreateToastNotification = jest.fn();
|
|
32
|
-
const mockOnError = jest.fn();
|
|
33
|
-
const mockOnSuccess = jest.fn();
|
|
34
|
-
const mockPaymentFlowRef: RefObject<PaymentFlowRef> = {
|
|
35
|
-
current: {
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
37
|
-
startLegacyBoxCheckout: jest.fn().mockImplementation((_payload, callback) => {
|
|
38
|
-
callback({ status: ChargeStatus.EXECUTED, final: true });
|
|
39
|
-
}),
|
|
40
|
-
startCheckout: jest.fn(),
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
45
|
-
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
46
|
-
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
47
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, CommandStatus.SUCCESS]);
|
|
48
|
-
|
|
49
|
-
const { result } = renderHook(() =>
|
|
50
|
-
sut({
|
|
51
|
-
checkoutId,
|
|
52
|
-
checkoutBookingId,
|
|
53
|
-
paymentFlowRef: mockPaymentFlowRef,
|
|
54
|
-
onError: mockOnError,
|
|
55
|
-
onSuccess: mockOnSuccess,
|
|
56
|
-
logger,
|
|
57
|
-
}),
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
await act(async () => {
|
|
61
|
-
const [submitCheckout] = result.current;
|
|
62
|
-
await submitCheckout({ paymentFlowPayload: mockPaymentFlowPayload, sizeChangeEnabled: true });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
await waitFor(() => {
|
|
66
|
-
const [, status] = result.current;
|
|
67
|
-
|
|
68
|
-
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
69
|
-
expect(mockCreateToastNotification).not.toHaveBeenCalled();
|
|
70
|
-
expect(mockSubmitCheckout).toHaveBeenCalled();
|
|
71
|
-
|
|
72
|
-
expect(status).toBe("success");
|
|
73
|
-
expect(mockOnSuccess).toHaveBeenCalled();
|
|
74
|
-
expect(mockOnError).not.toHaveBeenCalled();
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("does not call blockCheckoutBooking if sizeChange is not enabled after calling 'submitCheckout'", async () => {
|
|
79
|
-
const mockBlockCheckoutBooking = jest.fn();
|
|
80
|
-
const mockSubmitCheckout = jest.fn();
|
|
81
|
-
const mockCreateToastNotification = jest.fn();
|
|
82
|
-
const mockOnError = jest.fn();
|
|
83
|
-
const mockPaymentFlowRef: RefObject<PaymentFlowRef> = {
|
|
84
|
-
current: {
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
86
|
-
startLegacyBoxCheckout: jest.fn().mockImplementation((_payload, callback) => {
|
|
87
|
-
callback({ status: ChargeStatus.EXECUTED, final: true });
|
|
88
|
-
}),
|
|
89
|
-
startCheckout: jest.fn(),
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
94
|
-
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
95
|
-
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
96
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, CommandStatus.SUCCESS]);
|
|
97
|
-
|
|
98
|
-
const { result } = renderHook(() =>
|
|
99
|
-
sut({ checkoutId, checkoutBookingId, paymentFlowRef: mockPaymentFlowRef, onError: mockOnError, logger }),
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
await act(async () => {
|
|
103
|
-
const [submitCheckout] = result.current;
|
|
104
|
-
await submitCheckout({ paymentFlowPayload: mockPaymentFlowPayload, sizeChangeEnabled: false });
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
await waitFor(() => {
|
|
108
|
-
const [, status] = result.current;
|
|
109
|
-
|
|
110
|
-
expect(mockBlockCheckoutBooking).not.toHaveBeenCalled();
|
|
111
|
-
expect(mockCreateToastNotification).not.toHaveBeenCalled();
|
|
112
|
-
expect(mockSubmitCheckout).toHaveBeenCalled();
|
|
113
|
-
|
|
114
|
-
expect(status).toBe("success");
|
|
115
|
-
expect(mockOnError).not.toHaveBeenCalled();
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("returns blockCheckoutBooking error as the status right after calling 'submitCheckout'", async () => {
|
|
120
|
-
const mockBlockCheckoutBooking = jest.fn();
|
|
121
|
-
const mockSubmitCheckout = jest.fn();
|
|
122
|
-
const mockCreateToastNotification = jest.fn();
|
|
123
|
-
const mockOnError = jest.fn();
|
|
124
|
-
const mockPaymentFlowRef: RefObject<PaymentFlowRef> = {
|
|
125
|
-
current: {
|
|
126
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
127
|
-
startLegacyBoxCheckout: jest.fn().mockImplementation((_payload, callback) => {
|
|
128
|
-
callback({ status: ChargeStatus.EXECUTED, final: true });
|
|
129
|
-
}),
|
|
130
|
-
startCheckout: jest.fn(),
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
135
|
-
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.ERROR]);
|
|
136
|
-
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.IDLE]);
|
|
137
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, CommandStatus.IDLE]);
|
|
138
|
-
|
|
139
|
-
const { result } = renderHook(() =>
|
|
140
|
-
sut({ checkoutId, checkoutBookingId, paymentFlowRef: mockPaymentFlowRef, onError: mockOnError, logger }),
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
await act(async () => {
|
|
144
|
-
const [submitCheckout] = result.current;
|
|
145
|
-
await submitCheckout({ paymentFlowPayload: mockPaymentFlowPayload, sizeChangeEnabled: true });
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
await waitFor(() => {
|
|
149
|
-
const [, status] = result.current;
|
|
150
|
-
|
|
151
|
-
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
152
|
-
expect(mockCreateToastNotification).not.toHaveBeenCalled();
|
|
153
|
-
expect(status).toBe("error");
|
|
154
|
-
expect(mockOnError).toHaveBeenCalled();
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test.each(errorChargeStatuses)(
|
|
159
|
-
"shows an 'error' notification when the checkout-flow fails (status %s)",
|
|
160
|
-
async (chargeStatus) => {
|
|
161
|
-
const mockBlockCheckoutBooking = jest.fn();
|
|
162
|
-
const mockSubmitCheckout = jest.fn();
|
|
163
|
-
const mockCreateToastNotification = jest.fn();
|
|
164
|
-
const mockOnError = jest.fn();
|
|
165
|
-
const mockPaymentFlowRef: RefObject<PaymentFlowRef> = {
|
|
166
|
-
current: {
|
|
167
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
168
|
-
startLegacyBoxCheckout: jest.fn().mockImplementation((_payload, callback) => {
|
|
169
|
-
callback({ status: chargeStatus, toaster: { id: `${chargeStatus}_toaster_id` }, final: true });
|
|
170
|
-
}),
|
|
171
|
-
startCheckout: jest.fn(),
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
176
|
-
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
177
|
-
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
178
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, CommandStatus.IDLE]);
|
|
179
|
-
|
|
180
|
-
const { result } = renderHook(() =>
|
|
181
|
-
sut({ checkoutId, checkoutBookingId, paymentFlowRef: mockPaymentFlowRef, onError: mockOnError, logger }),
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
await act(async () => {
|
|
185
|
-
const [submitCheckout] = result.current;
|
|
186
|
-
await submitCheckout({ paymentFlowPayload: mockPaymentFlowPayload, sizeChangeEnabled: true });
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
await waitFor(() => {
|
|
190
|
-
const [, status] = result.current;
|
|
191
|
-
|
|
192
|
-
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
193
|
-
expect(mockCreateToastNotification).toHaveBeenCalledWith(
|
|
194
|
-
expect.objectContaining({
|
|
195
|
-
level: NotificationLevel.ERROR,
|
|
196
|
-
bodyI18nKey: `${chargeStatus}_toaster_id`,
|
|
197
|
-
}),
|
|
198
|
-
);
|
|
199
|
-
expect(mockSubmitCheckout).not.toHaveBeenCalled();
|
|
200
|
-
|
|
201
|
-
expect(status).toBe("error");
|
|
202
|
-
expect(mockOnError).toHaveBeenCalled();
|
|
203
|
-
});
|
|
204
|
-
},
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
test("returns submitCheckout error as the status right after calling 'submitCheckout'", async () => {
|
|
208
|
-
const mockBlockCheckoutBooking = jest.fn();
|
|
209
|
-
const mockSubmitCheckout = jest.fn();
|
|
210
|
-
const mockCreateToastNotification = jest.fn();
|
|
211
|
-
const mockOnError = jest.fn();
|
|
212
|
-
const mockPaymentFlowRef: RefObject<PaymentFlowRef> = {
|
|
213
|
-
current: {
|
|
214
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
215
|
-
startLegacyBoxCheckout: jest.fn().mockImplementation((_payload, callback) => {
|
|
216
|
-
callback({ status: ChargeStatus.EXECUTED, final: true });
|
|
217
|
-
}),
|
|
218
|
-
startCheckout: jest.fn(),
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
223
|
-
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
224
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, CommandStatus.ERROR]);
|
|
225
|
-
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
226
|
-
|
|
227
|
-
const { result } = renderHook(() =>
|
|
228
|
-
sut({ checkoutId, checkoutBookingId, paymentFlowRef: mockPaymentFlowRef, onError: mockOnError, logger }),
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
await act(async () => {
|
|
232
|
-
const [submitCheckout] = result.current;
|
|
233
|
-
submitCheckout({ paymentFlowPayload: mockPaymentFlowPayload, sizeChangeEnabled: true });
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
await waitFor(() => {
|
|
237
|
-
const [, status] = result.current;
|
|
238
|
-
|
|
239
|
-
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
240
|
-
expect(mockCreateToastNotification).not.toHaveBeenCalled();
|
|
241
|
-
expect(mockSubmitCheckout).toHaveBeenCalled();
|
|
242
|
-
|
|
243
|
-
expect(status).toBe("error");
|
|
244
|
-
expect(mockOnError).toHaveBeenCalled();
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test("returns submitCheckout error as the status right after calling 'submitCheckout' if CheckoutBooking isExpired", async () => {
|
|
249
|
-
const mockBlockCheckoutBooking = jest.fn();
|
|
250
|
-
const mockSubmitCheckout = jest.fn();
|
|
251
|
-
const mockCreateToastNotification = jest.fn();
|
|
252
|
-
const mockOnError = jest.fn();
|
|
253
|
-
const mockOnSuccess = jest.fn();
|
|
254
|
-
const mockPaymentFlowRef: RefObject<PaymentFlowRef> = {
|
|
255
|
-
current: {
|
|
256
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
257
|
-
startLegacyBoxCheckout: jest.fn().mockImplementation((_payload, callback) => {
|
|
258
|
-
callback({ status: ChargeStatus.EXECUTED, final: true });
|
|
259
|
-
}),
|
|
260
|
-
startCheckout: jest.fn(),
|
|
261
|
-
},
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: true }) as CheckoutBookingProjection);
|
|
265
|
-
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
266
|
-
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
267
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, CommandStatus.SUCCESS]);
|
|
268
|
-
|
|
269
|
-
const { result } = renderHook(() =>
|
|
270
|
-
sut({
|
|
271
|
-
checkoutId,
|
|
272
|
-
checkoutBookingId,
|
|
273
|
-
paymentFlowRef: mockPaymentFlowRef,
|
|
274
|
-
onError: mockOnError,
|
|
275
|
-
onSuccess: mockOnSuccess,
|
|
276
|
-
logger,
|
|
277
|
-
}),
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
await act(async () => {
|
|
281
|
-
const [submitCheckout] = result.current;
|
|
282
|
-
await submitCheckout({ paymentFlowPayload: mockPaymentFlowPayload, sizeChangeEnabled: true });
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
await waitFor(() => {
|
|
286
|
-
const [, status] = result.current;
|
|
287
|
-
|
|
288
|
-
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
289
|
-
expect(mockCreateToastNotification).not.toHaveBeenCalled();
|
|
290
|
-
expect(mockSubmitCheckout).not.toHaveBeenCalled();
|
|
291
|
-
|
|
292
|
-
expect(status).toBe("error");
|
|
293
|
-
expect(mockOnSuccess).not.toHaveBeenCalled();
|
|
294
|
-
expect(mockOnError).toHaveBeenCalled();
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
});
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { RefObject, useCallback, useMemo, useState } from "react";
|
|
2
|
-
import { CommandStatus } from "@lookiero/messaging-react";
|
|
3
|
-
import { PaymentFlowRef } from "@lookiero/payments-front";
|
|
4
|
-
import { Logger } from "@lookiero/sty-psp-logging";
|
|
5
|
-
import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
|
|
6
|
-
import {
|
|
7
|
-
ViewCheckoutBookingById,
|
|
8
|
-
viewCheckoutBookingById,
|
|
9
|
-
ViewCheckoutBookingByIdResult,
|
|
10
|
-
} from "../../../projection/checkoutBooking/viewCheckoutBookingById";
|
|
11
|
-
import { PaymentFlowPayloadProjection } from "../../../projection/payment/paymentFlowPayload";
|
|
12
|
-
import { MESSAGING_CONTEXT_ID } from "../../delivery/baseBootstrap";
|
|
13
|
-
import { useSubmitCheckout as useSubmitCheckoutCommand } from "../../domain/checkout/react/useSubmitCheckout";
|
|
14
|
-
import { useBlockCheckoutBooking } from "../../domain/checkoutBooking/react/useBlockCheckoutBooking";
|
|
15
|
-
import { I18nMessages } from "../i18n/i18n";
|
|
16
|
-
import { useQueryBus } from "./useQueryBus";
|
|
17
|
-
|
|
18
|
-
enum ChargeStatus {
|
|
19
|
-
EXECUTED = "EXECUTED",
|
|
20
|
-
REQUIRES_ACTION = "REQUIRES_ACTION",
|
|
21
|
-
REQUIRED_ACTION_CANCELLED = "REQUIRED_ACTION_CANCELLED",
|
|
22
|
-
REJECTED = "REJECTED",
|
|
23
|
-
CANCELLED = "CANCELLED",
|
|
24
|
-
TO_CONFIRM = "TO_CONFIRM",
|
|
25
|
-
ERROR = "ERROR",
|
|
26
|
-
UNKNOWN = "UNKNOWN",
|
|
27
|
-
}
|
|
28
|
-
interface LegacyBoxCheckout {
|
|
29
|
-
readonly status: ChargeStatus;
|
|
30
|
-
readonly toaster: {
|
|
31
|
-
id: string;
|
|
32
|
-
} | null;
|
|
33
|
-
readonly final: boolean;
|
|
34
|
-
readonly id?: string;
|
|
35
|
-
readonly translation?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type Status = "idle" | "loading" | "success" | "error";
|
|
39
|
-
|
|
40
|
-
interface SubmitCheckoutFunctionArgs {
|
|
41
|
-
readonly paymentFlowPayload: PaymentFlowPayloadProjection;
|
|
42
|
-
readonly sizeChangeEnabled: boolean;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface SubmitCheckoutFunction {
|
|
46
|
-
(args: SubmitCheckoutFunctionArgs): Promise<void>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
type UseSubmitCheckoutResult = [submitCheckout: SubmitCheckoutFunction, status: Status];
|
|
50
|
-
|
|
51
|
-
interface UseSubmitCheckoutFunctionArgs {
|
|
52
|
-
readonly checkoutId: string;
|
|
53
|
-
readonly checkoutBookingId: string;
|
|
54
|
-
readonly paymentFlowRef: RefObject<PaymentFlowRef>;
|
|
55
|
-
readonly onError: () => void;
|
|
56
|
-
readonly onSuccess?: () => void;
|
|
57
|
-
readonly logger: Logger;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
interface UseSubmitCheckoutFunction {
|
|
61
|
-
(args: UseSubmitCheckoutFunctionArgs): UseSubmitCheckoutResult;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const useSubmitCheckout: UseSubmitCheckoutFunction = ({
|
|
65
|
-
checkoutId,
|
|
66
|
-
checkoutBookingId,
|
|
67
|
-
paymentFlowRef,
|
|
68
|
-
onError,
|
|
69
|
-
onSuccess,
|
|
70
|
-
logger,
|
|
71
|
-
}) => {
|
|
72
|
-
const queryBus = useQueryBus();
|
|
73
|
-
const [submitCheckoutCommand, submitCheckoutCommandStatus] = useSubmitCheckoutCommand({ checkoutId, logger });
|
|
74
|
-
const [blockCheckoutBooking, blockCheckoutBookingStatus] = useBlockCheckoutBooking({ checkoutBookingId, logger });
|
|
75
|
-
const [createNotification] = useCreateToastNotification({ contextId: MESSAGING_CONTEXT_ID, logger });
|
|
76
|
-
const [checkoutBookingExpired, setCheckoutBookingExpired] = useState(false);
|
|
77
|
-
|
|
78
|
-
const [startLegacyBoxCheckoutStatus, setStartLegacyBoxCheckoutStatus] = useState<Status>("idle");
|
|
79
|
-
|
|
80
|
-
const submitCheckout: SubmitCheckoutFunction = useCallback(
|
|
81
|
-
async ({ paymentFlowPayload, sizeChangeEnabled }) => {
|
|
82
|
-
try {
|
|
83
|
-
sizeChangeEnabled && (await blockCheckoutBooking());
|
|
84
|
-
} catch (error) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const checkoutBooking = await queryBus<ViewCheckoutBookingById, ViewCheckoutBookingByIdResult>(
|
|
89
|
-
viewCheckoutBookingById({ checkoutBookingId }),
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
if (checkoutBooking?.isExpired) {
|
|
93
|
-
setCheckoutBookingExpired(true);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
paymentFlowRef.current?.startLegacyBoxCheckout(
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
99
|
-
// @ts-ignore
|
|
100
|
-
paymentFlowPayload,
|
|
101
|
-
async ({ status, toaster, final }: LegacyBoxCheckout) => {
|
|
102
|
-
setStartLegacyBoxCheckoutStatus("loading");
|
|
103
|
-
|
|
104
|
-
if (final) {
|
|
105
|
-
if (status === ChargeStatus.EXECUTED) {
|
|
106
|
-
setStartLegacyBoxCheckoutStatus("success");
|
|
107
|
-
await submitCheckoutCommand();
|
|
108
|
-
onSuccess?.();
|
|
109
|
-
} else {
|
|
110
|
-
createNotification({
|
|
111
|
-
level: NotificationLevel.ERROR,
|
|
112
|
-
bodyI18nKey: toaster?.id || I18nMessages.CHECKOUT_TOAST_PAYMENT_ERROR,
|
|
113
|
-
});
|
|
114
|
-
setStartLegacyBoxCheckoutStatus("error");
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
);
|
|
119
|
-
},
|
|
120
|
-
[
|
|
121
|
-
queryBus,
|
|
122
|
-
checkoutBookingId,
|
|
123
|
-
paymentFlowRef,
|
|
124
|
-
blockCheckoutBooking,
|
|
125
|
-
submitCheckoutCommand,
|
|
126
|
-
onSuccess,
|
|
127
|
-
createNotification,
|
|
128
|
-
],
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const status: Status = useMemo(() => {
|
|
132
|
-
if (
|
|
133
|
-
blockCheckoutBookingStatus === CommandStatus.LOADING ||
|
|
134
|
-
startLegacyBoxCheckoutStatus === "loading" ||
|
|
135
|
-
submitCheckoutCommandStatus === CommandStatus.LOADING
|
|
136
|
-
) {
|
|
137
|
-
return "loading";
|
|
138
|
-
}
|
|
139
|
-
if (
|
|
140
|
-
blockCheckoutBookingStatus === CommandStatus.SUCCESS &&
|
|
141
|
-
startLegacyBoxCheckoutStatus === "success" &&
|
|
142
|
-
submitCheckoutCommandStatus === CommandStatus.SUCCESS
|
|
143
|
-
) {
|
|
144
|
-
return "success";
|
|
145
|
-
}
|
|
146
|
-
if (
|
|
147
|
-
blockCheckoutBookingStatus === CommandStatus.ERROR ||
|
|
148
|
-
startLegacyBoxCheckoutStatus === "error" ||
|
|
149
|
-
submitCheckoutCommandStatus === CommandStatus.ERROR ||
|
|
150
|
-
checkoutBookingExpired
|
|
151
|
-
) {
|
|
152
|
-
onError();
|
|
153
|
-
return "error";
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return "idle";
|
|
157
|
-
}, [
|
|
158
|
-
blockCheckoutBookingStatus,
|
|
159
|
-
startLegacyBoxCheckoutStatus,
|
|
160
|
-
submitCheckoutCommandStatus,
|
|
161
|
-
checkoutBookingExpired,
|
|
162
|
-
onError,
|
|
163
|
-
]);
|
|
164
|
-
|
|
165
|
-
return [submitCheckout, status];
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
export type { Status, SubmitCheckoutFunction };
|
|
169
|
-
export { useSubmitCheckout };
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { waitFor } from "@testing-library/react-native";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { QueryStatus } from "@lookiero/messaging-react";
|
|
4
|
-
import { Country } from "@lookiero/sty-psp-locale";
|
|
5
|
-
import { Segment } from "@lookiero/sty-psp-segment";
|
|
6
|
-
import { CheckoutItemStatus } from "../../../../../../domain/checkoutItem/model/checkoutItem";
|
|
7
|
-
import { checkout } from "../../../../../projection/checkout/checkout.mock";
|
|
8
|
-
import { useViewFirstAvailableCheckoutByCustomerId } from "../../../../../projection/checkout/react/useViewFirstAvailableCheckoutByCustomerId";
|
|
9
|
-
import { useViewIsSizeChangeEnabledByCheckoutId } from "../../../../../projection/checkout/react/useViewIsSizeChangeEnabledByCheckoutId";
|
|
10
|
-
import { paymentFlowPayload as mockPaymentFlowPayload } from "../../../../../projection/payment/paymentFlowPayload.mock";
|
|
11
|
-
import { useViewPaymentFlowPayloadByCheckoutId } from "../../../../../projection/payment/react/useViewPaymentFlowPayloadByCheckoutId";
|
|
12
|
-
import { pricing } from "../../../../../projection/pricing/pricing.mock";
|
|
13
|
-
import { useViewPricingByCheckoutId } from "../../../../../projection/pricing/react/useViewPricingByCheckoutId";
|
|
14
|
-
import { useSubmitCheckout } from "../../../../hooks/useSubmitCheckout";
|
|
15
|
-
import { Routes } from "../../../../routing/routes";
|
|
16
|
-
import { render } from "../../../../test/render";
|
|
17
|
-
import { CheckoutPaymentModal } from "./CheckoutPaymentModal";
|
|
18
|
-
|
|
19
|
-
const customerId = "a8fff6d7-708c-41a7-b42a-58c5706d33df";
|
|
20
|
-
const country = Country.ES;
|
|
21
|
-
const segment = Segment.WOMEN;
|
|
22
|
-
const orderNumber = 3691625;
|
|
23
|
-
const isFirstOrder = false;
|
|
24
|
-
const getAuthToken = () => Promise.resolve("token");
|
|
25
|
-
const mockCheckout = checkout({
|
|
26
|
-
items: [
|
|
27
|
-
{ status: CheckoutItemStatus.RETURNED },
|
|
28
|
-
{ status: CheckoutItemStatus.KEPT },
|
|
29
|
-
{ status: CheckoutItemStatus.KEPT },
|
|
30
|
-
{ status: CheckoutItemStatus.KEPT },
|
|
31
|
-
{ status: CheckoutItemStatus.REPLACED },
|
|
32
|
-
],
|
|
33
|
-
});
|
|
34
|
-
const mockPricing = pricing();
|
|
35
|
-
|
|
36
|
-
jest.mock("../../../../hooks/useStaticInfo", () => ({
|
|
37
|
-
useStaticInfo: () => ({
|
|
38
|
-
customer: { customerId, country, segment },
|
|
39
|
-
basePath: "",
|
|
40
|
-
}),
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
jest.mock("../../../../../projection/checkout/react/useViewFirstAvailableCheckoutByCustomerId");
|
|
44
|
-
jest.mock("../../../../../projection/payment/react/useViewPaymentFlowPayloadByCheckoutId");
|
|
45
|
-
jest.mock("../../../../../projection/checkout/react/useViewIsSizeChangeEnabledByCheckoutId");
|
|
46
|
-
jest.mock("../../../../../projection/pricing/react/useViewPricingByCheckoutId");
|
|
47
|
-
jest.mock("../../../../hooks/useSubmitCheckout");
|
|
48
|
-
jest.mock("../../../../../tracking/useTrackCheckout");
|
|
49
|
-
|
|
50
|
-
const mockStartLegacyBoxCheckout = jest.fn();
|
|
51
|
-
jest.mock("@lookiero/payments-front", () => {
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
53
|
-
const { useImperativeHandle, forwardRef } = require("react");
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
CheckoutStatus: {
|
|
57
|
-
REJECTED: "REJECTED",
|
|
58
|
-
ERROR: "ERROR",
|
|
59
|
-
FULFILLED: "FULFILLED",
|
|
60
|
-
},
|
|
61
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention, react/display-name
|
|
64
|
-
PaymentFlow: forwardRef((params, ref) => {
|
|
65
|
-
useImperativeHandle(ref, () => ({
|
|
66
|
-
startLegacyBoxCheckout: mockStartLegacyBoxCheckout,
|
|
67
|
-
}));
|
|
68
|
-
|
|
69
|
-
return null;
|
|
70
|
-
}),
|
|
71
|
-
PaymentMethod: {
|
|
72
|
-
["GOOGLE_PAY"]: "google_pay",
|
|
73
|
-
},
|
|
74
|
-
Section: {
|
|
75
|
-
["BOX_CHECKOUT"]: "box-checkout",
|
|
76
|
-
},
|
|
77
|
-
PaymentInstrumentSelect: jest.fn(() => <></>),
|
|
78
|
-
};
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const mockUseNavigate = jest.fn();
|
|
82
|
-
jest.mock("react-router-native", () => ({
|
|
83
|
-
...jest.requireActual("react-router-native"),
|
|
84
|
-
useNavigate: () => mockUseNavigate,
|
|
85
|
-
}));
|
|
86
|
-
|
|
87
|
-
describe("CheckoutPaymentModal component", () => {
|
|
88
|
-
it("renders correctly", async () => {
|
|
89
|
-
const mockSubmitCheckout = jest.fn();
|
|
90
|
-
(useViewFirstAvailableCheckoutByCustomerId as jest.Mock).mockReturnValue([mockCheckout, QueryStatus.SUCCESS]);
|
|
91
|
-
(useViewPaymentFlowPayloadByCheckoutId as jest.Mock).mockReturnValue([mockPaymentFlowPayload, QueryStatus.SUCCESS]);
|
|
92
|
-
(useViewIsSizeChangeEnabledByCheckoutId as jest.Mock).mockReturnValue([true, QueryStatus.SUCCESS]);
|
|
93
|
-
(useViewPricingByCheckoutId as jest.Mock).mockReturnValue([mockPricing, QueryStatus.SUCCESS]);
|
|
94
|
-
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, "success"]);
|
|
95
|
-
|
|
96
|
-
await waitFor(() => {
|
|
97
|
-
render(
|
|
98
|
-
<CheckoutPaymentModal
|
|
99
|
-
coupon={null}
|
|
100
|
-
getAuthToken={getAuthToken}
|
|
101
|
-
isFirstOrder={isFirstOrder}
|
|
102
|
-
orderNumber={orderNumber}
|
|
103
|
-
subscription="b"
|
|
104
|
-
/>,
|
|
105
|
-
);
|
|
106
|
-
expect(mockSubmitCheckout).toHaveBeenCalled();
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("navigates back to /checkout when checkout-flow fails", async () => {
|
|
111
|
-
(useViewFirstAvailableCheckoutByCustomerId as jest.Mock).mockReturnValue([mockCheckout, QueryStatus.SUCCESS]);
|
|
112
|
-
(useViewPaymentFlowPayloadByCheckoutId as jest.Mock).mockReturnValue([mockPaymentFlowPayload, QueryStatus.SUCCESS]);
|
|
113
|
-
(useViewIsSizeChangeEnabledByCheckoutId as jest.Mock).mockReturnValue([true, QueryStatus.SUCCESS]);
|
|
114
|
-
(useViewPricingByCheckoutId as jest.Mock).mockReturnValue([mockPricing, QueryStatus.SUCCESS]);
|
|
115
|
-
(useSubmitCheckout as jest.Mock).mockImplementation(({ onError }) => {
|
|
116
|
-
const submitCheckout = () => onError();
|
|
117
|
-
|
|
118
|
-
return [submitCheckout, "error"];
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
await waitFor(() => {
|
|
122
|
-
render(
|
|
123
|
-
<CheckoutPaymentModal
|
|
124
|
-
coupon={null}
|
|
125
|
-
getAuthToken={getAuthToken}
|
|
126
|
-
isFirstOrder={isFirstOrder}
|
|
127
|
-
orderNumber={orderNumber}
|
|
128
|
-
subscription="b"
|
|
129
|
-
/>,
|
|
130
|
-
);
|
|
131
|
-
expect(mockUseNavigate).toHaveBeenCalledWith(`/${Routes.CHECKOUT}`, { replace: true });
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
});
|