mcpField
T
testing-and-go-live

testing-and-go-live

github.com/dodopayments测试与质量13205 次安装3 周前更新
代码仓库

关于 testing-and-go-live

面向接入 Dodo Payments 的开发者,提供支付流程测试与上线准备指南。涵盖测试和生产环境隔离、支付及 Webhook 验证,以及产品迁移和上线检查。

主要功能

  1. 01区分测试与生产环境
  2. 02测试卡片及区域支付方式
  3. 03测试订阅续费
  4. 04本地监听和触发 Webhook
  5. 05测试产品迁移至生产
  6. 06生产上线检查清单

适用场景

  1. 01验证支付成功、拒绝及续费失败
  2. 02在本地或暂存环境测试 Webhook
  3. 03准备从测试模式切换至生产
  4. 04将测试环境产品配置迁移至生产

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dodopayments/skills --skill testing-and-go-live

安装后在 Claude Code 中输入/testing-and-go-live确认已加载。

详细介绍

测试与正式上线

此技能涵盖测试模式、测试付款方式、Webhook 测试和正式上线检查清单。构建需要在正式上线前验证的付款流程,或准备从测试环境切换到生产环境时,请使用此技能。

何时使用此技能

  • 你需要测试银行卡付款成功/拒绝场景、订阅续费或区域付款方式。
  • 你正在本地或预发布环境中设置 Webhook 测试。
  • 你正准备上线到生产环境,需要一份正式上线检查清单。
  • 你想确认测试环境和正式环境已正确隔离。
  • 你正在将产品从测试环境复制到正式环境。

核心概念

测试模式与正式模式: Dodo Payments 维护着两个完全独立的环境。每个环境都有自己的基础 URL、API 密钥、Webhook、产品、客户和交易。数据不会在两个环境之间转移。

  • 测试模式: https://test.dodopayments.com
  • 正式模式: https://live.dodopayments.com

每个环境都需要使用从控制面板签发的独立 API 密钥。如果未指定 environment,SDK 默认使用 live_mode,这在开发过程中很容易造成严重问题。

测试付款方式: Dodo 记录了用于测试的特定银行卡号、VPA 和付款场景。这些方式仅在测试模式下有效。

Webhook 测试: CLI 提供用于在本地监听 Webhook,以及触发测试事件(无需实际付款)的命令。


设置测试模式

开发期间始终显式设置 environment: 'test_mode'。默认值为 live_mode。

import DodoPayments from 'dodopayments';

const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode', // REQUIRED — defaults to 'live_mode'
});
import os

from dodopayments import DodoPayments

client = DodoPayments(
    bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
    environment="test_mode",  # defaults to "live_mode"
)
client := dodopayments.NewClient(
    option.WithBearerToken("dodo_test_..."),
    option.WithEnvironmentTestMode(), // defaults to WithEnvironmentLiveMode()
)

从 Dodo 控制面板获取测试 API 密钥。测试密钥的前缀为 dodo_test_。


测试付款方式

银行卡付款成功与拒绝场景

在测试模式下使用以下银行卡号,并设置有效期为 06/32(或 12/34),CVV 为 123。

场景银行卡号结果
成功4242 4242 4242 4242付款成功
拒绝4000 0000 0000 0002付款被拒绝
拒绝(余额不足)4000 0000 0000 9995余额不足错误

仅使用 Testing Process 页面列出的银行卡;其他 Stripe 风格的测试卡号(例如“银行卡遗失”变体)并未记录为适用于 Dodo。

订阅续费失败

要测试订阅续费失败,请使用以下银行卡:

银行卡号有效期CVV行为
4000 0000 0000 034112/34123在订阅下次扣款时被拒绝(续费、升级或降级)

先使用付款成功的银行卡创建订阅,然后在客户门户中将其付款方式切换为此卡。

UPI(印度)

使用以下 VPA 测试 UPI 付款成功和失败。账单国家/地区必须为 IN,货币必须为 INR(非印度商家还需要启用 Adaptive Currency):

VPA结果
success@upi付款成功
failure@upi付款失败
BNPL、电子钱包和区域付款方式

