Skip to content

Commit 9499152

Browse files
authored
Merge pull request #68 from developit/perf-test-harness
Perf test harness
2 parents 8d14f03 + 37831c9 commit 9499152

File tree

4 files changed

+154
-17
lines changed

4 files changed

+154
-17
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"build:babel": "cd packages/babel-plugin-htm && npm run build",
1414
"build:babel-transform-jsx": "cd packages/babel-plugin-transform-jsx-to-htm && npm run build",
1515
"test": "eslint src/**/*.mjs test/**/*.mjs && npm run build && jest test",
16+
"test:perf": "v8 test/__perftest.mjs",
1617
"release": "npm t && git commit -am \"$npm_package_version\" && git tag $npm_package_version && git push && git push --tags && npm publish"
1718
},
1819
"files": [

test/__d8.mjs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*global globalThis*/
2+
3+
const queue = [];
4+
let stack = [];
5+
let index = 0;
6+
7+
async function process() {
8+
const id = index++;
9+
if (id === queue.length) {
10+
queue.length = index = 0;
11+
return;
12+
}
13+
const [op, name, fn, extra] = queue[id];
14+
queue[id] = undefined;
15+
await processors[op](name, fn, extra);
16+
await process();
17+
}
18+
19+
const processors = {
20+
async describe(name, fn, path) {
21+
stack.push(name);
22+
log('INFO', name);
23+
await fn();
24+
stack.pop();
25+
},
26+
async test(name, fn, path) {
27+
let stackBefore = stack;
28+
stack = path.concat(name);
29+
logBuffer = [];
30+
await new Promise(resolve => {
31+
let calls = 0;
32+
const done = () => {
33+
if (calls++) throw Error(`Callback called multiple times\n\t${name}`);
34+
log('INFO', `✅ ${name}`);
35+
resolve();
36+
};
37+
Promise.resolve(done)
38+
.then(fn)
39+
.then(() => calls || done())
40+
.catch(err => {
41+
log('ERROR', `🚨 ${name}`);
42+
log('ERROR', '\t' + String(err.stack || err.message || err));
43+
resolve();
44+
});
45+
});
46+
for (let i=0; i<logBuffer.length; i++) log(...logBuffer[i]);
47+
logBuffer = undefined;
48+
stack = stackBefore;
49+
}
50+
};
51+
52+
53+
let logBuffer;
54+
55+
function wrap(obj, method) {
56+
obj[method] = function() {
57+
let out = ' ';
58+
for (let i=0; i<arguments.length; i++) {
59+
let val = arguments[i];
60+
if (typeof val === 'object' && val) {
61+
val = JSON.stringify(val);
62+
}
63+
if (out) out += ' ';
64+
out += val;
65+
}
66+
if (method!=='error') out = `\u001b[37m${out}\u001b[0m`;
67+
if (logBuffer) {
68+
logBuffer.push([method.toUpperCase(), out]);
69+
}
70+
else {
71+
log(method.toUpperCase(), out);
72+
}
73+
};
74+
}
75+
wrap(console, 'log');
76+
wrap(console, 'info');
77+
wrap(console, 'warn');
78+
wrap(console, 'error');
79+
80+
function log(type, msg) {
81+
if (type === 'ERROR') {
82+
msg = `\u001b[31m${msg}\u001b[39m`;
83+
}
84+
if (type === 'SUCCESS') {
85+
msg = `\u001b[32m${msg}\u001b[39m`;
86+
}
87+
print(Array.from({ length: stack.length }).fill(' ').join('') + msg);
88+
}
89+
90+
function push(op, name, fn, extra) {
91+
if (queue.push([op, name, fn, extra]) === 1) {
92+
setTimeout(process);
93+
}
94+
}
95+
96+
globalThis.describe = (name, fn) => {
97+
push('describe', name, fn, stack.slice());
98+
};
99+
100+
globalThis.test = (name, fn) => {
101+
push('test', name, fn, stack.slice());
102+
};
103+
104+
globalThis.expect = (subject) => new Expect(subject);
105+
106+
const SUBJECT = Symbol.for('subject');
107+
const NEGATED = Symbol.for('negated');
108+
class Expect {
109+
constructor(subject) {
110+
this[SUBJECT] = subject;
111+
}
112+
get not() {
113+
this[NEGATED] = true;
114+
return this;
115+
}
116+
toBeGreaterThan(value) {
117+
const subject = this[SUBJECT];
118+
const negated = this[NEGATED];
119+
120+
const isOver = subject > value;
121+
let msg = `Expected ${subject}${negated?' not':''} to be greater than ${value}`;
122+
if (logBuffer) {
123+
for (let i=logBuffer.length; i-- > -1; ) {
124+
if (i<0 || logBuffer[i][2] === 1) {
125+
logBuffer.splice(i+1, 0, [isOver !== negated ? 'SUCCESS' : 'ERROR', ' ' + msg, 1]);
126+
break;
127+
}
128+
}
129+
}
130+
else {
131+
log(isOver !== negated ? 'SUCCESS' : 'ERROR', ' ' + msg);
132+
}
133+
}
134+
}

test/__perftest.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import './__d8.mjs';
2+
import './perf.test.mjs';

test/perf.test.mjs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ describe('performance', () => {
2020
test('creation', () => {
2121
const results = [];
2222
const Foo = ({ name }) => html`<div class="foo">${name}</div>`;
23-
const statics = [
24-
'\n<div id=app data-loading="true">\n\t<h1>Hello World</h1>\n\t<ul class="items" id=', '>\n\t',
25-
'\n\t</ul>\n\t\n\t<', ' name="foo" />\n\t<', ' name="other">content</', '>\n\n</div>'
26-
];
2723
let count = 0;
2824
function go(count) {
25+
const statics = [
26+
'\n<div id=app'+(++count)+' data-loading="true">\n\t<h1>Hello World</h1>\n\t<ul class="items" id=', '>\n\t',
27+
'\n\t</ul>\n\t\n\t<', ' name="foo" />\n\t<', ' name="other">content<//>\n\n</div>'
28+
];
2929
return html(
30-
statics.concat(['count:', count]),
30+
statics,
3131
`id${count}`,
32-
html(['<li data-id="','">', '</li>'], 'i'+count, 'some text #'+count),
33-
Foo, Foo, Foo
32+
html`<li data-id="${'i' + count}">${'some text #' + count}</li>`,
33+
Foo, Foo
3434
);
3535
}
3636
let now = performance.now();
@@ -50,18 +50,18 @@ describe('performance', () => {
5050
test('usage', () => {
5151
const results = [];
5252
const Foo = ({ name }) => html`<div class="foo">${name}</div>`;
53-
const statics = [
54-
'\n<div id=app data-loading="true">\n\t<h1>Hello World</h1>\n\t<ul class="items" id=', '>\n\t',
55-
'\n\t</ul>\n\t\n\t<', ' name="foo" />\n\t<', ' name="other">content</', '>\n\n</div>'
56-
];
5753
let count = 0;
5854
function go(count) {
59-
return html(
60-
statics,
61-
`id${count}`,
62-
html(['<li data-id="','">', '</li>'], 'i'+count, 'some text #'+count),
63-
Foo, Foo, Foo
64-
);
55+
return html`
56+
<div id="app" data-loading="true">
57+
<h1>Hello World</h1>
58+
<ul class="items" id=${`id${count}`}>
59+
${html`<li data-id="${'i' + count}">${'some text #' + count}</li>`}
60+
</ul>
61+
<${Foo} name="foo" />
62+
<${Foo} name="other">content<//>
63+
</div>
64+
`;
6565
}
6666
let now = performance.now();
6767
const start = now;

0 commit comments

Comments
 (0)