blob: 10a8cc82beadb75776c620016db7b6f046bd0714 [file] [log] [blame]
<!DOCTYPE html>
<meta charset="utf-8" />
<title>Popup invoking attribute</title>
<link rel="author" href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<body>
<script>
const buttonLogic = (t,s,h) => {
// This mimics the expected logic for button invokers:
let expectedBehavior = t ? "toggle" : (s ? "show" : (h ? "hide" : "none"));
let expectedId = t || s || h || 1;
if (!t && s && h) {
// Special case - only use toggle if the show/hide idrefs match.
expectedBehavior = (s === h) ? "toggle" : "show";
}
return {expectedBehavior, expectedId};
}
const noActivationLogic = (t,s,h) => {
// This does not activate any pop-ups.
return {expectedBehavior: "none", expectedId: 1};
}
function makeElementWithType(element,type) {
return (test) => {
const el = Object.assign(document.createElement(element),{type});
document.body.appendChild(el);
test.add_cleanup(() => el.remove());
return el;
};
}
const supportedButtonTypes = ['button','reset','submit',''].map(type => {
return {
name: `<button type="${type}">`,
makeElement: makeElementWithType('button',type),
invokeFn: el => el.click(),
getExpectedLogic: buttonLogic,
supported: true,
};
});
const supportedInputButtonTypes = ['button','reset','submit','image'].map(type => {
return {
name: `<input type="${type}">`,
makeElement: makeElementWithType('input',type),
invokeFn: el => el.click(),
getExpectedLogic: buttonLogic,
supported: true,
};
});
const unsupportedTypes = ['text','email','password','search','tel','url','checkbox','radio','range','file','color','date','datetime-local','month','time','week','number'].map(type => {
return {
name: `<input type="${type}">`,
makeElement: makeElementWithType('input',type),
invokeFn: (el) => {el.focus();},
getExpectedLogic: noActivationLogic, // None of these support pop-up invocation
supported: false,
};
});
const invokers = [
...supportedButtonTypes,
...supportedInputButtonTypes,
...unsupportedTypes,
];
window.addEventListener('load', () => {
["auto","hint","manual"].forEach(type => {
invokers.forEach(testcase => {
let t_set = [1], s_set = [1], h_set = [1];
if (testcase.supported) {
t_set = s_set = h_set = [0,1,2]; // Test all permutations
}
t_set.forEach(t => {
s_set.forEach(s => {
h_set.forEach(h => {
[false,true].forEach(use_idl => {
promise_test(async test => {
const popUp1 = Object.assign(document.createElement('div'),{popUp: type, id: 'pop-up-1'});
const popUp2 = Object.assign(document.createElement('div'),{popUp: type, id: 'pop-up-2'});
assert_equals(popUp1.popUp,type);
assert_equals(popUp2.popUp,type);
assert_not_equals(popUp1.id,popUp2.id);
const invoker = testcase.makeElement(test);
if (use_idl) {
invoker.popUpToggleTarget = t===1 ? popUp1.id : (t===2 ? popUp2.id : null);
invoker.popUpShowTarget = s===1 ? popUp1.id : (s===2 ? popUp2.id : null);
invoker.popUpHideTarget = h===1 ? popUp1.id : (h===2 ? popUp2.id : null);
} else {
if (t) invoker.setAttribute('popuptoggletarget',t===1 ? popUp1.id : popUp2.id);
if (s) invoker.setAttribute('popupshowtarget',s===1 ? popUp1.id : popUp2.id);
if (h) invoker.setAttribute('popuphidetarget',h===1 ? popUp1.id : popUp2.id);
}
assert_true(!document.getElementById(popUp1.id));
assert_true(!document.getElementById(popUp2.id));
document.body.appendChild(popUp1);
document.body.appendChild(popUp2);
test.add_cleanup(() => {
popUp1.remove();
popUp2.remove();
});
const {expectedBehavior, expectedId} = testcase.getExpectedLogic(t,s,h);
const otherId = expectedId !== 1 ? 1 : 2;
function assert_popUp(num,state,message) {
assert_true(num>0,`Invalid expectedId ${num}`);
assert_equals((num===1 ? popUp1 : popUp2).matches(':top-layer'),state,message || "");
}
assert_popUp(expectedId,false);
assert_popUp(otherId,false);
await testcase.invokeFn(invoker);
assert_popUp(otherId,false,'The other pop-up should never change');
switch (expectedBehavior) {
case "toggle":
case "show":
assert_popUp(expectedId,true,'Toggle or show should show the pop-up');
(expectedId===1 ? popUp1 : popUp2).hidePopUp(); // Hide the pop-up
break;
case "hide":
case "none":
assert_popUp(expectedId,false,'Hide or none should leave the pop-up hidden');
break;
default:
assert_unreached();
}
(expectedId===1 ? popUp1 : popUp2).showPopUp(); // Show the pop-up directly
assert_popUp(expectedId,true);
assert_popUp(otherId,false);
await testcase.invokeFn(invoker);
assert_popUp(otherId,false,'The other pop-up should never change');
switch (expectedBehavior) {
case "toggle":
case "hide":
assert_popUp(expectedId,false,'Toggle or hide should hide the pop-up');
break;
case "show":
case "none":
assert_popUp(expectedId,true,'Show or none should leave the pop-up showing');
break;
default:
assert_unreached();
}
},`Test ${testcase.name}, t=${t}, s=${s}, h=${h}, ${use_idl ? "IDL" : "Content Attr"}, with popup=${type}`);
});
});
});
});
});
});
});
</script>
<button popuptoggletarget=p1>Toggle Popup 1</button>
<div popup id=p1 style="border: 5px solid red;top: 100px;left: 100px;">This is pop-up #1</div>
<script>
function clickOn(element) {
const actions = new test_driver.Actions();
return actions.pointerMove(0, 0, {origin: element})
.pointerDown({button: actions.ButtonType.LEFT})
.pointerUp({button: actions.ButtonType.LEFT})
.send();
}
const popUp = document.querySelector('[popup]');
const button = document.querySelector('button');
let showCount = 0;
let hideCount = 0;
popUp.addEventListener('show',() => ++showCount);
popUp.addEventListener('hide',() => ++hideCount);
async function assertState(expectOpen,expectShow,expectHide) {
assert_equals(popUp.matches(':top-layer'),expectOpen,'Popup open state is incorrect');
await new Promise(resolve => requestAnimationFrame(resolve));
assert_equals(showCount,expectShow,'Show count is incorrect');
assert_equals(hideCount,expectHide,'Hide count is incorrect');
}
window.addEventListener('load', () => {
promise_test(async () => {
showCount = hideCount = 0;
await assertState(false,0,0);
await clickOn(button);
await assertState(true,1,0);
popUp.hidePopUp();
await assertState(false,1,1);
button.click();
await assertState(true,2,1);
popUp.hidePopUp();
await assertState(false,2,2);
}, "Clicking a popuptoggletarget button opens a closed pop-up (also check event counts)");
promise_test(async () => {
showCount = hideCount = 0;
await assertState(false,0,0);
await clickOn(button);
await assertState(true,1,0);
await clickOn(button);
await assertState(false,1,1);
}, "Clicking a popuptoggletarget button closes an open pop-up (also check event counts)");
});
</script>