From fdd9022376dcd95475918800e22fb39713e2a48a Mon Sep 17 00:00:00 2001 From: Stevche Radevski Date: Mon, 3 Jun 2024 17:04:18 +0200 Subject: [PATCH] chore: Move payment tests to http folder (#7588) --- .../api/__tests__/admin/payment-collection.js | 221 --------------- .../api/__tests__/admin/payment.js | 262 ------------------ .../admin/payment-collection.spec.ts | 128 +++++++++ .../__tests__/payment/admin/payment.spec.ts | 120 ++++++++ packages/core/types/src/payment/common.ts | 4 +- .../src/api/admin/payments/validators.ts | 1 + 6 files changed, 251 insertions(+), 485 deletions(-) delete mode 100644 integration-tests/api/__tests__/admin/payment-collection.js delete mode 100644 integration-tests/api/__tests__/admin/payment.js create mode 100644 integration-tests/http/__tests__/payment-collection/admin/payment-collection.spec.ts create mode 100644 integration-tests/http/__tests__/payment/admin/payment.spec.ts diff --git a/integration-tests/api/__tests__/admin/payment-collection.js b/integration-tests/api/__tests__/admin/payment-collection.js deleted file mode 100644 index 739d2a336f..0000000000 --- a/integration-tests/api/__tests__/admin/payment-collection.js +++ /dev/null @@ -1,221 +0,0 @@ -const path = require("path") - -const startServerWithEnvironment = - require("../../../environment-helpers/start-server-with-environment").default -const { useApi } = require("../../../environment-helpers/use-api") -const { useDb } = require("../../../environment-helpers/use-db") -const adminSeeder = require("../../../helpers/admin-seeder") - -const { - simplePaymentCollectionFactory, -} = require("../../../factories/simple-payment-collection-factory") - -jest.setTimeout(30000) - -const adminHeaders = { - headers: { - "x-medusa-access-token": "test_token", - }, -} - -describe("/admin/payment-collections", () => { - let medusaProcess - let dbConnection - - let payCol = null - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..")) - const [process, connection] = await startServerWithEnvironment({ - cwd, - }) - dbConnection = connection - medusaProcess = process - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - - medusaProcess.kill() - }) - - describe("GET /admin/payment-collections/:id", () => { - beforeEach(async () => { - await adminSeeder(dbConnection) - - payCol = await simplePaymentCollectionFactory(dbConnection, { - description: "paycol description", - amount: 10000, - }) - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - it("gets payment collection", async () => { - const api = useApi() - - const response = await api.get( - `/admin/payment-collections/${payCol.id}`, - adminHeaders - ) - - expect(response.data.payment_collection).toEqual( - expect.objectContaining({ - id: payCol.id, - type: "order_edit", - status: "not_paid", - description: "paycol description", - amount: 10000, - }) - ) - - expect(response.status).toEqual(200) - }) - }) - - describe("POST /admin/payment-collections/:id", () => { - beforeEach(async () => { - await adminSeeder(dbConnection) - - payCol = await simplePaymentCollectionFactory(dbConnection, { - description: "paycol description", - amount: 10000, - }) - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - it("updates a payment collection", async () => { - const api = useApi() - - const response = await api.post( - `/admin/payment-collections/${payCol.id}`, - { - description: "new description", - metadata: { - a: 1, - b: [1, 2, "3"], - }, - }, - adminHeaders - ) - - expect(response.data.payment_collection).toEqual( - expect.objectContaining({ - id: payCol.id, - type: "order_edit", - amount: 10000, - description: "new description", - metadata: { - a: 1, - b: [1, 2, "3"], - }, - authorized_amount: null, - }) - ) - - expect(response.status).toEqual(200) - }) - }) - - describe("POST /admin/payment-collections/:id/authorize", () => { - beforeEach(async () => { - await adminSeeder(dbConnection) - - payCol = await simplePaymentCollectionFactory(dbConnection, { - description: "paycol description", - amount: 10000, - }) - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - it("marks a payment collection as authorized", async () => { - const api = useApi() - - const response = await api.post( - `/admin/payment-collections/${payCol.id}/authorize`, - undefined, - adminHeaders - ) - - expect(response.data.payment_collection).toEqual( - expect.objectContaining({ - id: payCol.id, - type: "order_edit", - status: "authorized", - description: "paycol description", - amount: 10000, - authorized_amount: 10000, - }) - ) - - expect(response.status).toEqual(200) - }) - }) - - describe("DELETE /admin/payment-collections/:id", () => { - beforeEach(async () => { - await adminSeeder(dbConnection) - - payCol = await simplePaymentCollectionFactory(dbConnection, { - description: "paycol description", - amount: 10000, - }) - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - it("delete a payment collection", async () => { - const api = useApi() - - const response = await api.delete( - `/admin/payment-collections/${payCol.id}`, - adminHeaders - ) - - expect(response.data).toEqual({ - id: `${payCol.id}`, - deleted: true, - object: "payment_collection", - }) - - expect(response.status).toEqual(200) - }) - - it("throws error when deleting an authorized payment collection", async () => { - const api = useApi() - - await api.post( - `/admin/payment-collections/${payCol.id}/authorize`, - undefined, - adminHeaders - ) - - try { - await api.delete( - `/admin/payment-collections/${payCol.id}`, - adminHeaders - ) - - expect(1).toBe(2) // should be ignored - } catch (res) { - expect(res.response.data.message).toBe( - "Cannot delete payment collection with status authorized" - ) - } - }) - }) -}) diff --git a/integration-tests/api/__tests__/admin/payment.js b/integration-tests/api/__tests__/admin/payment.js deleted file mode 100644 index 4b02461a41..0000000000 --- a/integration-tests/api/__tests__/admin/payment.js +++ /dev/null @@ -1,262 +0,0 @@ -const { medusaIntegrationTestRunner } = require("medusa-test-utils") -const { createAdminUser } = require("../../../helpers/create-admin-user") -const { breaking } = require("../../../helpers/breaking") -const { ModuleRegistrationName } = require("@medusajs/modules-sdk") - -jest.setTimeout(30000) - -const adminHeaders = { - headers: { - "x-medusa-access-token": "test_token", - }, -} - -let { simpleCustomerFactory, simplePaymentCollectionFactory } = {} - -const createV1PaymentSetup = async (dbConnection, payCol, api) => { - // create payment collection - payCol = await simplePaymentCollectionFactory(dbConnection, { - description: "paycol description", - amount: 1000, - }) - - // create payment session - const payColRes = await api.post( - `/store/payment-collections/${payCol.id}/sessions`, - { - provider_id: "test-pay", - } - ) - - // authorize payment session - await api.post( - `/store/payment-collections/${payCol.id}/sessions/batch/authorize`, - { - session_ids: payColRes.data.payment_collection.payment_sessions.map( - ({ id }) => id - ), - } - ) - - // get payment collection - const response = await api.get( - `/admin/payment-collections/${payCol.id}`, - adminHeaders - ) - - // return payment - return response.data.payment_collection.payments[0] -} - -medusaIntegrationTestRunner({ - // env: { MEDUSA_FF_MEDUSA_V2: true }, - testSuite: ({ dbConnection, getContainer, api }) => { - let container - let paymentService - - beforeAll(() => { - ;({ - simplePaymentCollectionFactory, - } = require("../../../factories/simple-payment-collection-factory")) - ;({ - simpleCustomerFactory, - } = require("../../../factories/simple-customer-factory")) - }) - - beforeEach(async () => { - container = getContainer() - await createAdminUser(dbConnection, adminHeaders, container) - - paymentService = container.resolve(ModuleRegistrationName.PAYMENT) - }) - - describe("Admin Payments API", () => { - let payCol - - beforeEach(async () => { - await simpleCustomerFactory(dbConnection, { - id: "customer", - email: "test@customer.com", - }) - }) - - it("Captures an authorized payment", async () => { - const payment = await breaking( - async () => { - const v1Payment = await createV1PaymentSetup( - dbConnection, - payCol, - api - ) - return v1Payment - }, - async () => { - const paymentCollection = - await paymentService.createPaymentCollections({ - region_id: "test-region", - amount: 1000, - currency_code: "usd", - }) - - const paymentSession = await paymentService.createPaymentSession( - paymentCollection.id, - { - provider_id: "pp_system_default", - amount: 1000, - currency_code: "usd", - data: {}, - } - ) - - const payment = await paymentService.authorizePaymentSession( - paymentSession.id, - {} - ) - - return payment - } - ) - - const response = await api.post( - `/admin/payments/${payment.id}/capture`, - undefined, - adminHeaders - ) - - expect(response.data.payment).toEqual( - expect.objectContaining({ - id: payment.id, - captured_at: expect.any(String), - ...breaking( - () => ({}), - () => ({ - captures: [ - expect.objectContaining({ - id: expect.any(String), - amount: 1000, - }), - ], - refunds: [], - }) - ), - amount: 1000, - }) - ) - expect(response.status).toEqual(200) - }) - - it("Refunds an captured payment", async () => { - const payment = await breaking( - async () => { - const v1Payment = await createV1PaymentSetup( - dbConnection, - payCol, - api - ) - - await api.post( - `/admin/payments/${v1Payment.id}/capture`, - undefined, - adminHeaders - ) - - return v1Payment - }, - async () => { - const paymentCollection = - await paymentService.createPaymentCollections({ - region_id: "test-region", - amount: 1000, - currency_code: "usd", - }) - - const paymentSession = await paymentService.createPaymentSession( - paymentCollection.id, - { - provider_id: "pp_system_default", - amount: 1000, - currency_code: "usd", - data: {}, - } - ) - - const payment = await paymentService.authorizePaymentSession( - paymentSession.id, - {} - ) - - await paymentService.capturePayment({ - payment_id: payment.id, - amount: 1000, - }) - - return payment - } - ) - - // refund - const response = await api.post( - `/admin/payments/${payment.id}/refund`, - { - amount: 500, - ...breaking( - () => ({ - // TODO: We should probably introduce this in V2 too - reason: "return", - note: "Do not like it", - }), - () => ({}) - ), - }, - adminHeaders - ) - - expect(response.status).toEqual(200) - - breaking( - async () => { - expect(response.data.refund).toEqual( - expect.objectContaining({ - payment_id: payment.id, - reason: "return", - amount: 500, - }) - ) - - const savedPayment = await api.get( - `/admin/payments/${payment.id}`, - adminHeaders - ) - - expect(savedPayment.data.payment).toEqual( - expect.objectContaining({ - amount_refunded: 500, - }) - ) - }, - () => { - expect(response.data.payment).toEqual( - expect.objectContaining({ - id: payment.id, - captured_at: expect.any(String), - captures: [ - expect.objectContaining({ - id: expect.any(String), - amount: 1000, - }), - ], - refunds: [ - expect.objectContaining({ - id: expect.any(String), - amount: 500, - }), - ], - amount: 1000, - }) - ) - } - ) - }) - }) - }, -}) diff --git a/integration-tests/http/__tests__/payment-collection/admin/payment-collection.spec.ts b/integration-tests/http/__tests__/payment-collection/admin/payment-collection.spec.ts new file mode 100644 index 0000000000..5d53745ad1 --- /dev/null +++ b/integration-tests/http/__tests__/payment-collection/admin/payment-collection.spec.ts @@ -0,0 +1,128 @@ +import { medusaIntegrationTestRunner } from "medusa-test-utils" +import { + createAdminUser, + adminHeaders, +} from "../../../../helpers/create-admin-user" + +jest.setTimeout(30000) + +medusaIntegrationTestRunner({ + env: {}, + testSuite: ({ dbConnection, getContainer, api }) => { + beforeEach(async () => { + const container = getContainer() + await createAdminUser(dbConnection, adminHeaders, container) + }) + + // TODO: Currently we don't have these endpoints, enable tests once they are added. + describe("/admin/payment-collections", () => { + it("lists payment collections", async () => {}) + }) + // describe("/admin/payment-collections/:id", () => { + // it("gets payment collection", async () => { + // const response = await api.get( + // `/admin/payment-collections/${paymentCollection.id}`, + // adminHeaders + // ) + + // expect(response.data.payment_collection).toEqual( + // expect.objectContaining({ + // id: paymentCollection.id, + // type: "order_edit", + // status: "not_paid", + // description: "paycol description", + // amount: 10000, + // }) + // ) + + // expect(response.status).toEqual(200) + // }) + + // it("updates a payment collection", async () => { + // const response = await api.post( + // `/admin/payment-collections/${paymentCollection.id}`, + // { + // description: "new description", + // metadata: { + // a: 1, + // b: [1, 2, "3"], + // }, + // }, + // adminHeaders + // ) + + // expect(response.status).toEqual(200) + // expect(response.data.payment_collection).toEqual( + // expect.objectContaining({ + // id: paymentCollection.id, + // type: "order_edit", + // amount: 10000, + // description: "new description", + // metadata: { + // a: 1, + // b: [1, 2, "3"], + // }, + // authorized_amount: null, + // }) + // ) + // }) + + // it("marks a payment collection as authorized", async () => { + // const response = await api.post( + // `/admin/payment-collections/${paymentCollection.id}/authorize`, + // undefined, + // adminHeaders + // ) + + // expect(response.data.payment_collection).toEqual( + // expect.objectContaining({ + // id: paymentCollection.id, + // type: "order_edit", + // status: "authorized", + // description: "paycol description", + // amount: 10000, + // authorized_amount: 10000, + // }) + // ) + + // expect(response.status).toEqual(200) + // }) + + // it("delete a payment collection", async () => { + // const response = await api.delete( + // `/admin/payment-collections/${paymentCollection.id}`, + // adminHeaders + // ) + + // expect(response.data).toEqual({ + // id: paymentCollection.id, + // deleted: true, + // object: "payment_collection", + // }) + + // expect(response.status).toEqual(200) + // }) + + // it("throws error when deleting an authorized payment collection", async () => { + // await api.post( + // `/admin/payment-collections/${paymentCollection.id}/authorize`, + // undefined, + // adminHeaders + // ) + + // try { + // await api.delete( + // `/admin/payment-collections/${paymentCollection.id}`, + // adminHeaders + // ) + + // expect(1).toBe(2) // should be ignored + // } catch (res) { + // expect(res.response.data.message).toBe( + // "Cannot delete payment collection with status authorized" + // ) + // } + // }) + // }) + }, +}) diff --git a/integration-tests/http/__tests__/payment/admin/payment.spec.ts b/integration-tests/http/__tests__/payment/admin/payment.spec.ts new file mode 100644 index 0000000000..e1b93d220d --- /dev/null +++ b/integration-tests/http/__tests__/payment/admin/payment.spec.ts @@ -0,0 +1,120 @@ +import { ModuleRegistrationName } from "@medusajs/utils" +import { adminHeaders } from "../../../../helpers/create-admin-user" +import { IPaymentModuleService } from "@medusajs/types" + +const { medusaIntegrationTestRunner } = require("medusa-test-utils") +const { createAdminUser } = require("../../../../helpers/create-admin-user") + +jest.setTimeout(30000) + +medusaIntegrationTestRunner({ + testSuite: ({ dbConnection, getContainer, api }) => { + let paymentModule: IPaymentModuleService + let paymentCollection + let payment + + beforeEach(async () => { + paymentModule = getContainer().resolve(ModuleRegistrationName.PAYMENT) + await createAdminUser(dbConnection, adminHeaders, getContainer()) + + const collection = ( + await api.post( + "/store/payment-collections", + { + cart_id: "test-cart", + region_id: "test-region", + amount: 1000, + currency_code: "usd", + }, + adminHeaders + ) + ).data.payment_collection + + paymentCollection = ( + await api.post( + `/store/payment-collections/${collection.id}/payment-sessions`, + { provider_id: "pp_system_default" }, + adminHeaders + ) + ).data.payment_collection + + const lastSession = paymentCollection.payment_sessions[0] + // TODO: Try to replace it with user behavior, like completing a cart. + await paymentModule.authorizePaymentSession(lastSession.id, {}) + + const payments = ( + await api.get( + `/admin/payments?payment_session_id=${lastSession.id}`, + adminHeaders + ) + ).data.payments + payment = payments[0] + }) + + it("Captures an authorized payment", async () => { + const response = await api.post( + `/admin/payments/${payment.id}/capture`, + undefined, + adminHeaders + ) + + expect(response.data.payment).toEqual( + expect.objectContaining({ + id: payment.id, + captured_at: expect.any(String), + captures: [ + expect.objectContaining({ + id: expect.any(String), + amount: 1000, + }), + ], + refunds: [], + amount: 1000, + }) + ) + expect(response.status).toEqual(200) + }) + + it("Refunds an captured payment", async () => { + await api.post( + `/admin/payments/${payment.id}/capture`, + undefined, + adminHeaders + ) + + // refund + const response = await api.post( + `/admin/payments/${payment.id}/refund`, + { + amount: 500, + // BREAKING: We should probably introduce reason and notes in V2 too + // reason: "return", + // note: "Do not like it", + }, + adminHeaders + ) + + // BREAKING: Response was `data.refund` in V1 with payment ID, reason, and amount + expect(response.status).toEqual(200) + expect(response.data.payment).toEqual( + expect.objectContaining({ + id: payment.id, + captured_at: expect.any(String), + captures: [ + expect.objectContaining({ + id: expect.any(String), + amount: 1000, + }), + ], + refunds: [ + expect.objectContaining({ + id: expect.any(String), + amount: 500, + }), + ], + amount: 1000, + }) + ) + }) + }, +}) diff --git a/packages/core/types/src/payment/common.ts b/packages/core/types/src/payment/common.ts index 1679686450..2dbc248c36 100644 --- a/packages/core/types/src/payment/common.ts +++ b/packages/core/types/src/payment/common.ts @@ -389,7 +389,7 @@ export interface FilterablePaymentProps /** * Filter the payments by the ID of their associated payment session. */ - session_id?: string | string[] | OperatorMap + payment_session_id?: string | string[] | OperatorMap /** * Filter the payments by the ID of their associated customer. @@ -574,7 +574,7 @@ export interface PaymentProviderDTO { export interface FilterablePaymentProviderProps extends BaseFilterable { /** - * The IDs to filter the payment collection by. + * The IDs to filter the payment provider by. */ id?: string | string[] | OperatorMap diff --git a/packages/medusa/src/api/admin/payments/validators.ts b/packages/medusa/src/api/admin/payments/validators.ts index f1e1af1c1a..7def18ce31 100644 --- a/packages/medusa/src/api/admin/payments/validators.ts +++ b/packages/medusa/src/api/admin/payments/validators.ts @@ -16,6 +16,7 @@ export const AdminGetPaymentsParams = createFindParams({ z.object({ q: z.string().optional(), id: z.union([z.string(), z.array(z.string())]).optional(), + payment_session_id: z.union([z.string(), z.array(z.string())]).optional(), created_at: createOperatorMap().optional(), updated_at: createOperatorMap().optional(), deleted_at: createOperatorMap().optional(),