// test/helpers.js - Shared Test Utilities
const crypto = require('hypercore-crypto')
const b4a = require('b4a')
/**
* Generate random hex token for testing
* @param {number} bytes - Number of bytes (default: 32)
* @returns {string} - Hex string
*/
function generateTestToken(bytes = 32) {
return b4a.toString(crypto.randomBytes(bytes), 'hex')
}
/**
* Generate test mnemonic (NOT cryptographically secure - testing only!)
* @param {number} words - Number of words (12 or 24)
* @returns {string} - Space-separated mnemonic
*/
function generateTestMnemonic(words = 12) {
// Use deterministic test mnemonics from fixtures
const testWords = [
'abandon', 'ability', 'able', 'about', 'above', 'absent',
'absorb', 'abstract', 'absurd', 'abuse', 'access', 'accident',
'account', 'accuse', 'achieve', 'acid', 'acoustic', 'acquire',
'across', 'act', 'action', 'actor', 'actress', 'actual'
]
return testWords.slice(0, words).join(' ')
}
/**
* Wait for async condition to be true
* @param {Function} condition - Async function returning boolean
* @param {number} timeout - Max wait time in ms (default: 5000)
* @param {number} interval - Check interval in ms (default: 100)
* @returns {Promise<void>}
*/
async function waitFor(condition, timeout = 5000, interval = 100) {
const startTime = Date.now()
while (Date.now() - startTime < timeout) {
if (await condition()) {
return
}
await new Promise(resolve => setTimeout(resolve, interval))
}
throw new Error(`Timeout waiting for condition after ${timeout}ms`)
}
/**
* Assert function throws with expected error
* @param {Function} fn - Function that should throw
* @param {string|RegExp} expectedError - Expected error message or pattern
* @returns {Promise<void>}
*/
async function assertThrows(fn, expectedError) {
let threw = false
let error = null
try {
await fn()
} catch (err) {
threw = true
error = err
}
if (!threw) {
throw new Error('Expected function to throw but it did not')
}
if (expectedError instanceof RegExp) {
if (!expectedError.test(error.message)) {
throw new Error(`Expected error matching ${expectedError} but got: ${error.message}`)
}
} else if (typeof expectedError === 'string') {
if (!error.message.includes(expectedError)) {
throw new Error(`Expected error containing "${expectedError}" but got: ${error.message}`)
}
}
}
/**
* Create temporary test directory
* @returns {string} - Path to temp directory
*/
function createTempDir() {
const os = require('bare-os')
const path = require('bare-path')
const fs = require('bare-fs')
const tmpDir = path.join(os.tmpdir(), `hyper-wallet-test-${Date.now()}`)
fs.mkdirSync(tmpDir, { recursive: true, mode: 0o700 })
return tmpDir
}
/**
* Clean up temporary test directory
* @param {string} dir - Directory to remove
*/
function cleanupTempDir(dir) {
const fs = require('bare-fs')
const path = require('bare-path')
if (fs.existsSync(dir)) {
const files = fs.readdirSync(dir)
for (const file of files) {
const filePath = path.join(dir, file)
const stat = fs.statSync(filePath)
if (stat.isDirectory()) {
cleanupTempDir(filePath)
} else {
fs.unlinkSync(filePath)
}
}
fs.rmdirSync(dir)
}
}
/**
* Sleep for specified milliseconds
* @param {number} ms - Milliseconds to sleep
* @returns {Promise<void>}
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
module.exports = {
generateTestToken,
generateTestMnemonic,
waitFor,
assertThrows,
createTempDir,
cleanupTempDir,
sleep
}