Skip to content

Commit ecca145

Browse files
committed
Website: use Jasmine framework for tests
I want to expand the website's code. We're gonna write some more tests, so to make testing easier, let's try out Jasmine. Start by porting our existing tests to Jasmine. I tried out Jest first, but Jest doesn't like .mjs files for some reason.
1 parent a65da97 commit ecca145

File tree

5 files changed

+263
-67
lines changed

5 files changed

+263
-67
lines changed

.github/workflows/build-and-test-web-demo.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ jobs:
4141
run: emmake cmake --install build --component wasm-demo --prefix website/demo
4242

4343
- name: JS configure
44-
run: cd website/demo && yarn
44+
run: cd website && yarn
4545
- name: JS test
46-
run: cd website/demo && yarn test
46+
run: cd website && yarn test demo/test-demo.mjs
4747

4848
- name: upload build to workflow
4949
uses: actions/upload-artifact@v2

website/demo/test.mjs renamed to website/demo/test-demo.mjs

Lines changed: 41 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,42 @@ function preElementWithHTML(html) {
1414
return element;
1515
}
1616

17-
let tests = {};
18-
19-
tests = {
20-
...tests,
21-
22-
"mark first word on line": () => {
17+
describe("markEditorText", () => {
18+
it("mark first word on line", () => {
2319
let editor = preElementWithHTML("hello world");
2420
markEditorText(editor, dom.window, [{ begin: 0, end: 5 }]);
2521
assert.strictEqual(editor.innerHTML, "<mark>hello</mark> world");
26-
},
22+
});
2723

28-
"mark last word on line": () => {
24+
it("mark last word on line", () => {
2925
let editor = preElementWithHTML("hello world");
3026
markEditorText(editor, dom.window, [{ begin: 6, end: 11 }]);
3127
assert.strictEqual(editor.innerHTML, "hello <mark>world</mark>");
32-
},
28+
});
3329

34-
"mark across two text nodes": () => {
30+
it("mark across two text nodes", () => {
3531
// <pre>helloworld</pre>
3632
let editor = dom.window.document.createElement("pre");
3733
editor.appendChild(dom.window.document.createTextNode("hello"));
3834
editor.appendChild(dom.window.document.createTextNode("world"));
3935

4036
markEditorText(editor, dom.window, [{ begin: 3, end: 8 }]);
4137
assert.strictEqual(editor.innerHTML, "hel<mark>lowor</mark>ld");
42-
},
38+
});
4339

44-
"marking deletes existing non-overlapping marks": () => {
40+
it("marking deletes existing non-overlapping marks", () => {
4541
let editor = preElementWithHTML("<mark>hello</mark> world");
4642
markEditorText(editor, dom.window, [{ begin: 6, end: 11 }]);
4743
assert.strictEqual(editor.innerHTML, "hello <mark>world</mark>");
48-
},
44+
});
4945

50-
"marking with no marks deletes existing marks": () => {
46+
it("marking with no marks deletes existing marks", () => {
5147
let editor = preElementWithHTML("<mark>hello</mark> <mark>world</mark>");
5248
markEditorText(editor, dom.window, []);
5349
assert.strictEqual(editor.innerHTML, "hello world");
54-
},
50+
});
5551

56-
"multiple new marks": () => {
52+
it("multiple new marks", () => {
5753
let editor = preElementWithHTML("hello world");
5854
markEditorText(editor, dom.window, [
5955
{ begin: 0, end: 5 },
@@ -63,51 +59,51 @@ tests = {
6359
editor.innerHTML,
6460
"<mark>hello</mark> <mark>world</mark>"
6561
);
66-
},
62+
});
6763

68-
"marking removes empty <mark>": () => {
64+
it("marking removes empty <mark>", () => {
6965
let editor = preElementWithHTML("<mark></mark> world");
7066
markEditorText(editor, dom.window, [{ begin: 1, end: 6 }]);
7167
assert.strictEqual(editor.innerHTML, " <mark>world</mark>");
72-
},
68+
});
7369

74-
"marking preserves <br> immediately after mark": () => {
70+
it("marking preserves <br> immediately after mark", () => {
7571
let editor = preElementWithHTML("hello<br>world");
7672
markEditorText(editor, dom.window, [{ begin: 0, end: 5 }]);
7773
assert.strictEqual(editor.innerHTML, "<mark>hello</mark><br>world");
78-
},
74+
});
7975

80-
"marking preserves <br> before inserted mark": () => {
76+
it("marking preserves <br> before inserted mark", () => {
8177
let editor = preElementWithHTML("one<br>twothree");
8278
markEditorText(editor, dom.window, [{ begin: 7, end: 7 + "three".length }]);
8379
assert.strictEqual(editor.innerHTML, "one<br>two<mark>three</mark>");
84-
},
80+
});
8581

86-
"marking preserves <br> after inserted mark": () => {
82+
it("marking preserves <br> after inserted mark", () => {
8783
let editor = preElementWithHTML("onetwo<br>three");
8884
markEditorText(editor, dom.window, [{ begin: 0, end: 3 }]);
8985
assert.strictEqual(editor.innerHTML, "<mark>one</mark>two<br>three");
90-
},
86+
});
9187

92-
"mark exactly over existing <mark>": () => {
88+
it("mark exactly over existing <mark>", () => {
9389
let editor = preElementWithHTML("<mark>hello</mark> world");
9490
markEditorText(editor, dom.window, [{ begin: 0, end: 5 }]);
9591
assert.strictEqual(editor.innerHTML, "<mark>hello</mark> world");
96-
},
92+
});
9793

98-
"mark starts at end of existing <mark>": () => {
94+
it("mark starts at end of existing <mark>", () => {
9995
let editor = preElementWithHTML("<mark>hello</mark>world");
10096
markEditorText(editor, dom.window, [{ begin: 5, end: 10 }]);
10197
assert.strictEqual(editor.innerHTML, "hello<mark>world</mark>");
102-
},
98+
});
10399

104-
"add empty mark": () => {
100+
it("add empty mark", () => {
105101
let editor = preElementWithHTML("helloworld");
106102
markEditorText(editor, dom.window, [{ begin: 5, end: 5 }]);
107103
assert.strictEqual(editor.innerHTML, "hello<mark></mark>world");
108-
},
104+
});
109105

110-
"add empty mark immediately after non-empty mark": () => {
106+
it("add empty mark immediately after non-empty mark", () => {
111107
let editor = preElementWithHTML("helloworld");
112108
markEditorText(editor, dom.window, [
113109
{ begin: 0, end: 5 },
@@ -117,22 +113,20 @@ tests = {
117113
editor.innerHTML,
118114
"<mark>hello</mark><mark></mark>world"
119115
);
120-
},
121-
};
116+
});
122117

123-
tests = {
124-
...tests,
125-
126-
"identical marks are merged": () => {
118+
it("identical marks are merged", () => {
127119
let editor = preElementWithHTML("helloworld");
128120
markEditorText(editor, dom.window, [
129121
{ begin: 0, end: 5 },
130122
{ begin: 0, end: 5 },
131123
]);
132124
assert.strictEqual(editor.innerHTML, "<mark>hello</mark>world");
133-
},
125+
});
126+
});
134127

135-
"marks are sorted before processing": () => {
128+
describe("sanitizeMarks", () => {
129+
it("marks are sorted before processing", () => {
136130
let marks = [
137131
{ begin: 6, end: 11 },
138132
{ begin: 0, end: 5 },
@@ -141,41 +135,24 @@ tests = {
141135
{ begin: 0, end: 5 },
142136
{ begin: 6, end: 11 },
143137
]);
144-
},
138+
});
145139

146-
"empty marks are preserved": () => {
140+
it("empty marks are preserved", () => {
147141
let marks = [{ begin: 6, end: 6 }];
148142
assert.deepStrictEqual(sanitizeMarks(marks), [{ begin: 6, end: 6 }]);
149-
},
150-
};
151-
152-
tests = {
153-
...tests,
143+
});
144+
});
154145

155-
"parse and lint returns errors": async () => {
146+
describe("parseAndLint", () => {
147+
it("parse and lint returns errors", async () => {
156148
let input = "undeclared_variable;\nanother_undeclared_variable;\n";
157149
let qljs = await loadQuickLintJS();
158150
let marks = qljs.parseAndLint(input);
159151
assert.deepStrictEqual(marks, [
160152
{ begin: 0, end: "undeclared_variable".length },
161153
{ begin: 21, end: 21 + "another_undeclared_variable".length },
162154
]);
163-
},
164-
};
165-
166-
async function main() {
167-
for (let testName in tests) {
168-
if (Object.prototype.hasOwnProperty.call(tests, testName)) {
169-
let test = tests[testName];
170-
console.log(`Running ${testName} ...`);
171-
await test();
172-
}
173-
}
174-
console.log("All tests passed");
175-
}
176-
main().catch((error) => {
177-
console.error(error.stack);
178-
process.exit(1);
155+
});
179156
});
180157

181158
// quick-lint-js finds bugs in JavaScript programs.

website/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"scripts": {
33
"fmt": "prettier --write '**/*.css' '**/*.html' '**/*.js' '**/*.mjs'",
4-
"test": "node --experimental-modules demo/test.mjs"
4+
"test": "node --experimental-modules run-tests.mjs"
55
},
66
"devDependencies": {
7+
"colors": "^1.4.0",
8+
"jasmine": "^3.7.0",
79
"jsdom": "16.4.0",
810
"prettier": "2.1.2"
911
}

website/run-tests.mjs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright (C) 2020 Matthew Glazar
2+
// See end of file for extended copyright information.
3+
4+
import Jasmine from "jasmine";
5+
import colors from "colors";
6+
import fs from "fs";
7+
8+
function main() {
9+
let jasmine = new Jasmine();
10+
jasmine.loadConfig({
11+
spec_files: ["!node_modules/**", "**/test-*.mjs"],
12+
stopSpecOnExpectationFailure: true,
13+
random: false,
14+
});
15+
jasmine.clearReporters();
16+
jasmine.addReporter(new BasicReporter());
17+
let { fileNames, testNames } = parseCommandLineOptions();
18+
jasmine.execute(fileNames, testNames);
19+
}
20+
21+
function parseCommandLineOptions() {
22+
let options = process.argv.slice(2);
23+
24+
let fileNames = [];
25+
let testNames = [];
26+
for (let option of options) {
27+
if (fs.existsSync(option)) {
28+
fileNames.push(option);
29+
} else {
30+
testNames.push(option);
31+
}
32+
}
33+
if (testNames.length > 1) {
34+
console.error(
35+
`${colors.red("ERROR")} only one test name filter is allowed`
36+
);
37+
process.exit(1);
38+
}
39+
return { fileNames, testNames };
40+
}
41+
42+
class BasicReporter {
43+
constructor() {
44+
this._executedTests = 0;
45+
}
46+
47+
jasmineStarted(_summary) {}
48+
49+
jasmineDone(summary) {
50+
switch (summary.overallStatus) {
51+
case "passed":
52+
if (this._executedTests === 0) {
53+
console.error(`${colors.red("ERROR")} no tests executed`);
54+
process.exit(1);
55+
}
56+
break;
57+
58+
case "incomplete":
59+
console.error(`${colors.red("ERROR")} ${summary.incompleteReason}`);
60+
process.exit(1);
61+
break;
62+
63+
case "failed":
64+
// specDone should have killed the process already. But just in case...
65+
console.error(`${colors.red("ERROR")} tests failed`);
66+
process.exit(1);
67+
break;
68+
69+
default:
70+
console.error(
71+
`${colors.red("ERROR")} unknown status: ${summary.overallStatus}`
72+
);
73+
process.exit(1);
74+
break;
75+
}
76+
}
77+
78+
suiteStarted(_suite) {}
79+
80+
suiteDone(_suite) {}
81+
82+
specStarted(spec) {
83+
console.error(`Running ${spec.fullName} ...`);
84+
}
85+
86+
specDone(spec) {
87+
switch (spec.status) {
88+
case "passed":
89+
console.error(`${colors.green("OK")} ${spec.fullName}`);
90+
this._executedTests += 1;
91+
break;
92+
93+
case "excluded":
94+
console.error(`${colors.yellow("SKIP")} ${spec.fullName}`);
95+
break;
96+
97+
default:
98+
case "failed":
99+
for (let failure of spec.failedExpectations) {
100+
console.error(failure.stack);
101+
}
102+
console.error(`${colors.red("FAIL")} ${spec.fullName}`);
103+
process.exit(1);
104+
break;
105+
}
106+
}
107+
}
108+
109+
main();
110+
111+
// quick-lint-js finds bugs in JavaScript programs.
112+
// Copyright (C) 2020 Matthew Glazar
113+
//
114+
// This file is part of quick-lint-js.
115+
//
116+
// quick-lint-js is free software: you can redistribute it and/or modify
117+
// it under the terms of the GNU General Public License as published by
118+
// the Free Software Foundation, either version 3 of the License, or
119+
// (at your option) any later version.
120+
//
121+
// quick-lint-js is distributed in the hope that it will be useful,
122+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
123+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
124+
// GNU General Public License for more details.
125+
//
126+
// You should have received a copy of the GNU General Public License
127+
// along with quick-lint-js. If not, see <https://www.gnu.org/licenses/>.

0 commit comments

Comments
 (0)