#node.js #jestjs #stripe-payments
#node.js #jestjs #stripe-платежи
Вопрос:
Я хотел бы издеваться над node Stripe SDK в Jest, потому что я не хочу запускать макет сервера API из Stripe, но я не могу понять, как это сделать. Я создаю __mocks__
каталог и добавляю stripe.js
, но не могу получить ничего полезного для экспорта.
Обычно я получаю TypeError: Cannot read property 'create' of undefined
при вызове strypegw.charges.create()
. Я использую синтаксис модуля ES6, поэтому я import stripe from 'stripe'
.
Комментарии:
1. Что именно ты пытаешься?
2. вам также придется издеваться над
resources
в Stripe-Node. Либо вручную добавьте все ресурсы в stripe.js или издеваться над ними в соответствии с github.com/stripe/stripe-node/blob/master/lib/stripe.js#L3423. Вы могли бы использовать сервис, подобный этому , где вы можете легко выполнять HTTP-вызовы из своих тестов. Может быть проще, чем макеты.
4. На самом деле это отличный вопрос, потому что не так просто создать макет Stripe «наилучшим практическим способом», если вы используете зависимость от узла. Я добавлю ответ для решения этой проблемы ниже.
Ответ №1:
// your-code.js
const stripe = require('stripe')('key');
const customer = await stripe.customers.create({
...
});
// __mocks__/stripe.js
class Stripe {}
const stripe = jest.fn(() => new Stripe());
module.exports = stripe;
module.exports.Stripe = Stripe;
// stripe.tests.js
const { Stripe } = require('stripe');
const createCustomerMock = jest.fn(() => ({
id: 1,
...
}));
Stripe.prototype.customers = {
create: createCustomerMock,
};
Комментарии:
1. Спасибо Сергею . После долгих исследований это решение работает для меня. Я пытался издеваться над модулем stripe, но безуспешно. У меня это работает нормально.
2. тем, кто безуспешно пытается это сделать, убедитесь, что согласно документам ,
__mocks__
каталог находится рядом с вашим файлом3. Как мне изменить макет, если я хочу использовать некоторые вложенные методы, такие как stripe.checkout.sessions.create?
4. @AleisterCrowley Я думаю, что что-то вроде
Stripe.prototype.checkout = { sessions: { create: createSessionMock, } };
5. Это не останавливает библиотеку Stripe от выполнения вызова API. Таким образом, вы по-прежнему получаете ошибки «Вы не предоставили ключ API»
Ответ №2:
Вот простое решение :
jest.mock("stripe", () => {
return jest.fn().mockImplementation(function {
return {
charges: {
create: () => "fake stripe response",
},
};
});
});
Я нашел это в документации jest о макетах класса ES6
Комментарии:
1. На самом деле это не сработало, когда я его тестировал. Я продолжал получать ошибку при вызове конструктора вот так
const stripe = new Stripe();
. Другой ответ от @Sergey, похоже, сработал. Есть ли причина, по которой это было бы так?2. да, у меня тоже самое — Сергей сработал. хотелось бы получить ответ на этот
Ответ №3:
Добавьте это во вспомогательную функцию и при необходимости вызовите ее в файле настройки jest или в верхней части теста.
// Mocking Stripe object
const elementMock = {
mount: jest.fn(),
destroy: jest.fn(),
on: jest.fn(),
update: jest.fn(),
};
const elementsMock = {
create: jest.fn().mockReturnValue(elementMock),
};
const stripeMock = {
elements: jest.fn().mockReturnValue(elementsMock),
createToken: jest.fn(() => Promise.resolve()),
createSource: jest.fn(() => Promise.resolve()),
};
// Set the global Stripe
window.Stripe = jest.fn().mockReturnValue(stripeMock);
При таком подходе вы также можете легко протестировать свой код, связанный с stripe
// Ex. of a token successfully created mock
stripeMock.createToken.mockResolvedValue({
token: {
id: 'test_id',
},
});
// Ex. of a failure mock
stripeMock.createToken.mockResolvedValue({
error: {
code: 'incomplete_number',
message: 'Your card number is incomplete.',
type: 'validation_error',
},
});
Ответ №4:
Начиная с stripe@9.6.0
, вы можете добавить direct spyOn
в Customer
класс вместо переопределения всего класса Stripe.
Короткий ответ:
jest.mock('stripe', () => {
const stripe = jest.requireActual('stripe');
jest.spyOn(stripe.resources.Customers.prototype, 'create')
.mockImplementation(() => (
Promise.resolve({id: 'stripe-test-id'})
));
return stripe;
})
Длинный ответ:
- Вы не хотите переопределять класс main
Stripe
, потому что существует множество статических значений и служебных помощников, которые может использовать ваше приложение, таких какStripe.errors.StripeError
. Было бы излишним издеваться над вещами, которые не нуждаются в издевательстве. - Причина, по которой
Stripe.prototype.customer
не работает, потому что.customer
это не метод до создания экземпляра. Смотрите https://github.com/stripe/stripe-node/blob/master/lib/stripe.js#L124 - К счастью, Stripe предоставляет свои ресурсы статически через
Stripe.resources
. Таким образом, вы можете напрямую следить за ресурсами. Когда создается экземпляр реального Stripe, он будет ссылаться на spies вместо реального класса для конкретного ресурса, который вы пытаетесь имитировать. Смотрите https://github.com/stripe/stripe-node/blob/master/lib/stripe.js#L51 - Быстрый и грязный способ издеваться над целым ресурсом — переопределить ссылки на ресурсы следующим образом:
Stripe.resources.Customers = {create: jest.fn()};
. Я бы не рекомендовал этого по причинам, указанным в пункте 1.