mirror of
https://github.com/webrecorder/pywb.git
synced 2025-03-24 06:59:52 +01:00
Merge branch 'client-side-tests' into develop
This commit is contained in:
commit
467ea0f68b
3
.editorconfig
Normal file
3
.editorconfig
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[*.js]
|
||||||
|
indent_style=space
|
||||||
|
indent_size=4
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -41,3 +41,6 @@ nosetests.xml
|
|||||||
.pydevproject
|
.pydevproject
|
||||||
|
|
||||||
.vagrant
|
.vagrant
|
||||||
|
|
||||||
|
# Node
|
||||||
|
node_modules/
|
||||||
|
17
.travis.yml
17
.travis.yml
@ -6,7 +6,14 @@ python:
|
|||||||
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
# - osx
|
|
||||||
|
addons:
|
||||||
|
sauce_connect: true
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.cache/pip
|
||||||
|
- node_modules
|
||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
@ -16,9 +23,15 @@ install:
|
|||||||
- pip install git+https://github.com/esnme/ultrajson.git
|
- pip install git+https://github.com/esnme/ultrajson.git
|
||||||
- python setup.py -q install
|
- python setup.py -q install
|
||||||
- pip install coverage pytest-cov coveralls --use-mirrors
|
- pip install coverage pytest-cov coveralls --use-mirrors
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export DISPLAY=:99.0
|
||||||
|
- sh -e /etc/init.d/xvfb start
|
||||||
|
|
||||||
script:
|
script:
|
||||||
python setup.py test
|
- python setup.py test
|
||||||
|
- cd karma-tests && make test
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
coveralls
|
coveralls
|
||||||
|
4
karma-tests/Makefile
Normal file
4
karma-tests/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
NODE_BIN_DIR=../node_modules/.bin
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(NODE_BIN_DIR)/karma start --single-run
|
9
karma-tests/dummy.html
Normal file
9
karma-tests/dummy.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<head><meta charset="UTF-8"></head>
|
||||||
|
<body>
|
||||||
|
<!-- This is a dummy page used in
|
||||||
|
tests of Wombat's live-rewriting
|
||||||
|
functionality.
|
||||||
|
!-->
|
||||||
|
</body>
|
||||||
|
</html>
|
108
karma-tests/karma.conf.js
Normal file
108
karma-tests/karma.conf.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
var sauceLabsConfig = {
|
||||||
|
testName: 'PyWB Client Tests',
|
||||||
|
};
|
||||||
|
|
||||||
|
// see https://github.com/karma-runner/karma-sauce-launcher/issues/73
|
||||||
|
if (process.env.TRAVIS_JOB_NUMBER) {
|
||||||
|
sauceLabsConfig.startConnect = false;
|
||||||
|
sauceLabsConfig.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
var WOMBAT_JS_PATH = 'pywb/static/wombat.js';
|
||||||
|
|
||||||
|
var sauceLaunchers = {
|
||||||
|
sl_chrome: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'chrome',
|
||||||
|
},
|
||||||
|
|
||||||
|
sl_firefox: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'firefox',
|
||||||
|
},
|
||||||
|
|
||||||
|
sl_safari: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'safari',
|
||||||
|
platform: 'OS X 10.11',
|
||||||
|
version: '9.0',
|
||||||
|
},
|
||||||
|
|
||||||
|
sl_edge: {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'MicrosoftEdge',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var localLaunchers = {
|
||||||
|
localFirefox: {
|
||||||
|
base: 'Firefox',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var customLaunchers = {};
|
||||||
|
|
||||||
|
if (process.env['SAUCE_USERNAME'] && process.env['SAUCE_ACCESS_KEY']) {
|
||||||
|
customLaunchers = sauceLaunchers;
|
||||||
|
} else {
|
||||||
|
console.error('Sauce Labs account details not set, ' +
|
||||||
|
'Karma tests will be run only against local browsers.' +
|
||||||
|
'Set SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables to ' +
|
||||||
|
'run tests against Sauce Labs browsers');
|
||||||
|
customLaunchers = localLaunchers;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '../',
|
||||||
|
|
||||||
|
frameworks: ['mocha', 'chai'],
|
||||||
|
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
pattern: WOMBAT_JS_PATH,
|
||||||
|
watched: true,
|
||||||
|
included: false,
|
||||||
|
served: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'karma-tests/dummy.html',
|
||||||
|
included: false,
|
||||||
|
served: true,
|
||||||
|
},
|
||||||
|
'karma-tests/*.spec.js',
|
||||||
|
],
|
||||||
|
|
||||||
|
preprocessors: {},
|
||||||
|
|
||||||
|
reporters: ['progress'],
|
||||||
|
|
||||||
|
port: 9876,
|
||||||
|
|
||||||
|
colors: true,
|
||||||
|
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
|
||||||
|
autoWatch: true,
|
||||||
|
|
||||||
|
sauceLabs: sauceLabsConfig,
|
||||||
|
|
||||||
|
// Set extended timeouts to account for the slowness
|
||||||
|
// in connecting to remote browsers (eg. when using
|
||||||
|
// Sauce Labs)
|
||||||
|
//
|
||||||
|
// See https://oligofren.wordpress.com/2014/05/27/running-karma-tests-on-browserstack/
|
||||||
|
captureTimeout: 3 * 60000,
|
||||||
|
browserNoActivityTimeout: 30 * 1000,
|
||||||
|
browserDisconnectTimeout: 10 * 1000,
|
||||||
|
browserDisconnectTolerance: 1,
|
||||||
|
|
||||||
|
customLaunchers: customLaunchers,
|
||||||
|
|
||||||
|
browsers: Object.keys(customLaunchers),
|
||||||
|
|
||||||
|
singleRun: false,
|
||||||
|
|
||||||
|
concurrency: Infinity
|
||||||
|
})
|
||||||
|
};
|
212
karma-tests/wombat.spec.js
Normal file
212
karma-tests/wombat.spec.js
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
var DEFAULT_TIMEOUT = 20000;
|
||||||
|
|
||||||
|
// creates a new document in an <iframe> and runs
|
||||||
|
// a WombatJS test case in it.
|
||||||
|
//
|
||||||
|
// A new <iframe> is used for each test so that each
|
||||||
|
// case is run with fresh Document and Window objects,
|
||||||
|
// since Wombat monkey-patches many Document and Window
|
||||||
|
// functions
|
||||||
|
//
|
||||||
|
function runWombatTest(testCase, done) {
|
||||||
|
// create an <iframe>
|
||||||
|
var testFrame = document.createElement('iframe');
|
||||||
|
testFrame.src = '/base/karma-tests/dummy.html';
|
||||||
|
document.body.appendChild(testFrame);
|
||||||
|
|
||||||
|
testFrame.contentWindow.addEventListener('load', function () {
|
||||||
|
var testDocument = testFrame.contentDocument;
|
||||||
|
|
||||||
|
function runFunctionInIFrame(func) {
|
||||||
|
testFrame.contentWindow.eval('(' + func.toString() + ')()');
|
||||||
|
}
|
||||||
|
|
||||||
|
// expose an error reporting function to the <iframe>
|
||||||
|
window.reportError = function(ex) {
|
||||||
|
done(new Error(ex));
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose utility methods for assertion testing in tests.
|
||||||
|
// (We used to expose chai asserts here but Karma's default
|
||||||
|
// error reporter replaces URLs in exception messages with
|
||||||
|
// the corresponding file paths, which is unhelpful for us
|
||||||
|
// since assert.equal() will often be called with URLs in our tests)
|
||||||
|
window.assert = {
|
||||||
|
equal: function (a, b) {
|
||||||
|
if (a !== b) {
|
||||||
|
console.error('Mismatch between', a, 'and', b);
|
||||||
|
throw new Error('AssertionError');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
runFunctionInIFrame(function () {
|
||||||
|
// re-assign the iframe's console object to the parent window's
|
||||||
|
// console so that messages are intercepted by Karma
|
||||||
|
// and output to wherever it is configured to send
|
||||||
|
// console logs (typically stdout)
|
||||||
|
console = window.parent.console;
|
||||||
|
window.onerror = function (message, url, line, col, error) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error.stack);
|
||||||
|
}
|
||||||
|
reportError(new Error(message));
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose chai's assertion testing API to the test script
|
||||||
|
window.assert = window.parent.assert;
|
||||||
|
window.reportError = window.parent.reportError;
|
||||||
|
|
||||||
|
// helpers which check whether DOM property overrides are supported
|
||||||
|
// in the current browser
|
||||||
|
window.domTests = {
|
||||||
|
areDOMPropertiesConfigurable: function () {
|
||||||
|
var descriptor = Object.getOwnPropertyDescriptor(Node.prototype, 'baseURI');
|
||||||
|
if (descriptor && !descriptor.configurable) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
runFunctionInIFrame(testCase.initScript);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Configuring Wombat failed: ' + e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
testFrame.contentWindow.eval(testCase.wombatScript);
|
||||||
|
runFunctionInIFrame(function () {
|
||||||
|
new window._WBWombat(wbinfo);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Initializing WombatJS failed: ' + e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testCase.html) {
|
||||||
|
testDocument.body.innerHTML = testCase.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testCase.testScript) {
|
||||||
|
try {
|
||||||
|
runFunctionInIFrame(testCase.testScript);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Test script failed: ' + e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testFrame.remove();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WombatJS', function () {
|
||||||
|
this.timeout(DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
var wombatScript;
|
||||||
|
|
||||||
|
before(function (done) {
|
||||||
|
// load the source of the WombatJS content
|
||||||
|
// rewriting script
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.open('GET', '/base/pywb/static/wombat.js');
|
||||||
|
req.onload = function () {
|
||||||
|
wombatScript = req.responseText;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
req.send();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load', function (done) {
|
||||||
|
runWombatTest({
|
||||||
|
initScript: function () {
|
||||||
|
wbinfo = {
|
||||||
|
wombat_opts: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
wombatScript: wombatScript,
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('anchor rewriting', function () {
|
||||||
|
var config;
|
||||||
|
beforeEach(function () {
|
||||||
|
config = {
|
||||||
|
initScript: function () {
|
||||||
|
wbinfo = {
|
||||||
|
wombat_opts: {},
|
||||||
|
prefix: window.location.origin,
|
||||||
|
wombat_ts: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
wombatScript: wombatScript,
|
||||||
|
html: '<a href="foobar.html" id="link">A link</a>',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rewrite links in dynamically injected <a> tags', function (done) {
|
||||||
|
config.testScript = function () {
|
||||||
|
if (domTests.areDOMPropertiesConfigurable()) {
|
||||||
|
var link = document.getElementById('link');
|
||||||
|
assert.equal(link.href, 'http:///base/karma-tests/foobar.html');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
runWombatTest(config, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('toString() should return the rewritten URL', function (done) {
|
||||||
|
config.testScript = function () {
|
||||||
|
if (domTests.areDOMPropertiesConfigurable()) {
|
||||||
|
var link = document.getElementById('link');
|
||||||
|
assert.equal(link.href, link.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
runWombatTest(config, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('base URL overrides', function () {
|
||||||
|
it('document.baseURI should return the original URL', function (done) {
|
||||||
|
runWombatTest({
|
||||||
|
initScript: function () {
|
||||||
|
wbinfo = {
|
||||||
|
wombat_opts: {},
|
||||||
|
prefix: window.location.origin,
|
||||||
|
wombat_ts: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
wombatScript: wombatScript,
|
||||||
|
testScript: function () {
|
||||||
|
var baseURI = document.baseURI;
|
||||||
|
if (typeof baseURI !== 'string') {
|
||||||
|
throw new Error('baseURI is not a string');
|
||||||
|
}
|
||||||
|
if (domTests.areDOMPropertiesConfigurable()) {
|
||||||
|
assert.equal(baseURI, 'http:///base/karma-tests/dummy.html');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow base.href to be assigned', function (done) {
|
||||||
|
runWombatTest({
|
||||||
|
initScript: function () {
|
||||||
|
wbinfo = {
|
||||||
|
wombat_opts: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
wombatScript: wombatScript,
|
||||||
|
testScript: function () {
|
||||||
|
'use strict';
|
||||||
|
var baseElement = document.createElement('base');
|
||||||
|
baseElement.href = 'http://foobar.com/base';
|
||||||
|
assert.equal(baseElement.href, 'http://foobar.com/base');
|
||||||
|
},
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
34
package.json
Normal file
34
package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "pywb",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Web archival replay tools",
|
||||||
|
"main": "index.js",
|
||||||
|
"directories": {
|
||||||
|
"doc": "doc",
|
||||||
|
"test": "tests"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/ikreymer/pywb.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ikreymer/pywb/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/ikreymer/pywb#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^3.4.1",
|
||||||
|
"karma": "^0.13.15",
|
||||||
|
"karma-chai": "^0.1.0",
|
||||||
|
"karma-chrome-launcher": "^0.2.1",
|
||||||
|
"karma-firefox-launcher": "^0.1.7",
|
||||||
|
"karma-html2js-preprocessor": "^0.1.0",
|
||||||
|
"karma-mocha": "^0.2.1",
|
||||||
|
"karma-sauce-launcher": "^0.3.0",
|
||||||
|
"mocha": "^2.3.4"
|
||||||
|
}
|
||||||
|
}
|
@ -363,26 +363,36 @@ var wombat_internal = function($wbwindow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//============================================
|
//============================================
|
||||||
// Define custom property
|
// Override a DOM property
|
||||||
function def_prop(obj, prop, set_func, get_func) {
|
function def_prop(obj, prop, set_func, get_func) {
|
||||||
|
// if the property is marked as non-configurable in the current
|
||||||
|
// browser, skip the override
|
||||||
|
var existingDescriptor = Object.getOwnPropertyDescriptor(obj, prop);
|
||||||
|
if (existingDescriptor && !existingDescriptor.configurable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no getter function was supplied, skip the override.
|
||||||
|
// See https://github.com/ikreymer/pywb/issues/147 for context
|
||||||
|
if (!get_func) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object.defineProperty(obj, prop, {
|
var descriptor = {
|
||||||
configurable: false,
|
configurable: true,
|
||||||
// enumerable: true,
|
get: get_func,
|
||||||
set: set_func,
|
};
|
||||||
get: get_func
|
|
||||||
});
|
if (set_func) {
|
||||||
|
descriptor.set = set_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(obj, prop, descriptor);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
var info = "Can't redefine prop " + prop;
|
console.warn('Failed to redefine property %s', prop, e.message);
|
||||||
console.warn(info);
|
|
||||||
//f (obj && obj.tagName) {
|
|
||||||
// info += " on " + obj.tagName;
|
|
||||||
//}
|
|
||||||
//if (value != obj[prop]) {
|
|
||||||
// obj[prop] = value;
|
|
||||||
//}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -757,15 +767,15 @@ var wombat_internal = function($wbwindow) {
|
|||||||
def_prop($wbwindow.HTMLBaseElement.prototype, "href", undefined, base_href_get);
|
def_prop($wbwindow.HTMLBaseElement.prototype, "href", undefined, base_href_get);
|
||||||
|
|
||||||
// Shared baseURI
|
// Shared baseURI
|
||||||
var orig_getter = $wbwindow.document.__lookupGetter__("baseURI");
|
var orig_getter = get_orig_getter($wbwindow.Node.prototype, "baseURI");
|
||||||
|
if (orig_getter) {
|
||||||
|
var get_baseURI = function() {
|
||||||
|
var res = orig_getter.call(this);
|
||||||
|
return extract_orig(res);
|
||||||
|
}
|
||||||
|
|
||||||
var get_baseURI = function() {
|
def_prop($wbwindow.Node.prototype, "baseURI", undefined, get_baseURI);
|
||||||
var res = orig_getter.call(this);
|
|
||||||
return extract_orig(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def_prop($wbwindow.HTMLElement.prototype, "baseURI", undefined, get_baseURI);
|
|
||||||
def_prop($wbwindow.HTMLDocument.prototype, "baseURI", undefined, get_baseURI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================
|
//============================================
|
||||||
@ -1387,6 +1397,9 @@ var wombat_internal = function($wbwindow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init_loc_override($wbwindow.HTMLAnchorElement.prototype, anchor_setter, anchor_getter);
|
init_loc_override($wbwindow.HTMLAnchorElement.prototype, anchor_setter, anchor_getter);
|
||||||
|
$wbwindow.HTMLAnchorElement.prototype.toString = function () {
|
||||||
|
return this.href;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user