Skip to content

Commit

Permalink
Don't fail-fast when loading HARs/HARPs
Browse files Browse the repository at this point in the history
Continue loading as many HARs/HARPs as we can.

Save the original request URL to the jqXHR object so that we can display
the URL in the case of error.

Add test that checks for errors when a missing HAR is attempted to be
loaded.
  • Loading branch information
gitgrimbo committed Jun 28, 2018
1 parent 2d0dddc commit 09c24cd
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 61 deletions.
1 change: 1 addition & 0 deletions tests/functional/.eslintrc.js
Expand Up @@ -4,6 +4,7 @@ The functional tests run on Node and can use more modern JS syntax.
module.exports = {
"rules": {
"indent": ["warn", 2],
"quotes": ["error", "double", { allowTemplateLiterals: true }],
},
"parserOptions": {
"ecmaVersion": 6
Expand Down
115 changes: 71 additions & 44 deletions tests/functional/testLoadMultipleFiles.js
Expand Up @@ -2,18 +2,19 @@
* Load multiple HAR files into the viewer.
*/
define([
'./config',
'./DriverUtils',
'dojo/node!@theintern/leadfoot',
"./config",
"./DriverUtils",
"dojo/node!@theintern/leadfoot",
], function(config, DriverUtils, leadfoot) {
const { registerSuite } = intern.getInterface("object");
const { assert } = intern.getPlugin("chai");
const { pollUntil } = leadfoot;
const { harViewerBase, testBase } = config;
const { harViewerBase, testBase, findTimeout } = config;

function makeFiles(num) {
var files = [];
for (var i = 0; i < num; i++) {
const files = [];
for (let i = 0; i < num; i++) {
// Although these n.har files have .har extension, they are actually HARPs.
files.push((i + 1) + ".har");
}
return files;
Expand All @@ -27,24 +28,27 @@ define([

function prefix(prefix, arr) {
return arr.map(function(it) {
return ("string" === typeof prefix) ? prefix + it : it;
return (typeof prefix === "string") ? prefix + it : it;
});
}

function testWithParamName(remote, baseUrl, paramName, files, expectedNumberOfPageTables) {
function testWithParamName(remote, baseUrl, paramName, files, expectedNumberOfPageTables, expectedNumberOfErrors) {
// Some of these tests need a larger timeout for finding DOM elements
// because we need the HAR to parse/display fully before we query the DOM.
var findTimeout = config.findTimeout;
var r = remote;
var utils = new DriverUtils(r);
const r = remote;
const utils = new DriverUtils(r);

if ("number" !== typeof expectedNumberOfPageTables) {
if (typeof expectedNumberOfPageTables !== "number") {
// If no explicit "expectedNumberOfPageTables" provided, default to number of files.
expectedNumberOfPageTables = files.length;
}

if (typeof expectedNumberOfErrors !== "number") {
expectedNumberOfErrors = 0;
}

// Put together URL that specifies multiple HAR files.
var url = harViewerBase + "?";
let url = harViewerBase + "?";
if (baseUrl) {
url += "baseUrl=" + baseUrl + "&";
}
Expand All @@ -58,76 +62,99 @@ define([
// path=1.har&path=2.har&path=3.har&path=4.har&path=5.har&
// path=6.har&path=7.har&path=8.har&path=9.har

var waitForFilesToLoadMs = findTimeout;
const waitForFilesToLoadMs = findTimeout;
const assertEpectedNumberOfPageTablesJS = [
`return (`,
` document.querySelectorAll(".pageTable").length === ${expectedNumberOfPageTables}`,
`) || null;`,
].join("");

return r
.setFindTimeout(findTimeout)
.get(url)
// Wait for 10 sec to load all HAR files.
// Return null or undefined to indicate poll not successful (yet).
// http://theintern.github.io/leadfoot/pollUntil.html
.then(pollUntil("return (document.querySelectorAll('.pageTable').length === " + expectedNumberOfPageTables + ") || null;", waitForFilesToLoadMs))
.then(null, function(err) {
// ignore pollUntil timeout error
return 0;
})
.then(pollUntil(assertEpectedNumberOfPageTablesJS, waitForFilesToLoadMs))
// ignore pollUntil timeout error because we repeat the .pageTable selector below
.catch(() => 1)
// We don't want to wait any longer for .pageTable or .errorTable elements to appear.
// They should already be there after the above pollUntil has waited.
.setFindTimeout(0)
.findAllByCssSelector(".pageTable")
.then(function(els) {
assert.strictEqual(els.length, expectedNumberOfPageTables);
})
.then((els) => assert.strictEqual(els.length, expectedNumberOfPageTables, ".pageTable"))
.end(Infinity)
.findAllByCssSelector(".errorTable")
.then((els) => assert.strictEqual(els.length, expectedNumberOfErrors, ".errorTable"))
.then(utils.cbAssertElementContainsText("css=.PreviewTab.selected", "Preview"));
}

registerSuite('testLoadMulipleFiles', {
'testLoadMulipleFiles using "path" and "baseUrl" parameters': function() {
// Using both "path" and "baseUrl" means we're loading JSONP/HARP
registerSuite("testLoadMulipleFiles", {
"testLoadMulipleFiles using 'path' and 'baseUrl' parameters": function() {
// Using both "path" and "baseUrl" means we"re loading JSONP/HARP
return testWithParamName(this.remote, testBase + "tests/hars/", "path", makeFiles(9));
},

'testLoadMulipleFiles using "path" parameter': function() {
// Using only "path" means we're loading HAR
var files = [
"browser-blocking-time.har",
"google.com.har",
"inline-scripts-block.har"
];
"testLoadMulipleFiles using 'path' parameter": function() {
// Using only "path" means we"re loading HAR
// Without baseUrl, files must point to resolveable URL.
// In this case, relative to the webapp.
files = prefix(harViewerBase + "examples/", files);
const files = prefix(harViewerBase + "examples/", [
"browser-blocking-time.har",
"google.com.har",
"inline-scripts-block.har",
]);
// Legacy "path" parameter only loads first "path", so expectedNumberOfPageTables===1.
return testWithParamName(this.remote, null, "path", files, 1);
},

'testLoadMulipleFiles using "harp" and "baseUrl" parameter': function() {
"testLoadMulipleFiles using 'harp' and 'baseUrl' parameter": function() {
return testWithParamName(this.remote, testBase + "tests/hars/", "harp", makeFiles(9));
},

'testLoadMulipleFiles using "harp" parameter': function() {
var files = prefix(testBase + "tests/hars/", makeFiles(9));
"testLoadMulipleFiles using 'harp' parameter": function() {
const files = prefix(testBase + "tests/hars/", makeFiles(9));
return testWithParamName(this.remote, null, "harp", files);
},

'testLoadMulipleFiles using "har" and "baseUrl" parameter': function() {
var files = [
"testLoadMulipleFiles using 'har' and 'baseUrl' parameter": function() {
const files = [
"browser-blocking-time.har",
"google.com.har",
"inline-scripts-block.har"
"inline-scripts-block.har",
];
// New "har" parameter loads all "har", so expectedNumberOfPageTables===3
// (which is the default files.length).
return testWithParamName(this.remote, harViewerBase + "examples/", "har", files);
},

'testLoadMulipleFiles using "har" parameter': function() {
var files = [
"testLoadMulipleFiles using 'har' parameter": function() {
const files = prefix(harViewerBase + "examples/", [
"browser-blocking-time.har",
"google.com.har",
"inline-scripts-block.har"
];
files = prefix(harViewerBase + "examples/", files);
"inline-scripts-block.har",
]);
// New "har" parameter loads all "har", so expectedNumberOfPageTables===3
// (which is the default files.length).
return testWithParamName(this.remote, null, "har", files);
},

"testLoadMulipleFiles using 'har' parameter - with missing HAR": function() {
const files = prefix(harViewerBase + "examples/", [
"browser-blocking-time.har",
"MISSING.har",
"inline-scripts-block.har",
]);
// Only 2 HARs should load properly, and 1 error
return testWithParamName(this.remote, null, "har", files, 2, 1);
},

"testLoadMulipleFiles using 'harp' parameter - with missing HARP": function() {
const files = prefix(testBase + "tests/hars/", makeFiles(3));
// change the middle file to be missing
files[1] = testBase + "MISSING.harp";
// Only 2 HARPs should load properly, and 1 error
return testWithParamName(this.remote, null, "harp", files, 2, 1).then(pollUntil("", 30*1000));
},
});
});
18 changes: 15 additions & 3 deletions webapp/scripts/harViewer.js
Expand Up @@ -143,11 +143,23 @@ HarView.prototype = Lib.extend(new TabView(),
Lib.fireEvent(content, "onViewerHARLoaded");
},

onLoadError: function(jqXHR, textStatus, errorThrown)
{
onLoadError: function(jqXHR, textStatus, errorThrown) {
var homeTab = this.getTab("Home");
if (homeTab)
var previewTab = this.getTab("Preview");

if (homeTab) {
homeTab.loadInProgress(true, jqXHR.statusText);
}

if (previewTab) {
previewTab.appendError({
errors: [{
property: jqXHR.statusText,
message: jqXHR.url,
}],
});
previewTab.select();
}

Trace.error("harModule.loadRemoteArchive; ERROR ", jqXHR, textStatus, errorThrown);
},
Expand Down
40 changes: 26 additions & 14 deletions webapp/scripts/preview/harModelLoader.js
Expand Up @@ -138,8 +138,7 @@ var Loader =
* @return {boolean}
* `true` if there was any HAR/HARP to load, `false` otherwise.
*/
loadArchives: function(hars, harps, callbackName, callback, errorCallback, doneCallback)
{
loadArchives: function(hars, harps, callbackName, callback, errorCallback, doneCallback) {
function done() {
if (doneCallback) {
doneCallback();
Expand Down Expand Up @@ -170,35 +169,48 @@ var Loader =
callbackName = "onInputData";
}

var loader = this;

function handleRest() {
if (hars.length + harps.length === 0) {
done();
return;
}

// Asynchronously load other HAR files (jQuery doesn't like it synchronously).
setTimeout(function() {
loader.loadArchives(hars, harps,
callbackName, callback, errorCallback, doneCallback);
}, 300);
}

var ajaxOpts = {
url: url,
context: this,
dataType: "json",

beforeSend: function(jqXHR, settings) {
jqXHR.url = settings.url;
},

success: function() {
if (callback) {
callback.apply(this, arguments);
}

if (hars.length + harps.length === 0) {
done();
return;
}

// Asynchronously load other HAR files (jQuery doesn't like it synchronously).
var self = this;
setTimeout(function() {
self.loadArchives(hars, harps,
callbackName, callback, errorCallback, doneCallback);
}, 300);
// Try to load the rest of the HARs/HARPs
handleRest();
},

error: function() {
// Here to place breakpoints :)
if (errorCallback) {
errorCallback.apply(this, arguments);
}
}

// Try to load the rest of the HARs/HARPs
handleRest();
},
};

if (isHarp) {
Expand Down

0 comments on commit 09c24cd

Please sign in to comment.