Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core(network-recorder): redirects started by script are set as initiators #7352

Merged
merged 6 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lighthouse-core/lib/network-recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,9 @@ class NetworkRecorder extends EventEmitter {
for (const record of records) {
const stackFrames = (record.initiator.stack && record.initiator.stack.callFrames) || [];
const initiatorURL = record.initiator.url || (stackFrames[0] && stackFrames[0].url);
const initiator = recordsByURL.get(initiatorURL) || record.redirectSource;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

presumably there was some reason I fellback this way but I have no idea what is was at this point and this seems to make more sense, so..... cool!

maybe add a comment so we don't forget again?

// If we were redirected to this request, our initiator is that redirect, otherwise, it's the
// initiator provided by the protocol. See https://github.com/GoogleChrome/lighthouse/pull/7352/
const initiator = record.redirectSource || recordsByURL.get(initiatorURL);
if (initiator) {
record.setInitiatorRequest(initiator);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"FB0836DEB3DBEF7ABC0655BE538C9E50","name":"commit","timestamp":7161.561296}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"FB0836DEB3DBEF7ABC0655BE538C9E50","name":"DOMContentLoaded","timestamp":7161.562802}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"FB0836DEB3DBEF7ABC0655BE538C9E50","name":"load","timestamp":7161.563057}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"FB0836DEB3DBEF7ABC0655BE538C9E50","name":"networkAlmostIdle","timestamp":7161.563436}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"FB0836DEB3DBEF7ABC0655BE538C9E50","name":"networkIdle","timestamp":7161.563436}},
{"method":"Network.requestWillBeSent","params":{"requestId":"82A9687A3E396289BF288BE28FAC977B","loaderId":"82A9687A3E396289BF288BE28FAC977B","documentURL":"http://localhost:10200/redirects-script.html","request":{"url":"http://localhost:10200/redirects-script.html","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":7162.22791,"wallTime":1551376568.301146,"initiator":{"type":"other"},"type":"Document","frameId":"E6C992E73862A3AB8AEADAC3772D5421","hasUserGesture":false}},
{"method":"Network.responseReceived","params":{"requestId":"82A9687A3E396289BF288BE28FAC977B","loaderId":"82A9687A3E396289BF288BE28FAC977B","timestamp":7162.231603,"type":"Document","response":{"url":"http://localhost:10200/redirects-script.html","status":200,"statusText":"OK","headers":{"Access-Control-Allow-Origin":"*","Date":"Thu, 28 Feb 2019 17:56:08 GMT","Connection":"keep-alive","Transfer-Encoding":"chunked"},"headersText":"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nDate: Thu, 28 Feb 2019 17:56:08 GMT\r\nConnection: keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n","mimeType":"text/html","requestHeaders":{"Host":"localhost:10200","Connection":"keep-alive","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9"},"requestHeadersText":"GET /redirects-script.html HTTP/1.1\r\nHost: localhost:10200\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\n","connectionReused":true,"connectionId":36,"remoteIPAddress":"127.0.0.1","remotePort":10200,"fromDiskCache":false,"fromServiceWorker":false,"encodedDataLength":140,"timing":{"requestTime":7162.228635,"proxyStart":-1,"proxyEnd":-1,"dnsStart":-1,"dnsEnd":-1,"connectStart":-1,"connectEnd":-1,"sslStart":-1,"sslEnd":-1,"workerStart":-1,"workerReady":-1,"sendStart":1.195,"sendEnd":1.237,"pushStart":0,"pushEnd":0,"receiveHeadersEnd":2.277},"protocol":"http/1.1","securityState":"neutral"},"frameId":"E6C992E73862A3AB8AEADAC3772D5421"}},
{"method":"Page.frameStartedLoading","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421"}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"init","timestamp":7162.233881}},
{"method":"Network.dataReceived","params":{"requestId":"82A9687A3E396289BF288BE28FAC977B","timestamp":7162.234907,"dataLength":569,"encodedDataLength":0}},
{"method":"Page.frameNavigated","params":{"frame":{"id":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","url":"http://localhost:10200/redirects-script.html","securityOrigin":"http://localhost:10200","mimeType":"text/html"}}},
{"method":"Network.loadingFinished","params":{"requestId":"82A9687A3E396289BF288BE28FAC977B","timestamp":7162.231334,"encodedDataLength":721,"shouldReportCorbBlocking":false}},
{"method":"Page.loadEventFired","params":{"timestamp":7162.2438}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"load","timestamp":7162.2438}},
{"method":"Page.frameStoppedLoading","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421"}},
{"method":"Page.domContentEventFired","params":{"timestamp":7162.244328}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"DOMContentLoaded","timestamp":7162.244328}},
{"method":"Page.frameAttached","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C","parentFrameId":"E6C992E73862A3AB8AEADAC3772D5421","stack":{"callFrames":[{"functionName":"","scriptId":"18","url":"http://localhost:10200/redirects-script.html","lineNumber":11,"columnNumber":20}]}}},
{"method":"Network.requestWillBeSent","params":{"requestId":"9E5F212F4468007C6952E996764DC56A","loaderId":"9E5F212F4468007C6952E996764DC56A","documentURL":"http://localhost:10200/redirects-script.html?redirect=http%3A%2F%2Flocalhost%3A10503%2Fredirects-script.html%3Fredirect%3Dhttps%253A%252F%252Fairhorner.com%252F","request":{"url":"http://localhost:10200/redirects-script.html?redirect=http%3A%2F%2Flocalhost%3A10503%2Fredirects-script.html%3Fredirect%3Dhttps%253A%252F%252Fairhorner.com%252F","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","Referer":"http://localhost:10200/redirects-script.html"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":7162.648846,"wallTime":1551376568.722058,"initiator":{"type":"script","stack":{"callFrames":[{"functionName":"","scriptId":"18","url":"http://localhost:10200/redirects-script.html","lineNumber":11,"columnNumber":20}]}},"type":"Document","frameId":"B19E293EA74DA749596009C93D1C1B4C","hasUserGesture":false}},
{"method":"Page.lifecycleEvent","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C","loaderId":"22E839E241B3EFB1229B834C62CE85D2","name":"init","timestamp":7162.646479}},
{"method":"Page.lifecycleEvent","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C","loaderId":"22E839E241B3EFB1229B834C62CE85D2","name":"DOMContentLoaded","timestamp":7162.647219}},
{"method":"Page.frameStartedLoading","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C"}},
{"method":"Page.lifecycleEvent","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C","loaderId":"FDBAAD6744CF4B5868BA77D740A41F7F","name":"init","timestamp":7162.647934}},
{"method":"Network.requestWillBeSent","params":{"requestId":"9E5F212F4468007C6952E996764DC56A","loaderId":"9E5F212F4468007C6952E996764DC56A","documentURL":"http://localhost:10503/redirects-script.html?redirect=https%3A%2F%2Fairhorner.com%2F","request":{"url":"http://localhost:10503/redirects-script.html?redirect=https%3A%2F%2Fairhorner.com%2F","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","Referer":"http://localhost:10200/redirects-script.html"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":7162.653028,"wallTime":1551376568.72624,"initiator":{"type":"script","stack":{"callFrames":[{"functionName":"","scriptId":"18","url":"http://localhost:10200/redirects-script.html","lineNumber":11,"columnNumber":20}]}},"redirectResponse":{"url":"http://localhost:10200/redirects-script.html?redirect=http%3A%2F%2Flocalhost%3A10503%2Fredirects-script.html%3Fredirect%3Dhttps%253A%252F%252Fairhorner.com%252F","status":302,"statusText":"Found","headers":{"Location":"http://localhost:10503/redirects-script.html?redirect=https%3A%2F%2Fairhorner.com%2F","Date":"Thu, 28 Feb 2019 17:56:08 GMT","Connection":"keep-alive","Transfer-Encoding":"chunked"},"headersText":"HTTP/1.1 302 Found\r\nLocation: http://localhost:10503/redirects-script.html?redirect=https%3A%2F%2Fairhorner.com%2F\r\nDate: Thu, 28 Feb 2019 17:56:08 GMT\r\nConnection: keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n","mimeType":"","requestHeaders":{"Host":"localhost:10200","Connection":"keep-alive","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3","Referer":"http://localhost:10200/redirects-script.html","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9"},"requestHeadersText":"GET /redirects-script.html?redirect=http%3A%2F%2Flocalhost%3A10503%2Fredirects-script.html%3Fredirect%3Dhttps%253A%252F%252Fairhorner.com%252F HTTP/1.1\r\nHost: localhost:10200\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nReferer: http://localhost:10200/redirects-script.html\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\n","connectionReused":true,"connectionId":36,"remoteIPAddress":"127.0.0.1","remotePort":10200,"fromDiskCache":false,"fromServiceWorker":false,"encodedDataLength":207,"timing":{"requestTime":7162.649486,"proxyStart":-1,"proxyEnd":-1,"dnsStart":-1,"dnsEnd":-1,"connectStart":-1,"connectEnd":-1,"sslStart":-1,"sslEnd":-1,"workerStart":-1,"workerReady":-1,"sendStart":0.504,"sendEnd":0.541,"pushStart":0,"pushEnd":0,"receiveHeadersEnd":2.924},"protocol":"http/1.1","securityState":"neutral"},"type":"Document","frameId":"B19E293EA74DA749596009C93D1C1B4C","hasUserGesture":false}},
{"method":"Network.requestWillBeSent","params":{"requestId":"9E5F212F4468007C6952E996764DC56A","loaderId":"9E5F212F4468007C6952E996764DC56A","documentURL":"https://airhorner.com/","request":{"url":"https://airhorner.com/","method":"GET","headers":{"Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","Referer":"http://localhost:10200/redirects-script.html"},"mixedContentType":"none","initialPriority":"VeryHigh","referrerPolicy":"no-referrer-when-downgrade"},"timestamp":7162.657095,"wallTime":1551376568.730307,"initiator":{"type":"script","stack":{"callFrames":[{"functionName":"","scriptId":"18","url":"http://localhost:10200/redirects-script.html","lineNumber":11,"columnNumber":20}]}},"redirectResponse":{"url":"http://localhost:10503/redirects-script.html?redirect=https%3A%2F%2Fairhorner.com%2F","status":302,"statusText":"Found","headers":{"Location":"https://airhorner.com/","Date":"Thu, 28 Feb 2019 17:56:08 GMT","Connection":"keep-alive","Transfer-Encoding":"chunked"},"headersText":"HTTP/1.1 302 Found\r\nLocation: https://airhorner.com/\r\nDate: Thu, 28 Feb 2019 17:56:08 GMT\r\nConnection: keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n","mimeType":"","requestHeaders":{"Host":"localhost:10503","Connection":"keep-alive","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3","Referer":"http://localhost:10200/redirects-script.html","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9"},"requestHeadersText":"GET /redirects-script.html?redirect=https%3A%2F%2Fairhorner.com%2F HTTP/1.1\r\nHost: localhost:10503\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nReferer: http://localhost:10200/redirects-script.html\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\n","connectionReused":false,"connectionId":54,"remoteIPAddress":"127.0.0.1","remotePort":10503,"fromDiskCache":false,"fromServiceWorker":false,"encodedDataLength":145,"timing":{"requestTime":7162.653422,"proxyStart":-1,"proxyEnd":-1,"dnsStart":0.379,"dnsEnd":0.393,"connectStart":0.393,"connectEnd":0.715,"sslStart":-1,"sslEnd":-1,"workerStart":-1,"workerReady":-1,"sendStart":0.808,"sendEnd":0.846,"pushStart":0,"pushEnd":0,"receiveHeadersEnd":3.006},"protocol":"http/1.1","securityState":"neutral"},"type":"Document","frameId":"B19E293EA74DA749596009C93D1C1B4C","hasUserGesture":false}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"firstPaint","timestamp":7162.716106}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"firstMeaningfulPaintCandidate","timestamp":7162.716115}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"networkAlmostIdle","timestamp":7162.244356}},
{"method":"Page.lifecycleEvent","params":{"frameId":"E6C992E73862A3AB8AEADAC3772D5421","loaderId":"82A9687A3E396289BF288BE28FAC977B","name":"networkIdle","timestamp":7162.256479}},
{"method":"Network.responseReceived","params":{"requestId":"9E5F212F4468007C6952E996764DC56A","loaderId":"9E5F212F4468007C6952E996764DC56A","timestamp":7162.979774,"type":"Document","response":{"url":"https://airhorner.com/","status":200,"statusText":"","headers":{"status":"200","date":"Thu, 28 Feb 2019 17:56:08 GMT","expires":"Thu, 28 Feb 2019 17:56:18 GMT"},"mimeType":"text/html","requestHeaders":{":method":"GET",":authority":"airhorner.com",":scheme":"https",":path":"/","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3694.0 Mobile Safari/537.36 Chrome-Lighthouse","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3","referer":"http://localhost:10200/redirects-script.html","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"connectionReused":false,"connectionId":62,"remotePort":443,"fromDiskCache":false,"fromServiceWorker":false,"encodedDataLength":2254,"timing":{"requestTime":7162.657451,"proxyStart":-1,"proxyEnd":-1,"dnsStart":0.35,"dnsEnd":91.4,"connectStart":91.4,"connectEnd":125.871,"sslStart":92.917,"sslEnd":125.864,"workerStart":-1,"workerReady":-1,"sendStart":126.138,"sendEnd":126.281,"pushStart":0,"pushEnd":0,"receiveHeadersEnd":317.295},"protocol":"h2","securityState":"secure","securityDetails":{"protocol":"TLS 1.2","keyExchange":"ECDHE_RSA","keyExchangeGroup":"X25519","cipher":"AES_128_GCM","certificateId":0,"subjectName":"airhorner.com","sanList":["airhorner.com"],"issuer":"Let's Encrypt Authority X3","validFrom":1549374063,"validTo":1557150063,"signedCertificateTimestampList":[],"certificateTransparencyCompliance":"compliant"}},"frameId":"B19E293EA74DA749596009C93D1C1B4C"}}, {"method":"Page.frameStoppedLoading","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C"}},
{"method":"Page.frameDetached","params":{"frameId":"B19E293EA74DA749596009C93D1C1B4C"}}
]
45 changes: 45 additions & 0 deletions lighthouse-core/test/lib/network-recorder-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const networkRecordsToDevtoolsLog = require('../network-records-to-devtools-log.
const assert = require('assert');
const devtoolsLogItems = require('../fixtures/artifacts/perflog/defaultPass.devtoolslog.json');
const redirectsDevtoolsLog = require('../fixtures/wikipedia-redirect.devtoolslog.json');
const redirectsScriptDevtoolsLog = require('../fixtures/redirects-from-script.devtoolslog.json');

/* eslint-env jest */
describe('network recorder', function() {
Expand Down Expand Up @@ -46,6 +47,50 @@ describe('network recorder', function() {
assert.equal(mainDocument.resourceType, 'Document');
});

it('sets initiators to redirects when original initiator is script', () => {
// The test page features script-initiated redirects:
/*
<!DOCTYPE html>
<script>
setTimeout(_ => {
// add an iframe to the page via script
// the iframe will open :10200/redirects-script.html
// which redirects to :10503/redirects-script.html
// which redirects to airhorner.com
const elem = document.createElement('iframe');
elem.src = 'http://localhost:10200/redirects-script.html?redirect=http%3A%2F%2Flocalhost%3A10503%2Fredirects-script.html%3Fredirect%3Dhttps%253A%252F%252Fairhorner.com%252F';
document.body.append(elem);
}, 400);
</script>
*/

const records = NetworkRecorder.recordsFromLogs(redirectsScriptDevtoolsLog);
assert.equal(records.length, 4);

const [mainDocument, iframeRedirectA, iframeRedirectB, iframeDocument] = records;
assert.equal(mainDocument.initiatorRequest, undefined);
assert.equal(mainDocument.redirectSource, undefined);
assert.equal(mainDocument.redirectDestination, undefined);
assert.equal(iframeRedirectA.initiatorRequest, mainDocument);
assert.equal(iframeRedirectA.redirectSource, undefined);
assert.equal(iframeRedirectA.redirectDestination, iframeRedirectB);
assert.equal(iframeRedirectB.initiatorRequest, iframeRedirectA);
assert.equal(iframeRedirectB.redirectSource, iframeRedirectA);
assert.equal(iframeRedirectB.redirectDestination, iframeDocument);
assert.equal(iframeDocument.initiatorRequest, iframeRedirectB);
assert.equal(iframeDocument.redirectSource, iframeRedirectB);
assert.equal(iframeDocument.redirectDestination, undefined);

const redirectURLs = iframeDocument.redirects.map(request => request.url);
assert.deepStrictEqual(redirectURLs, [iframeRedirectA.url, iframeRedirectB.url]);

assert.equal(mainDocument.resourceType, 'Document');
assert.equal(iframeRedirectA.resourceType, undefined);
assert.equal(iframeRedirectB.resourceType, undefined);
assert.equal(iframeDocument.resourceType, 'Document');
});


it('recordsFromLogs ignores records with an invalid URL', function() {
const logs = [
{ // valid request
Expand Down