如何在Vue测试中Mock第三方Window对象?解决createMidtransToken方法测试报错问题
createMidtransToken Method in Your Vue Component The error you're seeing happens because your current way of defining window.MidtransNew3ds is incorrect—you're not properly setting up the object that contains the getCardToken mock function. Let's break down the fix and build out a complete test suite for this method.
Step 1: Fix the window.MidtransNew3ds Mock
Your original Object.defineProperty usage is misconfigured. Instead, directly assign a mock object to window.MidtransNew3ds before your tests, and clean it up afterward to avoid cross-test contamination.
// In your CheckoutButton.spec.js import { shallowMount } from '@vue/test-utils'; import CheckoutButton from '@/components/CheckoutButton.vue'; describe('CheckoutButton', () => { let wrapper; beforeEach(() => { // Initialize the mock MidtransNew3ds object before each test window.MidtransNew3ds = { getCardToken: jest.fn() }; // Mount the component with necessary mocks wrapper = shallowMount(CheckoutButton, { global: { mocks: { $store: { state: { payment: { creditCardPayload: { number: '4111111111111111', expiry_month: '12', expiry_year: '2025' } } } }, $alertModal: { show: jest.fn() } }, data() { return { paymentTypeChoosen: { type: 'credit_card' } }; }, methods: { payCheckout: jest.fn(), handleRouteError: jest.fn() } } }); }); afterEach(() => { // Clean up the mock after each test delete window.MidtransNew3ds; jest.clearAllMocks(); wrapper.unmount(); }); // Your initial test, now working it('Should call MidtransNew3ds.getCardToken when createMidtransToken runs', () => { wrapper.vm.createMidtransToken(); expect(window.MidtransNew3ds.getCardToken).toHaveBeenCalled(); // Optional: Verify it's called with the correct parameters expect(window.MidtransNew3ds.getCardToken).toHaveBeenCalledWith( wrapper.vm.$store.state.payment.creditCardPayload, expect.objectContaining({ onSuccess: expect.any(Function), onFailure: expect.any(Function) }) ); }); });
Step 2: Test Success and Failure Scenarios
To make your tests comprehensive, verify that the callback functions work as expected:
Test Success Callback
it('Should trigger payCheckout with the correct payload on token success', () => { const mockTokenId = 'midtrans-token-12345'; // Mock getCardToken to trigger the onSuccess callback window.MidtransNew3ds.getCardToken.mockImplementation((card, options) => { options.onSuccess({ token_id: mockTokenId }); }); wrapper.vm.createMidtransToken(); expect(wrapper.vm.payCheckout).toHaveBeenCalledWith({ ...wrapper.vm.paymentTypeChoosen, token: mockTokenId }); });
Test Failure Callback
it('Should show error alert when token creation fails', () => { const mockErrorMessage = 'Invalid card details'; // Mock getCardToken to trigger the onFailure callback window.MidtransNew3ds.getCardToken.mockImplementation((card, options) => { options.onFailure({ status_message: mockErrorMessage }); }); wrapper.vm.createMidtransToken(); expect(wrapper.vm.$alertModal.show).toHaveBeenCalledWith(expect.objectContaining({ type: 'error', title: 'Transaksi Dibatalkan', text: mockErrorMessage, buttonEvent: expect.any(Function) })); // Optional: Test the button event triggers handleRouteError const alertOptions = wrapper.vm.$alertModal.show.mock.calls[0][0]; alertOptions.buttonEvent(); expect(wrapper.vm.handleRouteError).toHaveBeenCalled(); });
Why Your Original Code Failed
Your original Object.defineProperty call tried to set getCardToken as a property of window.MidtransNew3ds, but you never actually created the MidtransNew3ds object itself. By directly assigning window.MidtransNew3ds = { getCardToken: jest.fn() }, you properly define the object and its mock method.
内容的提问来源于stack exchange,提问作者Jalu Wibowo

