Files
xo-stack/packages/stack/tests/protocols/paypro.test.ts
T

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();
},
);
});