@pooflabs/test
v0.0.6
Published
Test SDK for Poof API - Mocking and test automation
Downloads
45
Readme
@pooflabs/test
Test SDK for TaroBase - Drop-in replacement for @pooflabs/web with mocking capabilities.
Features
- Zero Code Changes: Works as a drop-in replacement for production SDK
- Mock Authentication: No real wallet needed - authenticate with any address
- Test Overrides: Mock user addresses, timestamps, and function returns
- Parent-Child Communication: Control tests from parent iframe via postMessage
- Origin Validation: Secure postMessage with origin allowlist (poof.new, v2.poof.new, localhost)
- Full Observability: Reports all API calls back to parent for monitoring
- SessionStorage Based: Configuration persists across page reloads during test
Installation
npm install @pooflabs/test
# or
yarn add @pooflabs/testQuick Start
1. Build-Time Substitution
Replace imports during build:
# Use sed or your build tool to replace imports
sed -i "s/@pooflabs\/web/@pooflabs\/test/g" src/**/*.ts2. Basic Usage (Standalone)
import { init, get, set } from '@pooflabs/test';
// Set test user in sessionStorage
sessionStorage.setItem('test-user-address', 'FvgqHMfL3YxzcJp7VfqAbJC9pFLdvvZCgTVPfW8tCvp8');
// Initialize (works exactly like production SDK)
await init({
appId: 'your-app-id',
apiKey: 'your-api-key'
});
// Use normally - test headers automatically injected
const user = await get('/users/123');
await set('/users/123', { name: 'Test User' });3. With Parent Iframe (Recommended)
Security Note: By default, only poof.new, v2.poof.new, and localhost origins can control the test iframe. See PARENT_API.md for customization.
Parent Window (Test Harness):
const testFrame = document.getElementById('test-iframe') as HTMLIFrameElement;
// Set test user
testFrame.contentWindow?.postMessage({
type: 'setUser',
payload: {
address: 'FvgqHMfL3YxzcJp7VfqAbJC9pFLdvvZCgTVPfW8tCvp8',
id: 'test-user-123'
}
}, '*');
// Set time override
testFrame.contentWindow?.postMessage({
type: 'setOverrides',
payload: {
timeOverride: '2025-01-01T00:00:00Z'
}
}, '*');
// Set function overrides
testFrame.contentWindow?.postMessage({
type: 'setOverrides',
payload: {
functionOverrides: {
'plugin.checkBalance': { balance: 1000 },
'plugin.getUserRole': 'admin'
}
}
}, '*');
// Get current state from child (including sessionStorage)
testFrame.contentWindow?.postMessage({ type: 'getState' }, '*');
// Disconnect user
testFrame.contentWindow?.postMessage({ type: 'disconnect' }, '*');
// Listen to events from test app
window.addEventListener('message', (event) => {
console.log('Test app event:', event.data);
switch (event.data.type) {
case 'ready':
console.log('App initialized');
break;
case 'apiCall':
console.log('API call:', event.data.payload);
break;
case 'authStateChanged':
console.log('Auth changed:', event.data.payload);
break;
case 'stateSnapshot':
console.log('Current state:', event.data.payload);
// payload includes: user, overrides, and all sessionStorage
break;
}
});Try the example: Open example-parent-harness.html in your browser to see a working test harness that controls a child iframe.
Child Window (Your App - No Code Changes):
// Your app code remains unchanged!
import { init, get, set } from '@pooflabs/web'; // Actually uses @pooflabs/test after build substitution
await init({ appId: 'your-app-id', apiKey: 'your-api-key' });
// Everything works normally, but with test overrides applied
const user = await get('/users/123');Test Headers
The following headers are automatically injected based on sessionStorage:
| Header | SessionStorage Key | Description |
|--------|-------------------|-------------|
| x-test-user-address | test-user-address | Override authenticated user address |
| x-test-time-override | test-time-override | Override server time (ISO 8601 string) |
| x-func-{name}-override | test-function-overrides | Override function return values |
Function Override Format
Function names are converted: plugin.functionName → x-func-plugin_functionname-override
Example:
// In test harness:
{
functionOverrides: {
'myPlugin.checkBalance': { balance: 1000 }
}
}
// Results in header:
// x-func-myplugin_checkbalance-override: {"balance":1000}PostMessage API
Parent → Child (Test Control)
// Set user
{ type: 'setUser', payload: { address: string, id?: string } }
// Set overrides
{ type: 'setOverrides', payload: {
timeOverride?: string,
functionOverrides?: { [name: string]: any }
}}
// Disconnect user
{ type: 'disconnect' }
// Clear all overrides
{ type: 'clearOverrides' }
// Get current state (child will respond with stateSnapshot)
{ type: 'getState' }Child → Parent (Observability)
// App ready
{ type: 'ready', payload: {} }
// API call made
{ type: 'apiCall', payload: {
method: string,
path: string,
headers: Record<string, string>,
timestamp: string
}}
// Auth state changed
{ type: 'authStateChanged', payload: {
authenticated: boolean,
user?: { address: string, id?: string }
}}
// State snapshot (sent when state changes or when parent requests it)
{ type: 'stateSnapshot', payload: {
user: { address: string, id?: string } | null,
overrides: {
timeOverride?: string,
functionOverrides?: { [name: string]: any }
},
sessionStorage: Record<string, string> // All 'test-*' keys
}}Advanced Usage
Direct TestCoordinator Access
import { testCoordinator } from '@pooflabs/test';
// Manually set user
testCoordinator.setUser({ address: '0x...', id: 'user-123' });
// Manually set overrides
testCoordinator.setOverrides({
timeOverride: '2025-01-01T00:00:00Z',
functionOverrides: { 'plugin.func': 'mocked-value' }
});
// Get current test headers
const headers = testCoordinator.getTestHeaders();
// Disconnect
testCoordinator.disconnect();Custom Auth Provider
import { MockAuthProvider } from '@pooflabs/test';
const provider = new MockAuthProvider();
await provider.login(); // Reads from sessionStorageArchitecture
┌─────────────────────────────────────────┐
│ Test Harness (Parent Window) │
│ - Controls test execution │
│ - Sends commands via postMessage │
│ - Observes app behavior │
└─────────────┬───────────────────────────┘
│ postMessage
↓
┌─────────────────────────────────────────┐
│ App (iframe with @pooflabs/test) │
│ ┌──────────────────────────────────┐ │
│ │ TestCoordinator (auto-init) │ │
│ │ - Listens to parent │ │
│ │ - Manages sessionStorage │ │
│ │ - Injects headers automatically │ │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ App Code (unchanged) │ │
│ │ Uses @pooflabs/test via alias │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘Differences from Production SDK
- Authentication: Uses
MockAuthProviderinstead of real wallets - Transactions: Returns mock signatures (backend still processes with test headers)
- Auto-Injection: Test headers automatically added to all API calls
- Observability: Reports all operations to parent window
- No Wallet Bundle: Smaller bundle size (no Privy/Phantom/etc.)
SessionStorage Keys
test-user-address: Current test user addresstest-user-id: Current test user ID (optional)test-time-override: Override server timetest-function-overrides: JSON string of function overrides
License
MIT
