-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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(legacy-javascript): use third-party-web for scoring #10849
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* @license Copyright 2020 The Lighthouse Authors. All Rights Reserved. | ||
* 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. | ||
*/ | ||
'use strict'; | ||
|
||
const thirdPartyWeb = require('third-party-web/httparchive-nostats-subset'); | ||
|
||
/** @typedef {import("third-party-web").IEntity} ThirdPartyEntity */ | ||
|
||
/** | ||
* `third-party-web` throws when the passed in string doesn't appear to have any domain whatsoever. | ||
* We pass in some not-so-url-like things, so make the dependent-code simpler by making this call safe. | ||
* @param {string} url | ||
* @return {ThirdPartyEntity|undefined} | ||
*/ | ||
function getEntity(url) { | ||
try { | ||
return thirdPartyWeb.getEntity(url); | ||
} catch (_) { | ||
return undefined; | ||
} | ||
} | ||
|
||
/** | ||
* @param {string} url | ||
* @param {ThirdPartyEntity | undefined} mainDocumentEntity | ||
*/ | ||
function isThirdParty(url, mainDocumentEntity) { | ||
const entity = getEntity(url); | ||
if (!entity) return false; | ||
if (entity === mainDocumentEntity) return false; | ||
return true; | ||
} | ||
|
||
/** | ||
* @param {string} url | ||
* @param {ThirdPartyEntity | undefined} mainDocumentEntity | ||
*/ | ||
function isFirstParty(url, mainDocumentEntity) { | ||
return !isThirdParty(url, mainDocumentEntity); | ||
} | ||
|
||
module.exports = { | ||
getEntity, | ||
isThirdParty, | ||
isFirstParty, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ const createArtifacts = (scripts) => { | |
url, | ||
})); | ||
return { | ||
URL: {finalUrl: '', requestedUrl: ''}, | ||
URL: {finalUrl: 'https://www.example.com', requestedUrl: 'https://www.example.com'}, | ||
devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(networkRecords)}, | ||
ScriptElements: scripts.map(({url, code}, index) => { | ||
return { | ||
|
@@ -83,6 +83,18 @@ describe('LegacyJavaScript audit', () => { | |
assert.equal(result.extendedInfo.signalCount, 0); | ||
}); | ||
|
||
it('passes code with a legacy polyfill in third party resource', async () => { | ||
const artifacts = createArtifacts([ | ||
{ | ||
code: 'String.prototype.repeat = function() {}', | ||
url: 'https://www.googletagmanager.com/a.js', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be nice to ensure the main entity logic is getting exercised too There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see us re-testing this particular logic over and over again ... maybe just one test in the and just assume that usage within audits is OK (treat like a dependency, for example we don't test that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
]); | ||
const result = await LegacyJavascript.audit(artifacts, {computedCache: new Map()}); | ||
assert.equal(result.score, 1); | ||
assert.equal(result.extendedInfo.signalCount, 1); | ||
}); | ||
|
||
it('fails code with a legacy polyfill', async () => { | ||
const artifacts = createArtifacts([ | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** | ||
* @license Copyright 2020 The Lighthouse Authors. All Rights Reserved. | ||
* 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. | ||
*/ | ||
'use strict'; | ||
|
||
/* eslint-env jest */ | ||
|
||
const thirdPartyWeb = require('../../lib/third-party-web.js'); | ||
|
||
describe('third party web', () => { | ||
it('basic', () => { | ||
expect(thirdPartyWeb.isThirdParty('https://www.example.com', undefined)).toBe(false); | ||
expect(thirdPartyWeb.isFirstParty('https://www.example.com', undefined)).toBe(true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe this is a better example of where the naming gets weird. Just reading this in isolation, I would have no idea why |
||
|
||
expect(thirdPartyWeb.isThirdParty('https://www.googletagmanager.com', undefined)).toBe(true); | ||
expect(thirdPartyWeb.isFirstParty('https://www.googletagmanager.com', undefined)).toBe(false); | ||
}); | ||
|
||
it('not third party if main document is same entity', () => { | ||
const mainDocumentEntity = thirdPartyWeb.getEntity('https://www.googletagmanager.com'); | ||
expect(thirdPartyWeb.isThirdParty('https://www.googletagmanager.com/a.js', mainDocumentEntity)).toBe(false); | ||
expect(thirdPartyWeb.isThirdParty('https://blah.atdmt.com', mainDocumentEntity)).toBe(true); | ||
expect(thirdPartyWeb.isThirdParty('https://www.example.com', mainDocumentEntity)).toBe(false); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can rename this? It isn't really a first party check, it's more of a "not a known majorish third party" check. As an example, up in
legacy-javascript.js
,URL.rootDomainsMatch(row.url, mainResource.url)
is being replaced with athirdPartyWeb.isFirstParty(row.url, mainDocumentEntity);
, which is a better choice for that check but also potentially a very different set of results, depending on the test page.(removing and doing a
if (!thirdPartyWeb.isThirdParty())
up above also seems very clear in its intention if we don't want to bikeshed on names)