cashtab-connect
Version:
A developer-friendly API for integrating with the Cashtab browser extension
322 lines • 14 kB
JavaScript
;
// Copyright (c) 2025 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const index_1 = require("../src/index");
// Simple mock for browser environment
const mockWindow = {
addEventListener: () => { },
postMessage: () => { },
};
// Mock global objects
globalThis.window = mockWindow;
describe('CashtabConnect', () => {
let cashtabConnect;
let messageListeners = [];
let postMessageCalls = [];
beforeEach(() => {
// Reset mocks
messageListeners = [];
postMessageCalls = [];
// Mock window.addEventListener
mockWindow.addEventListener = (event, listener) => {
if (event === 'message') {
messageListeners.push(listener);
}
};
// Mock window.postMessage
mockWindow.postMessage = (message) => {
postMessageCalls.push(message);
};
cashtabConnect = new index_1.CashtabConnect();
});
afterEach(() => {
cashtabConnect.destroy();
});
describe('constructor', () => {
it('should create a new instance with default parameters', () => {
(0, chai_1.expect)(cashtabConnect).to.be.instanceOf(index_1.CashtabConnect);
});
it('should create a new instance with custom parameters', () => {
const customConnect = new index_1.CashtabConnect(5000);
(0, chai_1.expect)(customConnect).to.be.instanceOf(index_1.CashtabConnect);
customConnect.destroy();
});
});
describe('requestAddress', () => {
it('should request address successfully', async () => {
const addressPromise = cashtabConnect.requestAddress();
// Simulate extension response
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
success: true,
address: 'ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0',
},
});
}
}, 10);
const address = await addressPromise;
(0, chai_1.expect)(address).to.equal('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0');
});
it('should handle address request denial', async () => {
const addressPromise = cashtabConnect.requestAddress();
// Simulate extension response
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
success: false,
reason: 'User denied the request',
},
});
}
}, 10);
try {
await addressPromise;
chai_1.expect.fail('Should have thrown an error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabAddressDeniedError);
(0, chai_1.expect)(error.message).to.include('User denied the request');
}
});
it('should handle old format address request approval', async () => {
const addressPromise = cashtabConnect.requestAddress();
// Simulate old format extension response
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
address: 'ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0',
},
});
}
}, 10);
const address = await addressPromise;
(0, chai_1.expect)(address).to.equal('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0');
});
it('should handle old format address request denial', async () => {
const addressPromise = cashtabConnect.requestAddress();
// Simulate old format extension response
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
address: 'Address request denied by user',
},
});
}
}, 10);
try {
await addressPromise;
chai_1.expect.fail('Should have thrown an error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabAddressDeniedError);
(0, chai_1.expect)(error.message).to.include('User denied the address request');
}
});
it('should handle timeout', async () => {
const shortTimeoutConnect = new index_1.CashtabConnect(100);
const addressPromise = shortTimeoutConnect.requestAddress();
try {
await addressPromise;
chai_1.expect.fail('Should have thrown a timeout error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabTimeoutError);
}
shortTimeoutConnect.destroy();
});
});
describe('sendXec', () => {
it('should send XEC successfully with approval', async () => {
const txPromise = cashtabConnect.sendXec('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0', '0.001');
// Simulate extension response with approval
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
txResponse: {
approved: true,
txid: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
},
},
});
}
}, 10);
const response = await txPromise;
(0, chai_1.expect)(response.success).to.equal(true);
(0, chai_1.expect)(response.txid).to.equal('1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef');
(0, chai_1.expect)(response.reason).to.equal(undefined);
});
it('should handle XEC transaction rejection', async () => {
const txPromise = cashtabConnect.sendXec('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0', '0.001');
// Simulate extension response with rejection
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
txResponse: {
approved: false,
reason: 'User rejected the transaction',
},
},
});
}
}, 10);
try {
await txPromise;
chai_1.expect.fail('Should have thrown an error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabTransactionDeniedError);
(0, chai_1.expect)(error.message).to.include('User rejected the transaction');
}
});
it('should handle XEC transaction timeout', async () => {
const shortTimeoutConnect = new index_1.CashtabConnect(100);
const txPromise = shortTimeoutConnect.sendXec('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0', '0.001');
try {
await txPromise;
chai_1.expect.fail('Should have thrown a timeout error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabTimeoutError);
}
shortTimeoutConnect.destroy();
});
});
describe('sendToken', () => {
it('should send token successfully with approval', async () => {
const txPromise = cashtabConnect.sendToken('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0', '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0', '1.0');
// Simulate extension response with approval
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
txResponse: {
approved: true,
txid: 'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
},
},
});
}
}, 10);
const response = await txPromise;
(0, chai_1.expect)(response.success).to.equal(true);
(0, chai_1.expect)(response.txid).to.equal('abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890');
(0, chai_1.expect)(response.reason).to.equal(undefined);
});
it('should handle token transaction rejection', async () => {
const txPromise = cashtabConnect.sendToken('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0', '0387947fd575db4fb19a3e322f635dec37fd192b5941625b66bc4b2c3008cbf0', '1.0');
// Simulate extension response with rejection
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
txResponse: {
approved: false,
reason: 'User rejected the token transaction',
},
},
});
}
}, 10);
try {
await txPromise;
chai_1.expect.fail('Should have thrown an error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabTransactionDeniedError);
(0, chai_1.expect)(error.message).to.include('User rejected the token transaction');
}
});
});
describe('sendBip21', () => {
it('should send BIP21 successfully with approval', async () => {
const txPromise = cashtabConnect.sendBip21('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0?amount=0.001&memo=Test');
// Simulate extension response with approval
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
txResponse: {
approved: true,
txid: 'fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321',
},
},
});
}
}, 10);
const response = await txPromise;
(0, chai_1.expect)(response.success).to.equal(true);
(0, chai_1.expect)(response.txid).to.equal('fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321');
(0, chai_1.expect)(response.reason).to.equal(undefined);
});
it('should handle BIP21 transaction rejection', async () => {
const txPromise = cashtabConnect.sendBip21('ecash:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76vn0?amount=0.001&memo=Test');
// Simulate extension response with rejection
setTimeout(() => {
const listener = messageListeners[0];
if (listener) {
listener({
source: window,
data: {
type: 'FROM_CASHTAB',
txResponse: {
approved: false,
reason: 'User rejected the BIP21 transaction',
},
},
});
}
}, 10);
try {
await txPromise;
chai_1.expect.fail('Should have thrown an error');
}
catch (error) {
(0, chai_1.expect)(error).to.be.instanceOf(index_1.CashtabTransactionDeniedError);
(0, chai_1.expect)(error.message).to.include('User rejected the BIP21 transaction');
}
});
});
describe('destroy', () => {
it('should clean up resources', () => {
(0, chai_1.expect)(() => cashtabConnect.destroy()).to.not.throw();
});
});
});
//# sourceMappingURL=test.js.map