10 changed files with 1260 additions and 22 deletions
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
[submodule "test/ttx/fonttools-code"] |
||||
path = test/ttx/fonttools-code |
||||
url = git://git.code.sf.net/p/fonttools/code |
@ -0,0 +1,149 @@
@@ -0,0 +1,149 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ |
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
||||
/* |
||||
* Copyright 2014 Mozilla Foundation |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/*jslint node: true */ |
||||
|
||||
'use strict'; |
||||
|
||||
var fs = require('fs'); |
||||
var crypto = require('crypto'); |
||||
var http = require('http'); |
||||
var https = require('https'); |
||||
|
||||
function downloadFile(file, url, callback) { |
||||
var completed = false; |
||||
var protocol = /^https:\/\//.test(url) ? https : http; |
||||
protocol.get(url, function (response) { |
||||
if (response.statusCode !== 200) { |
||||
if (!completed) { |
||||
completed = true; |
||||
callback('HTTP ' + response.statusCode); |
||||
} |
||||
return; |
||||
} |
||||
var stream = fs.createWriteStream(file); |
||||
stream.on('error', function (err) { |
||||
if (!completed) { |
||||
completed = true; |
||||
callback(err); |
||||
} |
||||
}); |
||||
response.pipe(stream); |
||||
stream.on('finish', function() { |
||||
stream.close(); |
||||
if (!completed) { |
||||
completed = true; |
||||
callback(); |
||||
} |
||||
}); |
||||
}).on('error', function (err) { |
||||
if (!completed) { |
||||
completed = true; |
||||
callback(err); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function downloadManifestFiles(manifest, callback) { |
||||
function downloadNext() { |
||||
if (i >= links.length) { |
||||
callback(); |
||||
return; |
||||
} |
||||
var file = links[i].file; |
||||
var url = links[i].url; |
||||
console.log('Downloading ' + url + ' to ' + file + '...'); |
||||
downloadFile(file, url, function (err) { |
||||
if (err) { |
||||
console.error('Error during downloading of ' + url + ': ' + err); |
||||
fs.writeFileSync(file, ''); // making it empty file
|
||||
fs.writeFileSync(file + '.error', err); |
||||
} |
||||
i++; |
||||
downloadNext(); |
||||
}); |
||||
} |
||||
|
||||
var links = manifest.filter(function (item) { |
||||
return item.link && !fs.existsSync(item.file); |
||||
}).map(function (item) { |
||||
var file = item.file; |
||||
var linkfile = file + '.link'; |
||||
var url = fs.readFileSync(linkfile).toString(); |
||||
url = url.replace(/\s+$/, ''); |
||||
return {file: file, url: url}; |
||||
}); |
||||
|
||||
var i = 0; |
||||
downloadNext(); |
||||
} |
||||
|
||||
function calculateMD5(file, callback) { |
||||
var hash = crypto.createHash('md5'); |
||||
var stream = fs.createReadStream(file); |
||||
stream.on('data', function (data) { |
||||
hash.update(data); |
||||
}); |
||||
stream.on('error', function (err) { |
||||
callback(err); |
||||
}); |
||||
stream.on('end', function() { |
||||
var result = hash.digest('hex'); |
||||
callback(null, result); |
||||
}); |
||||
} |
||||
|
||||
function verifyManifestFiles(manifest, callback) { |
||||
function verifyNext() { |
||||
if (i >= manifest.length) { |
||||
callback(error); |
||||
return; |
||||
} |
||||
var item = manifest[i]; |
||||
if (fs.existsSync(item.file + '.error')) { |
||||
console.error('WARNING: File was not downloaded. See "' + |
||||
item.file + '.error" file.'); |
||||
error = true; |
||||
i++; |
||||
verifyNext(); |
||||
return; |
||||
} |
||||
calculateMD5(item.file, function (err, md5) { |
||||
if (err) { |
||||
console.log('WARNING: Unable to open file for reading "' + err + '".'); |
||||
error = true; |
||||
} else if (!item.md5) { |
||||
console.error('WARNING: Missing md5 for file "' + item.file + '". ' + |
||||
'Hash for current file is "' + md5 + '"'); |
||||
error = true; |
||||
} else if (md5 !== item.md5) { |
||||
console.error('WARNING: MD5 of file "' + item.file + |
||||
'" does not match file. Expected "' + |
||||
item.md5 + '" computed "' + md5 + '"'); |
||||
error = true; |
||||
} |
||||
i++; |
||||
verifyNext(); |
||||
}); |
||||
} |
||||
var i = 0; |
||||
var error = false; |
||||
verifyNext(); |
||||
} |
||||
|
||||
exports.downloadManifestFiles = downloadManifestFiles; |
||||
exports.verifyManifestFiles = verifyManifestFiles; |
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ |
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
||||
/* |
||||
* Copyright 2014 Mozilla Foundation |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/*jslint node: true */ |
||||
|
||||
'use strict'; |
||||
|
||||
var fs = require('fs'); |
||||
var path = require('path'); |
||||
var spawn = require('child_process').spawn; |
||||
|
||||
var ttxResourcesHome = path.join(__dirname, '..', 'ttx'); |
||||
|
||||
var nextTTXTaskId = Date.now(); |
||||
|
||||
function runTtx(ttxResourcesHome, fontPath, registerOnCancel, callback) { |
||||
fs.realpath(ttxResourcesHome, function (err, ttxResourcesHome) { |
||||
var fontToolsHome = path.join(ttxResourcesHome, 'fonttools-code'); |
||||
fs.realpath(fontPath, function (err, fontPath) { |
||||
var ttxPath = path.join('Tools', 'ttx'); |
||||
if (!fs.existsSync(path.join(fontToolsHome, ttxPath))) { |
||||
callback('TTX was not found, please checkout PDF.js submodules'); |
||||
return; |
||||
} |
||||
var ttxEnv = { |
||||
'PYTHONPATH': path.join(fontToolsHome, 'Lib'), |
||||
'PYTHONDONTWRITEBYTECODE': true |
||||
}; |
||||
var ttxStdioMode = 'ignore'; |
||||
var ttx = spawn('python', [ttxPath, fontPath], |
||||
{cwd: fontToolsHome, stdio: ttxStdioMode, env: ttxEnv}); |
||||
var ttxRunError; |
||||
registerOnCancel(function (reason) { |
||||
ttxRunError = reason; |
||||
callback(reason); |
||||
ttx.kill(); |
||||
}); |
||||
ttx.on('error', function (err) { |
||||
ttxRunError = err; |
||||
callback('Unable to execute ttx'); |
||||
}); |
||||
ttx.on('close', function (code) { |
||||
if (ttxRunError) { |
||||
return; |
||||
} |
||||
callback(); |
||||
}); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
exports.translateFont = function translateFont(content, registerOnCancel, |
||||
callback) { |
||||
var buffer = new Buffer(content, 'base64'); |
||||
var taskId = (nextTTXTaskId++).toString(); |
||||
var fontPath = path.join(ttxResourcesHome, taskId + '.otf'); |
||||
var resultPath = path.join(ttxResourcesHome, taskId + '.ttx'); |
||||
|
||||
fs.writeFileSync(fontPath, buffer); |
||||
runTtx(ttxResourcesHome, fontPath, registerOnCancel, function (err) { |
||||
fs.unlink(fontPath); |
||||
if (err) { |
||||
console.error(err); |
||||
callback(err); |
||||
} else if (!fs.existsSync(resultPath)) { |
||||
callback('Output was not generated'); |
||||
} else { |
||||
callback(null, fs.readFileSync(resultPath)); |
||||
fs.unlink(resultPath); |
||||
} |
||||
}); |
||||
}; |
@ -0,0 +1,723 @@
@@ -0,0 +1,723 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ |
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
||||
/* |
||||
* Copyright 2014 Mozilla Foundation |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/*jslint node: true */ |
||||
|
||||
'use strict'; |
||||
|
||||
var WebServer = require('./webserver.js').WebServer; |
||||
var WebBrowser = require('./webbrowser.js').WebBrowser; |
||||
var path = require('path'); |
||||
var fs = require('fs'); |
||||
var os = require('os'); |
||||
var url = require('url'); |
||||
var spawn = require('child_process').spawn; |
||||
var testUtils = require('./testutils.js'); |
||||
|
||||
function parseOptions() { |
||||
function describeCheck(fn, text) { |
||||
fn.toString = function () { |
||||
return text; |
||||
}; |
||||
return fn; |
||||
} |
||||
|
||||
var yargs = require('yargs') |
||||
.usage('Usage: $0') |
||||
.boolean(['help', 'masterMode', 'reftest', 'unitTest', 'fontTest', |
||||
'noPrompts', 'noDownload']) |
||||
.string(['manifestFile', 'browser', 'browserManifestFile', |
||||
'port', 'statsFile', 'statsDelay']) |
||||
.alias('browser', 'b').alias('help', 'h').alias('masterMode', 'm') |
||||
.describe('help', 'Show this help message') |
||||
.describe('masterMode', 'Run the script in master mode.') |
||||
.describe('noPrompts', |
||||
'Uses default answers (intended for CLOUD TESTS only!).') |
||||
.describe('manifestFile', |
||||
'A path to JSON file in the form of test_manifest.json') |
||||
.default('manifestFile', 'test_manifest.json') |
||||
.describe('browser', 'The path to a single browser ') |
||||
.describe('browserManifestFile', 'A path to JSON file in the form of ' + |
||||
'those found in resources/browser_manifests/') |
||||
.describe('reftest', 'Automatically start reftest showing comparison ' + |
||||
'test failures, if there are any.') |
||||
.describe('port', 'The port the HTTP server should listen on.') |
||||
.default('port', 8000) |
||||
.describe('unitTest', 'Run the unit tests.') |
||||
.describe('fontTest', 'Run the font tests.') |
||||
.describe('noDownload', 'Skips test PDFs downloading.') |
||||
.describe('statsFile', 'The file where to store stats.') |
||||
.describe('statsDelay', 'The amount of time in milliseconds the browser ' + |
||||
'should wait before starting stats.') |
||||
.default('statsDelay', 0) |
||||
.check(describeCheck(function (argv) { |
||||
return +argv.reftest + argv.unitTest + argv.fontTest + |
||||
argv.masterMode <= 1; |
||||
}, '--reftest, --unitTest, --fontTest and --masterMode must not be ' + |
||||
'specified at the same time.')) |
||||
.check(describeCheck(function (argv) { |
||||
return !argv.masterMode || argv.manifestFile === 'test_manifest.json'; |
||||
}, 'when --masterMode is specified --manifestFile shall be equal ' + |
||||
'test_manifest.json')) |
||||
.check(describeCheck(function (argv) { |
||||
return !argv.browser || !argv.browserManifestFile; |
||||
}, '--browser and --browserManifestFile must not be specified at the ' +'' + |
||||
'same time.')); |
||||
var result = yargs.argv; |
||||
if (result.help) { |
||||
yargs.showHelp(); |
||||
process.exit(0); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
var refsTmpDir = 'tmp'; |
||||
var testResultDir = 'test_snapshots'; |
||||
var refsDir = 'ref'; |
||||
var eqLog = 'eq.log'; |
||||
var browserTimeout = 120; |
||||
|
||||
function monitorBrowserTimeout(session, onTimeout) { |
||||
if (session.timeoutMonitor) { |
||||
clearTimeout(session.timeoutMonitor); |
||||
} |
||||
if (!onTimeout) { |
||||
session.timeoutMonitor = null; |
||||
return; |
||||
} |
||||
session.timeoutMonitor = setTimeout(function () { |
||||
onTimeout(session); |
||||
}, browserTimeout * 1000); |
||||
} |
||||
|
||||
function updateRefImages() { |
||||
function sync(removeTmp) { |
||||
console.log(' Updating ref/ ... '); |
||||
testUtils.copySubtreeSync(refsTmpDir, refsDir); |
||||
if (removeTmp) { |
||||
testUtils.removeDirSync(refsTmpDir); |
||||
} |
||||
console.log('done'); |
||||
} |
||||
|
||||
if (options.noPrompts) { |
||||
sync(false); // don't remove tmp/ for botio
|
||||
return; |
||||
} |
||||
testUtils.confirm('Would you like to update the master copy in ref/? [yn] ', |
||||
function (confirmed) { |
||||
if (confirmed) { |
||||
sync(true); |
||||
} else { |
||||
console.log(' OK, not updating.'); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function examineRefImages() { |
||||
startServer(); |
||||
var startUrl = 'http://' + server.host + ':' + server.port + |
||||
'/test/resources/reftest-analyzer.html#web=/test/eq.log'; |
||||
var browser = WebBrowser.create(sessions[0].config); |
||||
browser.start(startUrl); |
||||
} |
||||
|
||||
function startRefTest(masterMode, showRefImages) { |
||||
function finalize() { |
||||
stopServer(); |
||||
var numErrors = 0; |
||||
var numFBFFailures = 0; |
||||
var numEqFailures = 0; |
||||
var numEqNoSnapshot = 0; |
||||
sessions.forEach(function (session) { |
||||
numErrors += session.numErrors; |
||||
numFBFFailures += session.numFBFFailures; |
||||
numEqFailures += session.numEqFailures; |
||||
numEqNoSnapshot += session.numEqNoSnapshot; |
||||
}); |
||||
var numFatalFailures = numErrors + numFBFFailures; |
||||
console.log(); |
||||
if (numFatalFailures + numEqFailures > 0) { |
||||
console.log('OHNOES! Some tests failed!'); |
||||
if (numErrors > 0) { |
||||
console.log(' errors: ' + numErrors); |
||||
} |
||||
if (numEqFailures > 0) { |
||||
console.log(' different ref/snapshot: ' + numEqFailures); |
||||
} |
||||
if (numFBFFailures > 0) { |
||||
console.log(' different first/second rendering: ' + numFBFFailures); |
||||
} |
||||
} else { |
||||
console.log('All regression tests passed.'); |
||||
} |
||||
var runtime = (Date.now() - startTime) / 1000; |
||||
console.log('Runtime was ' + runtime.toFixed(1) + ' seconds'); |
||||
|
||||
if (options.statsFile) { |
||||
fs.writeFileSync(options.statsFile, JSON.stringify(stats, null, 2)); |
||||
} |
||||
if (masterMode) { |
||||
if (numEqFailures + numEqNoSnapshot > 0) { |
||||
console.log(); |
||||
console.log('Some eq tests failed or didn\'t have snapshots.'); |
||||
console.log('Checking to see if master references can be updated...'); |
||||
if (numFatalFailures > 0) { |
||||
console.log(' No. Some non-eq tests failed.'); |
||||
} else { |
||||
console.log( |
||||
' Yes! The references in tmp/ can be synced with ref/.'); |
||||
updateRefImages(); |
||||
} |
||||
} |
||||
} else if (showRefImages && numEqFailures > 0) { |
||||
console.log(); |
||||
console.log('Starting reftest harness to examine ' + numEqFailures + |
||||
' eq test failures.'); |
||||
examineRefImages(numEqFailures); |
||||
} |
||||
} |
||||
|
||||
function setup() { |
||||
if (fs.existsSync(refsTmpDir)) { |
||||
console.error('tmp/ exists -- unable to proceed with testing'); |
||||
process.exit(1); |
||||
} |
||||
|
||||
if (fs.existsSync(eqLog)) { |
||||
fs.unlink(eqLog); |
||||
} |
||||
if (fs.existsSync(testResultDir)) { |
||||
testUtils.removeDirSync(testResultDir); |
||||
} |
||||
|
||||
startTime = Date.now(); |
||||
startServer(); |
||||
server.hooks['POST'].push(refTestPostHandler); |
||||
onAllSessionsClosed = finalize; |
||||
|
||||
startBrowsers('/test/test_slave.html', function (session) { |
||||
session.masterMode = masterMode; |
||||
session.taskResults = {}; |
||||
session.tasks = {}; |
||||
session.remaining = manifest.length; |
||||
manifest.forEach(function (item) { |
||||
var rounds = item.rounds || 1; |
||||
var roundsResults = []; |
||||
roundsResults.length = rounds; |
||||
session.taskResults[item.id] = roundsResults; |
||||
session.tasks[item.id] = item; |
||||
}); |
||||
session.numErrors = 0; |
||||
session.numFBFFailures = 0; |
||||
session.numEqNoSnapshot = 0; |
||||
session.numEqFailures = 0; |
||||
monitorBrowserTimeout(session, handleSessionTimeout); |
||||
}); |
||||
} |
||||
function checkRefsTmp() { |
||||
if (masterMode && fs.existsSync(refsTmpDir)) { |
||||
if (options.noPrompt) { |
||||
testUtils.removeDirSync(refsTmpDir); |
||||
setup(); |
||||
return; |
||||
} |
||||
console.log('Temporary snapshot dir tmp/ is still around.'); |
||||
console.log('tmp/ can be removed if it has nothing you need.'); |
||||
testUtils.confirm('SHOULD THIS SCRIPT REMOVE tmp/? THINK CAREFULLY [yn] ', |
||||
function (confirmed) { |
||||
if (confirmed) { |
||||
testUtils.removeDirSync(refsTmpDir); |
||||
} |
||||
setup(); |
||||
}); |
||||
} else { |
||||
setup(); |
||||
} |
||||
} |
||||
|
||||
var startTime; |
||||
var manifest = JSON.parse(fs.readFileSync(options.manifestFile)); |
||||
if (options.noDownload) { |
||||
checkRefsTmp(); |
||||
} else { |
||||
ensurePDFsDownloaded(checkRefsTmp); |
||||
} |
||||
} |
||||
|
||||
function handleSessionTimeout(session) { |
||||
if (session.closed) { |
||||
return; |
||||
} |
||||
var browser = session.name; |
||||
console.log('TEST-UNEXPECTED-FAIL | test failed ' + browser + |
||||
' has not responded in ' + browserTimeout + 's'); |
||||
session.numErrors += session.remaining; |
||||
session.remaining = 0; |
||||
closeSession(browser); |
||||
} |
||||
|
||||
function checkEq(task, results, browser, masterMode) { |
||||
var taskId = task.id; |
||||
var refSnapshotDir = path.join(refsDir, os.platform(), browser, taskId); |
||||
var testSnapshotDir = path.join(testResultDir, os.platform(), browser, |
||||
taskId); |
||||
|
||||
var pageResults = results[0]; |
||||
var taskType = task.type; |
||||
var numEqNoSnapshot = 0; |
||||
var numEqFailures = 0; |
||||
for (var page = 0; page < pageResults.length; page++) { |
||||
if (!pageResults[page]) { |
||||
continue; |
||||
} |
||||
var testSnapshot = pageResults[page].snapshot; |
||||
if (testSnapshot && testSnapshot.indexOf('data:image/png;base64,') === 0) { |
||||
testSnapshot = new Buffer(testSnapshot.substring(22), 'base64'); |
||||
} else { |
||||
console.error('Valid snapshot was not found.'); |
||||
} |
||||
|
||||
var refSnapshot = null; |
||||
var eq = false; |
||||
var refPath = path.join(refSnapshotDir, (page + 1) + '.png'); |
||||
if (!fs.existsSync(refPath)) { |
||||
numEqNoSnapshot++; |
||||
if (!masterMode) { |
||||
console.log('WARNING: no reference snapshot ' + refPath); |
||||
} |
||||
} else { |
||||
refSnapshot = fs.readFileSync(refPath); |
||||
eq = (refSnapshot.toString('hex') === testSnapshot.toString('hex')); |
||||
if (!eq) { |
||||
console.log('TEST-UNEXPECTED-FAIL | ' + taskType + ' ' + taskId + |
||||
' | in ' + browser + ' | rendering of page ' + (page + 1) + |
||||
' != reference rendering'); |
||||
|
||||
testUtils.ensureDirSync(testSnapshotDir); |
||||
fs.writeFileSync(path.join(testSnapshotDir, (page + 1) + '.png'), |
||||
testSnapshot); |
||||
fs.writeFileSync(path.join(testSnapshotDir, (page + 1) + '_ref.png'), |
||||
refSnapshot); |
||||
|
||||
// NB: this follows the format of Mozilla reftest output so that
|
||||
// we can reuse its reftest-analyzer script
|
||||
fs.appendFileSync(eqLog, 'REFTEST TEST-UNEXPECTED-FAIL | ' + browser + |
||||
'-' + taskId + '-page' + (page + 1) + ' | image comparison (==)\n' + |
||||
'REFTEST IMAGE 1 (TEST): ' + |
||||
path.join(testSnapshotDir, (page + 1) + '.png') + '\n' + |
||||
'REFTEST IMAGE 2 (REFERENCE): ' + |
||||
path.join(testSnapshotDir, (page + 1) + '_ref.png') + '\n'); |
||||
numEqFailures++; |
||||
} |
||||
} |
||||
if (masterMode && (!refSnapshot || !eq)) { |
||||
var tmpSnapshotDir = path.join(refsTmpDir, os.platform(), browser, |
||||
taskId); |
||||
testUtils.ensureDirSync(tmpSnapshotDir); |
||||
fs.writeFileSync(path.join(tmpSnapshotDir, (page + 1) + '.png'), |
||||
testSnapshot); |
||||
} |
||||
} |
||||
|
||||
var session = getSession(browser); |
||||
session.numEqNoSnapshot += numEqNoSnapshot; |
||||
if (numEqFailures > 0) { |
||||
session.numEqFailures += numEqFailures; |
||||
} else { |
||||
console.log('TEST-PASS | ' + taskType + ' test ' + taskId + ' | in ' + |
||||
browser); |
||||
} |
||||
} |
||||
|
||||
function checkFBF(task, results, browser) { |
||||
var numFBFFailures = 0; |
||||
var round0 = results[0], round1 = results[1]; |
||||
if (round0.length !== round1.length) { |
||||
console.error('round 1 and 2 sizes are different'); |
||||
} |
||||
|
||||
for (var page = 0; page < round1.length; page++) { |
||||
var r0Page = round0[page], r1Page = round1[page]; |
||||
if (!r0Page) { |
||||
continue; |
||||
} |
||||
if (r0Page.snapshot !== r1Page.snapshot) { |
||||
console.log('TEST-UNEXPECTED-FAIL | forward-back-forward test ' + |
||||
task.id + ' | in ' + browser + ' | first rendering of page ' + |
||||
(page + 1) + ' != second'); |
||||
numFBFFailures++; |
||||
} |
||||
} |
||||
|
||||
if (numFBFFailures > 0) { |
||||
getSession(browser).numFBFFailures += numFBFFailures; |
||||
} else { |
||||
console.log('TEST-PASS | forward-back-forward test ' + task.id + |
||||
' | in ' + browser); |
||||
} |
||||
} |
||||
|
||||
function checkLoad(task, results, browser) { |
||||
// Load just checks for absence of failure, so if we got here the
|
||||
// test has passed
|
||||
console.log('TEST-PASS | load test ' + task.id + ' | in ' + browser); |
||||
} |
||||
|
||||
function checkRefTestResults(browser, id, results) { |
||||
var failed = false; |
||||
var session = getSession(browser); |
||||
var task = session.tasks[id]; |
||||
results.forEach(function (roundResults, round) { |
||||
roundResults.forEach(function (pageResult, page) { |
||||
if (!pageResult) { |
||||
return; // no results
|
||||
} |
||||
if (pageResult.failure) { |
||||
failed = true; |
||||
if (fs.existsSync(task.file + '.error')) { |
||||
console.log('TEST-SKIPPED | PDF was not downloaded ' + id + ' | in ' + |
||||
browser + ' | page' + (page + 1) + ' round ' + |
||||
(round + 1) + ' | ' + pageResult.failure); |
||||
} else { |
||||
session.numErrors++; |
||||
console.log('TEST-UNEXPECTED-FAIL | test failed ' + id + ' | in ' + |
||||
browser + ' | page' + (page + 1) + ' round ' + |
||||
(round + 1) + ' | ' + pageResult.failure); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
if (failed) { |
||||
return; |
||||
} |
||||
switch (task.type) { |
||||
case 'eq': |
||||
case 'text': |
||||
checkEq(task, results, browser, session.masterMode); |
||||
break; |
||||
case 'fbf': |
||||
checkFBF(task, results, browser); |
||||
break; |
||||
case 'load': |
||||
checkLoad(task, results, browser); |
||||
break; |
||||
default: |
||||
throw new Error('Unknown test type'); |
||||
} |
||||
} |
||||
|
||||
function refTestPostHandler(req, res) { |
||||
var parsedUrl = url.parse(req.url, true); |
||||
var pathname = parsedUrl.pathname; |
||||
if (pathname !== '/tellMeToQuit' && |
||||
pathname !== '/info' && |
||||
pathname !== '/submit_task_results') { |
||||
return false; |
||||
} |
||||
|
||||
var body = ''; |
||||
req.on('data', function (data) { |
||||
body += data; |
||||
}); |
||||
req.on('end', function () { |
||||
res.writeHead(200, {'Content-Type': 'text/plain'}); |
||||
res.end(); |
||||
|
||||
if (pathname === '/tellMeToQuit') { |
||||
// finding by path
|
||||
var browserPath = parsedUrl.query.path; |
||||
var session = sessions.filter(function (session) { |
||||
return session.config.path === browserPath; |
||||
})[0]; |
||||
monitorBrowserTimeout(session, null); |
||||
closeSession(session.name); |
||||
return; |
||||
} |
||||
|
||||
var data = JSON.parse(body); |
||||
if (pathname === '/info') { |
||||
console.log(data.message); |
||||
return; |
||||
} |
||||
|
||||
var browser = data.browser; |
||||
var round = data.round; |
||||
var id = data.id; |
||||
var page = data.page - 1; |
||||
var failure = data.failure; |
||||
var snapshot = data.snapshot; |
||||
var lastPageNum = data.lastPageNum; |
||||
|
||||
var session = getSession(browser); |
||||
monitorBrowserTimeout(session, handleSessionTimeout); |
||||
|
||||
var taskResults = session.taskResults[id]; |
||||
if (!taskResults[round]) { |
||||
taskResults[round] = []; |
||||
} |
||||
|
||||
if (taskResults[round][page]) { |
||||
console.error('Results for ' + browser + ':' + id + ':' + round + |
||||
':' + page + ' were already submitted'); |
||||
// TODO abort testing here?
|
||||
} |
||||
|
||||
taskResults[round][page] = { |
||||
failure: failure, |
||||
snapshot: snapshot |
||||
}; |
||||
if (stats) { |
||||
stats.push({ |
||||
'browser': browser, |
||||
'pdf': id, |
||||
'page': page, |
||||
'round': round, |
||||
'stats': data.stats |
||||
}); |
||||
} |
||||
|
||||
var isDone = taskResults[taskResults.length - 1] && |
||||
taskResults[taskResults.length - 1][lastPageNum - 1]; |
||||
if (isDone) { |
||||
checkRefTestResults(browser, id, taskResults); |
||||
session.remaining--; |
||||
} |
||||
}); |
||||
return true; |
||||
} |
||||
|
||||
function startUnitTest(url, name) { |
||||
var startTime = Date.now(); |
||||
startServer(); |
||||
server.hooks['POST'].push(unitTestPostHandler); |
||||
onAllSessionsClosed = function () { |
||||
stopServer(); |
||||
var numRuns = 0, numErrors = 0; |
||||
sessions.forEach(function (session) { |
||||
numRuns += session.numRuns; |
||||
numErrors += session.numErrors; |
||||
}); |
||||
console.log(); |
||||
console.log('Run ' + numRuns + ' tests'); |
||||
if (numErrors > 0) { |
||||
console.log('OHNOES! Some ' + name + ' tests failed!'); |
||||
console.log(' ' + numErrors + ' of ' + numRuns + ' failed'); |
||||
} else { |
||||
console.log('All ' + name + ' tests passed.'); |
||||
} |
||||
var runtime = (Date.now() - startTime) / 1000; |
||||
console.log(name + ' tests runtime was ' + runtime.toFixed(1) + ' seconds'); |
||||
}; |
||||
startBrowsers(url, function (session) { |
||||
session.numRuns = 0; |
||||
session.numErrors = 0; |
||||
}); |
||||
} |
||||
|
||||
function unitTestPostHandler(req, res) { |
||||
var parsedUrl = url.parse(req.url); |
||||
var pathname = parsedUrl.pathname; |
||||
if (pathname !== '/tellMeToQuit' && |
||||
pathname !== '/info' && |
||||
pathname !== '/ttx' && |
||||
pathname !== '/submit_task_results') { |
||||
return false; |
||||
} |
||||
|
||||
var body = ''; |
||||
req.on('data', function (data) { |
||||
body += data; |
||||
}); |
||||
req.on('end', function () { |
||||
if (pathname === '/ttx') { |
||||
var translateFont = require('./font/ttxdriver.js').translateFont; |
||||
var onCancel = null, ttxTimeout = 10000; |
||||
var timeoutId = setTimeout(function () { |
||||
if (onCancel) { |
||||
onCancel('TTX timeout'); |
||||
} |
||||
}, ttxTimeout); |
||||
translateFont(body, function (fn) { |
||||
onCancel = fn; |
||||
}, function (err, xml) { |
||||
clearTimeout(timeoutId); |
||||
res.writeHead(200, {'Content-Type': 'text/xml'}); |
||||
res.end(err ? '<error>' + err + '</error>' : xml); |
||||
}); |
||||
return; |
||||
} |
||||
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'}); |
||||
res.end(); |
||||
|
||||
var data = JSON.parse(body); |
||||
if (pathname === '/tellMeToQuit') { |
||||
closeSession(data.browser); |
||||
return; |
||||
} |
||||
if (pathname === '/info') { |
||||
console.log(data.message); |
||||
return; |
||||
} |
||||
var session = getSession(data.browser); |
||||
session.numRuns++; |
||||
var message = data.status + ' | ' + data.description; |
||||
if (data.status === 'TEST-UNEXPECTED-FAIL') { |
||||
session.numErrors++; |
||||
} |
||||
if (data.error) { |
||||
message += ' | ' + data.error; |
||||
} |
||||
console.log(message); |
||||
}); |
||||
return true; |
||||
} |
||||
|
||||
function startBrowsers(url, initSessionCallback) { |
||||
var browsers; |
||||
if (options.browserManifestFile) { |
||||
browsers = JSON.parse(fs.readFileSync(options.browserManifestFile)); |
||||
} else if (options.browser) { |
||||
var browserPath = options.browser; |
||||
var name = path.basename(browserPath, path.extname(browserPath)); |
||||
browsers = [{name: name, path: browserPath}]; |
||||
} else { |
||||
console.error('Specify either browser or browserManifestFile.'); |
||||
process.exit(1); |
||||
} |
||||
sessions = []; |
||||
browsers.forEach(function (b) { |
||||
var browser = WebBrowser.create(b); |
||||
var startUrl = getServerBaseAddress() + url + |
||||
'?browser=' + encodeURIComponent(b.name) + |
||||
'&manifestFile=' + encodeURIComponent('/test/' + options.manifestFile) + |
||||
'&path=' + encodeURIComponent(b.path) + |
||||
'&delay=' + options.statsDelay + |
||||
'&masterMode=' + options.masterMode; |
||||
browser.start(startUrl); |
||||
var session = { |
||||
name: b.name, |
||||
config: b, |
||||
browser: browser, |
||||
closed: false |
||||
}; |
||||
if (initSessionCallback) { |
||||
initSessionCallback(session); |
||||
} |
||||
sessions.push(session); |
||||
}); |
||||
} |
||||
|
||||
function stopBrowsers(callback) { |
||||
var count = sessions.length; |
||||
sessions.forEach(function (session) { |
||||
if (session.closed) { |
||||
return; |
||||
} |
||||
session.browser.stop(function () { |
||||
session.closed = true; |
||||
count--; |
||||
if (count === 0 && callback) { |
||||
callback(); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function getServerBaseAddress() { |
||||
return 'http://' + host + ':' + server.port; |
||||
} |
||||
|
||||
function startServer() { |
||||
server = new WebServer(); |
||||
server.host = host; |
||||
server.port = options.port; |
||||
server.root = '..'; |
||||
server.start(); |
||||
} |
||||
|
||||
function stopServer() { |
||||
server.stop(); |
||||
} |
||||
|
||||
function getSession(browser) { |
||||
return sessions.filter(function (session) { |
||||
return session.name === browser; |
||||
})[0]; |
||||
} |
||||
|
||||
function closeSession(browser) { |
||||
var i = 0; |
||||
while (i < sessions.length && sessions[i].name !== browser) { |
||||
i++; |
||||
} |
||||
if (i < sessions.length) { |
||||
var session = sessions[i]; |
||||
session.browser.stop(function () { |
||||
session.closed = true; |
||||
var allClosed = sessions.every(function (s) { |
||||
return s.closed; |
||||
}); |
||||
if (allClosed && onAllSessionsClosed) { |
||||
onAllSessionsClosed(); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
function ensurePDFsDownloaded(callback) { |
||||
var downloadUtils = require('./downloadutils.js'); |
||||
var downloadManifestFiles = downloadUtils.downloadManifestFiles; |
||||
var manifest = JSON.parse(fs.readFileSync(options.manifestFile)); |
||||
downloadUtils.downloadManifestFiles(manifest, function () { |
||||
downloadUtils.verifyManifestFiles(manifest, function (hasErrors) { |
||||
if (hasErrors) { |
||||
console.log('Unable to verify the checksum for the files that are ' + |
||||
'used for testing.'); |
||||
console.log('Please re-download the files, or adjust the MD5 ' + |
||||
'checksum in the manifest for the files listed above.\n'); |
||||
} |
||||
callback(); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function main() { |
||||
if (options.statsFile) { |
||||
stats = []; |
||||
} |
||||
|
||||
if (!options.browser && !options.browserManifestFile) { |
||||
startServer(); |
||||
} else if (options.unitTest) { |
||||
startUnitTest('/test/unit/unit_test.html', 'unit'); |
||||
} else if (options.fontTest) { |
||||
startUnitTest('/test/font/font_test.html', 'font'); |
||||
} else { |
||||
startRefTest(options.masterMode, options.reftest); |
||||
} |
||||
} |
||||
|
||||
var server; |
||||
var sessions; |
||||
var onAllSessionsClosed; |
||||
var host = '127.0.0.1'; |
||||
var options = parseOptions(); |
||||
var stats; |
||||
|
||||
main(); |
@ -0,0 +1,146 @@
@@ -0,0 +1,146 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ |
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
||||
/* |
||||
* Copyright 2014 Mozilla Foundation |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/*jslint node: true */ |
||||
|
||||
'use strict'; |
||||
|
||||
var fs = require('fs'); |
||||
var path = require('path'); |
||||
|
||||
exports.removeDirSync = function removeDirSync(dir) { |
||||
var files = fs.readdirSync(dir); |
||||
files.forEach(function (filename) { |
||||
var file = path.join(dir, filename); |
||||
var stats = fs.statSync(file); |
||||
if (stats.isDirectory()) { |
||||
removeDirSync(file); |
||||
} else { |
||||
fs.unlinkSync(file); |
||||
} |
||||
}); |
||||
fs.rmdirSync(dir); |
||||
}; |
||||
|
||||
exports.copySubtreeSync = function copySubtreeSync(src, dest) { |
||||
var files = fs.readdirSync(src); |
||||
if (!fs.existsSync(dest)) { |
||||
fs.mkdirSync(dest); |
||||
} |
||||
files.forEach(function (filename) { |
||||
var srcFile = path.join(src, filename); |
||||
var file = path.join(dest, filename); |
||||
var stats = fs.statSync(srcFile); |
||||
if (stats.isDirectory()) { |
||||
copySubtreeSync(srcFile, file); |
||||
} else { |
||||
fs.writeFileSync(file, fs.readFileSync(srcFile)); |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
exports.ensureDirSync = function ensureDirSync(dir) { |
||||
if (fs.existsSync(dir)) { |
||||
return; |
||||
} |
||||
var parts = dir.split(path.sep), i = parts.length; |
||||
while (i > 1 && !fs.existsSync(parts.slice(0, i - 1).join(path.sep))) { |
||||
i--; |
||||
} |
||||
if (i < 0 || (i === 0 && parts[0])) { |
||||
throw new Error(); |
||||
} |
||||
|
||||
while (i <= parts.length) { |
||||
fs.mkdirSync(parts.slice(0, i).join(path.sep)); |
||||
i++; |
||||
} |
||||
}; |
||||
|
||||
var stdinBuffer = '', endOfStdin = false, stdinInitialized = false; |
||||
var stdinOnLineCallbacks = []; |
||||
|
||||
function handleStdinBuffer() { |
||||
if (endOfStdin) { |
||||
if (stdinBuffer && stdinOnLineCallbacks.length > 0) { |
||||
var callback = stdinOnLineCallbacks.shift(); |
||||
callback(stdinBuffer); |
||||
stdinBuffer = null; |
||||
} |
||||
while (stdinOnLineCallbacks.length > 0) { |
||||
var callback = stdinOnLineCallbacks.shift(); |
||||
callback(); |
||||
} |
||||
return; |
||||
} |
||||
while (stdinOnLineCallbacks.length > 0) { |
||||
var i = stdinBuffer.indexOf('\n'); |
||||
if (i < 0) { |
||||
return; |
||||
} |
||||
var callback = stdinOnLineCallbacks.shift(); |
||||
var result = stdinBuffer.substring(0, i + 1); |
||||
stdinBuffer = stdinBuffer.substring(i + 1); |
||||
callback(result); |
||||
} |
||||
// all callbacks handled, stop stdin processing
|
||||
process.stdin.pause(); |
||||
} |
||||
|
||||
function initStdin() { |
||||
process.stdin.setEncoding('utf8'); |
||||
|
||||
process.stdin.on('data', function(chunk) { |
||||
stdinBuffer += chunk; |
||||
handleStdinBuffer(); |
||||
}); |
||||
|
||||
process.stdin.on('end', function() { |
||||
endOfStdin = true; |
||||
handleStdinBuffer(); |
||||
}); |
||||
} |
||||
|
||||
exports.prompt = function prompt(message, callback) { |
||||
if (!stdinInitialized) { |
||||
process.stdin.resume(); |
||||
initStdin(); |
||||
stdinInitialized = true; |
||||
} else if (stdinOnLineCallbacks.length === 0) { |
||||
process.stdin.resume(); |
||||
} |
||||
|
||||
process.stdout.write(message); |
||||
stdinOnLineCallbacks.push(callback); |
||||
handleStdinBuffer(); |
||||
}; |
||||
|
||||
exports.confirm = function confirm(message, callback) { |
||||
exports.prompt(message, function (answer) { |
||||
if (answer === undefined) { |
||||
callback(); |
||||
return; |
||||
} |
||||
if (answer[0].toLowerCase() === 'y') { |
||||
callback(true); |
||||
} else if (answer[0].toLowerCase() === 'n') { |
||||
callback(false); |
||||
} else { |
||||
confirm(message, callback); |
||||
} |
||||
}); |
||||
}; |
@ -1,19 +1,3 @@
@@ -1,19 +1,3 @@
|
||||
This folder is a place for temporary files generated by ttx |
||||
If `git clone --recursive` was not used, please run `git submodile init; git submodule update` to pull fonttools code. |
||||
|
||||
# About TTX Installation |
||||
|
||||
The numpy module is required -- use "easy_install numpy" to install it. |
||||
|
||||
Download and extract fonttools from http://sourceforge.net/projects/fonttools/ in any folder on your computer. |
||||
|
||||
From the font tools directory run "python setup.py install" from the command line. |
||||
|
||||
# TTX for Mac Change |
||||
|
||||
On Mac OSX, if you are getting error message related to "/Library/Python/2.7/site-packages/FontTools/fontTools/ttLib/macUtils.py", line 18, in MyOpenResFile, use the following patch to change the fonttools |
||||
|
||||
https://github.com/mcolyer/fonttools/commit/e732bd3ba63c51df9aed903eb2147fa1af1bfdc2 |
||||
|
||||
# TTX for Windows Change |
||||
|
||||
On Windows, if ttx generate an exception, it waits for a key to be pressed. Pleaase change "/c/mozilla-build/python/Lib/site-packages/Font-Tools/fontTools/ttx.py" file: replace the waitForKeyPress function body with just 'return'. |
||||
Note: python 2.6 for 32-bit is required to run ttx. |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
Subproject commit 48ea31215c9886ab2a1c6bfe81c4a6cf308f275b |
@ -0,0 +1,147 @@
@@ -0,0 +1,147 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ |
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
||||
/* |
||||
* Copyright 2014 Mozilla Foundation |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/*jslint node: true */ |
||||
|
||||
'use strict'; |
||||
|
||||
var os = require('os'); |
||||
var fs = require('fs'); |
||||
var path = require('path'); |
||||
var spawn = require('child_process').spawn; |
||||
var testUtils = require('./testutils.js'); |
||||
|
||||
var tempDirPrefix = 'pdfjs_'; |
||||
|
||||
function WebBrowser(name, path) { |
||||
this.name = name; |
||||
this.path = path; |
||||
this.tmpDir = null; |
||||
this.profileDir = null; |
||||
this.process = null; |
||||
this.finished = false; |
||||
this.callback = null; |
||||
} |
||||
WebBrowser.prototype = { |
||||
start: function (url) { |
||||
this.tmpDir = path.join(os.tmpdir(), tempDirPrefix + this.name); |
||||
if (!fs.existsSync(this.tmpDir)) { |
||||
fs.mkdirSync(this.tmpDir); |
||||
} |
||||
this.process = this.startProcess(url); |
||||
}, |
||||
getProfileDir: function () { |
||||
if (!this.profileDir) { |
||||
var profileDir = path.join(this.tmpDir, 'profile'); |
||||
if (fs.existsSync(profileDir)) { |
||||
testUtils.removeDirSync(profileDir); |
||||
} |
||||
fs.mkdirSync(profileDir); |
||||
this.profileDir = profileDir; |
||||
this.setupProfileDir(profileDir); |
||||
} |
||||
return this.profileDir; |
||||
}, |
||||
buildArguments: function (url) { |
||||
return [url]; |
||||
}, |
||||
setupProfileDir: function (dir) { |
||||
}, |
||||
startProcess: function (url) { |
||||
var args = this.buildArguments(url); |
||||
var proc = spawn(this.path, args); |
||||
proc.on('close', function (code) { |
||||
this.finished = true; |
||||
if (this.callback) { |
||||
this.callback.call(null, code); |
||||
} |
||||
this.cleanup(); |
||||
}.bind(this)); |
||||
return proc; |
||||
}, |
||||
cleanup: function () { |
||||
testUtils.removeDirSync(this.tmpDir); |
||||
}, |
||||
stop: function (callback) { |
||||
if (this.finished) { |
||||
if (callback) { |
||||
callback(); |
||||
} |
||||
} else { |
||||
this.callback = callback; |
||||
} |
||||
|
||||
this.process.kill(); |
||||
this.process = null; |
||||
} |
||||
}; |
||||
|
||||
var firefoxResourceDir = path.join(__dirname, 'resources', 'firefox'); |
||||
|
||||
function FirefoxBrowser(name, path) { |
||||
if (os.platform() === 'darwin') { |
||||
var m = /([^.\/]+)\.app(\/?)$/.exec(path); |
||||
if (m) { |
||||
path += (m[2] ? '' : '/') + 'Contents/MacOS/firefox'; |
||||
} |
||||
} |
||||
WebBrowser.call(this, name, path); |
||||
} |
||||
FirefoxBrowser.prototype = Object.create(WebBrowser.prototype); |
||||
FirefoxBrowser.prototype.buildArguments = function (url) { |
||||
var profileDir = this.getProfileDir(); |
||||
var args = []; |
||||
if (os.platform() === 'darwin') { |
||||
args.push('-foreground'); |
||||
} |
||||
args.push('-no-remote', '-profile', profileDir, url); |
||||
return args; |
||||
}; |
||||
FirefoxBrowser.prototype.setupProfileDir = function (dir) { |
||||
testUtils.copySubtreeSync(firefoxResourceDir, dir); |
||||
}; |
||||
|
||||
function ChromiumBrowser(name, path) { |
||||
if (os.platform() === 'darwin') { |
||||
var m = /([^.\/]+)\.app(\/?)$/.exec(path); |
||||
if (m) { |
||||
path += (m[2] ? '' : '/') + 'Contents/MacOS/' + m[1]; |
||||
console.log(path); |
||||
} |
||||
} |
||||
WebBrowser.call(this, name, path); |
||||
} |
||||
ChromiumBrowser.prototype = Object.create(WebBrowser.prototype); |
||||
ChromiumBrowser.prototype.buildArguments = function (url) { |
||||
var profileDir = this.getProfileDir(); |
||||
return ['--user-data-dir=' + profileDir, |
||||
'--no-first-run', '--disable-sync', url]; |
||||
}; |
||||
|
||||
WebBrowser.create = function (desc) { |
||||
var name = desc.name; |
||||
if (/firefox/i.test(name)) { |
||||
return new FirefoxBrowser(desc.name, desc.path); |
||||
} |
||||
if (/(chrome|chromium)/i.test(name)) { |
||||
return new ChromiumBrowser(desc.name, desc.path); |
||||
} |
||||
return new WebBrowser(desc.name, desc.path); |
||||
}; |
||||
|
||||
|
||||
exports.WebBrowser = WebBrowser; |
Loading…
Reference in new issue