Token导航 LogoToken导航TokenDH.com
开发敏感数据github未标认证来源可访问许可证需确认审计异常

paystack-testing薪资测试

Agent Skill

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

总安装

245

周安装

10

GitHub Stars

1

下载量

79
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:paystack-testing(薪资测试)
来源仓库:https://github.com/rexedge/paystack
仓库路径:skills/paystack-testing
安装命令:
npx skills add https://github.com/rexedge/paystack --skill paystack-testing
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/rexedge/paystack --skill paystack-testing

简介

paystack-testing 用于辅助测试设计、自动化测试、用例整理和回归验证。

  • 适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。
  • 使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑。
  • 涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。
  • 当前分类为开发,功能聚焦于测试支持。

SKILL.md

Paystack Testing

Complete guide for testing Paystack integrations in test mode.

Depends on: paystack-setup for the paystackRequest helper.

Test Environment Setup

Environment Variables

# .env.test (or .env.local for development)
PAYSTACK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Never commit real keys. Use sk_test_* / pk_test_* keys from your Paystack Dashboard → Settings → API Keys & Webhooks.

Test vs Live Mode

AspectTest ModeLive Mode
Key prefixsk_test_ / pk_test_sk_live_ / pk_live_
Real chargesNoYes
WebhooksSent to test webhook URLSent to live webhook URL
Card validationSimulatedReal bank processing
TransfersSimulated (no real payout)Real bank transfers

Test Card Numbers

Use these with the Paystack Popup or Charge API in test mode:

Card NumberExpiryCVVBehavior
4084 0840 8408 4081Any future date408Successful transaction
4084 0840 8408 4081Any future date408PIN auth → use 1234
5060 6666 6666 6666 666Any future date123Verve card — success
5078 5078 5078 5078 12Any future date081Insufficient funds
4000 0000 0000 0002Any future dateAnyCard declined

PIN, OTP, and other test values

AuthTest Value
PIN1234
OTP123456
Phone08012345678
Birthday1999-12-31

Integration Tests with TypeScript

Transaction Flow Test

import { describe, it, expect, beforeAll } from "vitest";

const BASE_URL = "https://api.paystack.co";
const SECRET_KEY = process.env.PAYSTACK_SECRET_KEY!;

async function paystackRequest<T = any>(
  path: string,
  options: RequestInit = {}
): Promise<{ status: boolean; message: string; data: T }> {
  const res = await fetch(`${BASE_URL}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${SECRET_KEY}`,
      "Content-Type": "application/json",
      ...options.headers,
    },
  });
  return res.json();
}

describe("Paystack Transaction Flow", () => {
  let authorizationUrl: string;
  let reference: string;

  it("should initialize a transaction", async () => {
    const res = await paystackRequest<{
      authorization_url: string;
      access_code: string;
      reference: string;
    }>("/transaction/initialize", {
      method: "POST",
      body: JSON.stringify({
        email: "test@example.com",
        amount: 50000, // ₦500
        callback_url: "https://example.com/callback",
      }),
    });

    expect(res.status).toBe(true);
    expect(res.data.authorization_url).toContain("paystack.com");
    expect(res.data.reference).toBeTruthy();
    authorizationUrl = res.data.authorization_url;
    reference = res.data.reference;
  });

  it("should verify transaction (pending before payment)", async () => {
    const res = await paystackRequest(`/transaction/verify/${reference}`);
    // In test mode without completing payment, status may be "abandoned"
    expect(res.status).toBe(true);
  });

  it("should list transactions", async () => {
    const res = await paystackRequest("/transaction?perPage=5");
    expect(res.status).toBe(true);
    expect(Array.isArray(res.data)).toBe(true);
  });
});

Customer API Tests

describe("Paystack Customers", () => {
  let customerCode: string;

  it("should create a customer", async () => {
    const res = await paystackRequest<{
      customer_code: string;
      email: string;
    }>("/customer", {
      method: "POST",
      body: JSON.stringify({
        email: `test-${Date.now()}@example.com`,
        first_name: "Test",
        last_name: "User",
      }),
    });

    expect(res.status).toBe(true);
    expect(res.data.customer_code).toMatch(/^CUS_/);
    customerCode = res.data.customer_code;
  });

  it("should fetch the customer", async () => {
    const res = await paystackRequest(`/customer/${customerCode}`);
    expect(res.status).toBe(true);
    expect(res.data.customer_code).toBe(customerCode);
  });
});

Plan + Subscription Tests

describe("Paystack Plans", () => {
  let planCode: string;

  it("should create a plan", async () => {
    const res = await paystackRequest<{ plan_code: string }>("/plan", {
      method: "POST",
      body: JSON.stringify({
        name: `Test Plan ${Date.now()}`,
        interval: "monthly",
        amount: 100000, // ₦1,000
      }),
    });

    expect(res.status).toBe(true);
    expect(res.data.plan_code).toMatch(/^PLN_/);
    planCode = res.data.plan_code;
  });

  it("should list plans", async () => {
    const res = await paystackRequest("/plan?perPage=5");
    expect(res.status).toBe(true);
  });

  it("should fetch the plan", async () => {
    const res = await paystackRequest(`/plan/${planCode}`);
    expect(res.status).toBe(true);
    expect(res.data.plan_code).toBe(planCode);
  });
});

Transfer Recipient + Transfer Tests

