core(artifacts): encapsulate node details in an object (#11695, reland #11474)

This commit is contained in:
Paul Irish 2020-12-07 18:58:17 -08:00 коммит произвёл GitHub
Родитель f329ca056f
Коммит 2cbbd289be
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
75 изменённых файлов: 1452 добавлений и 984 удалений

Просмотреть файл

@ -23,7 +23,9 @@ const expectations = [
// deep in the DOM, and the sample LHR test has plenty of places that would catch
// a regression in `devtoolsNodePath` calculation. Keep just one for the benefit
// of other smoke test runners.
devtoolsNodePath: '2,HTML,0,HEAD,3,SCRIPT',
node: {
devtoolsNodePath: '2,HTML,0,HEAD,3,SCRIPT',
},
},
{
type: 'application/javascript',

Просмотреть файл

@ -18,9 +18,6 @@ const expectations = [
id: 'checkout',
name: 'checkout',
autocomplete: 'on',
nodeLabel:
'Name on card: \nCredit card number: \nExpiry Date: \nMM\n01\n02\n03\n04\n05\n06\n07\n08\n09…',
snippet: '<form id="checkout" name="checkout" action="../done.html" method="post">',
},
inputs: [
{
@ -32,10 +29,11 @@ const expectations = [
attribute: 'sectio-red shipping cc-namez',
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'textarea',
snippet:
node: {
nodeLabel: 'textarea',
snippet:
'<textarea type="text" id="name_cc1" name="name_cc1" autocomplete="sectio-red shipping cc-namez" placeholder="John Doe">',
},
}},
{
id: 'CCNo1',
name: 'CCNo1',
@ -45,10 +43,11 @@ const expectations = [
attribute: 'cc-number',
prediction: 'HTML_TYPE_CREDIT_CARD_NUMBER',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="CCNo1" name="CCNo1" autocomplete="cc-number" placeholder="5555 5555 5555 5555">',
},
}},
{
id: 'CCExpiresMonth1',
name: 'CCExpiresMonth1',
@ -57,9 +56,10 @@ const expectations = [
attribute: 'cc-exp-month',
prediction: 'HTML_TYPE_CREDIT_CARD_EXP_MONTH',
},
nodeLabel: 'MM\n01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n11\n12',
snippet:
'<select id="CCExpiresMonth1" name="CCExpiresMonth1" autocomplete="cc-exp-month">',
node: {
nodeLabel: 'MM\n01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n11\n12',
snippet:
'<select id="CCExpiresMonth1" name="CCExpiresMonth1" autocomplete="cc-exp-month">'},
},
{
id: 'CCExpiresYear1',
@ -69,10 +69,11 @@ const expectations = [
attribute: 'section-red billing cc-exp-year',
prediction: 'HTML_TYPE_CREDIT_CARD_EXP_YEAR',
},
nodeLabel: 'YY\n2019\n2020\n2021\n2022\n2023\n2024\n2025\n2026\n2027\n2028\n2029',
snippet:
node: {
nodeLabel: 'YY\n2019\n2020\n2021\n2022\n2023\n2024\n2025\n2026\n2027\n2028\n2029',
snippet:
'<select id="CCExpiresYear1" autocomplete="section-red billing cc-exp-year">',
},
}},
{
id: 'cvc1',
name: 'cvc1',
@ -82,32 +83,44 @@ const expectations = [
attribute: 'cc-csc',
prediction: 'HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE',
},
nodeLabel: 'input',
snippet: '<input id="cvc1" name="cvc1" autocomplete="cc-csc" placeholder="555">',
node: {
nodeLabel: 'input',
snippet: '<input id="cvc1" name="cvc1" autocomplete="cc-csc" placeholder="555">'},
},
],
labels: [
{
for: 'name_cc1',
nodeLabel: 'Name on card:',
snippet: '<label for="name_cc1">',
node: {
nodeLabel: 'Name on card:',
snippet: '<label for="name_cc1">'},
},
{
for: 'CCNo1',
nodeLabel: 'Credit card number:',
snippet: '<label for="CCNo1">',
node: {
nodeLabel: 'Credit card number:',
snippet: '<label for="CCNo1">'},
},
{
for: 'CCExpiresMonth1',
nodeLabel: 'Expiry Date:',
snippet: '<label for="CCExpiresMonth1">',
node: {
nodeLabel: 'Expiry Date:',
snippet: '<label for="CCExpiresMonth1">',
},
},
{
for: 'cvc1',
nodeLabel: 'CVC:',
snippet: '<label for="cvc1">',
node: {
nodeLabel: 'CVC:',
snippet: '<label for="cvc1">',
},
},
],
node: {
nodeLabel:
'Name on card: \nCredit card number: \nExpiry Date: \nMM\n01\n02\n03\n04\n05\n06\n07\n08\n09…',
snippet: '<form id="checkout" name="checkout" action="../done.html" method="post">',
},
},
{
inputs: [
@ -120,10 +133,11 @@ const expectations = [
attribute: 'name',
prediction: 'HTML_TYPE_NAME',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="name_shipping" autocomplete="name" placeholder="John Doe">',
},
}},
{
id: 'address_shipping',
name: '',
@ -133,10 +147,11 @@ const expectations = [
attribute: 'shippin street-address',
prediction: 'ADDRESS_HOME_LINE1',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="address_shipping" autocomplete="shippin street-address" placeholder="Your address">',
},
}},
{
id: 'city_shipping',
name: '',
@ -146,10 +161,11 @@ const expectations = [
attribute: 'mobile section-red shipping address-level2',
prediction: 'ADDRESS_HOME_CITY',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="city_shipping" placeholder="city you live" autocomplete="mobile section-red shipping address-level2">',
},
}},
{
id: 'state_shipping',
name: '',
@ -158,8 +174,9 @@ const expectations = [
attribute: null,
prediction: 'ADDRESS_HOME_STATE',
},
nodeLabel: 'Select a state\nCA\nMA\nNY\nMD\nOR\nOH\nIL\nDC',
snippet: '<select id="state_shipping">',
node: {
nodeLabel: 'Select a state\nCA\nMA\nNY\nMD\nOR\nOH\nIL\nDC',
snippet: '<select id="state_shipping">'},
},
{
id: 'zip_shipping',
@ -170,8 +187,9 @@ const expectations = [
attribute: null,
prediction: 'ADDRESS_HOME_ZIP',
},
nodeLabel: 'input',
snippet: '<input type="text" id="zip_shipping">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" id="zip_shipping">'},
},
{
id: 'name_billing',
@ -182,10 +200,11 @@ const expectations = [
attribute: 'sectio-red billing name',
prediction: 'NAME_FULL',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="name_billing" name="name_billing" placeholder="your name" autocomplete="sectio-red billing name">',
},
}},
{
id: 'address_billing',
name: 'address_billing',
@ -195,10 +214,11 @@ const expectations = [
attribute: 'billing street-address',
prediction: 'HTML_TYPE_STREET_ADDRESS',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="address_billing" name="address_billing" autocomplete="billing street-address" placeholder="your address">',
},
}},
{
id: 'city_billing',
name: 'city_billing',
@ -208,10 +228,11 @@ const expectations = [
attribute: 'section-red shipping ',
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="city_billing" name="city_billing" placeholder="city you live in" autocomplete="section-red shipping ">',
},
}},
{
id: 'state_billing',
name: 'state_billing',
@ -220,10 +241,11 @@ const expectations = [
attribute: null,
prediction: 'ADDRESS_HOME_STATE',
},
nodeLabel:
node: {
nodeLabel:
'\n Select a state\n CA\n MA\n NY\n …',
snippet: '<select id="state_billing" name="state_billing">',
},
snippet: '<select id="state_billing" name="state_billing">',
}},
{
id: 'zip_billing',
name: '',
@ -233,9 +255,10 @@ const expectations = [
attribute: null,
prediction: 'ADDRESS_HOME_ZIP',
},
nodeLabel: 'input',
snippet: '<input type="text" id="zip_billing">',
},
node: {
nodeLabel: 'input',
snippet: '<input type="text" id="zip_billing">',
}},
{
id: 'name_cc2',
name: 'name_cc2',
@ -245,10 +268,11 @@ const expectations = [
attribute: 'cc-name',
prediction: 'HTML_TYPE_CREDIT_CARD_NAME_FULL',
},
nodeLabel: 'textarea',
snippet:
node: {
nodeLabel: 'textarea',
snippet:
'<textarea type="text" id="name_cc2" name="name_cc2" autocomplete="cc-name">',
},
}},
{
id: 'CCNo2',
name: 'CCNo2',
@ -258,10 +282,11 @@ const expectations = [
attribute: 'section-red cc-number',
prediction: 'HTML_TYPE_CREDIT_CARD_NUMBER',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" id="CCNo2" name="CCNo2" autocomplete="section-red cc-number">',
},
}},
{
id: 'CCExpiresMonth2',
name: 'CCExpiresMonth2',
@ -270,9 +295,10 @@ const expectations = [
attribute: null,
prediction: 'CREDIT_CARD_EXP_MONTH',
},
nodeLabel: 'MM\n01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n11\n12',
snippet: '<select id="CCExpiresMonth2" name="CCExpiresMonth2">',
},
node: {
nodeLabel: 'MM\n01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n11\n12',
snippet: '<select id="CCExpiresMonth2" name="CCExpiresMonth2">',
}},
{
id: 'CCExpiresYear',
name: '',
@ -281,8 +307,9 @@ const expectations = [
attribute: null,
prediction: 'CREDIT_CARD_EXP_4_DIGIT_YEAR',
},
nodeLabel: 'YY\n2019\n2020\n2021\n2022\n2023\n2024\n2025\n2026\n2027\n2028\n2029',
snippet: '<select id="CCExpiresYear">',
node: {
nodeLabel: 'YY\n2019\n2020\n2021\n2022\n2023\n2024\n2025\n2026\n2027\n2028\n2029',
snippet: '<select id="CCExpiresYear">'},
},
{
id: 'cvc2',
@ -293,9 +320,10 @@ const expectations = [
attribute: 'cc-csc',
prediction: 'HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE',
},
nodeLabel: 'input',
snippet: '<input id="cvc2" name="cvc2" autocomplete="cc-csc">',
},
node: {
nodeLabel: 'input',
snippet: '<input id="cvc2" name="cvc2" autocomplete="cc-csc">',
}},
{
id: 'mobile-number',
name: 'mobile-number',
@ -305,10 +333,11 @@ const expectations = [
attribute: 'section-red shipping mobile tel',
prediction: 'HTML_TYPE_TEL',
},
nodeLabel: 'input',
snippet:
node: {
nodeLabel: 'input',
snippet:
'<input type="text" name="mobile-number" id="mobile-number" autocomplete="section-red shipping mobile tel">',
},
}},
{
id: 'random',
name: 'random',
@ -318,90 +347,107 @@ const expectations = [
attribute: null,
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'input',
snippet: '<input type="text" name="random" id="random">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="random" id="random">'},
},
],
labels: [
{
for: 'name_shipping',
nodeLabel: 'Name:',
snippet: '<label for="name_shipping">',
node: {
nodeLabel: 'Name:',
snippet: '<label for="name_shipping">'},
},
{
for: 'address_shipping',
nodeLabel: 'Address:',
snippet: '<label for="address_shipping">',
node: {
nodeLabel: 'Address:',
snippet: '<label for="address_shipping">'},
},
{
for: 'city_shipping',
nodeLabel: 'City:',
snippet: '<label for="city_shipping">',
node: {
nodeLabel: 'City:',
snippet: '<label for="city_shipping">'},
},
{
for: 'Sstate_shipping',
nodeLabel: 'State:',
snippet: '<label for="Sstate_shipping">',
node: {
nodeLabel: 'State:',
snippet: '<label for="Sstate_shipping">'},
},
{
for: 'zip_shipping',
nodeLabel: 'Zip:',
snippet: '<label for="zip_shipping">',
node: {
nodeLabel: 'Zip:',
snippet: '<label for="zip_shipping">'},
},
{
for: 'name_billing',
nodeLabel: 'Name:',
snippet: '<label for="name_billing">',
node: {
nodeLabel: 'Name:',
snippet: '<label for="name_billing">'},
},
{
for: 'address_billing',
nodeLabel: 'Address:',
snippet: '<label for="address_billing">',
node: {
nodeLabel: 'Address:',
snippet: '<label for="address_billing">'},
},
{
for: 'city_billing',
nodeLabel: 'City:',
snippet: '<label for="city_billing">',
node: {
nodeLabel: 'City:',
snippet: '<label for="city_billing">'},
},
{
for: 'state_billing',
nodeLabel: 'State:',
snippet: '<label for="state_billing">',
node: {
nodeLabel: 'State:',
snippet: '<label for="state_billing">'},
},
{
for: 'zip_billing',
nodeLabel: 'Zip:',
snippet: '<label for="zip_billing">',
node: {
nodeLabel: 'Zip:',
snippet: '<label for="zip_billing">'},
},
{
for: 'name_cc2',
nodeLabel: 'Name on card:',
snippet: '<label for="name_cc2">',
node: {
nodeLabel: 'Name on card:',
snippet: '<label for="name_cc2">'},
},
{
for: 'CCNo2',
nodeLabel: 'Credit card number:',
snippet: '<label for="CCNo2">',
node: {
nodeLabel: 'Credit card number:',
snippet: '<label for="CCNo2">'},
},
{
for: 'CCExpiresMonth2',
nodeLabel: 'Expiry Date:',
snippet: '<label for="CCExpiresMonth2">',
node: {
nodeLabel: 'Expiry Date:',
snippet: '<label for="CCExpiresMonth2">'},
},
{
for: 'cvc2',
nodeLabel: 'CVC:',
snippet: '<label for="cvc2">',
node: {
nodeLabel: 'CVC:',
snippet: '<label for="cvc2">'},
},
{
for: 'mobile-number',
nodeLabel: 'Mobile phone Number:',
snippet: '<label for="mobile-number">',
node: {
nodeLabel: 'Mobile phone Number:',
snippet: '<label for="mobile-number">'},
},
{
for: 'random',
nodeLabel: 'Random Page Input:',
snippet: '<label for="random">',
node: {
nodeLabel: 'Random Page Input:',
snippet: '<label for="random">'},
},
],
},

