- خانه
- سندباکس و تست
راهنماها
راهبرد سندباکس و تست
سه درگاه از یازده درگاه ماتریس سندباکس تولید واقعی دارند. هشت درگاه دیگر به استاب محلی نیاز دارند، و دانستن اینکه کدامها کداماند پیش از برنامهریزی یک فصل، زمان زیادی نجات میدهد.
| درگاه | پروتکل | سندباکس | یادداشتها | وضعیت در SDK |
|---|---|---|---|---|
| زرینپال · ZarinPal | REST (JSON) | بله | سندباکس تولید در sandbox.zarinpal.com | پشتیبانیشده |
| آیدیپی · IDPay | REST (JSON) | بله | سندباکس تولید از طریق هدر درخواست X-SANDBOX | برنامهریزیشده |
| بهپرداخت ملت · Behpardakht Mellat | SOAP 1.1 (WSDL) | خیر | ندارد، نیاز به سندباکس محلی | برنامهریزیشده |
| سامان کیش · Saman SEP | REST / SOAP، مبتنی بر توکن | خیر | ندارد، نیاز به سندباکس محلی | برنامهریزیشده |
| سداد بانک ملی · Sadad Melli | REST / SOAP | خیر | ندارد | فقط سند |
| تجارت الکترونیک پارسیان · Parsian PEC | SOAP / توکن REST | خیر | ندارد | فقط سند |
| پرداخت الکترونیک پاسارگاد · Pasargad PEP | REST / ریدایرکت | خیر | ندارد | فقط سند |
| آسان پرداخت · Asan Pardakht | REST / SOAP | خیر | ندارد | فقط سند |
| پرداخت نوین آرین · Pardakht Novin | REST / SOAP | خیر | ندارد | فقط سند |
| ایرانکیش · IranKish | REST / SOAP | خیر | ندارد | فقط سند |
| سیزپی · SizPay | REST (JSON) | بله | سندباکس موجود است | فقط سند |
زرینپال: همان که امروز میتوانید استفاده کنید
sandbox: true نشانی پایه آداپتور را به https://sandbox.zarinpal.com/pg تغییر میدهد و هیچ چیز دیگری. شکل درخواست، کدهای پاسخ و جریان وریفای درست مثل تولید است. آتوریتی سندباکس با S و آتوریتی پروداکشن با A شروع میشود — یک assertion ارزان برای نگه داشتن در fixtureهای تست.
import { describe, it, expect } from 'vitest';
import { UnoPay, ZarinpalAdapter, GatewayProviderError,
PaymentValidationError, toRials } from 'unopay';
describe('sandbox integration', () => {
const unopay = new UnoPay({
zarinpal: new ZarinpalAdapter({ merchantId: 'sandbox-merchant', sandbox: true }),
});
it('normalises Toman to Rials', () => {
expect(toRials(50_000, 'IRT')).toBe(500_000);
expect(toRials(500_000, 'IRR')).toBe(500_000);
// a typo is silently IRR — assert the behaviour you actually get
expect(toRials(50_000, 'TOMN')).toBe(50_000);
});
it('creates a payment against the sandbox', async () => {
const payment = await unopay.createPayment('zarinpal', {
amount: 1000,
currency: 'IRT',
callbackUrl: 'https://example.com/callback',
});
expect(payment.redirectUrl).toContain('sandbox.zarinpal.com');
expect(payment.transactionId.startsWith('S')).toBe(true);
expect(payment.providerToken).toBe(payment.transactionId);
});
it('rejects a callback with no Authority before any network call', async () => {
await expect(
unopay.verifyCallback('zarinpal', { method: 'GET', query: {}, body: {} }),
).rejects.toBeInstanceOf(PaymentValidationError);
});
it('surfaces a gateway rejection as GatewayProviderError', async () => {
await expect(
unopay.createPayment('zarinpal', {
amount: 1000,
currency: 'IRT',
callbackUrl: 'https://example.com/callback',
metadata: { description: 'x'.repeat(300) }, // over the gateway limit
}),
).rejects.toBeInstanceOf(GatewayProviderError);
});
});
برای هشت درگاه بدون سندباکس: آداپتور را استاب کنید
برای تست یکپارچهسازی خود به درگاه نیاز ندارید. به چیزی نیاز دارید که GatewayAdapter را برآورده کند. چون اینترفیس دو متدی است، یک استاب بیست خط است و در میکروثانیه اجرا میشود.
import {
UnoPay, PaymentError, GatewayNetworkError,
type GatewayAdapter, type PaymentRequest, type PaymentResult,
type CallbackRequest, type VerificationResult,
} from 'unopay';
// Scripted outcomes so you can exercise every branch without a gateway.
export function makeStub(outcome: 'paid' | 'declined' | 'fault'): GatewayAdapter {
return {
async createPayment(req: PaymentRequest): Promise<PaymentResult> {
if (outcome === 'fault') throw new GatewayNetworkError('stub network failure');
return {
redirectUrl: 'https://stub.test/start/STUB-1',
transactionId: 'STUB-1',
providerToken: 'STUB-1',
};
},
async verifyCallback(req: CallbackRequest): Promise<VerificationResult> {
if (outcome === 'fault') throw new GatewayNetworkError('stub network failure');
const ok = outcome === 'paid';
return {
isSuccessful: ok,
transactionId: ok ? 'REF-1' : req.query.Authority ?? 'unknown',
settledAmount: Number(req.query.amount ?? 0),
errorReason: ok ? undefined : 'stubbed decline',
};
},
};
}
// Your handler code is unchanged — only the adapter differs.
export const stubbed = new UnoPay({ gateway: makeStub('paid') });
// stubbed.createPayment('gateway', …) // 'gateway' is the only legal key
استاب برای منطق هندلر خودتان، سندباکس برای قالب سیمی آداپتور، و یک کالبک واقعی ضبطشده بهعنوان fixture برای رگرسیون. لایه سوم همان چیزی است که تیمها رد میکنند و باگهای «فیلد عوض نام داده» را میگیرد.