describe("Paystack Transfers", () => {
  let recipientCode: string;

  it("should create a transfer recipient", async () => {
    const res = await paystackRequest<{ recipient_code: string }>(
      "/transferrecipient",
      {
        method: "POST",
        body: JSON.stringify({
          type: "nuban",
          name: "Test Recipient",
          account_number: "0000000000",
          bank_code: "058",
          currency: "NGN",
        }),
      }
    );

    expect(res.status).toBe(true);
    expect(res.data.recipient_code).toMatch(/^RCP_/);
    recipientCode = res.data.recipient_code;
  });

  it("should initiate a transfer (test mode)", async () => {
    const res = await paystackRequest("/transfer", {
      method: "POST",
      body: JSON.stringify({
        source: "balance",
        amount: 10000, // ₦100
        recipient: recipientCode,
        reason: "Test transfer",
      }),
    });

    // In test mode, transfers are simulated
    expect(res.status).toBe(true);
  });
});

Webhook Testing

Unit Test for Webhook Signature Validation

import { createHmac } from "crypto";
import { describe, it, expect } from "vitest";

function validateWebhookSignature(
  body: string,
  signature: string,
  secret: string
): boolean {
  const hash = createHmac("sha512", secret).update(body).digest("hex");
  return hash === signature;
}

describe("Webhook Signature Validation", () => {
  const secret = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

  it("should validate a correct signature", () => {
    const body = JSON.stringify({
      event: "charge.success",
      data: { reference: "test_ref_123" },
    });
    const signature = createHmac("sha512", secret).update(body).digest("hex");

    expect(validateWebhookSignature(body, signature, secret)).toBe(true);
  });

  it("should reject an invalid signature", () => {
    const body = JSON.stringify({ event: "charge.success" });
    expect(validateWebhookSignature(body, "invalid_hash", secret)).toBe(false);
  });

  it("should reject a tampered body", () => {
    const body = JSON.stringify({ event: "charge.success" });
    const signature = createHmac("sha512", secret).update(body).digest("hex");
    const tampered = JSON.stringify({ event: "charge.failed" });

    expect(validateWebhookSignature(tampered, signature, secret)).toBe(false);
  });
});

Testing Webhooks Locally

Use Paystack's test mode + a tunnel service:

# 1. Start your local server
npm run dev

# 2. Expose localhost via tunnel (pick one)
npx localtunnel --port 3000
# or
ngrok http 3000

# 3. Set the tunnel URL as your test webhook URL in Paystack Dashboard
#    Dashboard → Settings → API Keys & Webhooks → Test Webhook URL

# 4. Trigger events by completing test transactions
#    Paystack will send webhooks to your tunnel URL

Mock Webhook Handler Test

import { describe, it, expect, vi } from "vitest";
import { createHmac } from "crypto";

// Simulates a POST to your webhook endpoint
async function simulateWebhook(
  handler: (req: Request) => Promise<Response>,
  event: string,
  data: Record<string, unknown>,
  secret: string
) {
  const body = JSON.stringify({ event, data });
  const signature = createHmac("sha512", secret).update(body).digest("hex");

  return handler(
    new Request("http://localhost/api/webhooks/paystack", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-paystack-signature": signature,
      },
      body,
    })
  );
}

describe("Webhook Handler", () => {
  const secret = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

  it("should process charge.success event", async () => {
    const processPayment = vi.fn();

    // Your actual webhook handler
    async function webhookHandler(req: Request): Promise<Response> {
      const body = await req.text();
      const sig = req.headers.get("x-paystack-signature")!;
      const hash = createHmac("sha512", secret).update(body).digest("hex");

      if (hash !== sig) {
        return new Response("Unauthorized", { status: 401 });
      }

      const { event, data } = JSON.parse(body);
      if (event === "charge.success") {
        processPayment(data);
      }
      return new Response("OK", { status: 200 });
    }

    const res = await simulateWebhook(
      webhookHandler,
      "charge.success",
      { reference: "test_123", amount: 50000, currency: "NGN" },
      secret
    );

    expect(res.status).toBe(200);
    expect(processPayment).toHaveBeenCalledWith(
      expect.objectContaining({ reference: "test_123" })
    );
  });
});

Bank Account Resolution Test

describe("Bank Verification", () => {
  it("should resolve a bank account", async () => {
    const res = await paystackRequest(
      "/bank/resolve?account_number=0000000000&bank_code=058"
    );
    // Test mode may return mock data
    expect(res.status).toBe(true);
  });

  it("should list banks", async () => {
    const res = await paystackRequest("/bank?country=nigeria&perPage=10");
    expect(res.status).toBe(true);
    expect(res.data.length).toBeGreaterThan(0);
    expect(res.data[0]).toHaveProperty("code");
    expect(res.data[0]).toHaveProperty("name");
  });
});

Vitest Configuration

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "node",
    testTimeout: 30_000, // API calls may take time
    setupFiles: ["./tests/setup.ts"],
  },
});
// tests/setup.ts
import { config } from "dotenv";
config({ path: ".env.test" });

if (!process.env.PAYSTACK_SECRET_KEY?.startsWith("sk_test_")) {
  throw new Error(
    "Tests must use test mode keys (sk_test_*). Never run tests with live keys."
  );
}

Checklist Before Going Live

  • All tests pass with sk_test_ keys
  • Webhook signature validation tested (valid + invalid + tampered)
  • Transaction initialize → verify flow tested
  • Error responses handled (invalid amount, missing fields, etc.)
  • Idempotency: duplicate references handled gracefully
  • Switch to sk_live_ / pk_live_ keys in production environment
  • Live webhook URL configured in Dashboard
  • IP whitelist verified for webhook source (52.31.139.75, 52.49.173.169, 52.214.14.220)

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

32.54%
按下载量换算26

Claude

30.53%
按下载量换算24

Cursor

19.82%
按下载量换算16

Gemini CLI

8.53%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

未通过

Snyk

可疑

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills