update node CI script to work with SauceLabs
This commit is contained in:
271
ci.js
271
ci.js
@@ -1,11 +1,12 @@
|
|||||||
const path = require("path"),
|
const path = require("path"),
|
||||||
port = 3000,
|
fs = require('fs'),
|
||||||
|
port = 5555,
|
||||||
colors = {
|
colors = {
|
||||||
"passed" : "\x1B[32m",
|
"passed" : "\x1B[32m",
|
||||||
"failed": "\x1B[31m",
|
"failed": "\x1B[31m",
|
||||||
"pending": "\x1B[33m",
|
"pending": "\x1B[33m",
|
||||||
"none": "\x1B[0m"
|
"none": "\x1B[0m"
|
||||||
};
|
},
|
||||||
symbols = {
|
symbols = {
|
||||||
"passed" : ".",
|
"passed" : ".",
|
||||||
"failed": "F",
|
"failed": "F",
|
||||||
@@ -13,138 +14,192 @@ const path = require("path"),
|
|||||||
"none": ""
|
"none": ""
|
||||||
},
|
},
|
||||||
host = `http://localhost:${port}`,
|
host = `http://localhost:${port}`,
|
||||||
exitCode = 0;
|
useSauce = process.env.USE_SAUCE === 'true';
|
||||||
|
let driver, server;
|
||||||
|
|
||||||
(async () => {
|
function pageGenerator() {
|
||||||
const html = await (() => {
|
const ejs = require("ejs"),
|
||||||
console.log("Generating index.html for express app...");
|
fg = require("fast-glob"),
|
||||||
const pug = require("pug"),
|
templatePath = path.resolve(__dirname, 'spec/support/index.html.ejs'),
|
||||||
fg = require("fast-glob"),
|
template = ejs.compile(fs.readFileSync(templatePath).toString()),
|
||||||
patterns = [
|
patterns = [
|
||||||
"lib/jasmine-core/jasmine.js",
|
"lib/jasmine-core/jasmine.js",
|
||||||
"lib/jasmine-core/json2.js",
|
"lib/jasmine-core/json2.js",
|
||||||
"lib/jasmine-core/jasmine-html.js",
|
"lib/jasmine-core/jasmine-html.js",
|
||||||
"lib/jasmine-core/boot.js",
|
"lib/jasmine-core/boot.js",
|
||||||
"src/core/requireCore.js",
|
"src/core/requireCore.js",
|
||||||
"src/core/base.js",
|
"src/core/base.js",
|
||||||
"src/core/util.js",
|
"src/core/util.js",
|
||||||
"src/core/Spec.js",
|
"src/core/Spec.js",
|
||||||
"src/core/Env.js",
|
"src/core/Env.js",
|
||||||
"src/**/*.js",
|
"src/**/*.js",
|
||||||
"spec/helpers/*.js",
|
"spec/helpers/*.js",
|
||||||
"spec/**/*[Ss]pec.js"
|
"spec/**/*[Ss]pec.js"
|
||||||
],
|
],
|
||||||
ignore = [
|
ignore = [
|
||||||
"spec/helpers/nodeDefineJasmineUnderTest.js",
|
"spec/helpers/nodeDefineJasmineUnderTest.js",
|
||||||
"spec/npmPackage/**/*",
|
"spec/npmPackage/**/*",
|
||||||
"lib/jasmine-core/node_boot.js"
|
"lib/jasmine-core/node_boot.js"
|
||||||
];
|
];
|
||||||
files = fg.sync(patterns, {ignore});
|
|
||||||
return Promise.resolve(pug.compileFile(path.resolve(__dirname, "index.pug"), { pretty: true })({files}));
|
|
||||||
})();
|
|
||||||
|
|
||||||
await (() => new Promise(resolve => {
|
return function toHtml() {
|
||||||
|
const files = fg.sync(patterns, {ignore});
|
||||||
|
return template({files});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildWebdriver() {
|
||||||
|
const webdriver = require("selenium-webdriver"),
|
||||||
|
Capability = webdriver.Capability;
|
||||||
|
if (useSauce) {
|
||||||
|
const username = process.env['SAUCE_USERNAME'],
|
||||||
|
accessKey = process.env['SAUCE_ACCESS_KEY'];
|
||||||
|
return new webdriver.Builder()
|
||||||
|
.withCapabilities({
|
||||||
|
name: `jasmine-core ${new Date().toISOString()}`,
|
||||||
|
[Capability.PLATFORM]: process.env['SAUCE_OS'],
|
||||||
|
[Capability.BROWSER_NAME]: process.env['JASMINE_BROWSER'],
|
||||||
|
[Capability.VERSION]: process.env['SAUCE_BROWSER_VERSION'],
|
||||||
|
build: `Core ${process.env['TRAVIS_BUILD_NUMBER'] || 'Ran locally'}`,
|
||||||
|
tags: ['Jasmine-Core'],
|
||||||
|
"tunnel-identifier": process.env['TRAVIS_JOB_NUMBER'] ? process.env['TRAVIS_BUILD_NUMBER'].toString() : null
|
||||||
|
})
|
||||||
|
.usingServer(`http://${username}:${accessKey}@localhost:4445/wd/hub`)
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
return new webdriver.Builder()
|
||||||
|
.forBrowser(process.env["JASMINE_BROWSER"] || "firefox")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resultsWithoutCircularReferences(driver, resultType, index, batchSize) {
|
||||||
|
return await driver.executeScript(
|
||||||
|
`var results = jsApiReporter.${resultType}Results(${index}, ${batchSize});\n` +
|
||||||
|
'for (var i = 0; i < results.length; i++) {\n' +
|
||||||
|
'var expectations = results[i].failedExpectations;\n' +
|
||||||
|
'if (results[i].passedExpectations) {\n' +
|
||||||
|
'expectations = expectations.concat(results[i].passedExpectations);\n' +
|
||||||
|
'}\n' +
|
||||||
|
'for (var j = 0; j < expectations.length; j++) {\n' +
|
||||||
|
'var expectation = expectations[j];\n' +
|
||||||
|
"try { JSON.stringify(expectation.expected); } catch (e) { expectation.expected = '<circular expected>'; }\n" +
|
||||||
|
"try { JSON.stringify(expectation.actual); } catch (e) { expectation.actual = '<circular actual>'; }\n" +
|
||||||
|
'}\n' +
|
||||||
|
'}\n' +
|
||||||
|
'return results;'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten(arr) {
|
||||||
|
return Array.prototype.concat.apply([], arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getResults(driver) {
|
||||||
|
const batchSize = 50,
|
||||||
|
specResults = [],
|
||||||
|
failedSuiteResults = [];
|
||||||
|
let index = 0,
|
||||||
|
slice = [];
|
||||||
|
|
||||||
|
do {
|
||||||
|
slice = await resultsWithoutCircularReferences(driver, 'spec', index, batchSize);
|
||||||
|
specResults.push(slice);
|
||||||
|
index += batchSize;
|
||||||
|
} while (slice.length === batchSize);
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
do {
|
||||||
|
slice = await resultsWithoutCircularReferences(driver, 'suite', index, batchSize);
|
||||||
|
failedSuiteResults.push(slice.filter(function(suite) { return suite.status === 'failed' }));
|
||||||
|
index += batchSize;
|
||||||
|
} while (slice.length === batchSize);
|
||||||
|
|
||||||
|
return {specResults: flatten(specResults), failedSuiteResults: flatten(failedSuiteResults)};
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
await new Promise(resolve => {
|
||||||
console.log("Creating an express app for browers to run the tests...")
|
console.log("Creating an express app for browers to run the tests...")
|
||||||
const express = require("express"),
|
const express = require("express"),
|
||||||
app = express();
|
app = express(),
|
||||||
|
html = pageGenerator();
|
||||||
|
|
||||||
app.use(express.static(__dirname));
|
app.use(express.static(__dirname));
|
||||||
app.get("/", (req, res) => res.send(html));
|
app.get("/", (req, res) => res.send(html()));
|
||||||
app.listen(port, resolve);
|
server = app.listen(port, resolve);
|
||||||
}))();
|
});
|
||||||
|
|
||||||
const driver = await (() => new Promise(resolve => (async () => {
|
|
||||||
console.log("Running the tests in browser...")
|
|
||||||
const webdriver = require("selenium-webdriver"),
|
|
||||||
driver = new webdriver.Builder()
|
|
||||||
.forBrowser(process.env["JASMINE_BROWSER"] || "firefox")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
await driver.get(`${host}/?throwFailures=false&failFast=false&random=true`)
|
console.log("Running the tests in browser...")
|
||||||
|
driver = buildWebdriver();
|
||||||
|
await driver.get(`${host}/?throwFailures=false&failFast=false&random=true`)
|
||||||
|
await new Promise(resolve => {
|
||||||
const intervalId = setInterval(async () => {
|
const intervalId = setInterval(async () => {
|
||||||
const isFinished = await driver.executeScript("return jsApiReporter && jsApiReporter.finished")
|
const isFinished = await driver.executeScript("return jsApiReporter && jsApiReporter.finished")
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
clearInterval(intervalId)
|
clearInterval(intervalId)
|
||||||
resolve(driver)
|
resolve();
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
})()))();
|
});
|
||||||
|
|
||||||
await (() => new Promise(resolve => (async () => {
|
const {specResults, failedSuiteResults} = await getResults(driver);
|
||||||
// output the summary
|
console.log(specResults.map(spec => `${colors[spec.status]}${symbols[spec.status]}`).join("") + colors["none"]);
|
||||||
(await driver.executeScript("return jsApiReporter && jsApiReporter.specs().map(function(spec) { return spec.status })"))
|
|
||||||
.map(status => `${colors[status]}${symbols[status]}`).join("") + colors["none"];
|
|
||||||
resolve();
|
|
||||||
})()))();
|
|
||||||
|
|
||||||
await (() => new Promise(resolve => (async () => {
|
const result = specResults.reduce((result, spec) => {
|
||||||
// output the pending and failure details
|
result[spec.status] = [...result[spec.status], spec];
|
||||||
const result = (await driver.executeScript("return jsApiReporter && jsApiReporter.specs().filter(function(spec) { return spec.status !== \"passed\" })"))
|
return result;
|
||||||
.reduce((result, spec) => {
|
}, {pending: [], failed: [], passed: []});
|
||||||
result[spec.status] = result[spec.status] || [];
|
|
||||||
result[spec.status] = [...result[spec.status], spec];
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
if ((result["pending"] || []).length) {
|
if (result.pending.length) {
|
||||||
console.log(`${colors["pending"]}Pending:`);
|
console.log(`${colors["pending"]}Pending:`);
|
||||||
result["pending"].forEach((spec, index) => {
|
result.pending.forEach((spec, index) => {
|
||||||
console.log(`${colors["none"]}${index}) ${spec.fullName}`)
|
console.log(`${colors["none"]}${index}) ${spec.fullName}`)
|
||||||
|
console.group();
|
||||||
|
console.log(`${colors["pending"]}${spec.pendingReason || "no reason given"}`);
|
||||||
|
console.groupEnd();
|
||||||
|
console.log();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.failed.length) {
|
||||||
|
process.exitCode = 1
|
||||||
|
console.log(`${colors["failed"]}Failed:`);
|
||||||
|
result["failed"].forEach((spec, index) => {
|
||||||
|
console.log(`${colors["none"]}${index}) ${spec.fullName}`)
|
||||||
|
console.group();
|
||||||
|
spec.failedExpectations.forEach((expect) => {
|
||||||
|
console.log(`${colors["none"]}Message:`);
|
||||||
console.group();
|
console.group();
|
||||||
console.log(`${colors["pending"]}${spec.pendingReason || "no reason given"}`);
|
console.log(`${colors["failed"]}${expect.message}`);
|
||||||
console.groupEnd();
|
console.groupEnd();
|
||||||
console.log();
|
console.log(`${colors["none"]}Stack:`);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result["failed"] || []).length) {
|
|
||||||
exitCode = 1
|
|
||||||
console.log(`${colors["failed"]}Failed:`);
|
|
||||||
result["failed"].forEach((spec, index) => {
|
|
||||||
console.log(`${colors["none"]}${index}) ${spec.fullName}`)
|
|
||||||
console.group();
|
console.group();
|
||||||
spec.failedExpectations.forEach((expect) => {
|
console.log(`${colors["failed"]}${expect.stack}`);
|
||||||
console.log(`${colors["none"]}Message:`);
|
|
||||||
console.group();
|
|
||||||
console.log(`${colors["failed"]}${expect.message}`);
|
|
||||||
console.groupEnd();
|
|
||||||
console.log(`${colors["none"]}Stack:`);
|
|
||||||
console.group();
|
|
||||||
console.log(`${colors["failed"]}${expect.stack}`);
|
|
||||||
console.groupEnd();
|
|
||||||
console.groupEnd();
|
|
||||||
})
|
|
||||||
console.groupEnd();
|
console.groupEnd();
|
||||||
console.log();
|
console.groupEnd();
|
||||||
});
|
})
|
||||||
}
|
console.groupEnd();
|
||||||
|
console.log();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
resolve();
|
const details = await driver.executeScript(`
|
||||||
})()))();
|
|
||||||
|
|
||||||
await (() => new Promise(resolve => (async () => {
|
|
||||||
const result = await driver.executeScript(`
|
|
||||||
return {
|
return {
|
||||||
executionTime: jsApiReporter.executionTime(),
|
executionTime: jsApiReporter.executionTime(),
|
||||||
random: jsApiReporter.runDetails.order.random,
|
random: jsApiReporter.runDetails.order.random,
|
||||||
seed: jsApiReporter.runDetails.order.seed,
|
seed: jsApiReporter.runDetails.order.seed
|
||||||
specCount: jsApiReporter.specs().length,
|
|
||||||
failureCount: jsApiReporter.specs().filter(function (spec) { return spec.status === \"failed\" }).length,
|
|
||||||
pendingCount: jsApiReporter.specs().filter(function (spec) { return spec.status === \"pending\" }).length
|
|
||||||
}`);
|
}`);
|
||||||
|
|
||||||
if (result.specCount > 0) {
|
console.log(`${colors["none"]}${specResults.length} spec(s), ${result.failed.length} failure(s), ${result.pending.length} pending spec(s)`);
|
||||||
console.log(`${colors["none"]}${result.specCount} spec(s), ${result.failureCount} failure(s), ${result.pendingCount} pending spec(s)`);
|
console.log(`Finished in ${details.executionTime / 1000} second(s)`);
|
||||||
console.log(`Finished in ${result.executionTime / 1000} second(s)`);
|
console.log(`Randomized with seed ${details.seed} ( ${host}/?random=${details.random}&seed=${details.seed} )`);
|
||||||
console.log(`Randomized with seed ${result.seed} ( ${host}/?random=${result.random}&seed=${result.seed} )`);
|
|
||||||
} else {
|
|
||||||
console.log(`No specs found`)
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
if (useSauce) {
|
||||||
})()))();
|
driver.executeScript(`sauce:job-result=${exitCode === 0}`);
|
||||||
|
}
|
||||||
await driver.close();
|
})().finally(() => {
|
||||||
process.exit(exitCode);
|
return Promise.all([driver.close(), new Promise(resolve => server.close(resolve))]);
|
||||||
})()
|
});
|
||||||
|
|
||||||
|
|||||||
10
index.pug
10
index.pug
@@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
html
|
|
||||||
head
|
|
||||||
title Jasmine suite
|
|
||||||
link(rel="shortcut icon" href="images/jasmine_favicon.png" type="image/png")
|
|
||||||
link(rel="stylesheet" href="lib/jasmine-core/jasmine.css" type="text/css" media="screen")
|
|
||||||
-
|
|
||||||
each file in files
|
|
||||||
script(src=file type="text/javascript")
|
|
||||||
body
|
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
"homepage": "https://jasmine.github.io",
|
"homepage": "https://jasmine.github.io",
|
||||||
"main": "./lib/jasmine-core.js",
|
"main": "./lib/jasmine-core.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"ejs": "^1.0.0",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"fast-glob": "^2.2.6",
|
"fast-glob": "^2.2.6",
|
||||||
"glob": "^7.1.3",
|
"glob": "^7.1.3",
|
||||||
@@ -33,7 +34,6 @@
|
|||||||
"jsdom": "^13.1.0",
|
"jsdom": "^13.1.0",
|
||||||
"load-grunt-tasks": "^4.0.0",
|
"load-grunt-tasks": "^4.0.0",
|
||||||
"node-sass": "^4.11.0",
|
"node-sass": "^4.11.0",
|
||||||
"pug": "^2.0.3",
|
|
||||||
"selenium-webdriver": "^3.6.0",
|
"selenium-webdriver": "^3.6.0",
|
||||||
"shelljs": "^0.8.3",
|
"shelljs": "^0.8.3",
|
||||||
"temp": "^0.9.0"
|
"temp": "^0.9.0"
|
||||||
|
|||||||
12
spec/support/index.html.ejs
Normal file
12
spec/support/index.html.ejs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Jasmine suite</title>
|
||||||
|
<link rel="shortcut icon" href="images/jasmine_favicon.png" type="image/png" />
|
||||||
|
<link rel="stylesheet" href="lib/jasmine-core/jasmine.css" type="text/css" media="screen" />
|
||||||
|
<% files.forEach(function(file) { %>
|
||||||
|
<script src="<%= file %>" type="text/javascript"></script>
|
||||||
|
<% }) %>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user