Просмотреть файл

@ -172,43 +172,49 @@ module.exports = [
TraceElements: [
{
traceEventType: 'largest-contentful-paint',
nodeLabel: 'img',
snippet: '<img src="../dobetterweb/lighthouse-480x318.jpg">',
boundingRect: {
top: 108,
bottom: 426,
left: 8,
right: 488,
width: 480,
height: 318,
node: {
nodeLabel: 'img',
snippet: '<img src="../dobetterweb/lighthouse-480x318.jpg">',
boundingRect: {
top: 108,
bottom: 426,
left: 8,
right: 488,
width: 480,
height: 318,
},
},
},
{
traceEventType: 'layout-shift',
selector: 'body > h1',
nodeLabel: 'Please don\'t move me',
snippet: '<h1>',
boundingRect: {
top: 465,
bottom: 502,
left: 8,
right: 352,
width: 344,
height: 37,
node: {
selector: 'body > h1',
nodeLabel: 'Please don\'t move me',
snippet: '<h1>',
boundingRect: {
top: 465,
bottom: 502,
left: 8,
right: 352,
width: 344,
height: 37,
},
},
score: '0.058 +/- 0.01',
},
{
traceEventType: 'layout-shift',
nodeLabel: 'Sorry!',
snippet: '<div style="height: 18px;">',
boundingRect: {
top: 426,
bottom: 444,
left: 8,
right: 352,
width: 344,
height: 18,
node: {
nodeLabel: 'Sorry!',
snippet: '<div style="height: 18px;">',
boundingRect: {
top: 426,
bottom: 444,
left: 8,
right: 352,
width: 344,
height: 18,
},
},
score: '0.026 +/- 0.01',
},
@ -218,16 +224,18 @@ module.exports = [
// https://chromiumdash.appspot.com/commit/995baabedf9e70d16deafc4bc37a2b215a9b8ec9
_minChromiumMilestone: 86,
traceEventType: 'animation',
selector: 'body > div#animate-me',
nodeLabel: 'div',
snippet: '<div id="animate-me">',
boundingRect: {
top: 8,
bottom: 108,
left: 8,
right: 108,
width: 100,
height: 100,
node: {
selector: 'body > div#animate-me',
nodeLabel: 'div',
snippet: '<div id="animate-me">',
boundingRect: {
top: 8,
bottom: 108,
left: 8,
right: 108,
width: 100,
height: 100,
},
},
animations: [
{

Просмотреть файл

@ -18,62 +18,98 @@ function headersParam(headers) {
const expectedGatheredTapTargets = [
{
snippet: /large-link-at-bottom-of-page/,
node: {
snippet: /large-link-at-bottom-of-page/,
},
},
{
snippet: /visible-target/,
node: {
snippet: /visible-target/,
},
},
{
snippet: /target-with-client-rect-outside-scroll-container/,
node: {
snippet: /target-with-client-rect-outside-scroll-container/,
},
},
{
snippet: /link-containing-large-inline-block-element/,
node: {
snippet: /link-containing-large-inline-block-element/,
},
},
{
snippet: /link-next-to-link-containing-large-inline-block-element/,
node: {
snippet: /link-next-to-link-containing-large-inline-block-element/,
},
},
{
snippet: /tap-target-containing-other-tap-targets/,
node: {
snippet: /tap-target-containing-other-tap-targets/,
},
},
{
snippet: /child-client-rect-hidden-by-overflow-hidden/,
node: {
snippet: /child-client-rect-hidden-by-overflow-hidden/,
},
},
{
snippet: /tap-target-next-to-child-client-rect-hidden-by-overflow-hidden/,
node: {
snippet: /tap-target-next-to-child-client-rect-hidden-by-overflow-hidden/,
},
},
{
snippet: /child-client-rect-overlapping-other-target/,
node: {
snippet: /child-client-rect-overlapping-other-target/,
},
shouldFail: true,
},
{
snippet: /tap-target-overlapped-by-other-targets-position-absolute-child-rect/,
node: {
snippet: /tap-target-overlapped-by-other-targets-position-absolute-child-rect/,
},
shouldFail: true,
},
{
snippet: /position-absolute-tap-target-fully-contained-in-other-target/,
node: {
snippet: /position-absolute-tap-target-fully-contained-in-other-target/,
},
},
{
snippet: /tap-target-fully-containing-position-absolute-target/,
node: {
snippet: /tap-target-fully-containing-position-absolute-target/,
},
},
{
snippet: /too-small-failing-tap-target/,
node: {
snippet: /too-small-failing-tap-target/,
},
shouldFail: true,
},
{
snippet: /large-enough-tap-target-next-to-too-small-tap-target/,
node: {
snippet: /large-enough-tap-target-next-to-too-small-tap-target/,
},
},
{
snippet: /zero-width-tap-target-with-overflowing-child-content/,
node: {
snippet: /zero-width-tap-target-with-overflowing-child-content/,
},
shouldFail: true,
},
{
snippet: /passing-tap-target-next-to-zero-width-target/,
node: {
snippet: /passing-tap-target-next-to-zero-width-target/,
},
},
{
snippet: /links-with-same-link-target-1/,
node: {
snippet: /links-with-same-link-target-1/,
},
},
{
snippet: /links-with-same-link-target-2/,
node: {
snippet: /links-with-same-link-target-2/,
},
},
];
@ -423,7 +459,7 @@ const expectations = [
},
},
artifacts: {
TapTargets: expectedGatheredTapTargets.map(({snippet}) => ({snippet})),
TapTargets: expectedGatheredTapTargets.map(({node}) => ({node})),
},
},
];

Просмотреть файл

@ -74,16 +74,16 @@ class AxeAudit extends Audit {
/** @type {LH.Audit.Details.Table['items']}>} */
let items = [];
if (rule && rule.nodes) {
items = rule.nodes.map(node => ({
items = rule.nodes.map(axeNode => ({
node: {
type: /** @type {'node'} */ ('node'),
lhId: node.lhId,
selector: node.selector,
path: node.devtoolsNodePath,
snippet: node.snippet,
boundingRect: node.boundingRect,
explanation: node.failureSummary,
nodeLabel: node.nodeLabel,
lhId: axeNode.node.lhId,
selector: axeNode.node.selector,
path: axeNode.node.devtoolsNodePath,
snippet: axeNode.node.snippet,
boundingRect: axeNode.node.boundingRect,
explanation: axeNode.failureSummary,
nodeLabel: axeNode.node.nodeLabel,
},
}));
}

Просмотреть файл

@ -245,11 +245,11 @@ class AutocompleteAudit extends Audit {
// Warning is created because while there is an autocomplete attribute, the autocomplete property does not exsist, thus the attribute's value is invalid.
if (input.autocomplete.attribute) {
warnings.push(str_(UIStrings.warningInvalid, {token: input.autocomplete.attribute,
snippet: input.snippet}));
snippet: input.node.snippet}));
}
if (validity.isValidOrder === false) {
warnings.push(str_(UIStrings.warningOrder, {tokens: input.autocomplete.attribute,
snippet: input.snippet}));
snippet: input.node.snippet}));
suggestion = UIStrings.reviewOrder;
}
// If the autofill prediction is not in our autofill suggestion mapping, then we warn
@ -262,8 +262,8 @@ class AutocompleteAudit extends Audit {
failingFormsData.push({
node: {
type: /** @type {'node'} */ ('node'),
snippet: input.snippet,
nodeLabel: input.nodeLabel,
snippet: input.node.snippet,
nodeLabel: input.node.nodeLabel,
},
suggestion: suggestion,
current: input.autocomplete.attribute,

Просмотреть файл

@ -60,7 +60,7 @@ class ExternalAnchorsUseRelNoopenerAudit extends Audit {
try {
return new URL(anchor.href).host !== pageHost;
} catch (err) {
warnings.push(str_(UIStrings.warning, {anchorHTML: anchor.snippet}));
warnings.push(str_(UIStrings.warning, {anchorHTML: anchor.node.snippet}));
return true;
}
})
@ -71,15 +71,15 @@ class ExternalAnchorsUseRelNoopenerAudit extends Audit {
return {
node: {
type: /** @type {'node'} */ ('node'),
path: anchor.devtoolsNodePath || '',
selector: anchor.selector || '',
nodeLabel: anchor.nodeLabel || '',
snippet: anchor.snippet || '',
path: anchor.node.devtoolsNodePath || '',
selector: anchor.node.selector || '',
nodeLabel: anchor.node.nodeLabel || '',
snippet: anchor.node.snippet || '',
},
href: anchor.href || 'Unknown',
target: anchor.target || '',
rel: anchor.rel || '',
outerHTML: anchor.snippet || '',
outerHTML: anchor.node.snippet || '',
};
});

Просмотреть файл

@ -47,8 +47,8 @@ class PasswordInputsCanBePastedIntoAudit extends Audit {
items.push({
node: {
type: /** @type {'node'} */ ('node'),
snippet: input.snippet,
path: input.devtoolsNodePath,
snippet: input.node.snippet,
path: input.node.devtoolsNodePath,
},
});
});

Просмотреть файл

@ -44,12 +44,12 @@ class LargestContentfulPaintElement extends Audit {
lcpElementDetails.push({
node: {
type: /** @type {'node'} */ ('node'),
lhId: lcpElement.lhId,
path: lcpElement.devtoolsNodePath,
selector: lcpElement.selector,
nodeLabel: lcpElement.nodeLabel,
snippet: lcpElement.snippet,
boundingRect: lcpElement.boundingRect,
lhId: lcpElement.node.lhId,
path: lcpElement.node.devtoolsNodePath,
selector: lcpElement.node.selector,
nodeLabel: lcpElement.node.nodeLabel,
snippet: lcpElement.node.snippet,
boundingRect: lcpElement.node.boundingRect,
},
});
}

Просмотреть файл

@ -45,12 +45,12 @@ class LayoutShiftElements extends Audit {
return {
node: {
type: /** @type {'node'} */ ('node'),
lhId: element.lhId,
path: element.devtoolsNodePath,
selector: element.selector,
nodeLabel: element.nodeLabel,
snippet: element.snippet,
boundingRect: element.boundingRect,
lhId: element.node.lhId,
path: element.node.devtoolsNodePath,
selector: element.node.selector,
nodeLabel: element.node.nodeLabel,
snippet: element.node.snippet,
boundingRect: element.node.boundingRect,
},
score: element.score,
};

Просмотреть файл

@ -137,10 +137,10 @@ class NonCompositedAnimations extends Audit {
/** @type LH.Audit.Details.NodeValue */
const node = {
type: 'node',
path: element.devtoolsNodePath,
selector: element.selector,
nodeLabel: element.nodeLabel,
snippet: element.snippet,
path: element.node.devtoolsNodePath,
selector: element.node.selector,
nodeLabel: element.node.nodeLabel,
snippet: element.node.snippet,
};
const animations = element.animations || [];

Просмотреть файл

@ -90,7 +90,7 @@ class PreloadLCPImageAudit extends Audit {
if (!lcpElement) return undefined;
const lcpImageElement = imageElements.find(elem => {
return elem.devtoolsNodePath === lcpElement.devtoolsNodePath;
return elem.node.devtoolsNodePath === lcpElement.node.devtoolsNodePath;
});
if (!lcpImageElement) return undefined;

Просмотреть файл

@ -83,10 +83,10 @@ class CrawlableAnchors extends Audit {
return {
node: {
type: 'node',
path: anchor.devtoolsNodePath || '',
selector: anchor.selector || '',
nodeLabel: anchor.nodeLabel || '',
snippet: anchor.snippet || '',
path: anchor.node.devtoolsNodePath || '',
selector: anchor.node.selector || '',
nodeLabel: anchor.node.nodeLabel || '',
snippet: anchor.node.snippet || '',
},
};
});

Просмотреть файл

@ -121,9 +121,9 @@ class Hreflang extends Audit {
source = {
type: 'node',
snippet: `<link rel="alternate" hreflang="${link.hreflang}" href="${link.hrefRaw}" />`,
path: link.devtoolsNodePath || '',
selector: link.selector || '',
nodeLabel: link.nodeLabel || '',
path: link.node !== null ? link.node.devtoolsNodePath : '',
selector: link.node !== null ? link.node.selector : '',
nodeLabel: link.node !== null ? link.node.nodeLabel : '',
};
} else if (link.source === 'headers') {
source = `Link: <${link.hrefRaw}>; rel="alternate"; hreflang="${link.hreflang}"`;

Просмотреть файл

@ -249,12 +249,12 @@ function targetToTableNode(target) {
return {
type: 'node',
lhId: target.lhId,
snippet: target.snippet,
path: target.devtoolsNodePath,
selector: target.selector,
lhId: target.node.lhId,
snippet: target.node.snippet,
path: target.node.devtoolsNodePath,
selector: target.node.selector,
boundingRect,
nodeLabel: target.nodeLabel,
nodeLabel: target.node.nodeLabel,
};
}

Просмотреть файл

@ -100,10 +100,10 @@ class UnsizedImages extends Audit {
url,
node: {
type: /** @type {'node'} */ ('node'),
path: image.devtoolsNodePath,
selector: image.selector,
nodeLabel: image.nodeLabel,
snippet: image.snippet,
path: image.node.devtoolsNodePath,
selector: image.node.selector,
nodeLabel: image.node.nodeLabel,
snippet: image.node.snippet,
},
});
}

Просмотреть файл

@ -61,7 +61,7 @@ function runA11yChecks() {
// @ts-expect-error
result.nodes.forEach(node => {
// @ts-expect-error - getNodeDetails put into scope via stringification
Object.assign(node, getNodeDetails(node.element));
node.node = getNodeDetails(node.element);
// avoid circular JSON concerns
node.element = node.any = node.all = node.none = undefined;
});

Просмотреть файл

@ -43,8 +43,6 @@ function collectAnchorElements() {
const anchorElements = getElementsInDocument('a'); // eslint-disable-line no-undef
return anchorElements.map(node => {
// @ts-expect-error - getNodeDetails put into scope via stringification
const nodeInfo = getNodeDetails(node);
if (node instanceof HTMLAnchorElement) {
return {
href: node.href,
@ -55,7 +53,8 @@ function collectAnchorElements() {
text: node.innerText, // we don't want to return hidden text, so use innerText
rel: node.rel,
target: node.target,
...nodeInfo,
// @ts-expect-error - getNodeDetails put into scope via stringification
node: getNodeDetails(node),
};
}
@ -67,7 +66,8 @@ function collectAnchorElements() {
text: node.textContent || '',
rel: '',
target: node.target.baseVal || '',
...nodeInfo,
// @ts-expect-error - getNodeDetails put into scope via stringification
node: getNodeDetails(node),
};
});
}
@ -109,7 +109,7 @@ class AnchorElements extends Gatherer {
// DOM.getDocument is necessary for pushNodesByBackendIdsToFrontend to properly retrieve nodeIds if the `DOM` domain was enabled before this gatherer, invoke it to be safe.
await driver.sendCommand('DOM.getDocument', {depth: -1, pierce: true});
const anchorsWithEventListeners = anchors.map(async anchor => {
const listeners = await getEventListeners(driver, anchor.devtoolsNodePath);
const listeners = await getEventListeners(driver, anchor.node.devtoolsNodePath);
return {
...anchor,

Просмотреть файл

@ -22,10 +22,10 @@ function findPasswordInputsWithPreventedPaste() {
new ClipboardEvent('paste', {cancelable: true})
)
)
.map(passwordInput => (
.map(passwordInput => ({
// @ts-expect-error - getNodeDetails put into scope via stringification
getNodeDetails(passwordInput)
));
node: getNodeDetails(passwordInput),
}));
}
class PasswordInputsWithPreventedPaste extends Gatherer {

Просмотреть файл

@ -23,6 +23,7 @@ function collectFormElements() {
const forms = new Map();
/** @type {LH.Artifacts.Form} */
const formlessObj = {
node: null,
inputs: [],
labels: [],
};
@ -39,16 +40,15 @@ function collectFormElements() {
id: parentFormElement.id,
name: parentFormElement.name,
autocomplete: parentFormElement.autocomplete,
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(parentFormElement),
},
// @ts-expect-error - getNodeDetails put into scope via stringification
node: getNodeDetails(parentFormElement),
inputs: [],
labels: [],
};
forms.set(parentFormElement, newFormObj);
}
const formObj = forms.get(parentFormElement) || formlessObj;
if (child instanceof HTMLInputElement || child instanceof HTMLTextAreaElement
|| child instanceof HTMLSelectElement) {
formObj.inputs.push({
@ -61,20 +61,21 @@ function collectFormElements() {
prediction: child.getAttribute('autofill-prediction'),
},
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(child),
node: getNodeDetails(child),
});
}
if (child instanceof HTMLLabelElement) {
formObj.labels.push({
for: child.htmlFor,
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(child),
node: getNodeDetails(child),
});
}
}
if (formlessObj.inputs.length > 0 || formlessObj.labels.length > 0) {
forms.set('formless', {
node: formlessObj.node,
inputs: formlessObj.inputs,
labels: formlessObj.labels,
});

Просмотреть файл

@ -29,7 +29,7 @@ function collectIFrameElements() {
// @ts-expect-error - put into scope via stringification
isPositionFixed: isPositionFixed(node), // eslint-disable-line no-undef
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(node),
node: getNodeDetails(node),
};
});
}

Просмотреть файл

@ -86,7 +86,7 @@ function getHTMLImages(allElements) {
// https://html.spec.whatwg.org/multipage/images.html#pixel-density-descriptor
usesSrcSetDensityDescriptor: / \d+(\.\d+)?x/.test(element.srcset),
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(element),
node: getNodeDetails(element),
};
});
}
@ -136,7 +136,7 @@ function getCSSImages(allElements) {
),
usesSrcSetDensityDescriptor: false,
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(element),
node: getNodeDetails(element),
});
}
@ -331,7 +331,7 @@ class ImageElements extends Gatherer {
element.mimeType = networkRecord.mimeType;
if (!element.isInShadowDOM && !element.isCss) {
await this.fetchSourceRules(driver, element.devtoolsNodePath, element);
await this.fetchSourceRules(driver, element.node.devtoolsNodePath, element);
}
// Images within `picture` behave strangely and natural size information isn't accurate,
// CSS images have no natural size information at all. Try to get the actual size if we can.

Просмотреть файл

@ -71,7 +71,7 @@ function getLinkElementsInDOM() {
hrefRaw,
source,
// @ts-expect-error - put into scope via stringification
...getNodeDetails(link),
node: getNodeDetails(link),
});
}
@ -121,10 +121,7 @@ class LinkElements extends Gatherer {
as: link.as || '',
crossOrigin: getCrossoriginFromHeader(link.crossorigin),
source: 'headers',
devtoolsNodePath: '',
selector: '',
nodeLabel: '',
snippet: '',
node: null,
});
}
}

