|
|
@@ -10,7 +10,9 @@ import { CREATE_PRODUCT, CREATE_PRODUCT_VARIANTS } from '@vendure/core/e2e/graph
|
|
|
import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN } from '@vendure/testing';
|
|
|
import gql from 'graphql-tag';
|
|
|
import nock from 'nock';
|
|
|
+import fetch from 'node-fetch';
|
|
|
import path from 'path';
|
|
|
+import { Stripe } from 'stripe';
|
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
|
|
|
|
import { initialData } from '../../../e2e-common/e2e-initial-data';
|
|
|
@@ -293,6 +295,101 @@ describe('Stripe payments', () => {
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ // https://github.com/vendure-ecommerce/vendure/issues/2450
|
|
|
+ it('Should not crash on signature validation failure', async () => {
|
|
|
+ const MOCKED_WEBHOOK_PAYLOAD = {
|
|
|
+ id: 'evt_0',
|
|
|
+ object: 'event',
|
|
|
+ api_version: '2022-11-15',
|
|
|
+ data: {
|
|
|
+ object: {
|
|
|
+ id: 'pi_0',
|
|
|
+ currency: 'usd',
|
|
|
+ status: 'succeeded',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ livemode: false,
|
|
|
+ pending_webhooks: 1,
|
|
|
+ request: {
|
|
|
+ id: 'req_0',
|
|
|
+ idempotency_key: '00000000-0000-0000-0000-000000000000',
|
|
|
+ },
|
|
|
+ type: 'payment_intent.succeeded',
|
|
|
+ };
|
|
|
+
|
|
|
+ const payloadString = JSON.stringify(MOCKED_WEBHOOK_PAYLOAD, null, 2);
|
|
|
+
|
|
|
+ const result = await fetch(`http://localhost:${serverPort}/payments/stripe`, {
|
|
|
+ method: 'post',
|
|
|
+ body: payloadString,
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
+ });
|
|
|
+
|
|
|
+ // We didn't provided any signatures, it should result in a 400 - Bad request
|
|
|
+ expect(result.status).toEqual(400);
|
|
|
+ });
|
|
|
+
|
|
|
+ // TODO: Contribution welcome: test webhook handling and order settlement
|
|
|
+ // https://github.com/vendure-ecommerce/vendure/issues/2450
|
|
|
+ it("Should validate the webhook's signature properly", async () => {
|
|
|
+ await shopClient.asUserWithCredentials(customers[0].emailAddress, 'test');
|
|
|
+
|
|
|
+ const { activeOrder } = await shopClient.query<GetActiveOrderQuery>(GET_ACTIVE_ORDER);
|
|
|
+ order = activeOrder!;
|
|
|
+
|
|
|
+ const MOCKED_WEBHOOK_PAYLOAD = {
|
|
|
+ id: 'evt_0',
|
|
|
+ object: 'event',
|
|
|
+ api_version: '2022-11-15',
|
|
|
+ data: {
|
|
|
+ object: {
|
|
|
+ id: 'pi_0',
|
|
|
+ currency: 'usd',
|
|
|
+ metadata: {
|
|
|
+ orderCode: order.code,
|
|
|
+ orderId: parseInt(order.id.replace('T_', ''), 10),
|
|
|
+ channelToken: E2E_DEFAULT_CHANNEL_TOKEN,
|
|
|
+ },
|
|
|
+ amount_received: order.totalWithTax,
|
|
|
+ status: 'succeeded',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ livemode: false,
|
|
|
+ pending_webhooks: 1,
|
|
|
+ request: {
|
|
|
+ id: 'req_0',
|
|
|
+ idempotency_key: '00000000-0000-0000-0000-000000000000',
|
|
|
+ },
|
|
|
+ type: 'payment_intent.succeeded',
|
|
|
+ };
|
|
|
+
|
|
|
+ const payloadString = JSON.stringify(MOCKED_WEBHOOK_PAYLOAD, null, 2);
|
|
|
+ const stripeWebhooks = new Stripe('test-api-secret', { apiVersion: '2023-08-16' }).webhooks;
|
|
|
+ const header = stripeWebhooks.generateTestHeaderString({
|
|
|
+ payload: payloadString,
|
|
|
+ secret: 'test-signing-secret',
|
|
|
+ });
|
|
|
+
|
|
|
+ const event = stripeWebhooks.constructEvent(payloadString, header, 'test-signing-secret');
|
|
|
+ expect(event.id).to.equal(MOCKED_WEBHOOK_PAYLOAD.id);
|
|
|
+ await setShipping(shopClient);
|
|
|
+ // Due to the `this.orderService.transitionToState(...)` fails with the internal lookup by id,
|
|
|
+ // we need to put the order into `ArrangingPayment` state manually before calling the webhook handler.
|
|
|
+ // const transitionResult = await adminClient.query(TRANSITION_TO_ARRANGING_PAYMENT, { id: order.id });
|
|
|
+ // expect(transitionResult.transitionOrderToState.__typename).toBe('Order')
|
|
|
+
|
|
|
+ const result = await fetch(`http://localhost:${serverPort}/payments/stripe`, {
|
|
|
+ method: 'post',
|
|
|
+ body: payloadString,
|
|
|
+ headers: { 'Content-Type': 'application/json', 'Stripe-Signature': header },
|
|
|
+ });
|
|
|
+
|
|
|
+ // I would expect to the status to be 200, but at the moment either the
|
|
|
+ // `orderService.transitionToState()` or the `orderService.addPaymentToOrder()`
|
|
|
+ // throws an error of 'error.entity-with-id-not-found'
|
|
|
+ expect(result.status).toEqual(200);
|
|
|
+ });
|
|
|
+
|
|
|
// https://github.com/vendure-ecommerce/vendure/issues/1630
|
|
|
describe('currencies with no fractional units', () => {
|
|
|
let japanProductId: string;
|
|
|
@@ -401,6 +498,4 @@ describe('Stripe payments', () => {
|
|
|
expect(createPaymentIntentPayload.currency).toBe('jpy');
|
|
|
});
|
|
|
});
|
|
|
-
|
|
|
- // TODO: Contribution welcome: test webhook handling and order settlement
|
|
|
});
|