Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dilirity committed Jul 24, 2024
1 parent 57dc718 commit bce7ee2
Show file tree
Hide file tree
Showing 12 changed files with 791 additions and 359 deletions.
677 changes: 321 additions & 356 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions projects/js-packages/critical-css-gen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"build:node": "tsc --project tsconfig.node.json",
"build": "npm run clean && npm run build:browser && npm run build:node",
"clean": "rm -rf lib/ && rm -rf dist/",
"test": "jest tests"
"test": "NODE_ENV=test NODE_PATH=./node_modules jest --forceExit --config=tests/config/jest.config.js"
},
"main": "./lib/back-end.js",
"browser": "./dist/bundle.js",
Expand All @@ -40,14 +40,16 @@
"eslint": "8.22.0",
"express": "4.18.1",
"https-browserify": "1.0.0",
"jest-environment-puppeteer": "6.1.1",
"jest": "29.7.0",
"jest-environment-puppeteer": "10.0.1",
"node-fetch": "3.2.10",
"nodemon": "3.1.2",
"os-browserify": "0.3.0",
"path-browserify": "1.0.1",
"playwright-core": "1.33.0",
"prettier": "npm:[email protected]",
"puppeteer": "16.2.0",
"puppeteer": "22.13.1",
"puppeteer-core": "22.13.1",
"rollup": "2.78.1",
"rollup-plugin-polyfill-node": "0.10.2",
"rollup-plugin-terser": "7.0.2",
Expand All @@ -73,6 +75,14 @@
"clean-css": "5.3.1",
"css-tree": "2.3.1"
},
"peerDependencies": {
"puppeteer-core": "22.13.1"
},
"peerDependenciesMeta": {
"puppeteer-core": {
"optional": true
}
},
"overrides": {
"eslint-plugin-jsdoc": "46.8.2"
}
Expand Down
12 changes: 12 additions & 0 deletions projects/js-packages/critical-css-gen/tests/babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
jest.setTimeout( 60000 );
jest.spyOn( global.console, 'log' ).mockImplementation( () => jest.fn() );
jest.spyOn( global.console, 'debug' ).mockImplementation( () => jest.fn() );
11 changes: 11 additions & 0 deletions projects/js-packages/critical-css-gen/tests/config/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
rootDir: '../',
testEnvironment: 'jest-environment-node',
testMatch: [ '**/?(*.)+(spec|test).js' ],
setupFilesAfterEnv: [ './config/jest-setup.js' ],
collectCoverageFrom: [ '../lib/*.js' ],
globalSetup: 'jest-environment-puppeteer/setup',
globalTeardown: 'jest-environment-puppeteer/teardown',
testPathIgnorePatterns: [ '/node_modules/', 'config/jest-setup.js', 'lib/*' ],
moduleDirectories: [ 'lib', 'node_modules' ],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* This rule is included using complex media="" rules, so should be appropriately wrapped */
div.complex_media_rules {
color: purple;
}
29 changes: 29 additions & 0 deletions projects/js-packages/critical-css-gen/tests/data/page-a/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<html>
<head>
<title>Test page</title>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="print.css" media="print" />
<link rel="stylesheet" href="min-width.css" media="(min-width: 50px)" />
<link
rel="stylesheet"
type="text/css"
media="only screen and (max-device-width: 480px) and (orientation: landscape)"
href="complex-rules.css"
/>
"
<meta name="testing-page" content="testing-page" />
</head>

<body>
<div class="top"></div>
<div class="four_eighty"></div>
<div class="eight_hundred"></div>
<div class="sir_not_appearing_in_this_film"></div>
<div class="min_width_screen"></div>
<div class="complex_media_rules"></div>

