Skip to content

How to use strict mode

Add strict: true to the state

Pass strict: true alongside data and/or behavior:

import { describe, it, mock, assert } from 'utest';

describe('strict mode', () => {
    it('dies on an unmocked ubus call', () => {
        assert.throws(() => {
            mock.inject('ubus', { strict: true, data: {} }, (m_ubus) => {
                m_ubus.connect().call('unmocked', 'method', {});
            });
        }, /strict mock/);
    });
});

The error message matches the pattern strict mock and identifies the module and function or key that was accessed.


Use with assert.throws to verify call gating

Wrap the code under test in a thunk and pass it to assert.throws(). Provide a pattern that matches the strict mock error so unrelated errors are not silently swallowed:

// uci: dies when code reads a package that was not seeded
assert.throws(() => {
    mock.inject('uci', { strict: true, data: {} }, (m_uci) => {
        m_uci.cursor().get('no-pkg', 'sec', 'opt');
    });
}, /strict mock/);

// uclient: dies when code requests an unmocked URL
assert.throws(() => {
    mock.inject('uclient', { strict: true, data: {} }, (m_uclient) => {
        let u = m_uclient.new('http://example.com/x', null, {});
        u.request('GET', {});
    });
}, /strict mock/);

Discover required keys before enabling strict mode

If you are unsure which keys your code accesses, run without strict mode first. Any unmocked key returns null silently, so the code runs freely and you can observe its behaviour. Then enable strict mode and seed exactly the keys you confirmed it needs:

// Without strict — unmocked keys return null silently
mock.inject('uci', {
    data: { 'network': { 'lan': { '.type': 'interface', 'ipaddr': '192.168.1.1' } } }
}, (m_uci) => {
    const result = get_lan_summary(m_uci.cursor());
});

// With strict — every accessed key must be seeded
mock.inject('uci', {
    strict: true,
    data: { 'network': { 'lan': { '.type': 'interface', 'ipaddr': '192.168.1.1', 'proto': 'static' } } }
}, (m_uci) => {
    const result = get_lan_summary(m_uci.cursor());
    assert.match('192.168.1.1', result.ip);
});

Combine strict with partial data

Seed the data you expect to be accessed and let strict mode catch anything unexpected. This verifies that the code under test does not make calls beyond what the test intends:

mock.inject('ubus', {
    strict: true,
    data: { 'system:board': { model: 'Test Router' } }
}, (m_ubus) => {
    let conn = m_ubus.connect();
    // This call is allowed — the key is seeded:
    assert.match('Test Router', conn.call('system', 'board', {}).model);

    // Any call to an unseeded object/method would die here.
});

Strict mode and lsdir / glob

For fs, strict mode suppresses the real filesystem when listing directories or matching globs. Only virtual entries appear in lsdir() and glob() results.


Next steps