diff --git a/package.json b/package.json index fbe67af..4612c1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fake-toss-payments-server", - "version": "2.0.3", + "version": "2.0.4", "description": "Fake toss-payments server for testing", "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/packages/api/package.json b/packages/api/package.json index a05712b..406b25d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "toss-payments-server-api", - "version": "2.0.3", + "version": "2.0.4", "description": "Toss Payments Server API", "main": "lib/index.js", "typings": "lib/index.d.ts", @@ -15,7 +15,7 @@ }, "homepage": "https://github.com/samchon/fake-toss-payments-server", "dependencies": { - "@nestia/fetcher": "^2.0.3", + "@nestia/fetcher": "^2.0.4", "typia": "^5.0.4" }, "keywords": [ diff --git a/packages/api/swagger.json b/packages/api/swagger.json index c50716e..c1f4cd3 100644 --- a/packages/api/swagger.json +++ b/packages/api/swagger.json @@ -13,7 +13,7 @@ "info": { "title": "Toss Payments API", "description": "Built by [fake-toss-payments-server](https://github.com/samchon/fake-toss-payments-server) with [nestia](https://github.com/samchon/nestia)", - "version": "2.0.3", + "version": "2.0.4", "license": { "name": "MIT" } diff --git a/src/api/functional/internal/index.ts b/src/api/functional/internal/index.ts index 7e4ca64..069c56b 100644 --- a/src/api/functional/internal/index.ts +++ b/src/api/functional/internal/index.ts @@ -27,7 +27,7 @@ import { NestiaSimulator } from "../../utils/NestiaSimulator"; * @param input 웹훅 이벤트 정보 * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossInternalController.webhook + * @controller [object Object] * @path POST /internal/webhook * @nestia Generated by Nestia - https://github.com/samchon/nestia */ @@ -105,7 +105,7 @@ export namespace webhook { * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossInternalController.deposit + * @controller [object Object] * @path GET /internal/:paymentKey/deposit * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/api/functional/v1/billing/authorizations/card/index.ts b/src/api/functional/v1/billing/authorizations/card/index.ts index 97c4123..7ad9356 100644 --- a/src/api/functional/v1/billing/authorizations/card/index.ts +++ b/src/api/functional/v1/billing/authorizations/card/index.ts @@ -28,7 +28,7 @@ import { NestiaSimulator } from "../../../../../utils/NestiaSimulator"; * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossBillingController.store + * @controller [object Object] * @path POST /v1/billing/authorizations/card * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/api/functional/v1/billing/authorizations/index.ts b/src/api/functional/v1/billing/authorizations/index.ts index 9515f50..b70b4d2 100644 --- a/src/api/functional/v1/billing/authorizations/index.ts +++ b/src/api/functional/v1/billing/authorizations/index.ts @@ -29,7 +29,7 @@ export * as card from "./card"; * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossBillingController.at + * @controller [object Object] * @path POST /v1/billing/authorizations/:billingKey * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/api/functional/v1/billing/index.ts b/src/api/functional/v1/billing/index.ts index d362dfc..f0c22d1 100644 --- a/src/api/functional/v1/billing/index.ts +++ b/src/api/functional/v1/billing/index.ts @@ -37,7 +37,7 @@ export * as authorizations from "./authorizations"; * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossBillingController.pay + * @controller [object Object] * @path POST /v1/billing/:billingKey * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/api/functional/v1/cash_receipts/index.ts b/src/api/functional/v1/cash_receipts/index.ts index 9cc2553..fbda66f 100644 --- a/src/api/functional/v1/cash_receipts/index.ts +++ b/src/api/functional/v1/cash_receipts/index.ts @@ -19,7 +19,7 @@ import { NestiaSimulator } from "../../../utils/NestiaSimulator"; * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossCashReceiptsController.store + * @controller [object Object] * @path POST /v1/cash-receipts * @nestia Generated by Nestia - https://github.com/samchon/nestia */ @@ -99,7 +99,7 @@ export namespace store { * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossCashReceiptsController.cancel + * @controller [object Object] * @path POST /v1/cash-receipts/:receiptKey/cancel * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/api/functional/v1/payments/index.ts b/src/api/functional/v1/payments/index.ts index e45c3fe..368e1d7 100644 --- a/src/api/functional/v1/payments/index.ts +++ b/src/api/functional/v1/payments/index.ts @@ -31,7 +31,7 @@ import { NestiaSimulator } from "../../../utils/NestiaSimulator"; * @returns 결제 정보 * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossPaymentsController.at + * @controller [object Object] * @path GET /v1/payments/:paymentKey * @nestia Generated by Nestia - https://github.com/samchon/nestia */ @@ -117,7 +117,7 @@ export namespace at { * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossPaymentsController.key_in + * @controller [object Object] * @path POST /v1/payments/key-in * @nestia Generated by Nestia - https://github.com/samchon/nestia */ @@ -207,7 +207,7 @@ export namespace key_in { * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossPaymentsController.approve + * @controller [object Object] * @path POST /v1/payments/:paymentKey * @nestia Generated by Nestia - https://github.com/samchon/nestia */ @@ -296,7 +296,7 @@ export namespace approve { * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossPaymentsController.cancel + * @controller [object Object] * @path POST /v1/payments/:paymentKey/cancel * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/api/functional/v1/virtual_accounts/index.ts b/src/api/functional/v1/virtual_accounts/index.ts index 3c58e4e..4d717c1 100644 --- a/src/api/functional/v1/virtual_accounts/index.ts +++ b/src/api/functional/v1/virtual_accounts/index.ts @@ -35,7 +35,7 @@ import { NestiaSimulator } from "../../../utils/NestiaSimulator"; * @security basic * @author Jeongho Nam - https://github.com/samchon * - * @controller FakeTossVirtualAccountsController.store + * @controller [object Object] * @path POST /v1/virtual-accounts * @nestia Generated by Nestia - https://github.com/samchon/nestia */ diff --git a/src/controllers/FakeTossPaymentsController.ts b/src/controllers/FakeTossPaymentsController.ts index bb832da..e6450de 100644 --- a/src/controllers/FakeTossPaymentsController.ts +++ b/src/controllers/FakeTossPaymentsController.ts @@ -166,23 +166,34 @@ export class FakeTossPaymentsController { FakeTossUserAuth.authorize(request); const payment: ITossPayment = FakeTossStorage.payments.get(paymentKey); + const amount: number = input.cancelAmount ?? payment.totalAmount; + + if (payment.balanceAmount < amount) + throw new nest.UnprocessableEntityException( + "Balance amount is not enough.", + ); + payment.status = "CANCELED"; payment.cancels ??= []; payment.cancels.push({ - cancelAmount: input.cancelAmount || payment.totalAmount, + cancelAmount: amount, cancelReason: input.cancelReason, - taxFreeAmount: input.taxFreeAmount || 0, - taxAmount: input.taxAmount || 0, - refundableAmount: input.refundableAmount || payment.totalAmount, + taxFreeAmount: input.taxFreeAmount ?? 0, + taxAmount: input.taxAmount ?? 0, + refundableAmount: input.refundableAmount ?? payment.totalAmount, canceledAt: new Date().toISOString(), }); + payment.balanceAmount -= amount; FakeTossWebhookProvider.webhook({ eventType: "PAYMENT_STATUS_CHANGED", data: { paymentKey: payment.paymentKey, orderId: payment.orderId, - status: "CANCELED", + status: + payment.balanceAmount === 0 + ? "CANCELED" + : "PARTIAL_CANCELED", }, }).catch(() => {}); diff --git a/test/features/internal/validate_fake_payment_cancel.ts b/test/features/internal/validate_fake_payment_cancel.ts new file mode 100644 index 0000000..1a5a203 --- /dev/null +++ b/test/features/internal/validate_fake_payment_cancel.ts @@ -0,0 +1,77 @@ +import { TestValidator } from "@nestia/e2e"; +import { sleep_for } from "tstl"; +import typia from "typia"; + +import toss from "toss-payments-server-api"; +import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; +import { ITossPaymentWebhook } from "toss-payments-server-api/lib/structures/ITossPaymentWebhook"; + +import { FakeTossStorage } from "../../../src/providers/FakeTossStorage"; +import { TestConnection } from "../../internal/TestConnection"; + +export const validate_fake_payment_cancel = + (generator: () => Promise, virtual: boolean) => async () => { + // 결제 완료 + const init: ITossPayment = await generator(); + + // 검증 로직 준비 + const validate = (cancelled: boolean) => (p: ITossPayment) => { + TestValidator.equals("balanceAmount")( + cancelled ? 0 : p.totalAmount, + )(p.balanceAmount); + TestValidator.equals("cancelAmount")( + (p.cancels ?? []) + .map((c) => c.cancelAmount) + .reduce((a, b) => a + b, 0), + )(cancelled ? p.totalAmount : 0); + TestValidator.equals("cancels?.length")(cancelled ? 1 : 0)( + p.cancels?.length ?? 0, + ); + TestValidator.predicate("cancel_history")( + cancelled + ? () => + p.cancels?.length === 1 && + p.cancels?.[0].cancelAmount === p.totalAmount + : () => !p.cancels?.length, + ); + }; + + // 결제 취소 전 검증 + validate(false)(init); + + // 결제 취소하기 (전액) + const cancelled: ITossPayment = + await toss.functional.v1.payments.cancel( + TestConnection.FAKE, + init.paymentKey, + { + paymentKey: init.paymentKey, + cancelReason: "테스트 결제 취소", + cancelAmount: init.totalAmount, + refundReceiveAccount: virtual + ? { + bank: "국민은행", + accountNumber: "12345678901234", + holderName: "홍길동", + } + : undefined, + }, + ); + typia.assert(cancelled); + validate(true)(cancelled); + + // 웹훅 검증 + await sleep_for(50); + const webhook: ITossPaymentWebhook = FakeTossStorage.webhooks.get( + init.paymentKey, + ); + TestValidator.equals("status")(webhook.data.status)("CANCELED"); + + // 결제 내역 재 조회하여 검증 + const reloaded: ITossPayment = await toss.functional.v1.payments.at( + TestConnection.FAKE, + init.paymentKey, + ); + typia.assert(reloaded); + validate(true)(reloaded); + }; diff --git a/test/features/internal/validate_fake_payment_cancel_over.ts b/test/features/internal/validate_fake_payment_cancel_over.ts new file mode 100644 index 0000000..ebfa5ef --- /dev/null +++ b/test/features/internal/validate_fake_payment_cancel_over.ts @@ -0,0 +1,44 @@ +import { TestValidator } from "@nestia/e2e"; +import typia from "typia"; + +import toss from "toss-payments-server-api"; +import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; + +import { TestConnection } from "../../internal/TestConnection"; + +export const validate_fake_payment_cancel_over = + (generator: () => Promise, virtual: boolean) => async () => { + // 결제 완료 + const payment: ITossPayment = await generator(); + + // 결제 취소하기 (전액 + 100) + await TestValidator.error("over")(() => + toss.functional.v1.payments.cancel( + TestConnection.FAKE, + payment.paymentKey, + { + paymentKey: payment.paymentKey, + cancelReason: "테스트 결제 취소", + cancelAmount: payment.totalAmount + 100, + refundReceiveAccount: virtual + ? { + bank: "국민은행", + accountNumber: "12345678901234", + holderName: "홍길동", + } + : undefined, + }, + ), + ); + + // 결제 내역 재 조회하여 다시 검증 + const reloaded: ITossPayment = await toss.functional.v1.payments.at( + TestConnection.FAKE, + payment.paymentKey, + ); + typia.assert(reloaded); + TestValidator.equals("balance")(payment.balanceAmount)( + payment.totalAmount, + ); + TestValidator.equals("cancels.length")(payment.cancels?.length ?? 0)(0); + }; diff --git a/test/features/internal/validate_fake_payment_cancel_partial.ts b/test/features/internal/validate_fake_payment_cancel_partial.ts new file mode 100644 index 0000000..d3cef5d --- /dev/null +++ b/test/features/internal/validate_fake_payment_cancel_partial.ts @@ -0,0 +1,69 @@ +import { ArrayUtil, TestValidator } from "@nestia/e2e"; +import { sleep_for } from "tstl"; +import typia from "typia"; + +import toss from "toss-payments-server-api"; +import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; + +import { FakeTossStorage } from "../../../src/providers/FakeTossStorage"; +import { TestConnection } from "../../internal/TestConnection"; + +export const validate_fake_payment_cancel_partial = + (generator: () => Promise, virtual: boolean) => async () => { + // 결제 완료 + const init: ITossPayment = await generator(); + + // 검증 로직 준비 + const validate = (count: number) => (p: ITossPayment) => { + const expected: number = (p.totalAmount / 5) * count; + + // VALIDATE CANCELLED AMOUNT + TestValidator.equals("balanceAmount")(p.totalAmount - expected)( + p.balanceAmount, + ); + TestValidator.equals("cancelAmount")( + (p.cancels ?? []) + .map((c) => c.cancelAmount) + .reduce((a, b) => a + b, 0), + )(expected); + TestValidator.equals("cancels?.length")(count)( + p.cancels?.length ?? 0, + ); + + // VALIDATE WEBHOOOK + if (count !== 0) { + const webhook = FakeTossStorage.webhooks.get(p.paymentKey); + TestValidator.equals("status")(webhook.data.status)( + count !== 5 ? "PARTIAL_CANCELED" : "CANCELED", + ); + } + }; + + // 결제 취소 전 검증 + await sleep_for(100); + validate(0)(init); + + // 5 회에 걸쳐 분할 취소 하기 + await ArrayUtil.asyncRepeat(5)(async (i) => { + const cancelled: ITossPayment = + await toss.functional.v1.payments.cancel( + TestConnection.FAKE, + init.paymentKey, + { + paymentKey: init.paymentKey, + cancelReason: "테스트 결제 취소", + cancelAmount: init.totalAmount / 5, + refundReceiveAccount: virtual + ? { + bank: "국민은행", + accountNumber: "12345678901234", + holderName: "홍길동", + } + : undefined, + }, + ); + typia.assert(cancelled); + await sleep_for(100); + validate(i + 1)(cancelled); + }); + }; diff --git a/test/features/examples/test_fake_billing_payment.ts b/test/features/test_fake_billing_payment.ts similarity index 74% rename from test/features/examples/test_fake_billing_payment.ts rename to test/features/test_fake_billing_payment.ts index 2302ca3..40125b2 100644 --- a/test/features/examples/test_fake_billing_payment.ts +++ b/test/features/test_fake_billing_payment.ts @@ -1,4 +1,5 @@ -import { assert } from "typia"; +import { TestValidator } from "@nestia/e2e"; +import typia from "typia"; import { v4 } from "uuid"; import toss from "toss-payments-server-api"; @@ -6,9 +7,9 @@ import { ITossBilling } from "toss-payments-server-api/lib/structures/ITossBilli import { ITossCardPayment } from "toss-payments-server-api/lib/structures/ITossCardPayment"; import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; -import { TestConnection } from "../../internal/TestConnection"; +import { TestConnection } from "../internal/TestConnection"; -export async function test_fake_billing_payment(): Promise { +export async function test_fake_billing_payment(): Promise { // 간편 결제 카드 등록하기 const billing: ITossBilling = await toss.functional.v1.billing.authorizations.card.store( @@ -23,7 +24,7 @@ export async function test_fake_billing_payment(): Promise { consumerName: "남정호", }, ); - assert(billing); + typia.assert(billing); // 간편 결제 카드로 결제하기 const payment: ITossPayment = await toss.functional.v1.billing.pay( @@ -37,11 +38,10 @@ export async function test_fake_billing_payment(): Promise { amount: 10_000, }, ); - assert(payment); + typia.assert(payment); // 간편 결제 카드로 결제시, 별도 승인 처리가 필요 없음 - if (payment.approvedAt === null || payment.status !== "DONE") - throw new Error( - "Bug on TossBillingController.pay(): failed to billing pay.", - ); + TestValidator.equals("approvedAt")(!!payment.approvedAt)(true); + TestValidator.equals("status")(payment.status)("DONE"); + return payment; } diff --git a/test/features/test_fake_billing_payment_cancel.ts b/test/features/test_fake_billing_payment_cancel.ts new file mode 100644 index 0000000..01e2aa3 --- /dev/null +++ b/test/features/test_fake_billing_payment_cancel.ts @@ -0,0 +1,7 @@ +import { validate_fake_payment_cancel } from "./internal/validate_fake_payment_cancel"; +import { test_fake_billing_payment } from "./test_fake_billing_payment"; + +export const test_fake_billing_payment_cancel = validate_fake_payment_cancel( + () => test_fake_billing_payment(), + false, +); diff --git a/test/features/test_fake_billing_payment_cancel_over.ts b/test/features/test_fake_billing_payment_cancel_over.ts new file mode 100644 index 0000000..efb6e9c --- /dev/null +++ b/test/features/test_fake_billing_payment_cancel_over.ts @@ -0,0 +1,5 @@ +import { validate_fake_payment_cancel_over } from "./internal/validate_fake_payment_cancel_over"; +import { test_fake_billing_payment } from "./test_fake_billing_payment"; + +export const test_fake_billing_payment_cancel_over = + validate_fake_payment_cancel_over(() => test_fake_billing_payment(), false); diff --git a/test/features/test_fake_billing_payment_cancel_partial.ts b/test/features/test_fake_billing_payment_cancel_partial.ts new file mode 100644 index 0000000..2741308 --- /dev/null +++ b/test/features/test_fake_billing_payment_cancel_partial.ts @@ -0,0 +1,8 @@ +import { validate_fake_payment_cancel_partial } from "./internal/validate_fake_payment_cancel_partial"; +import { test_fake_billing_payment } from "./test_fake_billing_payment"; + +export const test_fake_billing_payment_cancel_partial = + validate_fake_payment_cancel_partial( + () => test_fake_billing_payment(), + false, + ); diff --git a/test/features/examples/test_fake_card_payment.ts b/test/features/test_fake_card_payment.ts similarity index 87% rename from test/features/examples/test_fake_card_payment.ts rename to test/features/test_fake_card_payment.ts index a5f8627..f543c2f 100644 --- a/test/features/examples/test_fake_card_payment.ts +++ b/test/features/test_fake_card_payment.ts @@ -1,13 +1,14 @@ import { TestValidator } from "@nestia/e2e"; +import typia from "typia"; import { v4 } from "uuid"; import toss from "toss-payments-server-api"; import { ITossCardPayment } from "toss-payments-server-api/lib/structures/ITossCardPayment"; import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; -import { TestConnection } from "../../internal/TestConnection"; +import { TestConnection } from "../internal/TestConnection"; -export async function test_fake_card_payment(): Promise { +export async function test_fake_card_payment(): Promise { //---- // 결제하기 //---- @@ -39,6 +40,7 @@ export async function test_fake_card_payment(): Promise { __approved: false, }, ); + typia.assert(payment); // 잘못된 `orderId` 로 승인 처리시, 불발됨 await TestValidator.error( @@ -77,8 +79,9 @@ export async function test_fake_card_payment(): Promise { amount: payment.totalAmount, }, ); - if (approved.approvedAt === null || approved.status !== "DONE") - throw new Error( - "Bug on FakeTossPaymentsController.approve(): failed to approve.", - ); + const card: ITossCardPayment = typia.assert(approved); + TestValidator.equals("approvedAt")(!!card.approvedAt)(true); + TestValidator.equals("status")(card.status)("DONE"); + + return card; } diff --git a/test/features/test_fake_card_payment_cancel.ts b/test/features/test_fake_card_payment_cancel.ts new file mode 100644 index 0000000..784d5d7 --- /dev/null +++ b/test/features/test_fake_card_payment_cancel.ts @@ -0,0 +1,7 @@ +import { validate_fake_payment_cancel } from "./internal/validate_fake_payment_cancel"; +import { test_fake_card_payment } from "./test_fake_card_payment"; + +export const test_fake_card_payment_cancel = validate_fake_payment_cancel( + () => test_fake_card_payment(), + false, +); diff --git a/test/features/test_fake_card_payment_cancel_over.ts b/test/features/test_fake_card_payment_cancel_over.ts new file mode 100644 index 0000000..f8427aa --- /dev/null +++ b/test/features/test_fake_card_payment_cancel_over.ts @@ -0,0 +1,5 @@ +import { validate_fake_payment_cancel_over } from "./internal/validate_fake_payment_cancel_over"; +import { test_fake_card_payment } from "./test_fake_card_payment"; + +export const test_fake_card_payment_cancel_over = + validate_fake_payment_cancel_over(() => test_fake_card_payment(), false); diff --git a/test/features/test_fake_card_payment_cancel_partial.ts b/test/features/test_fake_card_payment_cancel_partial.ts new file mode 100644 index 0000000..4e4a7de --- /dev/null +++ b/test/features/test_fake_card_payment_cancel_partial.ts @@ -0,0 +1,5 @@ +import { validate_fake_payment_cancel_partial } from "./internal/validate_fake_payment_cancel_partial"; +import { test_fake_card_payment } from "./test_fake_card_payment"; + +export const test_fake_card_payment_cancel_partial = + validate_fake_payment_cancel_partial(() => test_fake_card_payment(), false); diff --git a/test/features/examples/test_fake_cash_receipt.ts b/test/features/test_fake_cash_receipt.ts similarity index 62% rename from test/features/examples/test_fake_cash_receipt.ts rename to test/features/test_fake_cash_receipt.ts index 691f92b..ef229ff 100644 --- a/test/features/examples/test_fake_cash_receipt.ts +++ b/test/features/test_fake_cash_receipt.ts @@ -1,14 +1,17 @@ -import { assert } from "typia"; +import { TestValidator } from "@nestia/e2e"; +import typia from "typia"; import toss from "toss-payments-server-api"; import { ITossCashReceipt } from "toss-payments-server-api/lib/structures/ITossCashReceipt"; import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; +import { ITossVirtualAccountPayment } from "toss-payments-server-api/lib/structures/ITossVirtualAccountPayment"; -import { TestConnection } from "../../internal/TestConnection"; +import { TestConnection } from "../internal/TestConnection"; import { test_fake_virtual_account_payment } from "./test_fake_virtual_account_payment"; export async function test_fake_cash_receipt(): Promise { - const payment: ITossPayment = await test_fake_virtual_account_payment(); + const payment: ITossVirtualAccountPayment = + await test_fake_virtual_account_payment(); const receipt: ITossCashReceipt = await toss.functional.v1.cash_receipts.store(TestConnection.FAKE, { type: "소득공제", @@ -18,14 +21,14 @@ export async function test_fake_cash_receipt(): Promise { registrationNumber: "8803111******", amount: payment.totalAmount, }); - assert(receipt); + typia.assert(receipt); const reloaded: ITossPayment = await toss.functional.v1.payments.at( TestConnection.FAKE, payment.paymentKey, ); - if (reloaded.cashReceipt === null) - throw new Error( - "Bug on cash_receipts.store(): failed to store it on the payment.", - ); + typia.assert(reloaded); + TestValidator.equals("receipt")(reloaded.cashReceipt?.receiptUrl)( + receipt.receiptUrl, + ); } diff --git a/test/features/storage/test_storage_capacity.ts b/test/features/test_fake_storage_capacity.ts similarity index 88% rename from test/features/storage/test_storage_capacity.ts rename to test/features/test_fake_storage_capacity.ts index bb554d5..31cc328 100644 --- a/test/features/storage/test_storage_capacity.ts +++ b/test/features/test_fake_storage_capacity.ts @@ -8,12 +8,12 @@ import toss from "toss-payments-server-api"; import { ITossBilling } from "toss-payments-server-api/lib/structures/ITossBilling"; import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; -import { TossFakeConfiguration } from "../../../src/FakeTossConfiguration"; -import { FakeTossStorage } from "../../../src/providers/FakeTossStorage"; -import { AdvancedRandomGenerator } from "../../internal/AdvancedRandomGenerator"; -import { TestConnection } from "../../internal/TestConnection"; +import { TossFakeConfiguration } from "../../src/FakeTossConfiguration"; +import { FakeTossStorage } from "../../src/providers/FakeTossStorage"; +import { AdvancedRandomGenerator } from "../internal/AdvancedRandomGenerator"; +import { TestConnection } from "../internal/TestConnection"; -export async function test_storage_capacity(): Promise { +export async function test_fake_storage_capacity(): Promise { const capacity: number = TossFakeConfiguration.EXPIRATION.capacity; FakeTossStorage.payments.clear(); diff --git a/test/features/storage/test_storage_expiration_time.ts b/test/features/test_fake_storage_expiration_time.ts similarity index 83% rename from test/features/storage/test_storage_expiration_time.ts rename to test/features/test_fake_storage_expiration_time.ts index 2ecff78..db1b51e 100644 --- a/test/features/storage/test_storage_expiration_time.ts +++ b/test/features/test_fake_storage_expiration_time.ts @@ -9,12 +9,12 @@ import toss from "toss-payments-server-api"; import { ITossCardPayment } from "toss-payments-server-api/lib/structures/ITossCardPayment"; import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayment"; -import { TossFakeConfiguration } from "../../../src/FakeTossConfiguration"; -import { FakeTossStorage } from "../../../src/providers/FakeTossStorage"; -import { AdvancedRandomGenerator } from "../../internal/AdvancedRandomGenerator"; -import { TestConnection } from "../../internal/TestConnection"; +import { TossFakeConfiguration } from "../../src/FakeTossConfiguration"; +import { FakeTossStorage } from "../../src/providers/FakeTossStorage"; +import { AdvancedRandomGenerator } from "../internal/AdvancedRandomGenerator"; +import { TestConnection } from "../internal/TestConnection"; -export async function test_storage_expiration_time(): Promise { +export async function test_fake_storage_expiration_time(): Promise { const time: number = TossFakeConfiguration.EXPIRATION.time; FakeTossStorage.payments.clear(); TossFakeConfiguration.EXPIRATION.time = 1; diff --git a/test/features/examples/test_fake_virtual_account_payment.ts b/test/features/test_fake_virtual_account_payment.ts similarity index 81% rename from test/features/examples/test_fake_virtual_account_payment.ts rename to test/features/test_fake_virtual_account_payment.ts index 626d1a1..b0cfd9d 100644 --- a/test/features/examples/test_fake_virtual_account_payment.ts +++ b/test/features/test_fake_virtual_account_payment.ts @@ -1,4 +1,5 @@ -import { assert } from "typia"; +import { TestValidator } from "@nestia/e2e"; +import typia from "typia"; import { v4 } from "uuid"; import toss from "toss-payments-server-api"; @@ -6,9 +7,9 @@ import { ITossPayment } from "toss-payments-server-api/lib/structures/ITossPayme import { ITossPaymentWebhook } from "toss-payments-server-api/lib/structures/ITossPaymentWebhook"; import { ITossVirtualAccountPayment } from "toss-payments-server-api/lib/structures/ITossVirtualAccountPayment"; -import { FakeTossStorage } from "../../../src/providers/FakeTossStorage"; -import { AdvancedRandomGenerator } from "../../internal/AdvancedRandomGenerator"; -import { TestConnection } from "../../internal/TestConnection"; +import { FakeTossStorage } from "../../src/providers/FakeTossStorage"; +import { AdvancedRandomGenerator } from "../internal/AdvancedRandomGenerator"; +import { TestConnection } from "../internal/TestConnection"; export async function test_fake_virtual_account_payment(): Promise { //---- @@ -41,7 +42,7 @@ export async function test_fake_virtual_account_payment(): Promise(payment); + typia.assert(payment); // 결제 요청 승인하기 // @@ -54,7 +55,7 @@ export async function test_fake_virtual_account_payment(): Promise(approved); + typia.assert(approved); //---- // 입금하기 @@ -71,13 +72,10 @@ export async function test_fake_virtual_account_payment(): Promise(reloaded); + typia.assert(reloaded); // 결제 완료 처리되었음을 알 수 있다 - if (reloaded.status !== "DONE") - throw new Error( - "Bug on FakeTossWebhookProvider.webhook(): failed to generate the exact webhook event.", - ); + TestValidator.equals("status")(reloaded.status)("DONE"); // 실제로 웹훅 이벤트 발생 내역을 보면, // 고객이 가상 계좌에 결제 금액을 입금하였을 때, @@ -85,10 +83,7 @@ export async function test_fake_virtual_account_payment(): Promise test_fake_virtual_account_payment(), + true, + ); diff --git a/test/features/test_fake_virtual_account_payment_cancel_over.ts b/test/features/test_fake_virtual_account_payment_cancel_over.ts new file mode 100644 index 0000000..ed42c82 --- /dev/null +++ b/test/features/test_fake_virtual_account_payment_cancel_over.ts @@ -0,0 +1,8 @@ +import { validate_fake_payment_cancel_over } from "./internal/validate_fake_payment_cancel_over"; +import { test_fake_virtual_account_payment } from "./test_fake_virtual_account_payment"; + +export const test_fake_virtual_account_payment_cancel_over = + validate_fake_payment_cancel_over( + () => test_fake_virtual_account_payment(), + true, + ); diff --git a/test/features/test_fake_virtual_account_payment_cancel_partial.ts b/test/features/test_fake_virtual_account_payment_cancel_partial.ts new file mode 100644 index 0000000..cc74f56 --- /dev/null +++ b/test/features/test_fake_virtual_account_payment_cancel_partial.ts @@ -0,0 +1,8 @@ +import { validate_fake_payment_cancel_partial } from "./internal/validate_fake_payment_cancel_partial"; +import { test_fake_virtual_account_payment } from "./test_fake_virtual_account_payment"; + +export const test_fake_virtual_account_payment_cancel_partial = + validate_fake_payment_cancel_partial( + () => test_fake_virtual_account_payment(), + true, + );