Skip to content

Commit

Permalink
Merge pull request #678 from w3c/use_nightmarejs
Browse files Browse the repository at this point in the history
Use nightmarejs
  • Loading branch information
Marcos Caceres committed Apr 14, 2016
2 parents fcf5068 + 5243894 commit 7f84f62
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 134 deletions.
4 changes: 2 additions & 2 deletions js/core/base-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
// these need to be improved, or complemented with proper UI indications
if (window.console) {
respecEvents.sub("warn", function (details) {
console.warn("WARN: ", details);
console.warn(details);
});
respecEvents.sub("error", function (details) {
console.error("ERROR: ", details);
console.error(details);
});
respecEvents.sub("start", function (details) {
if (respecConfig && respecConfig.trace) console.log(">>> began: " + details);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"async": "^2.0.0-rc.2",
"chai": "^3.5.0",
"colors": "^1.1.2",
"command-line-args": "^2.1.6",
"epipebomb": "^0.1.1",
"express": "^4.13.4",
"fs-extra": "^0.26.7",
Expand All @@ -41,7 +42,7 @@
"mocha": "^2.4.5",
"moment": "^2.12.0",
"mozilla-download": "^1.1.1",
"phantomjs-prebuilt": "^2.1.7",
"nightmare": "^2.2.0",
"promise-polyfill": "^4.0.3",
"prompt": "^1.0.0",
"requirejs": "^2.2.0",
Expand Down
4 changes: 2 additions & 2 deletions tests/headless.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const excludedFiles = new Set([
"embedder.html",
"starter.html",
"basic.built.html",
"manifest.html",
]);

const runRespec2html = async(function*(server) {
Expand All @@ -56,8 +57,7 @@ const runRespec2html = async(function*(server) {

// Incrementally spawn processes and add them to process counter.
const executables = sources.map((source) => {
let cmd = "phantomjs --ssl-protocol=any ./tools/respec2html.js " +
`--delay 1 -w -e ${server}/examples/${source} /dev/null 10`;
let cmd = `node ./tools/respec2html.js ${server}/examples/${source} > /dev/null`;
return cmd;
}).map(
toExecutable
Expand Down
295 changes: 166 additions & 129 deletions tools/respec2html.js
Original file line number Diff line number Diff line change
@@ -1,141 +1,178 @@
#!/usr/bin/env phantomjs --ssl-protocol=any

/*global phantom, respecEvents, respecConfig, require*/
// respec2html is a command line utility that converts a ReSpec source file to an HTML file.
// Depends on PhantomJS <http://phantomjs.org>.
#!/usr/local/bin/node

/*jshint node: true, browser: false*/
"use strict";
var page = require("webpage").create();
var args = require("system").args.slice();
var fs = require("fs");
var timer;
var reportErrors = false;
var reportWarnings = false;
var ignoreScripts = false;
var errors = [];
var warnings = [];
var delay = 0;
const async = require("marcosc-async");
const colors = require("colors");
const os = require("os");
colors.setTheme({
data: "grey",
debug: "cyan",
error: "red",
help: "cyan",
important: "red",
info: "green",
input: "grey",
prompt: "grey",
verbose: "cyan",
warn: "yellow",
});
const optionDefinitions = [{
alias: "h",
defaultValue: false,
description: "Display this usage guide.",
name: "help",
type: Boolean,
}, {
alias: "s",
defaultOption: true,
description: "URL to ReSpec source file.",
multiple: false,
name: "src",
type: String,
}, {
alias: "o",
defaultOption: false,
description: "Path to output file. When omitted, just stdout.",
multiple: false,
name: "out",
type: String,
}, {
alias: "t",
defaultValue: 10,
name: "timeout",
type: Number,
}, {
alias: "e",
default: false,
description: "Report ReSpec errors on stderr.",
name: "haltonerror",
type: Boolean,
}, {
alias: "w",
default: false,
description: "Report ReSpec warnings on stderr.",
name: "haltonwarn",
type: Boolean,
}];

// report console.error on stderr
console.error = function() {
require("system").stderr.write(Array.prototype.join.call(arguments, " ") + "\n");
const tasks = {
showHelp() {
const getUsage = require("command-line-usage");
const appDetails = {
title: "respec2html",
description: "Converts a ReSpec source file to HTML and prints to std out.",
footer: "Project home: [underline]{https://github.com/w3c/respec}"
};
console.log(getUsage(optionDefinitions, appDetails));
},
writeTo(outPath, data) {
const fsp = require("fs-promise");
const path = require("path");
return async.task(function* () {
let newFilePath = "";
if (path.isAbsolute(outPath)) {
newFilePath = outPath;
} else {
newFilePath = path.resolve(process.cwd(), outPath);
}
try {
yield fsp.writeFile(newFilePath, data, "utf-8");
} catch (err) {
console.error(err, err.stack);
process.exit(1);
}
});
},
makeTempDir(prefix) {
const fs = require("fs");
return new Promise((resolve, reject) => {
fs.mkdtemp(prefix, (err, folder) => {
return (err) ? reject(err) : resolve(folder);
});
});
},
};

var eOption = args.indexOf("-e");
if (eOption !== -1) {
args.splice(args.indexOf("-e"), 1);
reportErrors = true;
}

if (args.indexOf("-w") !== -1) {
args.splice(args.indexOf("-w"), 1);
reportWarnings = true;
}

if (args.indexOf("--delay") !== -1) {
delay = args.splice(args.indexOf("--delay"), 2)[1];
}

if (args.indexOf("--exclude-script") !== -1) {
var idx = args.indexOf("--exclude-script");
var values = args.splice(idx, 2);
ignoreScripts = values[1];
}

// Reading other parameters
var source = args[1];
var output = args[2];
var timeout = isNaN(args[3]) ? 5 : parseInt(args[3], 10);

if (args.length < 2 || args.length > 4) {
var usage = "Usage:\n phantomjs --ssl-protocol=any respec2html.js [-e] [-w] " +
"[--exclude-script url] respec-source [html-output] [timeout]\n" +
" respec-source ReSpec source file, or an URL to the file\n" +
" [-e] Report ReSpec errors on stderr\n" +
" [-w] Report ReSpec warnings on stderr\n" +
" [--exclude-script url] Do not load scripts whose source\n" +
" starts with the passed URL\n" +
" [html-output] Name for the HTML file to be generated,\n" +
" defaults to stdout\n" +
" [timeout] An optional timeout in seconds, default is 10\n";
console.error(usage);
phantom.exit(2);
function makeConsoleMsgHandler(nightmare) {
return function handleConsoleMessages(parsedArgs) {
nightmare.on("console", (type, message) => {
const abortOnWarning = parsedArgs.haltonwarn && type === "warn";
const abortOnError = parsedArgs.haltonerror && type === "error";
const output = `ReSpec ${type}: ${colors.debug(message)}`;
switch (type) {
case "error":
console.error(colors.error(`😱 ${output}`));
break;
case "warn":
// Ignore Nightmare's poling of respecDone
if (/document\.respecDone/.test(message)) {
return;
}
console.error(colors.warn(`😳 ${output}`));
break;
}
if (abortOnError || abortOnWarning) {
nightmare.proc.kill();
process.exit(1);
}
});
};
}

// Dealing with ReSpec source being loaded with scheme-relative link
// i.e. <script src='//www.w3.org/Tools/respec/respec-w3c-common'>
page.onResourceRequested = function(requestData, networkRequest) {
if (requestData.url === "file://www.w3.org/Tools/respec/respec-w3c-common") {
networkRequest.changeUrl("https://www.w3.org/Tools/respec/respec-w3c-common");
} else if (ignoreScripts && requestData.url.indexOf(ignoreScripts) === 0) {
networkRequest.abort();
}
};

page.onConsoleMessage = function(msg) {
if (msg.match(/^ERROR: /)) {
errors.push(msg);
} else if (msg.match(/^WARN: /)) {
warnings.push(msg);
async.task(function* run() {
const cli = require("command-line-args")(optionDefinitions);
let parsedArgs;
try {
parsedArgs = cli.parse();
} catch (err) {
console.error(err.stack);
tasks.showHelp();
process.exit(2);
}
};

page.onError = function(msg) {
errors.push(msg);
};

page.open(source, function(status) {
if (status !== "success") {
console.error("Unable to access ReSpec source file.");
return phantom.exit(1);
if (parsedArgs.help || !parsedArgs.src) {
tasks.showHelp();
return;
}
setTimeout(function() {
page.evaluateAsync(function() {
$.ajaxSetup({
timeout: 4000
});

function saveToPhantom() {
require(["core/ui", "ui/save-html"], function(ui, saver) {
saver.show(ui, respecConfig, document, respecEvents);
window.callPhantom({
html: saver.toString()
});
});
}
if (document.respecDone) {
saveToPhantom();
} else {
respecEvents.sub("end-all", saveToPhantom);
}
}, delay * 1000);
});
timer = setInterval(function() {
if (timeout === 0) {
clearInterval(timer);
console.error("Timeout loading " + source + ".\n" +
" Is it a valid ReSpec source file?\n" +
" Did you forget --ssl-protocol=any?");
phantom.exit(1);
const userData = yield tasks.makeTempDir(os.tmpDir() + "/respec2html-");
const Nightmare = require("nightmare");
const nightmare = new Nightmare({
show: false,
timeout: parsedArgs.timeout,
webPreferences: {
"images": false,
"defaultEncoding": "utf-8",
userData,
}
}, 1000);
});

page.onCallback = function(data) {
clearInterval(timer);
var code = 0;
if (warnings.length && reportWarnings) {
console.error(warnings.join("\n"));
code = 65;
}
if (errors.length && reportErrors) {
console.error(errors.join("\n"));
code = 64;
});
nightmare.useragent("respec2html");
const url = require("url")
.parse(parsedArgs.src)
.href;
const handleConsoleMessages = makeConsoleMsgHandler(nightmare);
handleConsoleMessages(parsedArgs);
const html = yield nightmare
.goto(url)
.wait(function () {
return document.respecDone;
})
.wait("#respec-modal-save-snapshot")
.click("#respec-modal-save-snapshot")
.wait(100)
.evaluate(function () {
var encodedText = document.querySelector("#respec-save-as-html").href;
var decodedText = decodeURIComponent(encodedText);
var cleanedUpText = decodedText.replace(/^data:text\/html;charset=utf-8,/, "");
return cleanedUpText;
})
.end();
if (!parsedArgs.out) {
return process.stdout.write(html);
}
if (output) {
fs.write(output, data.html, "w");
} else {
console.log(data.html);
try {
yield tasks.writeTo(parsedArgs.out, html);
} catch (err) {
console.error(err.stack);
process.exit(1);
}
phantom.exit(code);
};
});

0 comments on commit 7f84f62

Please sign in to comment.