Skip to content

Commit 92375f8

Browse files
authored
Replace coverage API with recursive document.stylesheets (#57)
1 parent 7812264 commit 92375f8

File tree

4 files changed

+92
-40
lines changed

4 files changed

+92
-40
lines changed

src/index.js

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module.exports = async (url, {
3232
// Set an explicit UserAgent, because the default UserAgent string includes something like
3333
// `HeadlessChrome/88.0.4298.0` and some websites/CDN's block that with a HTTP 403
3434
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0')
35-
await page.coverage.startCSSCoverage()
35+
3636
url = normalizeUrl(url, {stripWWW: false})
3737

3838
let response
@@ -70,23 +70,44 @@ module.exports = async (url, {
7070
return response.text()
7171
}
7272

73-
const coverage = await page.coverage.stopCSSCoverage()
74-
7573
// Get all CSS generated with the CSSStyleSheet API
7674
// This is primarily for CSS-in-JS solutions
7775
// See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText
7876
const styleSheetsApiCss = await page.evaluate(() => {
79-
return [...document.styleSheets]
80-
// Only take the stylesheets without href, because those with href are
81-
// <link> tags, and we already tackled those with the Coverage API
82-
.filter(stylesheet => stylesheet.href === null)
83-
.map(stylesheet => {
84-
return {
85-
type: stylesheet.ownerNode.tagName.toLowerCase(),
86-
href: stylesheet.href || document.location.href,
87-
css: [...stylesheet.cssRules].map(({cssText}) => cssText).join('\n')
77+
function getCssFromStyleSheet(stylesheet) {
78+
var items = []
79+
var styleType = stylesheet.ownerNode ?
80+
stylesheet.ownerNode.tagName.toLowerCase() :
81+
'import'
82+
83+
var sheetCss = ''
84+
85+
for (var rule of stylesheet.cssRules) {
86+
// eslint-disable-next-line no-undef
87+
if (rule instanceof CSSImportRule) {
88+
var imported = getCssFromStyleSheet(rule.styleSheet)
89+
items = items.concat(imported)
8890
}
89-
})
91+
92+
sheetCss += rule.cssText
93+
94+
items.push({
95+
type: styleType,
96+
href: stylesheet.href || document.location.href,
97+
css: sheetCss
98+
})
99+
}
100+
101+
return items
102+
}
103+
104+
let styles = []
105+
106+
for (const stylesheet of document.styleSheets) {
107+
styles = styles.concat(getCssFromStyleSheet(stylesheet))
108+
}
109+
110+
return styles
90111
})
91112

92113
// Get all inline styles: <element style="">
@@ -116,21 +137,7 @@ module.exports = async (url, {
116137

117138
await browser.close()
118139

119-
const links = coverage
120-
// Filter out the <style> tags that were found in the coverage
121-
// report since we've conducted our own search for them.
122-
// A coverage CSS item with the same url as the url of the page
123-
// we requested is an indication that this was a <style> tag
124-
.filter(entry => entry.url !== url)
125-
.map(entry => ({
126-
href: entry.url,
127-
css: entry.text,
128-
type: 'link-or-import'
129-
}))
130-
131-
const css = links
132-
.concat(styleSheetsApiCss)
133-
.concat(inlineStyles === 'exclude' ? [] : inlineCss)
140+
const css = styleSheetsApiCss.concat(inlineCss)
134141

135142
// Return the complete structure ...
136143
if (origins === 'include') {

test/index.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,25 @@ test('it finds css in a <link> tag - HTML', async t => {
2020

2121
t.true(actual.includes('.link-in-html { }'))
2222
t.true(actual.includes('@import url("import-in-css.css")'))
23-
t.true(actual.includes('.css-imported-with-css {}'))
23+
t.true(actual.includes('.css-imported-with-css { }'))
24+
t.snapshot(actual)
2425
})
2526

2627
test('it finds css in a <link> tag - JS', async t => {
2728
const actual = await extractCss(server.url + '/link-tag-js.html')
2829

29-
t.true(actual.includes('.link-tag-created-with-js {}'))
30+
t.true(actual.includes('.link-tag-created-with-js'))
3031
t.true(actual.includes('@import url("import-in-css.css")'))
31-
t.true(actual.includes('.css-imported-with-css {}'))
32+
t.true(actual.includes('.css-imported-with-css { }'))
33+
t.snapshot(actual)
3234
})
3335

3436
test('it finds css in a <style> tag - HTML', async t => {
3537
const actual = await extractCss(server.url + '/style-tag-html.html')
3638

3739
t.true(actual.includes('.fixture { color: red; }'))
3840
t.true(actual.includes('@import url("import-in-css.css")'))
39-
t.true(actual.includes('.css-imported-with-css {}'))
41+
t.true(actual.includes('.css-imported-with-css { }'))
4042
t.snapshot(actual)
4143
})
4244

@@ -49,14 +51,15 @@ test('it reports CSS in a <style> tag in HTML only once', async t => {
4951
const lastOccurence = actual.lastIndexOf('.fixture')
5052

5153
t.is(firstOccurence, lastOccurence)
54+
t.snapshot(actual)
5255
})
5356

5457
test('it finds css in a <style> tag - JS', async t => {
5558
const actual = await extractCss(server.url + '/style-tag-js.html')
5659

5760
t.true(actual.includes('.fixture { color: red; }'))
5861
t.true(actual.includes('@import url("import-in-js.css")'))
59-
t.true(actual.includes('.css-imported-with-js {}'))
62+
t.true(actual.includes('.css-imported-with-js { }'))
6063
t.snapshot(actual)
6164
})
6265

@@ -72,11 +75,12 @@ test('it finds CSS implemented in a mixed methods (inline, links, style tags)',
7275
const actual = await extractCss(server.url + '/kitchen-sink.html')
7376

7477
t.true(actual.includes('@import url("import-in-css.css")'))
75-
t.true(actual.includes('.css-imported-with-css {}'))
78+
t.true(actual.includes('.css-imported-with-css { }'))
7679
t.true(actual.includes('[x-extract-css-inline-style]'))
7780
t.true(actual.includes('[x-extract-css-inline-style] { background-image: url(\'background-image-inline-style-attribute-in-html\'); }'))
7881
t.true(actual.includes('[x-extract-css-inline-style] { background-image: url("background-image-inline-style-js-cssText"); }'))
7982
t.true(actual.includes('[x-extract-css-inline-style] { background-image: url("background-image-inline-style-js-with-prop"); }'))
83+
t.snapshot(actual)
8084
})
8185

8286
test('it finds inline styles - HTML', async t => {
@@ -111,13 +115,13 @@ test('it returns an array of entries when the `origins` option equals `include`'
111115
})
112116

113117
t.true(Array.isArray(actual), 'Result should be an array when { origins: `include` }')
114-
t.is(actual.length, 10)
118+
t.is(actual.length, 12)
115119

116120
function isString(item) {
117121
return typeof item === 'string'
118122
}
119123

120-
t.true(actual.every(item => isString(item.type) && ['link-or-import', 'style', 'inline'].includes(item.type)))
124+
t.true(actual.every(item => isString(item.type) && ['link', 'import', 'style', 'inline'].includes(item.type)))
121125
t.true(actual.every(item => isString(item.href)))
122126
t.true(actual.every(item => item.href.startsWith('http://localhost:') && /\.(html|css)$/.test(item.href)))
123127
t.true(actual.every(item => isString(item.css)))

test/snapshots/index.js.md

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,69 @@ The actual snapshot is saved in `index.js.snap`.
44

55
Generated by [AVA](https://avajs.dev).
66

7+
## it finds css in a <link> tag - HTML
8+
9+
> Snapshot 1
10+
11+
`.css-imported-with-css { }␊
12+
@import url("import-in-css.css");␊
13+
@import url("import-in-css.css");.link-in-html { }`
14+
15+
## it finds css in a <link> tag - JS
16+
17+
> Snapshot 1
18+
19+
`.css-imported-with-css { }␊
20+
@import url("import-in-css.css");␊
21+
@import url("import-in-css.css");.link-tag-created-with-js { }`
22+
723
## it finds css in a <style> tag - HTML
824

925
> Snapshot 1
1026
11-
`.css-imported-with-css {}␊
27+
`.css-imported-with-css { }␊
1228
@import url("import-in-css.css");␊
13-
.fixture { color: red; }`
29+
@import url("import-in-css.css");.fixture { color: red; }`
30+
31+
## it reports CSS in a <style> tag in HTML only once
32+
33+
> Snapshot 1
34+
35+
`.css-imported-with-css { }␊
36+
@import url("import-in-css.css");␊
37+
@import url("import-in-css.css");.fixture { color: red; }`
1438

1539
## it finds css in a <style> tag - JS
1640

1741
> Snapshot 1
1842
19-
`.css-imported-with-js {}␊
43+
`.css-imported-with-js { }␊
2044
@import url("import-in-js.css");␊
21-
.fixture { color: red; }`
45+
@import url("import-in-js.css");.fixture { color: red; }`
2246

2347
## it finds css-in-js
2448

2549
> Snapshot 1
2650
2751
'.bcMPWx { color: blue; }'
2852

53+
## it finds CSS implemented in a mixed methods (inline, links, style tags)
54+
55+
> Snapshot 1
56+
57+
`.css-imported-with-css { }␊
58+
@import url("import-in-css.css");␊
59+
@import url("import-in-css.css");.link-in-html { }␊
60+
.style-tag-in-html { color: green; }␊
61+
.js-insertRule { color: red; }␊
62+
.css-imported-with-css { }␊
63+
@import url("import-in-css.css");␊
64+
@import url("import-in-css.css");.link-tag-created-with-js { }␊
65+
.style-tag-js { }␊
66+
[x-extract-css-inline-style] { background-image: url('background-image-inline-style-attribute-in-html'); }␊
67+
[x-extract-css-inline-style] { background-image: url("background-image-inline-style-js-cssText"); }␊
68+
[x-extract-css-inline-style] { background-image: url("background-image-inline-style-js-with-prop"); }`
69+
2970
## it finds inline styles - HTML
3071

3172
> Snapshot 1

test/snapshots/index.js.snap

254 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)