8000 Added Jest (unit tests are WIP) · ulyssear/css-in-js-in-html@4fd5e17 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4fd5e17

Browse files
committed
Added Jest (unit tests are WIP)
1 parent b05c4ba commit 4fd5e17

File tree

6 files changed

+146
-7
lines changed

6 files changed

+146
-7
lines changed

jest-puppeteer.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
"launch": {
3+
"headless": "false"
4+
},
5+
"browserContext": "default"
6+
}

jest.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
"preset": "jest-puppeteer",
3+
"verbose": true
4+
}

package.json

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
"description": "",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no t 8000 est specified\" && exit 1",
7+
"test": "jest",
88
"format": "rome format --write --indent-style tab --line-width 160 --quote-style single index.js",
9-
"lint": "rome check index.js",
10-
"lint:fix": "rome check --apply-suggested index.js",
11-
"build": "esbuild index.js --bundle --outfile=index.min.js --minify --sourcemap"
9+
"lint": "rome check src/index.js",
10+
"lint:fix": "rome check --apply-suggested src/index.js",
11+
"build": "esbuild src/index.js --bundle --outfile=build/index.min.js --minify --sourcemap",
12+
"build:hot": "npm run build -- --watch",
13+
"start": "concurrently -n \"build,serve\" \"npm run build:hot\" \"npx serve build\""
1214
},
1315
"repository": {
1416
"type": "git",
@@ -22,6 +24,12 @@
2224
"license": "MIT",
2325
"dependencies": {
2426
"esbuild": "^0.16.13",
25-
"rome": "^11.0.0"
27+
"rome": "^11.0.0",
28+
"serve": "^14.1.2"
29+
},
30+
"devDependencies": {
31+
"concurrently": "^7.6.0",
32+
"jest": "^29.3.1",
33+
"jest-puppeteer": "^6.2.0"
2634
}
2735
}

index.js renamed to src/index.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ function apply_custom_class(element, className) {
267267

268268
function do_apply(element, selectors, classes, events, media_query) {
269269
if (media_query) {
270+
if ('(' !== media_query[0]) {
271+
media_query = `(${media_query})`;
272+
}
270273
if (!window.matchMedia(media_query).matches) {
271274
return;
272275
}
@@ -361,7 +364,7 @@ function do_apply(element, selectors, classes, events, media_query) {
361364
function init(document, event = undefined) {
362365
const tag_console = `init : ${event ? `(${event.type})` : ''}`;
363366
console.time(tag_console);
364-
console.log(event?.type);
367+
// console.log(event?.type);
365368

366369
const elements = document.querySelectorAll('*:not(head, head *)[class]');
367370

@@ -374,7 +377,7 @@ function init(document, event = undefined) {
374377
}
375378
}
376379

377-
const observer = new MutationObserver(init);
380+
const observer = new MutationObserver(init_observer);
378381
observer.observe(document, {
379382
attributes: true,
380383
attributeFilter: ['class'],
@@ -388,9 +391,28 @@ function init(document, event = undefined) {
388391
document.body.removeAttribute('hidden');
389392
}
390393

394+
function init_observer(record) {
395+
console.time('init_observer');
396+
for (let i = 0; i < record.length; i++) {
397+
const { type, target, attributeName } = record[i];
398+
if (type === 'attributes' && attributeName === 'class') {
399+
apply_custom_class(target, target.className);
400+
}
401+
if (type === 'childList') {
402+
const elements = target.querySelectorAll('*:not(head, head *)[class]');
403+
for (let j = 0; j < elements.length; j++) {
404+
const element = elements[j];
405+
apply_custom_class(element, element.className);
406+
}
407+
}
408+
}
409+
console.timeEnd('init_observer');
410+
}
411+
391412
const CSS_IN_JS_IN_HTML = {
392413
// apply: apply_custom_class,
393414
init,
415+
fromClassNameToGroups: split_classname_to_classes_groups
394416
};
395417

396418
window.CSS_IN_JS_IN_HTML = CSS_IN_JS_IN_HTML;

tests/index.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Document test</title>
8+
</head>
9+
<body>
10+
<div id="example"></div>
11+
<div id="example-second">
12+
<ul>
13+
<li>One</li>
14+
<li>Two</li>
15+
<li>Three</li>
16+
</ul>
17+
</div>
18+
</body>
19+
</html>

tests/index.test.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const path = require('path');
2+
3+
async function getComputedStyle(element, pseudoElement = null) {
4+
return page.evaluate((element, pseudoElement) => {
5+
const style = window.getComputedStyle(element, pseudoElement);
6+
return JSON.parse(JSON.stringify(style));
7+
}, element, pseudoElement);
8+
}
9+
10+
async function getClasses(element) {
11+
return page.evaluate((element) => element.className, element);
12+
}
13+
14+
async function sleep(ms) {
15+
return new Promise(resolve => setTimeout(resolve, ms));
16+
}
17+
18+
const COLORS = {
19+
red: 'rgb(255, 0, 0)',
20+
green: 'rgb(0, 128, 0)',
21+
blue: 'rgb(0, 0, 255)',
22+
};
23+
24+
const EXAMPLES = {
25+
first: '.example',
26+
second: '.example:nth-of-type(2)'
27+
}
28+
29+
describe('CSS-in-JS-in-HTML process', () => {
30+
31+
beforeAll(async () => {
32+
const url = 'file://' + path.join(__dirname, 'index.html');
33+
34+
await page.goto(url);
35+
await page.addScriptTag({ path: path.join(__dirname, '..', 'build', 'index.min.js') });
36+
37+
await page.addScriptTag({
38+
content: `CSS_IN_JS_IN_HTML.init(document, null);`
39+
});
40+
});
41+
42+
describe('Classes only', () => {
43+
it('class "background-[red]" should be "background" as "red"', async () => {
44+
const element = await page.evaluate( async () => {
45+
const element = document.querySelector('#example');
46+
element.className = 'background-[red]';
47+
await Promise.resolve(setTimeout(() => {}, 1000));
48+
return JSON.parse(JSON.stringify(getComputedStyle(element)));
49+
});
50+
expect(element.backgroundColor).toBe(COLORS.red);
51+
});
52+
53+
it('class "background-[green] color-[blue]" should be "background" as "green" and "color" as "blue"', async () => {
54+
const element = await page.evaluate( async () => {
55+
const element = document.querySelector('#example');
56+
element.className = 'background-[green] color-[blue]';
57+
await Promise.resolve(setTimeout(() => {}, 1000));
58+
return JSON.parse(JSON.stringify(getComputedStyle(element)));
59+
});
60+
expect(element.backgroundColor).toBe(COLORS.green);
61+
expect(element.color).toBe(COLORS.blue);
62+
});
63+
});
64+
65+
describe('Selectors + Classes', () => {
66+
it('class "[ul]:display-[flex]" should be "display" as "flex" for every "ul" element in child tree', async () => {
67+
const is_every_ul_flex = await page.evaluate( async () => {
68+
const element = document.querySelector('#example-second');
69+
element.className = '[ul]:display-[flex]';
70+
await Promise.resolve(setTimeout(() => {}, 1000));
71+
const every_ul = element.querySelectorAll('ul');
72+
const check_every_ul = Array.from(every_ul).every((ul) => {
73+
return ul.style.display === 'flex';
74+
});
75+
return check_every_ul;
76+
});
77+
expect(is_every_ul_flex).toBe(true);
78+
});
79+
});
80+
});

0 commit comments

Comments
 (0)
0