测试模式支持 BNPL、Apple Pay、Google Pay 和欧洲付款方式(Giropay、iDEAL、Bancontact)。具体测试场景因付款方式而异。请参阅 Testing Process 文档,了解最新的测试矩阵。


测试订阅续费

若要指定日期触发订阅续费,而无需等待,请更新 next_billing_date:

await client.subscriptions.update('sub_123', {
  next_billing_date: '2026-05-03T00:00:00Z',
});
client.subscriptions.update(
    'sub_123',
    next_billing_date='2026-05-03T00:00:00Z'
)
// NextBillingDate is param.Field[time.Time], not a string. Passing a string
// literal compiles to param.Field[string] and will not type-check.
client.Subscriptions.Update(ctx, "sub_123", dodopayments.SubscriptionUpdateParams{
    NextBillingDate: dodopayments.F(time.Date(2026, time.May, 3, 0, 0, 0, 0, time.UTC)),
})

这会立即安排续费。如果你使用了订阅续费失败卡,扣款失败时会触发 payment.failed,受影响的订阅会进入 on_hold 状态,并触发 subscription.on_hold。


Webhook 测试

CLI 与 SDK 分开提供:

npm install -g dodopayments-cli
dodo login

dodo login 会打开 API Keys 页面,接受粘贴的密钥,并询问这是测试模式还是正式模式。测试密钥和正式密钥可以各自保持一个已认证状态。

在本地监听 Webhook
dodo wh listen http://localhost:3000/webhook

此命令通过出站中继,将真实的测试模式事件转发到你的本地 URL。它不是隧道:没有任何服务会公开监听,也不会打印供你粘贴到控制面板的 URL。如果你需要可注册的 HTTPS URL,请改用 ngrok——具体流程见 webhook-integration 技能。

运行前请了解以下两项限制:

  • 必须使用测试模式密钥。 监听流程不支持实时模式密钥。
  • 直接模式下必须提供 URL 参数。 仅输入 dodo wh listen 只能在交互式 TUI 中作为 /wh listen 使用,它会打开向导。

通过这种方式接收的事件带有有效签名,因此请照常使用 webhooks.unwrap() 对其进行验证。

触发模拟 Webhook 事件
dodo wh trigger payment.success http://localhost:3000/webhook

为所选事件发送逼真的模拟载荷。此操作离线运行,即使在未登录时也能使用——这正是关键所在:这些载荷没有签名。 由于没有有效签名可供验证,unwrap() 会拒绝它们。

触发的事件只能使用 unsafeUnwrap(),切勿在也会接收真实流量的端点上使用。触发器名称的格式为 <category>.<event>,例如 payment.success、subscription.active 或 dispute.opened。

触发器名称不一定与载荷的 type 相同。 payment.success 会发送 type: "payment.succeeded",refund.success 会发送 refund.succeeded,而 licence.created 会发送 license_key.created。请在处理程序中根据载荷类型进行分支;case 'payment.success' 永远不会匹配。

与 listen 一样,直接模式下必须提供两个参数;在 TUI 中使用 /wh trigger 则会打开向导。

Webhook 签名验证

详见 webhook-integration 技能。请验证所有通过网络接收的 Webhook,无论是测试模式还是实时模式。唯一的例外是上文由 dodo wh trigger 生成的无签名载荷。


将产品从测试模式复制到实时模式

产品因环境而异。你不能在生产环境中重复使用测试产品 ID。请改为在实时模式下重新创建产品,或使用控制面板导出并重新导入。

手动方法:

  1. 记下测试模式下的产品详情(名称、价格、税务类别等)。
  2. 在实时模式下创建配置相同的新产品。
  3. 更新代码,使用新的实时产品 ID。

编程方法:

从测试模式获取产品,提取其配置,然后在实时模式下创建产品。API 密钥按模式区分——测试密钥无法通过实时模式的身份验证,反之亦然——因此需要两个不同的密钥:

// In test mode
const testClient = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_TEST_API_KEY,
  environment: 'test_mode',
});
const testProduct = await testClient.products.retrieve('pdt_test_123');