<script>
document.writeln(["script", "created", "content"].join("-"));
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@media screen {
/* This rule should appear inside two media rules; min-width and screen */
div.min_width_screen {
color: pink;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* These rules are included in a media="print" link, and so should not be
included in the end result, ever. */

div.sir_not_appearing_in_this_film {
color: red;
}
54 changes: 54 additions & 0 deletions projects/js-packages/critical-css-gen/tests/data/page-a/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
body {
padding: 0px;
margin: 0px;
}

div.top {
position: absolute;
top: 0px;
}

div.four_eighty {
position: absolute;
top: 480px;
}

div.six_hundred {
position: absolute;
top: 600px;
}

div.seven_sixty_eight {
position: absolute;
top: 768px;
}

@media print {
div.top::before {
content: "print";
}
}

@media not screen {
div.top::before {
content: "not screen";
}
}

@media print {
div.top::before {
content: "print";
}
}

@media screen {
div.top::before {
content: "screen";
}
}

@media all {
div.top::before {
content: "all";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/* global CriticalCSSGenerator */
const puppeteer = require( 'puppeteer' );

Check failure on line 2 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

There should be no empty line between import groups

const path = require( 'path' );

Check failure on line 4 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

`path` import should occur before import of `puppeteer`
const TestServer = require( '../lib/test-server' );
const { dataDirectory } = require( '../lib/data-directory' );

Check failure on line 6 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

`../lib/data-directory` import should occur before import of `../lib/test-server`

let testServer = null;
let browser;

describe( 'Iframe interface', () => {
// Start test server to serve wrapped content.
beforeAll( async () => {
testServer = new TestServer( {
'page-a': path.join( dataDirectory, 'page-a' ),
} );
await testServer.start();

browser = await puppeteer.launch();
} );

// Kill test server.
afterAll( async () => {
if ( testServer ) {
await testServer.stop();
testServer = null;
}
if ( browser ) {
await browser.close();
}
} );

it( 'Successfully generates via iframes', async () => {
const page = await browser.newPage();
page.on( 'console', msg => process.stderr.write( msg.text() + '\n\n' ) );
await page.goto( testServer.getUrl() );

const innerUrl = path.join( testServer.getUrl(), 'page-a' );

const [ css, warnings ] = await page.evaluate( url => {
return CriticalCSSGenerator.generateCriticalCSS( {
urls: [ url ],
viewports: [ { width: 640, height: 480 } ],
browserInterface: new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: ( url, innerWindow, innerDocument ) => {

Check failure on line 45 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'url' is already declared in the upper scope on line 40 column 50
return !! innerDocument.querySelector( 'meta[name="testing-page"]' );
},
} ),
} );
}, innerUrl );

expect( warnings ).toHaveLength( 0 );
expect( css ).toContain( 'div.top' );

await page.close();
} );

it( 'Allows scripts if not explicitly turned off', async () => {

Check warning on line 58 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Test has no assertions
const page = await browser.newPage();
await page.goto( testServer.getUrl() );

const innerUrl = path.join( testServer.getUrl(), 'page-a' );

// Will throw an error if the inner page does not contain
// 'script-created-content'; a string appended to page-a by a script.
await page.evaluate( async url => {
const iframeInterface = new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: ( url, innerWindow, innerDocument ) => {

Check failure on line 68 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'url' is already declared in the upper scope on line 66 column 30
return innerDocument.documentElement.innerHTML.includes( 'script-created-content' );
},
} );

await iframeInterface.loadPage( url );
}, innerUrl );

await page.close();
} );

it( 'Blocks scripts if turned off', async () => {

Check warning on line 79 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Test has no assertions
const page = await browser.newPage();
await page.goto( testServer.getUrl() );

const innerUrl = path.join( testServer.getUrl(), 'page-a' );

// Will throw an error if the inner page contains
// 'script-created-content'; a string appended to page-a by a script.
await page.evaluate( async url => {
const iframeInterface = new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: ( url, innerWindow, innerDocument ) => {

Check failure on line 89 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'url' is already declared in the upper scope on line 87 column 30
return ! innerDocument.documentElement.innerHTML.includes( 'script-created-content' );
},
allowScripts: false,
} );

await iframeInterface.loadPage( url );
}, innerUrl );

await page.close();
} );

