Testing Guide
A stub wallet adapter
The SDK does not ship a mock wallet adapter — the package contains no test scaffolding, so nothing here is importable from @tokenflight/swap. Write your own stub against the public IWalletAdapter interface; it is small enough to keep in your test utilities and you stay in control of what it returns.
import type {
IWalletAdapter,
WalletAction,
WalletActionResult,
WalletActionType,
WalletEvent,
WalletEventType,
} from '@tokenflight/swap';
const TEST_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045';
export class StubWalletAdapter implements IWalletAdapter {
readonly name = 'Stub Wallet';
readonly supportedActionTypes: WalletActionType[] = ['eip1193_request'];
private connected = false;
private handlers = new Map<WalletEventType, Set<(event: WalletEvent) => void>>();
async connect(): Promise<void> {
this.connected = true;
this.emit({ type: 'connect', data: { address: TEST_ADDRESS } });
}
async disconnect(): Promise<void> {
this.connected = false;
this.emit({ type: 'disconnect' });
}
isConnected(): boolean {
return this.connected;
}
async getAddress(): Promise<string | null> {
return this.connected ? TEST_ADDRESS : null;
}
async executeWalletAction(_action: WalletAction): Promise<WalletActionResult> {
return { success: true, txHash: `0x${'a'.repeat(64)}` };
}
on(event: WalletEventType, handler: (event: WalletEvent) => void): void {
if (!this.handlers.has(event)) this.handlers.set(event, new Set());
this.handlers.get(event)!.add(handler);
}
off(event: WalletEventType, handler: (event: WalletEvent) => void): void {
this.handlers.get(event)?.delete(handler);
}
private emit(event: WalletEvent): void {
this.handlers.get(event.type)?.forEach((handler) => handler(event));
}
}Extend it per test: reject in connect() to exercise your onSwapError path, return { success: false, error: 'User rejected' } from executeWalletAction() to exercise a declined signature, or emit accountsChanged to check that your UI follows.
Unit testing
Vitest / Jest Example
describe('PaymentWidget', () => {
let widget: InstanceType<typeof TokenFlightWidget>;
let container: HTMLDivElement;
afterEach(() => {
widget?.destroy();
container?.remove();
});
it('should initialize without errors', () => {
container = document.createElement('div');
document.body.appendChild(container);
const adapter = new StubWalletAdapter();
widget = new TokenFlightWidget({
container,
config: {
toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' },
tradeType: 'EXACT_OUTPUT',
amount: '100',
theme: 'dark',
},
walletAdapter: adapter,
});
expect(() => widget.initialize()).not.toThrow();
});
it('should fire onDepositError callback', async () => {
container = document.createElement('div');
document.body.appendChild(container);
let capturedError: SwapErrorData | null = null;
widget = new TokenFlightWidget({
container,
config: {
toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' },
tradeType: 'EXACT_OUTPUT',
amount: '100',
theme: 'dark',
},
walletAdapter: new StubWalletAdapter(),
callbacks: {
onDepositError: (error) => {
capturedError = error;
},
},
});
widget.initialize();
// The callback will fire when an error occurs during widget operation
// Test your error handling logic here
});
});React Testing (React Testing Library)
it('renders the payment widget container', () => {
const adapter = new StubWalletAdapter();
const { container } = render(
<PaymentWidget walletAdapter={adapter} theme="dark" />
);
// The widget mounts inside a Shadow DOM — use container queries
expect(container.querySelector('div')).toBeTruthy();
});E2E Testing with Playwright
The SDK's own E2E tests use Playwright with Chromium. You can follow the same pattern:
test('payment widget loads and displays', async ({ page }) => {
await page.goto('/your-page-with-widget');
// Wait for the custom element to be defined
await page.waitForFunction(() =>
customElements.get('tokenflight-widget') !== undefined
);
// Access Shadow DOM content
const widget = page.locator('tokenflight-widget');
const shadow = widget.locator('internal:shadow=.tf-container');
await expect(shadow).toBeVisible();
});Testnet / Sandbox Mode
⚠️ Coming soon: A dedicated testnet mode with test tokens is not yet available. Currently, the widget connects to the production Hyperstream API.
For development and testing:
- Use your own stub adapter for automated tests
- Test with small amounts on supported chains
- Use the
onConnectWalletcallback to intercept wallet actions during integration testing
CI Integration
For CI pipelines, attach your stub adapter to the widget on the test page — set it as the __walletAdapter property on the element, or pass it to registerWidgetElement({ walletAdapter }) before the element upgrades:
// playwright.config.ts
export default defineConfig({
webServer: {
command: 'pnpm build && pnpm preview',
port: 4173,
},
use: {
browserName: 'chromium',
},
});Key points for CI:
- Build the project before running E2E tests
- Chromium is the primary supported browser for testing
- Shadow DOM selectors need special handling (use
locator('internal:shadow=...')in Playwright) - API calls can be mocked with Playwright's
page.route()for deterministic tests