const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); const root = path.join(__dirname, '..'); function apiResponse(data) { return { headers: { get: () => '' }, ok: true, status: 200, statusText: 'OK', text: () => Promise.resolve(JSON.stringify({ code: 'OK', data })), }; } function harness(search = '') { const requests = []; const storage = new Map(); const location = { hash: '', hostname: 'h5.global-interaction.com', href: `https://h5.global-interaction.com/guild/fami/wallet/${search}`, origin: 'https://h5.global-interaction.com', pathname: '/guild/fami/wallet/', search, }; const window = { atob: (value) => Buffer.from(value, 'base64').toString('binary'), crypto: { randomUUID: () => 'fixed-uuid' }, document: { currentScript: null, documentElement: { setAttribute: () => {} }, }, dispatchEvent: () => {}, fetch: (rawURL, options = {}) => { const url = new URL(rawURL); requests.push({ url, options }); if (url.pathname === '/api/v1/point-wallet/overview') { return Promise.resolve( apiResponse({ balance: { available_amount: 2000000, display_usd: '20.00', }, points_per_usd: 100000, fee_bps: 500, minimum_points: 1000000, coin_sellers: [ { user_id: '9007199254740001', display_user_id: '443344', nickname: 'Seller', point_amount: 100000, seller_coin_amount: 92000, }, ], }) ); } if (url.pathname === '/api/v1/wallet/transactions') { return Promise.resolve( apiResponse({ transactions: [ { transaction_id: 'tx-1', biz_type: 'point_transfer_to_coin_seller', available_delta: -1000000, }, ], }) ); } return Promise.resolve(apiResponse({})); }, localStorage: { getItem: (key) => storage.get(key) || null, removeItem: (key) => storage.delete(key), setItem: (key, value) => storage.set(key, String(value)), }, location, }; window.window = window; return { context: vm.createContext({ Buffer, CustomEvent: function CustomEvent() {}, Date, Error, FormData, JSON, Math, Number, Object, Promise, String, URL, URLSearchParams, console, document: window.document, window, }), requests, window, }; } function run(context, file) { vm.runInContext(fs.readFileSync(path.join(root, file), 'utf8'), context, { filename: file, }); } async function main() { const browser = harness('?token=test-token&env=test'); run(browser.context, 'guild/packages/core/product-context.js'); run(browser.context, 'guild/products/fami/product.js'); run(browser.context, 'common/api.js'); run(browser.context, 'guild/packages/wallet/wallet.js'); const data = await browser.window.HyGuild.wallet.load(); assert.equal(data.balance.available, 2000000); assert.equal(data.sellers[0].userId, '9007199254740001'); assert.equal(data.sellers[0].sellerCoinAmount, 92000); assert.equal(data.history[0].bizType, 'point_transfer_to_coin_seller'); await browser.window.HyGuild.wallet.transferToCoinSeller( data.sellers[0].userId, 1000000 ); const transfer = browser.requests.find( ({ url }) => url.pathname === '/api/v1/point-wallet/transfer-to-coin-seller' ); assert.deepEqual(JSON.parse(transfer.options.body), { command_id: 'fami-point-coin-seller:fixed-uuid', seller_user_id: '9007199254740001', point_amount: 1000000, }); browser.requests.forEach(({ options }) => assert.equal(options.headers['X-App-Code'], 'fami') ); const mockBrowser = harness('?mock=1'); run(mockBrowser.context, 'guild/packages/core/product-context.js'); run(mockBrowser.context, 'guild/products/fami/product.js'); run(mockBrowser.context, 'guild/packages/wallet/wallet.js'); const mock = await mockBrowser.window.HyGuild.wallet.load(); assert.equal(mock.sellers.length, 2); assert.equal(mockBrowser.requests.length, 0); console.log('Fami wallet tests passed'); } main().catch((error) => { console.error(error); process.exitCode = 1; });