// In live mode
const liveClient = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_LIVE_API_KEY,
  environment: 'live_mode',
});
const liveProduct = await liveClient.products.create({
  name: testProduct.name,
  price: testProduct.price,
  tax_category: testProduct.tax_category,
  // ... other fields
});

上线检查清单

切换到生产环境前,请逐项确认:

企业与合规
  • 已在 Dodo 控制面板完成 KYC(了解你的客户)验证。
  • 企业验证已获批准。
  • 控制面板中的企业信息正确无误。
API 与密钥
  • 已从控制面板获取实时 API 密钥(前缀为 dodo_live_)。
  • 已轮换或撤销意外提交到代码仓库的所有测试密钥。
  • 代码使用 environment: 'live_mode'(或省略此项,因为实时模式是默认设置)。
Webhook
  • Webhook 端点可通过 HTTPS 公开访问。
  • 已在控制面板中将 Webhook URL 更新为生产域名。
  • 已更新环境变量中的 Webhook 密钥。
  • Webhook 处理程序使用 client.webhooks.unwrap() 或 standardwebhooks 包验证签名。
  • 已在生产环境(或使用实时密钥的预发布环境)中端到端测试 Webhook 流程。
产品与结账
  • 所有产品均在实时模式下创建(而非从测试模式复制)。
  • 结账代码使用实时产品 ID。
  • 返回 URL 指向生产域名。
  • 产品的税务类别正确无误。
监控与支持
  • 已设置对支付失败、Webhook 投递和 API 错误的监控。
  • 知道如何访问 Dodo 仪表板查看交易和争议。
  • 已制定处理退款和拒付的计划。

常见错误

未设置 environment

SDK 默认使用 live_mode。如果在开发期间忘记设置 environment: 'test_mode',测试代码就会访问生产环境并产生真实扣款。

// WRONG — this hits live mode
const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
});

// CORRECT
const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: 'test_mode',
});
在生产环境中重复使用测试产品 ID

测试环境和生产环境完全隔离。测试模式中的产品 ID 在生产模式中不存在。请务必在生产模式中创建新产品,或使用仪表板迁移产品。

// WRONG — pdt_test_123 does not exist in live mode
const session = await liveClient.checkoutSessions.create({
  product_cart: [{ product_id: 'pdt_test_123', quantity: 1 }],
});

// CORRECT — use a live product ID
const session = await liveClient.checkoutSessions.create({
  product_cart: [{ product_id: 'pdt_live_456', quantity: 1 }],
});
忘记为生产环境重新配置 Webhook

测试模式和生产模式使用不同的 Webhook 端点和密钥。如果将测试 Webhook 配置复制到生产环境,却未更新 URL 和密钥,Webhook 将投递失败或发送到错误的位置。

  • 在生产环境变量中更新 DODO_PAYMENTS_WEBHOOK_KEY。
  • 在仪表板中将 Webhook URL 更新为生产域名。
  • 在生产环境中测试 Webhook 投递。
在生产环境中未验证 Webhook 签名

请务必使用 client.webhooks.unwrap() 或 standardwebhooks 包验证 Webhook 签名。切勿信任未经验证的 Webhook,即使它来自 Dodo。

// WRONG — no verification
app.post('/webhook', (req, res) => {
  const event = req.body;
  handleEvent(event);
  res.json({ received: true });
});

// CORRECT
app.post('/webhook', async (req, res) => {
  try {
    const unwrapped = client.webhooks.unwrap(req.body.toString(), {
      headers: {
        'webhook-id': req.headers['webhook-id'] as string,
        'webhook-signature': req.headers['webhook-signature'] as string,
        'webhook-timestamp': req.headers['webhook-timestamp'] as string,
      },
    });
    handleEvent(unwrapped);
    res.json({ received: true });
  } catch (error) {
    res.status(401).json({ error: 'Invalid signature' });
  }
});
混用测试密钥和生产密钥

测试密钥(前缀为 dodo_test_)只能与 https://test.dodopayments.com 配合使用。生产密钥需从仪表板按模式签发。在生产模式中使用测试密钥会导致身份验证错误。


资源

评论

支持 Markdown