Node.js TypeScript环境下使用Jest模拟Stripe API遇到的问题
Let's break down why your current approaches aren't working and fix them step by step. The core issue here is that your stripe.ts module exports a pre-initialized Stripe instance, not the Stripe constructor function. Your mock setups weren't matching this export structure, leading to the undefined error.
Why Your Original Methods Failed
- Method 1 (mocks directory): You mocked the Stripe constructor, but your business code imports the already-created instance from
stripe.ts, not the constructor itself. ModifyingStripe.prototypehad no effect on the instance your code was actually using. - Method 2 (Direct test mock): You returned a function from your mock instead of an object matching the Stripe instance structure. Your code tried to access
stripe.customerson a function, which doesn't have that property—hence the undefined error.
Solution 1: Use a mocks Directory Correctly
Since your module exports an instance, your mock should export a matching mock instance.
Step 1: Create the Mock File
Create src/payment-gateways/__mocks__/stripe.ts (note the directory placement: it should sit alongside the real stripe.ts, not in your tests folder):
// src/payment-gateways/__mocks__/stripe.ts const mockCustomerCreate = jest.fn(() => Promise.resolve({ id: 'test-customer-123' })); export default { customers: { create: mockCustomerCreate } };
Step 2: Use the Mock in Your Test
In stripe.test.ts, tell Jest to use your mock and assert against it:
// src/tests/stripe.test.ts import stripe from '../../payment-gateways/stripe'; // Enable the mock for the stripe module jest.mock('../../payment-gateways/stripe'); describe('stripe workflow', () => { beforeEach(() => { // Reset mock calls between tests to avoid cross-test pollution jest.clearAllMocks(); }); it('creates a customer', async () => { // Execute your business logic (e.g., Apollo mutation) await apollo.mutate({ /* your mutation details */ }); // Assert the create method was called expect(stripe.customers.create).toHaveBeenCalled(); // Optional: Assert with specific expected parameters expect(stripe.customers.create).toHaveBeenCalledWith({ email: 'test@example.com', // Add other expected fields here }); }); });
Solution 2: Direct Mock in the Test File
If you prefer not to use a mocks directory, adjust your direct mock to return an object matching the Stripe instance structure (not a function):
// src/tests/stripe.test.ts // Mock the stripe module directly, returning a mock instance jest.mock('../../payment-gateways/stripe', () => ({ customers: { create: jest.fn(() => Promise.resolve({ id: 'test-customer-123' })) } })); import stripe from '../../payment-gateways/stripe'; describe('stripe workflow', () => { beforeEach(() => { jest.clearAllMocks(); }); it('creates a customer', async () => { await apollo.mutate({ /* your mutation details */ }); expect(stripe.customers.create).toHaveBeenCalled(); }); });
Key Takeaways
- Always match your mock structure to what your module actually exports. Since
stripe.tsexports an instance, your mock must be an object with the same properties (likecustomers.create). - Use
jest.clearAllMocks()inbeforeEachto reset mock state between tests, ensuring clean test runs. - If you need to mock more Stripe methods later, just extend the mock object with additional properties (e.g.,
charges: { create: jest.fn() }).
内容的提问来源于stack exchange,提问作者PmmZenha

