170 lines
5.5 KiB
TypeScript
170 lines
5.5 KiB
TypeScript
import { test, expect, describe } from 'vitest';
|
|
|
|
import { PayPro } from '../../src/protocols/paypro.js';
|
|
import { Address, Satoshis } from '@xocash/primitives';
|
|
|
|
const BCH_ADDRESS = 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted';
|
|
const CASH_ADDRESS = 'bitcoincash:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyquzsnp0a';
|
|
const TEST_TOKEN_CATEGORY_ID =
|
|
'f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63';
|
|
|
|
const BASE_RAW = {
|
|
address: Address.fromCashAddr(CASH_ADDRESS),
|
|
satoshis: Satoshis.fromSats(546),
|
|
};
|
|
|
|
const SUCCESS_CASES = [
|
|
// Basic URI
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted',
|
|
raw: BASE_RAW,
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
|
},
|
|
// Basic URI with amount
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?amount=0.00000546',
|
|
raw: BASE_RAW,
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
|
},
|
|
// Basic URI with Sats and Amount
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?s=546&amount=0.00000546',
|
|
raw: BASE_RAW,
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
|
},
|
|
// URI with Tokens and Fungible Tokens
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000',
|
|
raw: {
|
|
...BASE_RAW,
|
|
satoshis: Satoshis.fromSats(657),
|
|
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
|
fungibleTokenAmount: 10000,
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=657&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000`,
|
|
},
|
|
// URI with Tokens and Non-Fungible Tokens
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01',
|
|
raw: {
|
|
...BASE_RAW,
|
|
satoshis: Satoshis.fromSats(654),
|
|
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
|
nftCommitment: '01',
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=654&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01`,
|
|
},
|
|
// URI with Sats, Token Category and Fungible Tokens
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000',
|
|
raw: {
|
|
...BASE_RAW,
|
|
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
|
fungibleTokenAmount: 10000,
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000`,
|
|
},
|
|
// URI with Sats, Token Category and Non-Fungible Tokens
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01',
|
|
raw: {
|
|
...BASE_RAW,
|
|
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
|
nftCommitment: '01',
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01`,
|
|
},
|
|
// URI with Expiry
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?e=1715769600',
|
|
raw: {
|
|
...BASE_RAW,
|
|
expiry: 1715769600,
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&e=1715769600`,
|
|
},
|
|
// URI with Message
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?m=Hello',
|
|
raw: {
|
|
...BASE_RAW,
|
|
message: 'Hello',
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&m=Hello`,
|
|
},
|
|
// URI with Message and Expiry
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?m=Hello&e=1715769600',
|
|
raw: {
|
|
...BASE_RAW,
|
|
message: 'Hello',
|
|
expiry: 1715769600,
|
|
},
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&m=Hello&e=1715769600`,
|
|
},
|
|
// URI with optional params
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?x-custom=value',
|
|
raw: BASE_RAW,
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
|
},
|
|
// URI with multiple optional params
|
|
{
|
|
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?x-custom=value&x-custom2=value2',
|
|
raw: BASE_RAW,
|
|
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
|
},
|
|
];
|
|
|
|
const FAILURE_CASES = [
|
|
// Duplicate amount
|
|
`${BCH_ADDRESS}?amount=1&amount=2`,
|
|
// Duplicate sats
|
|
`${BCH_ADDRESS}?s=1&s=2`,
|
|
// Duplicate token category
|
|
`${BCH_ADDRESS}?c=1&c=2`,
|
|
// Category without tokens
|
|
`${BCH_ADDRESS}?c=1`,
|
|
// Fungible tokens without category
|
|
`${BCH_ADDRESS}?f=1`,
|
|
// Non-fungible tokens without category
|
|
`${BCH_ADDRESS}?n=1`,
|
|
// Amount and sats are different
|
|
`${BCH_ADDRESS}?s=1&amount=2`,
|
|
// requestUrl is populated
|
|
`${BCH_ADDRESS}?r=https://example.com`,
|
|
// Invalid key
|
|
`${BCH_ADDRESS}?invalid=1`,
|
|
// Invalid amount
|
|
`${BCH_ADDRESS}?amount=invalid`,
|
|
// Invalid sats
|
|
`${BCH_ADDRESS}?s=invalid`,
|
|
// Invalid expiry
|
|
`${BCH_ADDRESS}?e=invalid`,
|
|
// Not an address
|
|
`bch:invalid`,
|
|
// Bip21
|
|
`bitcoincash:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyquzsnp0a`,
|
|
// Bip21 with amount
|
|
`bitcoincash:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyquzsnp0a?amount=0.00000546`,
|
|
];
|
|
|
|
describe('PayProPaymentUrl', () => {
|
|
test.each(SUCCESS_CASES)('should be able to parse a valid url', (url) => {
|
|
const paymentUrl = PayPro.from(url.url);
|
|
expect(paymentUrl.toRaw()).toEqual(url.raw);
|
|
if (url.result) {
|
|
expect(paymentUrl.toUrl()).toEqual(url.result);
|
|
} else {
|
|
expect(paymentUrl.toUrl()).toEqual(url.url);
|
|
}
|
|
});
|
|
|
|
test.each(FAILURE_CASES)(
|
|
'should throw an error for an invalid url',
|
|
(url) => {
|
|
expect(() => PayPro.from(url)).toThrow();
|
|
},
|
|
);
|
|
});
|