function mounting(create) {
const node = document.createElement('div');
try {
owned(() => foreign(node, create, () => ({ level: 1 }), 'gauge'));
} catch (e) {
return String(e && e.message ? e.message : e);
}
return '';
}
function conforming() {
return { update() {}, destroy() {} };
}
test('a conforming module mounts and is not refused', () => {
assert.equal(mounting(() => conforming()), '');
});
test('every non-callable import is refused, naming the declaration', () => {
const imported = [
[5, 'a number'],
['mount', 'a string'],
[{ mount: () => conforming() }, 'an object'],
[undefined, 'undefined'],
[null, 'null'],
];
for (const [value, described] of imported) {
const message = mounting(value);
assert.ok(message.includes('`gauge`'), 'unnamed declaration for ' + described + ': ' + message);
assert.ok(message.includes(described), 'wrong description: ' + message);
assert.ok(
message.includes('mount(node, props) -> { update(props), destroy() }'),
'the contract is not stated: ' + message
);
}
assert.equal(imported.length, 5, 'the fixture list shrank without the assertion moving');
});
test('a class is refused before it is called', () => {
const message = mounting(class Scene {});
assert.ok(message.includes('`gauge`'), 'unnamed declaration: ' + message);
assert.ok(message.includes('a class'), 'the message does not say it is a class: ' + message);
assert.ok(message.includes('`new`'), 'the message does not say why: ' + message);
});
test('an ordinary function is not mistaken for a class', () => {
assert.equal(
mounting(function mount() {
return conforming();
}),
''
);
assert.equal(mounting(() => conforming()), '');
});
test('a handle missing either method is refused, naming which', () => {
const cases = [
[() => ({ destroy() {} }), 'no `update`'],
[() => ({ update() {} }), 'no `destroy`'],
[() => ({}), 'neither `update` nor `destroy`'],
[() => ({ update: 1, destroy: 2 }), 'neither `update` nor `destroy`'],
];
for (const [create, expected] of cases) {
const message = mounting(create);
assert.ok(message.includes('`gauge`'), 'unnamed declaration: ' + message);
assert.ok(message.includes(expected), 'expected ' + expected + ', got: ' + message);
}
assert.equal(cases.length, 4, 'the fixture list shrank without the assertion moving');
});
test('a mount that returns something other than a handle is refused', () => {
for (const [create, described] of [
[() => undefined, 'undefined'],
[() => null, 'null'],
[() => 7, 'a number'],
]) {
const message = mounting(create);
assert.ok(message.includes('`gauge`'), 'unnamed declaration: ' + message);
assert.ok(message.includes(described), 'expected ' + described + ', got: ' + message);
}
});
test('a write after a checked mount still reaches update', () => {
const node = document.createElement('div');
const [level, setLevel] = signal(1);
const seen = [];
owned(() =>
foreign(
node,
() => ({
update(next) {
seen.push(next.level);
},
destroy() {},
}),
() => ({ level: level() }),
'gauge'
)
);
setLevel(2);
setLevel(3);
assert.equal(seen.join(','), '2,3');
});