vanilla-test 2.1.0

Minimal, dependency-free testing for native Rust and browser WebAssembly
Documentation
const page = {
    status: document.querySelector('[data-rust-browser-status]'),
    detail: document.querySelector('[data-rust-browser-detail]'),
    score: document.querySelector('[data-rust-browser-score]'),
    target: document.querySelector('[data-rust-browser-target]'),
    checks: document.querySelector('[data-rust-browser-checks]'),
    result: document.querySelector('[data-rust-browser-result]'),
    passed: document.querySelector('[data-rust-browser-passed]'),
    failed: document.querySelector('[data-rust-browser-failed]'),
    skipped: document.querySelector('[data-rust-browser-skipped]'),
    harness: document.querySelector('[data-rust-browser-harness]')
};
const context = { harnessStatus: 'not run' };
const counts = { passed: 0, failed: 0, skipped: 0 };
const siteTests = [...document.querySelectorAll('[data-rust-browser-site-check]')].map((element) => ({
    name: element.dataset.rustBrowserSiteCheck,
    blocks: false,
    run() {
        const actual = element.innerText.trim();
        const expected = element.dataset.rustBrowserExpected;
        if (!element.isConnected) throw new Error('element is not connected');
        const style = getComputedStyle(element);
        if (element.getClientRects().length === 0 || style.visibility !== 'visible' || style.opacity === '0') {
            throw new Error('element is not visible');
        }
        if (!actual) throw new Error('element has no text');
        if (expected && actual !== expected) {
            throw new Error(`expected "${expected}", received "${actual}"`);
        }
        return expected ? `text is "${actual}"` : 'element is present';
    }
}));
const tests = [
    ...siteTests,
    {
        name: 'browser runner exposes its result contract',
        blocks: false,
        run() {
            const missing = Object.entries(page)
                .filter(([, element]) => !element)
                .map(([name]) => name);
            if (missing.length > 0) throw new Error(`missing ${missing.join(', ')}`);
            return 'status, target label, totals, and result list are present';
        }
    },
    {
        name: 'WebAssembly test artifact responds successfully',
        async run() {
            context.response = await fetch('./vanilla-test-tests.wasm');
            if (!context.response.ok) throw new Error(`HTTP ${context.response.status}`);
            return `HTTP ${context.response.status}`;
        }
    },
    {
        name: 'server sends application/wasm',
        run() {
            const contentType = context.response.headers
                .get('content-type')
                ?.split(';')[0]
                .trim()
                .toLowerCase();
            if (contentType !== 'application/wasm') {
                throw new Error(`received ${contentType || 'no Content-Type'}`);
            }
            return contentType;
        }
    },
    {
        name: 'browser instantiates the generated test module',
        async run() {
            const module = await WebAssembly.instantiateStreaming(context.response);
            context.instance = module.instance;
            return 'native streaming compilation';
        }
    },
    {
        name: 'generated libtest harness exports main()',
        run() {
            if (typeof context.instance.exports.main !== 'function') {
                throw new TypeError('main() is not a function');
            }
            context.main = context.instance.exports.main;
            return 'safe callable export';
        }
    },
    {
        name: 'Rust libtest harness runs its own tests',
        run() {
            try {
                const exitCode = context.main();
                context.harnessStatus = `status ${exitCode}`;
                if (exitCode !== 0) throw new Error(`status ${exitCode}`);
                return 'all Rust tests passed; status 0';
            } catch (error) {
                if (context.harnessStatus === 'not run') context.harnessStatus = 'panic or trap';
                throw error;
            }
        }
    }
];

function record(state, name, note) {
    const level = state === 'failed' ? 'error' : state === 'skipped' ? 'warn' : 'log';
    const symbol = state === 'passed' ? '' : state === 'failed' ? '×' : '';
    const message = `${symbol} ${name}${note ? `  ${note}` : ''}`;
    counts[state] += 1;
    console[level](message);

    if (!page.checks) return;
    page.checks.querySelector('[data-rust-browser-waiting]')?.remove();
    const item = document.createElement('li');
    if (state === 'failed') item.className = 'failure';
    if (state === 'skipped') item.className = 'pending';
    item.textContent = `${name}${note ? `  ${note}` : ''}`;
    page.checks.append(item);
}

function finish(error) {
    const { passed, failed, skipped } = counts;
    const ok = failed === 0;
    const state = ok ? 'passed' : 'failed';
    const detail = ok
        ? 'The browser contract passed and Cargo’s Rust test inventory returned status 0.'
        : `${error?.message || String(error)} · ${passed} passed · ${failed} failed · ${skipped} skipped.`;

    document.documentElement.dataset.rustBrowser = state;
    if (page.result) page.result.dataset.ok = String(ok);
    if (page.status) page.status.textContent = ok ? 'Passed' : 'Failed';
    if (page.detail) page.detail.textContent = detail;
    if (page.score) {
        page.score.textContent = `${passed}/${tests.length}`;
        page.score.setAttribute('aria-label', `${passed} of ${tests.length} browser checks passed`);
    }
    if (page.passed) page.passed.textContent = String(passed);
    if (page.failed) page.failed.textContent = String(failed);
    if (page.skipped) page.skipped.textContent = String(skipped);
    if (page.harness) page.harness.textContent = context.harnessStatus;
    console[ok ? 'log' : 'error'](`Rust browser example ${state}: ${passed}/${tests.length} checks passed.`);
}

let failure;
let blockedBy;
for (const test of tests) {
    if (blockedBy) {
        record('skipped', test.name, `blocked by ${blockedBy}`);
        continue;
    }

    try {
        record('passed', test.name, await test.run());
    } catch (error) {
        failure ??= error;
        if (test.blocks !== false) blockedBy = test.name;
        record('failed', test.name, error?.message || String(error));
    }
}
finish(failure);