Skip to content

Commit

Permalink
fix(screenshots): prevent infinite blocking (#3)
Browse files Browse the repository at this point in the history
Global functions alert and confirm block and never return without user
action which won't happen in headless mode. This fix makes these
functions return immediately.

This also improves tests to catch more issues with screenshots (like
timing out or not generating one per example).
  • Loading branch information
Thomaash committed Oct 7, 2019
1 parent 71dd0c3 commit b28725c
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 48 deletions.
23 changes: 21 additions & 2 deletions .circleci/config.yml
Expand Up @@ -4,6 +4,23 @@
#
version: 2.1

commands:
install-deps-for-screenshot-taking:
description: Install headless Chromium dependencies
steps:
- run:
name: Install Headless Chromium dependencies
command: |
sudo apt-get install -yq \
ca-certificates fonts-liberation gconf-service libappindicator1 \
libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 \
libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 \
libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 \
libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 \
libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget \
xdg-utils
executors:
node:
docker:
Expand Down Expand Up @@ -39,7 +56,7 @@ jobs:
- persist_to_workspace:
root: .
paths:
- '*'
- "*"

build:
executor: node
Expand All @@ -53,7 +70,7 @@ jobs:
- persist_to_workspace:
root: .
paths:
- 'bin'
- "bin"

lint:
executor: node
Expand All @@ -71,6 +88,8 @@ jobs:
- attach_workspace:
at: .

- install-deps-for-screenshot-taking

- run: npm run test

release:
Expand Down
5 changes: 5 additions & 0 deletions @types/index.d.ts
Expand Up @@ -7,3 +7,8 @@ declare module "*.html" {
const value: string;
export default value;
}

declare module "*.txt" {
const value: string;
export default value;
}
4 changes: 2 additions & 2 deletions rollup.config.js
Expand Up @@ -26,11 +26,11 @@ export default ["generate-examples-index"].map(name => {
external,
plugins: [
nodeResolve({
extensions: [".ts", ".js", ".json", ".css", ".html"],
extensions: [".css", ".html", ".js", ".json", ".ts", ".txt"],
preferBuiltins: true
}),
string({
include: ["**/*.{css,html}"]
include: ["**/*.{css,html,txt}"]
}),
typescript({
objectHashIgnoreUnknownHack: true,
Expand Down
6 changes: 5 additions & 1 deletion src/generate-examples-index/index.ts
@@ -1,6 +1,7 @@
import Pageres from "pageres";
import $ from "cheerio";
import Pageres from "pageres";
import childProcess from "child_process";
import commonScreenshotScript from "./screenshot-script.js.txt";
import crypto from "crypto";
import fs from "fs";
import globby from "globby";
Expand Down Expand Up @@ -530,6 +531,9 @@ class ContentBuilder {
);
const screenshotPage = $.load(example.html);
screenshotPage("head").prepend(
$("<script>")
.attr("type", "text/javascript")
.text(commonScreenshotScript),
$("<script>")
.attr("type", "text/javascript")
.text(this._screenshotScript)
Expand Down
25 changes: 0 additions & 25 deletions src/generate-examples-index/screenshot-script.js

This file was deleted.

12 changes: 12 additions & 0 deletions src/generate-examples-index/screenshot-script.js.txt
@@ -0,0 +1,12 @@
/* global window: false */

/**
* Simulates confirmation usind window.confirm and window.alert otherwise the
* screenshot generator would just hang forever.
*/
(function() {
window.alert = function() {};
window.confirm = function() {
return true;
};
})();
52 changes: 34 additions & 18 deletions test/generate-examples-index/basic.test.ts
Expand Up @@ -3,60 +3,76 @@ import childProcess from "child_process";
import fs from "fs";
import path from "path";
import tmp from "tmp-promise";
import util from "util";
import { expect } from "chai";

const exec = childProcess.execSync;
const exec = util.promisify(childProcess.exec);
const executable = path.resolve(
`${exec("npm root")}/../bin/generate-examples-index.js`
);
const examplesPath = path.resolve(`${__dirname}/examples`);

const baseURL = "https://visjs.github.io/vis-test";
const nmExamples = 6;
const title = "Test Examples";

describe("generate-examples-index", function(): void {
const { name: output } = tmp.fileSync({ mode: 0o600, postfix: "html" });
const { name: outputDir } = tmp.dirSync({ mode: 0o700 });
const outputIndex = path.join(outputDir, "index.html");
const outputScreenshots = path.join(outputDir, "thumbnails");
let $index: CheerioStatic;

it("built", function(): void {
it("is executable built", function(): void {
expect(
fs.existsSync(executable),
"The built executable has to be present for any of the following tests to pass."
).to.be.true;
});

it("generate index", function(): void {
this.timeout(60000);
it("generate index", async function(): Promise<void> {
this.timeout(10 * 60 * 1000);

exec(
await exec(
[
"node",
executable,
"-c test-element",
"-i",
`-d "${examplesPath}"`,
`-o ${output}`,
`-t "${title}"`,
`-w "${baseURL}"`
"--container-id test-element",
"--index",
"--screenshots",
`--examples-directory "${examplesPath}"`,
`--output "${outputIndex}"`,
`--title "${title}"`,
`--web-url "${baseURL}"`
].join(" ")
);

$index = $.load(fs.readFileSync(output, "utf-8"));
});

describe("verify index", function(): void {
it("valid HTML", function(): void {
$index = $.load(fs.readFileSync(outputIndex, "utf-8"));
});

it("title", function(): void {
expect($index("title").text()).to.equal(title);
});

it("examples", function(): void {
it("links", function(): void {
expect(
$index(".example-link").length,
"There should be 4 links to examples."
).to.equal(4);
`There should be ${nmExamples} links to examples.`
).to.equal(nmExamples);
});

it("screenshots", function(): void {
expect(
fs.readdirSync(outputScreenshots),
`There should be ${nmExamples} screenshots.`
).have.lengthOf(nmExamples);
});

for (const i of [0, 1, 2, 3]) {
for (const i of new Array(nmExamples)
.fill(null)
.map((_value, i): number => i)) {
describe(`example ${i + 1}`, function(): void {
function getNthExample(n: number): Cheerio {
return $index(".example-link").eq(n);
Expand Down
16 changes: 16 additions & 0 deletions test/generate-examples-index/examples/example-alert.html
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Test | Alert</title>

<script type="text/javascript" src="../dist/test.min.js"></script>

<script type="text/javascript">
alert("This is just a test.");
</script>
</head>

<body>
<div id="test-element"></div>
</body>
</html>
16 changes: 16 additions & 0 deletions test/generate-examples-index/examples/example-confirm.html
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Test | Confirm</title>

<script type="text/javascript" src="../dist/test.min.js"></script>

<script type="text/javascript">
Confirm("This is just a test.");
</script>
</head>

<body>
<div id="test-element"></div>
</body>
</html>

0 comments on commit b28725c

Please sign in to comment.