Просмотреть файл

@ -29,10 +29,10 @@ function collectAllScriptElements() {
async: script.async,
defer: script.defer,
source: script.closest('head') ? 'head' : 'body',
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(script),
content: script.src ? null : script.text,
requestId: null,
// @ts-expect-error - getNodeDetails put into scope via stringification
node: getNodeDetails(script),
};
});
}
@ -108,10 +108,6 @@ class ScriptElements extends Gatherer {
matchedScriptElement.content = content;
} else {
scripts.push({
devtoolsNodePath: '',
snippet: '',
selector: '',
nodeLabel: '',
type: null,
src: record.url,
id: null,
@ -120,10 +116,10 @@ class ScriptElements extends Gatherer {
source: 'network',
requestId: record.requestId,
content,
node: null,
});
}
}
return scripts;
}
}

Просмотреть файл

@ -270,7 +270,7 @@ function gatherTapTargets(tapTargetsSelector) {
clientRects: visibleClientRects,
href: /** @type {HTMLAnchorElement} */(tapTargetElement)['href'] || '',
// @ts-expect-error - getNodeDetails put into scope via stringification
...getNodeDetails(tapTargetElement),
node: getNodeDetails(tapTargetElement),
});
}

Просмотреть файл

@ -30,7 +30,7 @@ function getNodeDetailsData() {
let traceElement;
if (elem) {
// @ts-expect-error - getNodeDetails put into scope via stringification
traceElement = getNodeDetails(elem);
traceElement = {node: getNodeDetails(elem)};
}
return traceElement;
}

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-allowed-attr audit', () => {
Accessibility: {
violations: [{
id: 'aria-allowed-attr',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-required-attr audit', () => {
Accessibility: {
violations: [{
id: 'aria-required-attr',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-required-children audit', () => {
Accessibility: {
violations: [{
id: 'aria-required-children',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-required-parent audit', () => {
Accessibility: {
violations: [{
id: 'aria-required-parent',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-roles audit', () => {
Accessibility: {
violations: [{
id: 'aria-roles',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-valid-attr audit', () => {
Accessibility: {
violations: [{
id: 'aria-valid-attr',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: aria-valid-attr-value audit', () => {
Accessibility: {
violations: [{
id: 'aria-valid-attr-value',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -26,7 +26,7 @@ describe('Accessibility: axe-audit', () => {
Accessibility: {
violations: [{
id: 'fake-aria-fail',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},
@ -128,13 +128,19 @@ describe('Accessibility: axe-audit', () => {
Accessibility: {
incomplete: [{
id: 'fake-axe-failure-case',
nodes: [{html: '<input id="multi-label-form-element" />'}],
nodes: [{
html: '<input id="multi-label-form-element" />',
node: {},
}],
help: 'http://example.com/',
}],
// TODO: remove: axe-core v3.3.0 backwards-compatibility test
violations: [{
id: 'fake-axe-failure-case',
nodes: [{html: '<input id="multi-label-form-element" />'}],
nodes: [{
html: '<input id="multi-label-form-element" />',
node: {},
}],
help: 'http://example.com/',
}],
},
@ -186,7 +192,12 @@ describe('Accessibility: axe-audit', () => {
violations: [
{
id: 'fake-axe-snippet-case',
nodes: [{html: '<input id="axes-source" />', snippet: '<input id="snippet"/>'}],
nodes: [{
html: '<input id="axes-source" />',
node: {
snippet: '<input id="snippet"/>',
},
}],
help: 'http://example.com/',
},
],

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: button-name audit', () => {
Accessibility: {
violations: [{
id: 'button-name',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: bypass audit', () => {
Accessibility: {
violations: [{
id: 'bypass',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: color-contrast audit', () => {
Accessibility: {
violations: [{
id: 'color-contrast',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: definition-list audit', () => {
Accessibility: {
violations: [{
id: 'definition-list',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: dlitem audit', () => {
Accessibility: {
violations: [{
id: 'dlitem',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: document-title audit', () => {
Accessibility: {
violations: [{
id: 'document-title',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: frame-title audit', () => {
Accessibility: {
violations: [{
id: 'frame-title',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: html-has-lang audit', () => {
Accessibility: {
violations: [{
id: 'html-has-lang',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: html-lang-valid audit', () => {
Accessibility: {
violations: [{
id: 'html-lang-valid',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: image-alt audit', () => {
Accessibility: {
violations: [{
id: 'image-alt',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: input-image-alt audit', () => {
Accessibility: {
violations: [{
id: 'input-image-alt',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: label audit', () => {
Accessibility: {
violations: [{
id: 'label',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: layout-table audit', () => {
Accessibility: {
violations: [{
id: 'layout-table',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: link-name audit', () => {
Accessibility: {
violations: [{
id: 'link-name',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: list audit', () => {
Accessibility: {
violations: [{
id: 'list',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: listitem audit', () => {
Accessibility: {
violations: [{
id: 'listitem',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: meta-refresh audit', () => {
Accessibility: {
violations: [{
id: 'meta-refresh',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: meta-viewport audit', () => {
Accessibility: {
violations: [{
id: 'meta-viewport',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: object-alt audit', () => {
Accessibility: {
violations: [{
id: 'object-alt',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: tabindex audit', () => {
Accessibility: {
violations: [{
id: 'tabindex',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: td-headers-attr audit', () => {
Accessibility: {
violations: [{
id: 'td-headers-attr',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: th-has-data-cells audit', () => {
Accessibility: {
violations: [{
id: 'th-has-data-cells',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: valid-lang audit', () => {
Accessibility: {
violations: [{
id: 'valid-lang',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: video-caption audit', () => {
Accessibility: {
violations: [{
id: 'video-caption',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -31,7 +31,7 @@ describe('Accessibility: video-description audit', () => {
Accessibility: {
violations: [{
id: 'video-description',
nodes: [{}],
nodes: [],
help: 'http://example.com/',
}],
},

Просмотреть файл

@ -25,8 +25,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: null,
prediction: 'HTML_TYPE_CREDIT_CARD_NAME_FULL',
},
nodeLabel: 'input',
snippet: '<input type="text" name="name_cc">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="name_cc">'},
},
{
id: '',
@ -37,8 +38,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: null,
prediction: 'HTML_TYPE_CREDIT_CARD_NUMBER',
},
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo">'},
},
],
labels: [],
@ -84,8 +86,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'namez',
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'input',
snippet: '<input type="text" name="name_cc" autocomplete="namez">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="name_cc" autocomplete="namez">'},
},
{
id: '',
@ -96,8 +99,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'ccc-num',
prediction: 'HTML_TYPE_CREDIT_CARD_NUMBER',
},
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo" autocomplete="ccc-num">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo" autocomplete="ccc-num">'},
},
],
labels: [],
@ -142,9 +146,10 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'section-red shipping cc-name',
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc" autocomplete="section-red shipping cc-name">',
node: {
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc" autocomplete="section-red shipping cc-name">'},
},
{
id: '',
@ -167,9 +172,10 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'section-red shipping mobile tel',
prediction: 'HTML_TYPE_TEL',
},
nodeLabel: 'input',
// eslint-disable-next-line max-len
snippet: '<input name="mobile-number" autocomplete="section-red shipping mobile tel">',
node: {
nodeLabel: 'input',
// eslint-disable-next-line max-len
snippet: '<input name="mobile-number" autocomplete="section-red shipping mobile tel">'},
},
],
labels: [],
@ -194,8 +200,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: null,
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'textarea',
snippet: '<textarea type="text" name="edge_case">',
node: {
nodeLabel: 'textarea',
snippet: '<textarea type="text" name="edge_case">'},
},
{
id: '',
@ -206,8 +213,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: null,
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'input',
snippet: '<input type="text" name="random">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="random">'},
},
],
labels: [],
@ -233,8 +241,10 @@ describe('Best Practices: autocomplete audit', () => {
prediction: 'HTML_TYPE_CREDIT_CARD_NAME_FULL',
},
autofillPredict: 'HTML_TYPE_CREDIT_CARD_NAME_FULL',
nodeLabel: 'textarea',
snippet: '<textarea type="text" name="name_cc2" autocomplete="sectio-red cc-name">',
node: {
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc2" autocomplete="sectio-red cc-name">'},
},
{
id: '',
@ -245,8 +255,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'shippin name',
prediction: 'NAME_FULL',
},
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo2" autocomplete="shippin name">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo2" autocomplete="shippin name">'},
},
],
labels: [],
@ -271,9 +282,10 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'shipping section-red cc-name',
prediction: 'HTML_TYPE_CREDIT_CARD_NAME_FULL',
},
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc2" autocomplete="shipping section-red cc-name">',
node: {
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc2" autocomplete="shipping section-red cc-name">'},
},
{
id: '',
@ -284,9 +296,10 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'shipping section-red mobile tel',
prediction: 'HTML_TYPE_TEL',
},
nodeLabel: 'input',
// eslint-disable-next-line max-len
snippet: '<input type="text" name="CCNo2" autocomplete="shipping section-red mobile tel">',
node: {
nodeLabel: 'input',
// eslint-disable-next-line max-len
snippet: '<input type="text" name="CCNo2" autocomplete="shipping section-red mobile tel">'},
},
],
labels: [],
@ -334,8 +347,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'namez',
prediction: 'UNKNOWN_TYPE',
},
nodeLabel: 'input',
snippet: '<input type="text" name="name_cc" autocomplete="namez">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="name_cc" autocomplete="namez">'},
},
{
id: '',
@ -346,8 +360,9 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'ccc-num',
prediction: 'HTML_TYPE_CREDIT_CARD_NUMBER',
},
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo" autocomplete="ccc-num">',
node: {
nodeLabel: 'input',
snippet: '<input type="text" name="CCNo" autocomplete="ccc-num">'},
},
],
labels: [],
@ -378,9 +393,10 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'shipping section-red cc-name',
prediction: 'HTML_TYPE_CREDIT_CARD_NAME_FULL',
},
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc2" autocomplete="shipping section-red cc-name">',
node: {
nodeLabel: 'textarea',
// eslint-disable-next-line max-len
snippet: '<textarea type="text" name="name_cc2" autocomplete="shipping section-red cc-name">'},
},
{
id: '',
@ -391,9 +407,10 @@ describe('Best Practices: autocomplete audit', () => {
attribute: 'shipping section-red mobile tel',
prediction: 'HTML_TYPE_TEL',
},
nodeLabel: 'input',
// eslint-disable-next-line max-len
snippet: '<input type="text" name="CCNo2" autocomplete="shipping section-red mobile tel">',
node: {
nodeLabel: 'input',
// eslint-disable-next-line max-len
snippet: '<input type="text" name="CCNo2" autocomplete="shipping section-red mobile tel">'},
},
],
labels: [],
@ -426,8 +443,9 @@ describe('Autocomplete Audit: Check Attribute Validity', () => {
attribute: '',
prediction: '',
},
nodeLabel: '',
snippet: '',
node: {
nodeLabel: '',
snippet: ''},
};
const output = Autocomplete.checkAttributeValidity(input);
const expectedOutput = {hasValidTokens: false};
@ -444,8 +462,9 @@ describe('Autocomplete Audit: Check Attribute Validity', () => {
attribute: 'section-foo name',
prediction: '',
},
nodeLabel: '',
snippet: '',
node: {
nodeLabel: '',
snippet: ''},
};
const output = Autocomplete.checkAttributeValidity(input);
const expectedOutput = {hasValidTokens: true, isValidOrder: true};
@ -462,8 +481,9 @@ describe('Autocomplete Audit: Check Attribute Validity', () => {
attribute: 'shipping mobile tel',
prediction: '',
},
nodeLabel: '',
snippet: '',
node: {
nodeLabel: '',
snippet: ''},
};
const output = Autocomplete.checkAttributeValidity(input);
const expectedOutput = {hasValidTokens: true, isValidOrder: true};
@ -481,8 +501,9 @@ describe('Autocomplete Audit: Check Attribute Validity', () => {
attribute: 'mobile shipping tel',
prediction: '',
},
nodeLabel: '',
snippet: '',
node: {
nodeLabel: '',
snippet: ''},
};
const output = Autocomplete.checkAttributeValidity(input);
const expectedOutput = {hasValidTokens: true, isValidOrder: false};
@ -499,8 +520,9 @@ describe('Autocomplete Audit: Check Attribute Validity', () => {
attribute: 'invalid-token',
prediction: '',
},
nodeLabel: '',
snippet: '',
node: {
nodeLabel: '',
snippet: ''},
};
const output = Autocomplete.checkAttributeValidity(input);
const expectedOutput = {hasValidTokens: false};

Просмотреть файл

@ -82,13 +82,17 @@ describe('External anchors use rel="noopener"', () => {
href: 'https://example.com/test',
target: '_blank',
rel: 'nofollow',
devtoolsNodePath: 'devtools',
node: {
devtoolsNodePath: 'devtools',
},
},
{
href: 'https://example.com/test1',
target: '_blank',
rel: '',
devtoolsNodePath: 'nodepath',
node: {
devtoolsNodePath: 'nodepath',
},
},
],
URL: {finalUrl: URL},
@ -103,7 +107,7 @@ describe('External anchors use rel="noopener"', () => {
it('fails when links have no href attribute', () => {
const auditResult = ExternalAnchorsAudit.audit({
AnchorElements: [{href: '', target: '_blank', rel: ''}],
AnchorElements: [{href: '', target: '_blank', rel: '', node: {}}],
URL: {finalUrl: URL},
});
assert.equal(auditResult.score, 0);
@ -112,12 +116,13 @@ describe('External anchors use rel="noopener"', () => {
});
it('fails when links have href attribute starting with a protocol', () => {
const node = {};
const auditResult = ExternalAnchorsAudit.audit({
AnchorElements: [
{href: 'http://', target: '_blank', rel: ''},
{href: 'http:', target: '_blank', rel: ''},
{href: 'https://', target: '_blank', rel: ''},
{href: 'https:', target: '_blank', rel: ''},
{href: 'http://', target: '_blank', rel: '', node},
{href: 'http:', target: '_blank', rel: '', node},
{href: 'https://', target: '_blank', rel: '', node},
{href: 'https:', target: '_blank', rel: '', node},
],
URL: {finalUrl: URL},
});

Просмотреть файл

@ -22,7 +22,7 @@ describe('Password inputs can be pasted into', () => {
it('fails when there are password inputs preventing paste', () => {
const auditResult = PasswordInputsCanBePastedIntoAudit.audit({
PasswordInputsWithPreventedPaste: [{snippet: ''}, {snippet: ''}],
PasswordInputsWithPreventedPaste: [{node: {snippet: ''}}, {node: {snippet: ''}}],
});
assert.equal(auditResult.score, 0);
assert.equal(auditResult.details.items.length, 2);

Просмотреть файл

@ -14,10 +14,12 @@ describe('Performance: largest-contentful-paint-element audit', () => {
const artifacts = {
TraceElements: [{
traceEventType: 'largest-contentful-paint',
devtoolsNodePath: '1,HTML,3,BODY,5,DIV,0,HEADER',
selector: 'div.l-header > div.chorus-emc__content',
nodeLabel: 'My Test Label',
snippet: '<h1 class="test-class">',
node: {
devtoolsNodePath: '1,HTML,3,BODY,5,DIV,0,HEADER',
selector: 'div.l-header > div.chorus-emc__content',
nodeLabel: 'My Test Label',
snippet: '<h1 class="test-class">',
},
}],
};

Просмотреть файл

@ -15,10 +15,12 @@ describe('Performance: layout-shift-elements audit', () => {
const artifacts = {
TraceElements: [{
traceEventType: 'layout-shift',
devtoolsNodePath: '1,HTML,3,BODY,5,DIV,0,HEADER',
selector: 'div.l-header > div.chorus-emc__content',
nodeLabel: 'My Test Label',
snippet: '<h1 class="test-class">',
node: {
devtoolsNodePath: '1,HTML,3,BODY,5,DIV,0,HEADER',
selector: 'div.l-header > div.chorus-emc__content',
nodeLabel: 'My Test Label',
snippet: '<h1 class="test-class">',
},
score: 0.3,
}],
};
@ -35,10 +37,12 @@ describe('Performance: layout-shift-elements audit', () => {
it('correctly surfaces multiple CLS elements', async () => {
const clsElement = {
traceEventType: 'layout-shift',
devtoolsNodePath: '1,HTML,3,BODY,5,DIV,0,HEADER',
selector: 'div.l-header > div.chorus-emc__content',
nodeLabel: 'My Test Label',
snippet: '<h1 class="test-class">',
node: {
devtoolsNodePath: '1,HTML,3,BODY,5,DIV,0,HEADER',
selector: 'div.l-header > div.chorus-emc__content',
nodeLabel: 'My Test Label',
snippet: '<h1 class="test-class">',
},
};
const artifacts = {
TraceElements: Array(4).fill(clsElement),

Просмотреть файл

@ -15,11 +15,13 @@ describe('Non-composited animations audit', () => {
TraceElements: [
{
traceEventType: 'animation',
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-boi',
nodeLabel: 'div',
snippet: '<div id="animated-boi">',
nodeId: 4,
node: {
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-boi',
nodeLabel: 'div',
snippet: '<div id="animated-boi">',
},
animations: [
{failureReasonsMask: 8192, unsupportedProperties: ['height', 'width']},
{name: 'alpha', failureReasonsMask: 8192, unsupportedProperties: ['color']},
@ -62,11 +64,13 @@ describe('Non-composited animations audit', () => {
TraceElements: [
{
traceEventType: 'animation',
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-1',
nodeLabel: 'div',
snippet: '<div id="animated-1">',
nodeId: 4,
node: {
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-1',
nodeLabel: 'div',
snippet: '<div id="animated-1">',
},
animations: [
{failureReasonsMask: 8192, unsupportedProperties: ['height']},
{failureReasonsMask: 8192, unsupportedProperties: ['height']},
@ -74,11 +78,13 @@ describe('Non-composited animations audit', () => {
},
{
traceEventType: 'animation',
devtoolsNodePath: '1,HTML,1,BODY,2,DIV',
selector: 'body > div#animated-2',
nodeLabel: 'div',
snippet: '<div id="animated-2">',
nodeId: 5,
node: {
devtoolsNodePath: '1,HTML,1,BODY,2,DIV',
selector: 'body > div#animated-2',
nodeLabel: 'div',
snippet: '<div id="animated-2">',
},
animations: [
{failureReasonsMask: 8192, unsupportedProperties: ['height']},
],
@ -122,11 +128,13 @@ describe('Non-composited animations audit', () => {
TraceElements: [
{
traceEventType: 'animation',
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-boi',
nodeLabel: 'div',
snippet: '<div id="animated-boi">',
nodeId: 4,
node: {
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-boi',
nodeLabel: 'div',
snippet: '<div id="animated-boi">',
},
animations: [
{failureReasonsMask: 0, unsupportedProperties: []},
{name: 'alpha', failureReasonsMask: 0, unsupportedProperties: []},
@ -147,11 +155,13 @@ describe('Non-composited animations audit', () => {
TraceElements: [
{
traceEventType: 'animation',
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-boi',
nodeLabel: 'div',
snippet: '<div id="animated-boi">',
nodeId: 4,
node: {
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated-boi',
nodeLabel: 'div',
snippet: '<div id="animated-boi">',
},
animations: [
{name: 'alpha', failureReasonsMask: 4, unsupportedProperties: []}, // kInvalidAnimationOrEffect
],
@ -171,11 +181,13 @@ describe('Non-composited animations audit', () => {
TraceElements: [
{
traceEventType: 'animation',
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated',
nodeLabel: 'div',
snippet: '<div id="animated">',
nodeId: 4,
node: {
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
selector: 'body > div#animated',
nodeLabel: 'div',
snippet: '<div id="animated">',
},
animations: [
{failureReasonsMask: 0b11100001011000, unsupportedProperties: ['height']},
],

Просмотреть файл

@ -31,13 +31,15 @@ describe('Performance: preload-lcp audit', () => {
TraceElements: [
{
traceEventType: 'largest-contentful-paint',
devtoolsNodePath: '1,HTML,1,BODY,3,DIV,2,IMG',
node: {
devtoolsNodePath: '1,HTML,1,BODY,3,DIV,2,IMG'},
},
],
ImageElements: [
{
src: imageUrl,
devtoolsNodePath: '1,HTML,1,BODY,3,DIV,2,IMG',
node: {
devtoolsNodePath: '1,HTML,1,BODY,3,DIV,2,IMG'},
},
],
};

Просмотреть файл

@ -16,6 +16,13 @@ function runAudit({
onclick = '',
name = '',
listeners = onclick.trim().length ? [{type: 'click'}] : [],
node = {
snippet: '',
devtoolsNodePath: '',
nodeSelector: '',
boundingRect: null,
selector: '',
},
}) {
const {score} = CrawlableAnchorsAudit.audit({
AnchorElements: [{
@ -24,6 +31,7 @@ function runAudit({
listeners,
onclick,
role,
node,
}],
});

Просмотреть файл

@ -8,17 +8,19 @@
const assert = require('assert').strict;
const HreflangAudit = require('../../../audits/seo/hreflang.js');
const node = {};
/* eslint-env jest */
describe('SEO: Document has valid hreflang code', () => {
it('fails when the language code provided in hreflang via link element is invalid', () => {
const artifacts = {
LinkElements: [
{rel: 'alternate', hreflang: 'xx1', hrefRaw: 'http://example.com/', source: 'headers'},
{rel: 'alternate', hreflang: 'XX-be', hrefRaw: 'http://example.com/', source: 'headers'},
{rel: 'alternate', hreflang: 'XX-be-Hans', hrefRaw: 'http://example.com/', source: 'head'},
{rel: 'alternate', hreflang: ' es', hrefRaw: 'http://example.com/', source: 'head'},
{rel: 'alternate', hreflang: ' es', hrefRaw: 'http://example.com/', source: 'headers'},
{rel: 'alternate', hreflang: 'xx1', hrefRaw: 'http://example.com/', source: 'headers', node},
{rel: 'alternate', hreflang: 'XX-be', hrefRaw: 'http://example.com/', source: 'headers', node},
{rel: 'alternate', hreflang: 'XX-be-Hans', hrefRaw: 'http://example.com/', source: 'head', node},
{rel: 'alternate', hreflang: ' es', hrefRaw: 'http://example.com/', source: 'head', node},
{rel: 'alternate', hreflang: ' es', hrefRaw: 'http://example.com/', source: 'headers', node},
],
};
@ -59,6 +61,7 @@ describe('SEO: Document has valid hreflang code', () => {
rel: 'alternate',
hreflang: hreflangValue,
hrefRaw: 'https://example.com',
node,
},
],
};
@ -76,10 +79,10 @@ describe('SEO: Document has valid hreflang code', () => {
it('returns all failing items', () => {
const artifacts = {
LinkElements: [
{rel: 'alternate', hreflang: 'xx1', hrefRaw: 'http://xx1.example.com/', source: 'headers'},
{rel: 'alternate', hreflang: 'xx2', hrefRaw: 'http://xx2.example.com/', source: 'headers'},
{rel: 'alternate', hreflang: 'xx3', hrefRaw: 'http://xx3.example.com/', source: 'head'},
{rel: 'alternate', hreflang: 'xx4', hrefRaw: 'http://xx4.example.com/', source: 'head'},
{rel: 'alternate', hreflang: 'xx1', hrefRaw: 'http://xx1.example.com/', source: 'headers', node},
{rel: 'alternate', hreflang: 'xx2', hrefRaw: 'http://xx2.example.com/', source: 'headers', node},
{rel: 'alternate', hreflang: 'xx3', hrefRaw: 'http://xx3.example.com/', source: 'head', node},
{rel: 'alternate', hreflang: 'xx4', hrefRaw: 'http://xx4.example.com/', source: 'head', node},
],
};
@ -91,8 +94,8 @@ describe('SEO: Document has valid hreflang code', () => {
it('fails when the hreflang url is not fully-qualified', () => {
const artifacts = {
LinkElements: [
{rel: 'alternate', hreflang: 'es', hrefRaw: 'example.com', source: 'head'},
{rel: 'alternate', hreflang: 'es', hrefRaw: '//example.com', source: 'headers'},
{rel: 'alternate', hreflang: 'es', hrefRaw: 'example.com', source: 'head', node},
{rel: 'alternate', hreflang: 'es', hrefRaw: '//example.com', source: 'headers', node},
],
};
@ -104,8 +107,8 @@ describe('SEO: Document has valid hreflang code', () => {
it('fails with an invalid language code and a href which is not fully-qualified', () => {
const artifacts = {
LinkElements: [
{rel: 'alternate', hreflang: ' es', hrefRaw: 'example.com', source: 'head'},
{rel: 'alternate', hreflang: 'xx1', hrefRaw: '//example.com', source: 'headers'},
{rel: 'alternate', hreflang: ' es', hrefRaw: 'example.com', source: 'head', node},
{rel: 'alternate', hreflang: 'xx1', hrefRaw: '//example.com', source: 'headers', node},
],
};
@ -116,10 +119,10 @@ describe('SEO: Document has valid hreflang code', () => {
it('outputs the reasons for which a hreflang failed', () => {
const artifacts = {
LinkElements: [
{rel: 'alternate', hreflang: '@@', hrefRaw: 'example.com', source: 'head'},
{rel: 'alternate', hreflang: 'fr', hrefRaw: 'example.com', source: 'head'},
{rel: 'alternate', hreflang: '@@', hrefRaw: 'https://example.com', source: 'head'},
{rel: 'alternate', hreflang: 'fr', hrefRaw: 'https://example.com', source: 'head'},
{rel: 'alternate', hreflang: '@@', hrefRaw: 'example.com', source: 'head', node},
{rel: 'alternate', hreflang: 'fr', hrefRaw: 'example.com', source: 'head', node},
{rel: 'alternate', hreflang: '@@', hrefRaw: 'https://example.com', source: 'head', node},
{rel: 'alternate', hreflang: 'fr', hrefRaw: 'https://example.com', source: 'head', node},
],
};

Просмотреть файл

@ -45,7 +45,9 @@ function getBorderlineTapTargets(options = {}) {
}
const mainTapTarget = {
snippet: '<main></main>',
node: {
snippet: '<main></main>',
},
clientRects: [
makeClientRects({
x: 0,
@ -54,7 +56,9 @@ function getBorderlineTapTargets(options = {}) {
],
};
const tapTargetBelow = {
snippet: '<below></below>',
node: {
snippet: '<below></below>',
},
clientRects: [
makeClientRects({
x: 0,
@ -63,7 +67,9 @@ function getBorderlineTapTargets(options = {}) {
],
};
const tapTargetToTheRight = {
snippet: '<right></right>',
node: {
snippet: '<right></right>',
},
clientRects: [
makeClientRects({
x: mainTapTarget.clientRects[0].left + TapTargetsAudit.FINGER_SIZE_PX,

Просмотреть файл

@ -10,8 +10,8 @@ const UnsizedImagesAudit = require('../../audits/unsized-images.js');
/* eslint-env jest */
function generateImage(props, src = 'https://google.com/logo.png', isCss = false,
isInShadowDOM = false, cssComputedPosition = 'static') {
const image = {src, isCss, isInShadowDOM, cssComputedPosition};
isInShadowDOM = false, cssComputedPosition = 'static', node = {}) {
const image = {src, isCss, isInShadowDOM, cssComputedPosition, node};
Object.assign(image, props);
return image;
}

Просмотреть файл

@ -24,7 +24,9 @@ describe('PasswordInputsWithPreventedPaste gatherer', () => {
evaluateAsync() {
return Promise.resolve([
{
snippet: '<input type="password" onpaste="return false"/>',
node: {
snippet: '<input type="password" onpaste="return false"/>',
},
},
]);
},
@ -32,7 +34,7 @@ describe('PasswordInputsWithPreventedPaste gatherer', () => {
})
.then(artifact => {
assert.ok(typeof artifact === 'object');
assert.ok(artifact[0].snippet.length > 0);
assert.ok(artifact[0].node.snippet.length > 0);
});
});
});

Просмотреть файл

@ -23,10 +23,7 @@ describe('Link Elements gatherer', () => {
hreflang: '',
as: '',
crossOrigin: null,
devtoolsNodePath: '',
nodeLabel: '',
snippet: '',
selector: '',
node: null,
...overrides,
};
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1836,7 +1836,15 @@
"path": "1,HTML,1,BODY,0,DIV,1,P",
"selector": "body > div > p",
"nodeLabel": "This domain is for use in illustrative examples in documents. You may use this …",
"snippet": "<p class=\"paragraph\">"
"snippet": "<p class=\"paragraph\">",
"boundingRect": {
"top": 574,
"bottom": 654,
"left": 132,
"right": 252,
"width": 120,
"height": 80
}
}
}
]
@ -3985,13 +3993,15 @@
{
"node": {
"type": "node",
"snippet": "<input type=\"password\" onpaste=\"event.preventDefault();\">"
"snippet": "<input type=\"password\" onpaste=\"event.preventDefault();\">",
"path": "3,HTML,1,BODY,58,INPUT"
}
},
{
"node": {
"type": "node",
"snippet": "<input type=\"password\" onpaste=\"return false;\">"
"snippet": "<input type=\"password\" onpaste=\"return false;\">",
"path": "3,HTML,1,BODY,62,INPUT"
}
}
]

38
types/artifacts.d.ts поставляемый
Просмотреть файл

@ -175,10 +175,11 @@ declare global {
id: string;
impact: string;
tags: Array<string>;
nodes: Array<NodeDetails & {
nodes: Array<{
html: string;
target: Array<string>;
failureSummary?: string;
node: NodeDetails;
}>;
// When rules error they set these properties
// https://github.com/dequelabs/axe-core/blob/eeff122c2de11dd690fbad0e50ba2fdb244b50e8/lib/core/base/audit.js#L684-L693
@ -219,9 +220,11 @@ declare global {
params: {name: string; value: string}[];
}
export interface IFrameElement extends NodeDetails {
export interface IFrameElement {
/** The `id` attribute of the iframe. */
id: string,
/** Details for node in DOM for the iframe element */
node: NodeDetails,
/** The `src` attribute of the iframe. */
src: string,
/** The iframe's ClientRect. @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect */
@ -238,7 +241,7 @@ declare global {
}
/** @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#Attributes */
export interface LinkElement extends NodeDetails {
export interface LinkElement {
/** The `rel` attribute of the link, normalized to lower case. @see https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types */
rel: 'alternate'|'canonical'|'dns-prefetch'|'preconnect'|'preload'|'stylesheet'|string;
/** The `href` attribute of the link or `null` if it was invalid in the header. */
@ -253,17 +256,20 @@ declare global {
crossOrigin: string | null
/** Where the link was found, either in the DOM or in the headers of the main document */
source: 'head'|'body'|'headers'
node: NodeDetails | null
}
export interface PasswordInputsWithPreventedPaste extends NodeDetails {}
export interface PasswordInputsWithPreventedPaste {node: NodeDetails}
export interface ScriptElement extends NodeDetails {
export interface ScriptElement {
type: string | null
src: string | null
/** The `id` property of the script element; null if it had no `id` or if `source` is 'network'. */
id: string | null
async: boolean
defer: boolean
/** Details for node in DOM for the script element */
node: NodeDetails | null
/** Where the script was discovered, either in the head, the body, or network records. */
source: 'head'|'body'|'network'
/** The content of the inline script or the network record with the matching URL, null if the script had a src and no network record could be found. */
@ -331,7 +337,7 @@ declare global {
}
/** @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes */
export interface AnchorElement extends NodeDetails {
export interface AnchorElement {
rel: string
/** The computed href property: https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-88517319, use `rawHref` for the exact attribute value */
href: string
@ -341,6 +347,7 @@ declare global {
text: string
role: string
target: string
node: NodeDetails
onclick: string
listeners?: Array<{
type: Crdp.DOMDebugger.EventListener['type']
@ -397,7 +404,7 @@ declare global {
errors: Crdp.Page.InstallabilityError[];
}
export interface ImageElement extends NodeDetails {
export interface ImageElement {
src: string;
/** The srcset attribute value. @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset */
srcset: string;
@ -445,6 +452,8 @@ declare global {
usesSrcSetDensityDescriptor: boolean;
/** The MIME type of the underlying image file. */
mimeType?: string;
/** Details for node in DOM for the image element */
node: NodeDetails;
/** The loading attribute of the image. */
loading?: string;
}
@ -490,14 +499,16 @@ declare global {
left: number;
}
export interface TapTarget extends NodeDetails {
export interface TapTarget {
node: NodeDetails;
href: string;
clientRects: Rect[];
}
export interface TraceElement extends NodeDetails {
export interface TraceElement {
traceEventType: 'largest-contentful-paint'|'layout-shift'|'animation';
score?: number;
node: NodeDetails;
nodeId?: number;
animations?: {name?: string, failureReasonsMask?: number, unsupportedProperties?: string[]}[];
}
@ -717,11 +728,12 @@ declare global {
export interface Form {
/** If attributes is missing that means this is a formless set of elements. */
attributes?: NodeDetails & {
attributes?: {
id: string;
name: string;
autocomplete: string;
};
node: NodeDetails | null;
inputs: Array<FormInput>;
labels: Array<FormLabel>;
}
@ -736,15 +748,13 @@ declare global {
attribute: string | null;
prediction: string | null;
}
nodeLabel: string;
snippet: string;
node: NodeDetails;
}
/** Attributes collected for every label element in the labels array from the forms interface */
export interface FormLabel {
for: string;
nodeLabel: string;
snippet: string;
node: NodeDetails;
}
/** Information about an event listener registered on the global object. */