it( 'Can successfully generate using an iframe with JavaScript off', async () => {
const page = await browser.newPage();
await page.goto( testServer.getUrl() );

const innerUrl = path.join( testServer.getUrl(), 'page-a' );

const [ css, warnings ] = await page.evaluate( url => {
return CriticalCSSGenerator.generateCriticalCSS( {
urls: [ url ],
viewports: [ { width: 640, height: 480 } ],
browserInterface: new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: ( url, innerWindow, innerDocument ) => {

Check failure on line 112 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'url' is already declared in the upper scope on line 107 column 50
return !! innerDocument.querySelector( 'meta[name="testing-page"]' );
},
allowScripts: false,
} ),
} );
}, innerUrl );

expect( warnings ).toHaveLength( 0 );
expect( css ).toContain( 'div.top' );

await page.close();
} );

it( 'Throws an error if a successRatio is not met', async () => {
const page = await browser.newPage();
await page.goto( testServer.getUrl() );

const innerUrl = path.join( testServer.getUrl(), 'page-a' );

Check failure on line 130 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'innerUrl' is assigned a value but never used

await expect( async () => {
await page.evaluate( () => {
return CriticalCSSGenerator.generateCriticalCSS( {
urls: [ 'about:blank', 'about:blank' ],
viewports: [ { width: 640, height: 480 } ],
browserInterface: new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: () => false,
} ),
successRatio: 0.5,
} );
} );
} ).rejects.toThrow( /Insufficient pages loaded/ );

await page.close();
} );

it( 'Does not throw an error if successRatio is met', async () => {
const page = await browser.newPage();
await page.goto( testServer.getUrl() );

const innerUrl = path.join( testServer.getUrl(), 'page-a' );

const [ css, warnings ] = await page.evaluate( url => {
return CriticalCSSGenerator.generateCriticalCSS( {
urls: [ 'about:blank', url ],
viewports: [ { width: 640, height: 480 } ],
browserInterface: new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: ( url, innerWindow, innerDocument ) => {

Check failure on line 159 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'url' is already declared in the upper scope on line 154 column 50
return !! innerDocument.querySelector( 'meta[name="testing-page"]' );
},
} ),
successRatio: 0.5,
} );
}, innerUrl );

expect( warnings ).toHaveLength( 0 );
expect( css ).toContain( 'div.top' );

await page.close();
} );

it( 'Does not load more pages than the maxPages specifies', async () => {
const page = await browser.newPage();
await page.goto( testServer.getUrl() );

const pageA = path.join( testServer.getUrl(), 'page-a' );
const pageB = path.join( testServer.getUrl(), 'page-b' );

const [ css, warnings, pages ] = await page.evaluate(
async ( pageA, pageB ) => {

Check failure on line 181 in projects/js-packages/critical-css-gen/tests/unit/browser-interface-iframe.test.js

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'pageA' is already declared in the upper scope on line 177 column 9
let pagesVerified = [];
const result = await CriticalCSSGenerator.generateCriticalCSS( {
urls: [ 'about:blank', pageA, pageB, 'about:blank' ],
viewports: [ { width: 640, height: 480 } ],
browserInterface: new CriticalCSSGenerator.BrowserInterfaceIframe( {
verifyPage: ( url, innerWindow, innerDocument ) => {
pagesVerified.push( url );
return !! innerDocument.querySelector( 'meta[name="testing-page"]' );
},
} ),
successRatio: 0.25,
maxPages: 1,
} );

return [ ...result, pagesVerified ];
},
pageA,
pageB
);

expect( pages ).not.toContain( pageB );
expect( warnings ).toHaveLength( 0 );
expect( css ).toContain( 'div.top' );

await page.close();
} );
} );
Loading

0 comments on commit bce7ee2

Please sign in to comment.