From badfb7c819746882d5ac7c8ca58c7cb66c34ec3e Mon Sep 17 00:00:00 2001 From: Oli Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Fri, 8 Mar 2024 09:04:57 +0100 Subject: [PATCH] test: Introduce V2 tests in Admin Payments API (#6621) --- .../api/__tests__/admin/payment.js | 263 +++++++++++++----- .../admin/payments/[id]/capture/route.ts | 7 +- .../admin/payments/[id]/refund/route.ts | 7 +- .../src/api-v2/admin/payments/middlewares.ts | 12 +- .../src/api-v2/admin/payments/query-config.ts | 5 + .../src/api-v2/admin/payments/validators.ts | 14 +- packages/payment/src/joiner-config.ts | 1 + 7 files changed, 221 insertions(+), 88 deletions(-) diff --git a/integration-tests/api/__tests__/admin/payment.js b/integration-tests/api/__tests__/admin/payment.js index 2d753924c1..4b02461a41 100644 --- a/integration-tests/api/__tests__/admin/payment.js +++ b/integration-tests/api/__tests__/admin/payment.js @@ -1,5 +1,7 @@ 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) @@ -11,9 +13,47 @@ const adminHeaders = { 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_PRODUCT_CATEGORIES: true }, + // env: { MEDUSA_FF_MEDUSA_V2: true }, testSuite: ({ dbConnection, getContainer, api }) => { + let container + let paymentService + beforeAll(() => { ;({ simplePaymentCollectionFactory, @@ -24,11 +64,13 @@ medusaIntegrationTestRunner({ }) beforeEach(async () => { - const container = getContainer() + container = getContainer() await createAdminUser(dbConnection, adminHeaders, container) + + paymentService = container.resolve(ModuleRegistrationName.PAYMENT) }) - describe("POST /admin/payment-collections/:id", () => { + describe("Admin Payments API", () => { let payCol beforeEach(async () => { @@ -36,42 +78,44 @@ medusaIntegrationTestRunner({ id: "customer", email: "test@customer.com", }) - - payCol = await simplePaymentCollectionFactory(dbConnection, { - description: "paycol description", - amount: 10000, - }) }) it("Captures an authorized payment", async () => { - // create payment session - const payColRes = await api.post( - `/store/payment-collections/${payCol.id}/sessions`, - { - provider_id: "test-pay", + 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 } ) - await api.post( - `/store/payment-collections/${payCol.id}/sessions/batch/authorize`, - { - session_ids: payColRes.data.payment_collection.payment_sessions.map( - ({ id }) => id - ), - } - ) - - const paymentCollections = await api.get( - `/admin/payment-collections/${payCol.id}`, - adminHeaders - ) - - expect( - paymentCollections.data.payment_collection.payments - ).toHaveLength(1) - - const payment = paymentCollections.data.payment_collection.payments[0] - - expect(payment.captured_at).toBe(null) const response = await api.post( `/admin/payments/${payment.id}/capture`, @@ -83,69 +127,134 @@ medusaIntegrationTestRunner({ expect.objectContaining({ id: payment.id, captured_at: expect.any(String), - amount: 10000, + ...breaking( + () => ({}), + () => ({ + captures: [ + expect.objectContaining({ + id: expect.any(String), + amount: 1000, + }), + ], + refunds: [], + }) + ), + amount: 1000, }) ) expect(response.status).toEqual(200) }) it("Refunds an captured payment", async () => { - // create payment session - const payColRes = await api.post( - `/store/payment-collections/${payCol.id}/sessions`, - { - provider_id: "test-pay", - } - ) - await api.post( - `/store/payment-collections/${payCol.id}/sessions/batch/authorize`, - { - session_ids: payColRes.data.payment_collection.payment_sessions.map( - ({ id }) => id - ), - } - ) + const payment = await breaking( + async () => { + const v1Payment = await createV1PaymentSetup( + dbConnection, + payCol, + api + ) - const paymentCollections = await api.get( - `/admin/payment-collections/${payCol.id}`, - adminHeaders - ) - const payment = paymentCollections.data.payment_collection.payments[0] - await api.post( - `/admin/payments/${payment.id}/capture`, - undefined, - adminHeaders + 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: 5000, - reason: "return", - note: "Do not like it", + amount: 500, + ...breaking( + () => ({ + // TODO: We should probably introduce this in V2 too + reason: "return", + note: "Do not like it", + }), + () => ({}) + ), }, adminHeaders ) - expect(response.data.refund).toEqual( - expect.objectContaining({ - payment_id: payment.id, - reason: "return", - amount: 5000, - }) - ) expect(response.status).toEqual(200) - const savedPayment = await api.get( - `/admin/payments/${payment.id}`, - adminHeaders - ) + breaking( + async () => { + expect(response.data.refund).toEqual( + expect.objectContaining({ + payment_id: payment.id, + reason: "return", + amount: 500, + }) + ) - expect(savedPayment.data.payment).toEqual( - expect.objectContaining({ - amount_refunded: 5000, - }) + 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/packages/medusa/src/api-v2/admin/payments/[id]/capture/route.ts b/packages/medusa/src/api-v2/admin/payments/[id]/capture/route.ts index aeba3ffd0d..bac1457625 100644 --- a/packages/medusa/src/api-v2/admin/payments/[id]/capture/route.ts +++ b/packages/medusa/src/api-v2/admin/payments/[id]/capture/route.ts @@ -1,5 +1,4 @@ import { capturePaymentWorkflow } from "@medusajs/core-flows" -import { Modules } from "@medusajs/modules-sdk" import { ContainerRegistrationKeys, remoteQueryObjectFromString, @@ -9,9 +8,10 @@ import { MedusaResponse, } from "../../../../../types/routing" import { defaultAdminPaymentFields } from "../../query-config" +import { AdminPostPaymentsCapturesReq } from "../../validators" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) @@ -22,6 +22,7 @@ export const POST = async ( input: { payment_id: id, captured_by: req.auth?.actor_id, + amount: req.validatedBody.amount, }, throwOnError: false, }) @@ -31,7 +32,7 @@ export const POST = async ( } const query = remoteQueryObjectFromString({ - entryPoint: Modules.PAYMENT, + entryPoint: "payments", variables: { id }, fields: defaultAdminPaymentFields, }) diff --git a/packages/medusa/src/api-v2/admin/payments/[id]/refund/route.ts b/packages/medusa/src/api-v2/admin/payments/[id]/refund/route.ts index ff3e9a90a5..bbff08339f 100644 --- a/packages/medusa/src/api-v2/admin/payments/[id]/refund/route.ts +++ b/packages/medusa/src/api-v2/admin/payments/[id]/refund/route.ts @@ -1,5 +1,4 @@ import { refundPaymentWorkflow } from "@medusajs/core-flows" -import { Modules } from "@medusajs/modules-sdk" import { ContainerRegistrationKeys, remoteQueryObjectFromString, @@ -9,9 +8,10 @@ import { MedusaResponse, } from "../../../../../types/routing" import { defaultAdminPaymentFields } from "../../query-config" +import { AdminPostPaymentsRefundsReq } from "../../validators" export const POST = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) @@ -22,6 +22,7 @@ export const POST = async ( input: { payment_id: id, created_by: req.auth?.actor_id, + amount: req.validatedBody.amount, }, throwOnError: false, }) @@ -31,7 +32,7 @@ export const POST = async ( } const query = remoteQueryObjectFromString({ - entryPoint: Modules.PAYMENT, + entryPoint: "payments", variables: { id }, fields: defaultAdminPaymentFields, }) diff --git a/packages/medusa/src/api-v2/admin/payments/middlewares.ts b/packages/medusa/src/api-v2/admin/payments/middlewares.ts index 4ea181c249..80f740068d 100644 --- a/packages/medusa/src/api-v2/admin/payments/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/payments/middlewares.ts @@ -1,8 +1,12 @@ -import { transformQuery } from "../../../api/middlewares" +import { transformBody, transformQuery } from "../../../api/middlewares" import { MiddlewareRoute } from "../../../types/middlewares" import { authenticate } from "../../../utils/authenticate-middleware" import * as queryConfig from "./query-config" -import { AdminGetPaymentsParams } from "./validators" +import { + AdminGetPaymentsParams, + AdminPostPaymentsCapturesReq, + AdminPostPaymentsRefundsReq, +} from "./validators" export const adminPaymentRoutesMiddlewares: MiddlewareRoute[] = [ { @@ -33,11 +37,11 @@ export const adminPaymentRoutesMiddlewares: MiddlewareRoute[] = [ { method: ["POST"], matcher: "/admin/payments/:id/capture", - middlewares: [], + middlewares: [transformBody(AdminPostPaymentsCapturesReq)], }, { method: ["POST"], matcher: "/admin/payments/:id/refund", - middlewares: [], + middlewares: [transformBody(AdminPostPaymentsRefundsReq)], }, ] diff --git a/packages/medusa/src/api-v2/admin/payments/query-config.ts b/packages/medusa/src/api-v2/admin/payments/query-config.ts index e8bfeb2581..e0e79c7b03 100644 --- a/packages/medusa/src/api-v2/admin/payments/query-config.ts +++ b/packages/medusa/src/api-v2/admin/payments/query-config.ts @@ -2,8 +2,13 @@ export const defaultAdminPaymentFields = [ "id", "currency_code", "amount", + "captured_at", "payment_collection_id", "payment_session_id", + "captures.id", + "captures.amount", + "refunds.id", + "refunds.amount", ] export const defaultAdminPaymentRelations = ["captures", "refunds"] diff --git a/packages/medusa/src/api-v2/admin/payments/validators.ts b/packages/medusa/src/api-v2/admin/payments/validators.ts index 73b66699ea..69d474b30c 100644 --- a/packages/medusa/src/api-v2/admin/payments/validators.ts +++ b/packages/medusa/src/api-v2/admin/payments/validators.ts @@ -1,5 +1,5 @@ import { Type } from "class-transformer" -import { IsOptional, ValidateNested } from "class-validator" +import { IsInt, IsOptional, ValidateNested } from "class-validator" import { DateComparisonOperator, FindParams, @@ -44,3 +44,15 @@ export class AdminGetPaymentsParams extends extendedFindParamsMixin({ @Type(() => DateComparisonOperator) deleted_at?: DateComparisonOperator } + +export class AdminPostPaymentsCapturesReq { + @IsInt() + @IsOptional() + amount?: number +} + +export class AdminPostPaymentsRefundsReq { + @IsInt() + @IsOptional() + amount?: number +} diff --git a/packages/payment/src/joiner-config.ts b/packages/payment/src/joiner-config.ts index 81f8a9eaea..dfbd145b7b 100644 --- a/packages/payment/src/joiner-config.ts +++ b/packages/payment/src/joiner-config.ts @@ -34,6 +34,7 @@ export const joinerConfig: ModuleJoinerConfig = { name: ["payment", "payments"], args: { entity: Payment.name, + methodSuffix: "Payments", }, }, {