bd-widgets
Version:
a library of user interface widgets built with Backdraft
150 lines (132 loc) • 5.01 kB
JavaScript
import {smoke} from '../node_modules/bd-smoke/smoke.js';
import {Component, e} from '../src/lib.js';
const assert = smoke.assert;
function delay(ms, resolve, value) {
ms ? setTimeout(() => resolve(value), ms) : resolve(ms);
}
function assertClassNameEq(_lhs, _rhs) {
const lhs = _lhs.trim().split(' ').sort();
const rhs = _rhs.trim().split(' ').sort();
if (lhs.length !== rhs.length || lhs.some((item, i) => (rhs[i] !== item))) {
assert(false, `"${_lhs}" !== "${_rhs}"`);
}
}
class TestContainer extends Component {
constructor(kwargs) {
super({ id: 'test-container', ...kwargs });
this._message = '';
this._prompt = '';
this.log = [];
this._throttle = 0;
}
get message() {
return this._message;
}
set message(value) {
this.bdMutate('message', '_message', value);
this.log.push(['message', value]);
}
get prompt() {
return this._prompt;
}
set prompt(value) {
this.bdMutate('prompt', '_prompt', value);
this.log.push(['prompt', value]);
}
start(test) {
this.test = test;
this.log = [];
this.log.push(['log', `starting test:${test.testName()}`]);
return this.log;
}
throttle(ms) {
this._throttle = ms;
}
finish(dump) {
if (dump) {
console.log(this.log.map(entry => smoke.stringify(entry)).join(',\n'));
}
while (this.children.length) {
this.delChild(this.children[0]);
}
this.message = 'test done';
this.prompt = 'nothing to do';
}
checkLog(expected) {
// i.e., return true iff there is NOT
// some log entry, i, such that there is an item, j in that entry that is different than expected
assert(!this.log.some((entry, i) => {
const expectedEntry = expected[i];
return entry.some((item, j) => {
if (smoke.stringify(item) !== smoke.stringify(expectedEntry[j])) {
this.test.logger.logNote(`unexpected log entry (${i}, ${j})`);
this.test.logger.logNote(`expected: ${smoke.stringify(expectedEntry)}`);
this.test.logger.logNote(`actual: ${smoke.stringify(entry)}`);
return true;
}
return false;
});
}));
}
monitor(component) {
component.constructor.watchables.forEach(prop => component.watch(prop, (newValue, oldValue, owner) => {
assert(owner === component);
// console.log('watch', prop, newValue, oldValue);
if (prop !== 'parent') {
this.log.push(['watch', prop, newValue, oldValue]);
}
}));
component.constructor.events.forEach(eventName => component.advise(eventName, event => {
// console.log('event', eventName, event);
if (event instanceof Event) {
this.log.push(['native event', eventName, { type: event.type }]);
} else if (event.nativeEvent instanceof Event) {
this.log.push(['native event', eventName, { type: event.nativeEvent.type }]);
} else {
this.log.push(['event', eventName, event]);
}
}));
}
waitForValue(component, prop, value, actions) {
if (typeof actions === 'string') {
this.prompt = actions;
} else if (actions) {
actions.prompt && (this.prompt = actions.prompt);
smoke.queueActions(actions);
}
return new Promise(resolve => {
const h = component.watch(prop, newValue => {
if (typeof value === 'function' ? value(newValue) : newValue === value) {
h.destroy();
delay(this._throttle, resolve);
}
});
});
}
waitForEvent(component, eventName, actions) {
if (typeof actions === 'string') {
this.prompt = actions;
} else if (actions) {
actions.prompt && (this.prompt = actions.prompt);
smoke.queueActions(actions);
}
return new Promise(resolve => {
const h = component.advise(eventName, () => {
h.destroy();
delay(this._throttle, resolve);
});
});
}
bdElements() {
const style = { margin: '1em', border: '1px solid black', padding: '1em' };
return e('div', { className: 'top' },
e('div', { className: 'widget-container', bdChildrenAttachPoint: true, style }),
e('div', { style: { margin: '1em' } },
e('h3', 'Should Now Observe'),
e('div', { bdReflect: 'message' }),
e('h4', 'Take these actions next...'),
e('div', { bdReflect: 'prompt' }),));
}
}
export {TestContainer, smoke, assert, assertClassNameEq};
export * from '../src/lib.js';