blob: 058d311d56475d4eccc5502a4066ff879a349a4e [file] [log] [blame]
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Tests that evaluating V8-embedder callbacks allows side-effect-free attribute getters. Should not crash.`);
await session.evaluate(`
var div = document.createElement('div');
div.id = 'foo';
div.className = 'bar baz';
div.setAttribute('attr1', 'attr1-value');
div.tabIndex = -1;
div.style.color = 'red';
var textNode = document.createTextNode('footext');
div.appendChild(textNode);
var textNode2 = document.createTextNode('bartext');
div.appendChild(textNode2);
var shadowContainer = document.createElement('div');
var shadowRoot = shadowContainer.attachShadow({mode: 'open'});
var divInShadow = document.createElement('div');
shadowRoot.appendChild(divInShadow);
`);
// Sanity check: test that setters are not allowed on whitelisted accessors.
await checkHasSideEffect(`document.title = "foo"`);
// Document
await checkHasNoSideEffect(`document.domain`);
await checkHasNoSideEffect(`document.referrer`);
await checkHasNoSideEffect(`document.cookie`);
await checkHasNoSideEffect(`document.title`);
await checkHasNoSideEffect(`document.documentElement`);
await checkHasNoSideEffect(`document.scrollingElement`);
await checkHasNoSideEffect(`document.body`);
await checkHasNoSideEffect(`document.head`);
await checkHasNoSideEffect(`document.location`);
await checkHasNoSideEffect(`document.defaultView`);
// DocumentOrShadowRoot
await checkHasNoSideEffect(`document.activeElement`);
// Element
await checkHasNoSideEffect(`div.tagName`);
await checkHasNoSideEffect(`div.id`);
await checkHasNoSideEffect(`div.className`);
await checkHasNoSideEffect(`div.classList`);
await checkHasNoSideEffect(`div.attributes`);
await checkHasNoSideEffect(`shadowContainer.shadowRoot`);
await checkHasNoSideEffect(`div.innerHTML`);
await checkHasNoSideEffect(`div.outerHTML`);
// HTMLElement
await checkHasNoSideEffect(`div.hidden`);
await checkHasNoSideEffect(`div.tabIndex`);
await checkHasNoSideEffect(`div.style`);
// Location
await checkHasNoSideEffect(`location.href`);
// Navigator
await checkHasNoSideEffect(`navigator.userAgent`);
// Node
var testNodes = ['div', 'document', 'textNode'];
for (var node of testNodes) {
await checkHasNoSideEffect(`${node}.nodeType`);
await checkHasNoSideEffect(`${node}.nodeName`);
await checkHasNoSideEffect(`${node}.nodeValue`);
await checkHasNoSideEffect(`${node}.textContent`);
await checkHasNoSideEffect(`${node}.isConnected`);
await checkHasNoSideEffect(`${node}.parentNode`);
await checkHasNoSideEffect(`${node}.parentElement`);
await checkHasNoSideEffect(`${node}.childNodes`);
await checkHasNoSideEffect(`${node}.firstChild`);
await checkHasNoSideEffect(`${node}.lastChild`);
await checkHasNoSideEffect(`${node}.previousSibling`);
await checkHasNoSideEffect(`${node}.nextSibling`);
await checkHasNoSideEffect(`${node}.ownerDocument`);
}
// ParentNode
for (var node of testNodes) {
await checkHasNoSideEffect(`${node}.childElementCount`);
await checkHasNoSideEffect(`${node}.children`);
await checkHasNoSideEffect(`${node}.firstElementChild`);
await checkHasNoSideEffect(`${node}.lastElementChild`);
}
// Window
await checkHasNoSideEffect(`devicePixelRatio`);
await checkHasNoSideEffect(`screenX`);
await checkHasNoSideEffect(`screenY`);
await checkHasNoSideEffect(`document`);
await checkHasNoSideEffect(`history`);
await checkHasNoSideEffect(`navigator`);
await checkHasNoSideEffect(`performance`);
await checkHasNoSideEffect(`window`);
await checkHasNoSideEffect(`location`);
// May update layout/scroll/style
await checkHasNoSideEffect(`div.scrollTop`);
await checkHasNoSideEffect(`div.scrollLeft`);
await checkHasNoSideEffect(`div.scrollWidth`);
await checkHasNoSideEffect(`div.scrollHeight`);
await checkHasNoSideEffect(`div.clientTop`);
await checkHasNoSideEffect(`div.clientLeft`);
await checkHasNoSideEffect(`div.clientWidth`);
await checkHasNoSideEffect(`div.clientHeight`);
await checkHasNoSideEffect(`innerWidth`);
await checkHasNoSideEffect(`innerHeight`);
await checkHasNoSideEffect(`outerWidth`);
await checkHasNoSideEffect(`outerHeight`);
await checkHasNoSideEffect(`div.offsetParent`);
await checkHasNoSideEffect(`div.offsetTop`);
await checkHasNoSideEffect(`div.offsetLeft`);
await checkHasNoSideEffect(`div.offsetWidth`);
await checkHasNoSideEffect(`div.offsetHeight`);
await checkHasNoSideEffect(`div.innerText`);
await checkHasNoSideEffect(`div.outerText`);
await checkHasNoSideEffect(`div.style.border`);
testRunner.completeTest();
async function checkHasSideEffect(expression) {
return checkExpression(expression, true);
}
async function checkHasNoSideEffect(expression) {
return checkExpression(expression, false);
}
async function checkExpression(expression, expectSideEffect) {
var response = await dp.Runtime.evaluate({expression, throwOnSideEffect: true});
var hasSideEffect = false;
var exceptionDetails = response.result.exceptionDetails;
if (exceptionDetails &&
exceptionDetails.exception.description.startsWith('EvalError: Possible side-effect in debug-evaluate'))
hasSideEffect = true;
const failed = (hasSideEffect !== expectSideEffect);
testRunner.log(`${failed ? 'FAIL: ' : ''}Expression \`${expression}\`\nhas side effect: ${hasSideEffect}, expected: ${expectSideEffect}`);
}
})