Newer
Older
diosmosis
a validé
/*!
* Piwik - free/libre analytics platform
diosmosis
a validé
*
* UI screenshot test runner Application class
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
var fs = require('fs'),
path = require('./path'),
DiffViewerGenerator = require('./diff-viewer').DiffViewerGenerator
var walk = function (dir, pattern, result) {
result = result || [];
fs.list(dir).forEach(function (item) {
if (item == '.'
|| item == '..'
) {
return;
}
var wholePath = path.join(dir, item);
if (fs.isDirectory(wholePath)) {
walk(wholePath, pattern, result);
} else if (wholePath.match(pattern)) {
result.push(wholePath);
}
});
return result;
};
var isCorePlugin = function (pathToPlugin) {
// if the plugin is a .git checkout, it's not part of core
var gitDir = path.join(pathToPlugin, '.git');
return !fs.exists(gitDir);
};
diosmosis
a validé
var Application = function () {
this.runner = null;
diosmosis
a validé
this.diffviewerDir = path.join(PIWIK_INCLUDE_PATH, 'tests/UI', config.screenshotDiffDir);
this.diffViewerGenerator = new DiffViewerGenerator(this.diffviewerDir);
diosmosis
a validé
};
Application.prototype.printHelpAndExit = function () {
console.log("Usage: phantomjs run-tests.js [options] [test-files]");
console.log();
console.log("Available options:");
console.log(" --help: Prints this message.");
console.log(" --persist-fixture-data: Persists test data in a database and does not execute tear down.");
console.log(" After the first run, the database setup will not be called, which");
console.log(" Makes running tests faster.");
console.log(" --plugin=name: Runs all tests for a plugin.");
console.log(" --keep-symlinks: If supplied, the recursive symlinks created in tests/PHPUnit/proxy");
console.log(" aren't deleted after tests are run. Specify this option if you'd like");
console.log(" to view pages phantomjs captures in a browser.");
console.log(" --print-logs: Prints webpage logs even if tests succeed.");
console.log(" --store-in-ui-tests-repo: Stores processed screenshots within the UI tests repository even if");
console.log(" the tests are in another plugin. For use with travis build.");
console.log(" --assume-artifacts: Assume the diffviewer and processed screenshots will be stored on the.");
console.log(" builds artifacts server. For use with travis build.");
console.log(" --screenshot-repo: Specifies the github repository that contains the expected screenshots");
console.log(" to link to in the diffviewer. For use with travis build.");
console.log(" --core: Only execute UI tests that are for Piwik core or Piwik core plugins.");
console.log(" --first-half: Only execute first half of all the test suites. Will be only applied if no")
console.log(" specific plugin or test-files requested");
console.log(" --second-half: Only execute second half of all the test suites. Will be only applied if no")
console.log(" specific plugin or test-files requested");
diosmosis
a validé
phantom.exit(0);
};
diosmosis
a validé
Application.prototype.init = function () {
var app = this;
// overwrite describe function so we can inject the base directory of a suite
var oldDescribe = describe;
describe = function () {
var suite = oldDescribe.apply(null, arguments);
suite.baseDirectory = app.currentModulePath.match(/\/plugins\//) ? path.dirname(app.currentModulePath) : uiTestsDir;
if (options['assume-artifacts']) {
suite.diffDir = path.join(PIWIK_INCLUDE_PATH, 'tests/UI', config.screenshotDiffDir);
} else {
suite.diffDir = path.join(suite.baseDirectory, config.screenshotDiffDir);
}
diosmosis
a validé
return suite;
};
};
diosmosis
a validé
Application.prototype.loadTestModules = function () {
diosmosis
a validé
var self = this,
pluginDir = path.join(PIWIK_INCLUDE_PATH, 'plugins');
diosmosis
a validé
// find all installed plugins
var plugins = fs.list(pluginDir).map(function (item) {
return path.join(pluginDir, item);
}).filter(function (path) {
return fs.isDirectory(path) && !path.match(/\/\.*$/);
});
// load all UI tests we can find
var modulePaths = walk(uiTestsDir, /_spec\.js$/);
if (options.core) {
plugins = plugins.filter(function (path) {
return isCorePlugin(path);
});
}
diosmosis
a validé
plugins.forEach(function (pluginPath) {
walk(path.join(pluginPath, 'Test'), /_spec\.js$/, modulePaths);
walk(path.join(pluginPath, 'tests'), /_spec\.js$/, modulePaths);
diosmosis
a validé
});
modulePaths.forEach(function (path) {
diosmosis
a validé
self.currentModulePath = path;
diosmosis
a validé
require(path);
});
// filter suites to run
if (options.tests.length) {
mocha.suite.suites = mocha.suite.suites.filter(function (suite) {
return options.tests.indexOf(suite.title) != -1;
});
}
if (options.plugin) {
mocha.suite.suites = mocha.suite.suites.filter(function (suite) {
return suite.baseDirectory.match(new RegExp("\/plugins\/" + options.plugin + "\/"));
});
}
var specificTestsRequested = options.plugin || options.tests.length;
if ((options['run-first-half-only'] || options['run-second-half-only']) && !specificTestsRequested) {
// run only first 50% of the test suites or only run last 50% of the test suites.
// we apply this option only if not a specific plugin or test suite was requested. Only there for travis to
// split tests into multiple jobs.
var numTestsFirstHalf = Math.round(mocha.suite.suites.length / 2);
mocha.suite.suites = mocha.suite.suites.filter(function (suite, index) {
if (options['run-first-half-only'] && index < numTestsFirstHalf) {
return true;
} else if (options['run-second-half-only'] && index >= numTestsFirstHalf) {
return true;
}
return false;
});
}
if (!mocha.suite.suites.length) {
console.log("No tests are executing... are you running tests for a plugin? Make sure to use the"
+ " --plugin=MyPlugin option.");
}
// configure suites (auto-add fixture setup/teardown)
mocha.suite.suites.forEach(function (suite) {
var fixture = typeof suite.fixture === 'undefined' ? "Piwik\\Tests\\Fixtures\\UITestFixture" : suite.fixture;
suite.beforeAll(function (done) {
var oldOptions = JSON.parse(JSON.stringify(options));
if (suite.optionsOverride) {
for (var key in suite.optionsOverride) {
options[key] = suite.optionsOverride[key];
}
}
diosmosis
a validé
// remove existing diffs
fs.list(suite.diffDir).forEach(function (item) {
var file = path.join(suite.diffDir, item);
if (fs.exists(file)
&& item.slice(-4) == '.png'
) {
fs.remove(file);
}
});
testEnvironment.setupFixture(fixture, done);
options = oldOptions;
});
// move to before other hooks
suite._beforeAll.unshift(suite._beforeAll.pop());
suite.afterAll(function (done) {
var oldOptions = JSON.parse(JSON.stringify(options));
if (suite.optionsOverride) {
for (var key in suite.optionsOverride) {
options[key] = suite.optionsOverride[key];
}
}
testEnvironment.teardownFixture(fixture, done);
options = oldOptions;
});
});
diosmosis
a validé
};
Application.prototype.runTests = function () {
var self = this;
// make sure all necessary directories exist (symlinks handled by PHP since phantomjs can't create any)
var dirsToCreate = [
path.join(PIWIK_INCLUDE_PATH, 'tmp/sessions')
];
dirsToCreate.forEach(function (path) {
if (!fs.isDirectory(path)) {
fs.makeTree(path);
}
});
this.doRunTests();
diosmosis
a validé
};
Application.prototype.doRunTests = function () {
var self = this;
diosmosis
a validé
// run tests
this.runner = mocha.run(function () {
// remove symlinks
if (!options['keep-symlinks']) {
var symlinks = ['libs', 'plugins', 'tests', 'misc', 'piwik.js'];
diosmosis
a validé
symlinks.forEach(function (item) {
var file = path.join(uiTestsDir, '..', 'PHPUnit', 'proxy', item);
diosmosis
a validé
if (fs.exists(file)) {
fs.remove(file);
}
});
}
// build diffviewer
Thomas Steur
a validé
self.diffViewerGenerator.generate(function () {
self.finish();
diosmosis
a validé
});
});
this.runner.on('fail', function(test, err) {
var indent = " ";
var message = "\n";
message += err && err.stack ? err.stack : err;
message = message.replace(/\n/g, "\n" + indent);
console.log(indent + message + "\n\n");
});
diosmosis
a validé
};
Application.prototype.finish = function () {
phantom.exit(this.runner ? this.runner.failures : -1);
diosmosis
a validé
};
diosmosis
a validé
Application.prototype.appendMissingExpected = function (screenName) {
var missingExpectedFilePath = path.join(this.diffviewerDir, 'missing-expected.list');
fs.write(missingExpectedFilePath, screenName + "\n", "a");
};
diosmosis
a validé
exports.Application = new Application();