popover-invoking-attribute.js (5715B)
1 const actionReflectionLogic = (action) => { 2 switch (action?.toLowerCase()) { 3 case "show": return "show"; 4 case "hide": return "hide"; 5 default: return "toggle"; 6 } 7 } 8 const noActivationLogic = (action) => { 9 return "none"; 10 } 11 function makeElementWithType(element,type) { 12 return (test) => { 13 const el = Object.assign(document.createElement(element),{type}); 14 document.body.appendChild(el); 15 test.add_cleanup(() => el.remove()); 16 return el; 17 }; 18 } 19 const supportedButtonTypes = ['button','reset','submit',''].map(type => { 20 return { 21 name: `<button type="${type}">`, 22 makeElement: makeElementWithType('button',type), 23 invokeFn: el => {el.focus(); el.click()}, 24 getExpectedLogic: actionReflectionLogic, 25 }; 26 }); 27 const supportedInputButtonTypes = ['button','reset','submit','image'].map(type => { 28 return { 29 name: `<input type="${type}">`, 30 makeElement: makeElementWithType('input',type), 31 invokeFn: el => {el.focus(); el.click()}, 32 getExpectedLogic: actionReflectionLogic, 33 }; 34 }); 35 const unsupportedTypes = ['text','email','password','search','tel','url','checkbox','radio','range','file','color','date','datetime-local','month','time','week','number'].map(type => { 36 return { 37 name: `<input type="${type}">`, 38 makeElement: makeElementWithType('input',type), 39 invokeFn: (el) => {el.focus();}, 40 getExpectedLogic: noActivationLogic, // None of these support popover invocation 41 }; 42 }); 43 const invokers = [ 44 ...supportedButtonTypes, 45 ...supportedInputButtonTypes, 46 ...unsupportedTypes, 47 ]; 48 function runPopoverInvokerTests(popoverTypes) { 49 window.addEventListener('load', () => { 50 popoverTypes.forEach(type => { 51 invokers.forEach(testcase => { 52 ["toggle","hide","show","ShOw","garbage",null,undefined].forEach(action => { 53 [false,true].forEach(use_idl_for_target => { 54 [false,true].forEach(use_idl_for_action => { 55 promise_test(async test => { 56 const popover = Object.assign(document.createElement('div'),{popover: type, id: 'my-popover'}); 57 assert_equals(popover.popover,type,'reflection'); 58 const invoker = testcase.makeElement(test); 59 if (use_idl_for_target) { 60 invoker.popoverTargetElement = popover; 61 assert_equals(invoker.getAttribute('popovertarget'),'','attribute value'); 62 } else { 63 invoker.setAttribute('popovertarget',popover.id); 64 } 65 if (use_idl_for_action) { 66 invoker.popoverTargetAction = action; 67 assert_equals(invoker.getAttribute('popovertargetaction'),String(action),'action reflection'); 68 } else { 69 invoker.setAttribute('popovertargetaction',action); 70 } 71 assert_true(!document.getElementById(popover.id)); 72 assert_equals(invoker.popoverTargetElement,null,'targetElement should be null before the popover is in the document'); 73 assert_equals(invoker.popoverTargetAction,actionReflectionLogic(action),'action should be correct immediately'); 74 document.body.appendChild(popover); 75 test.add_cleanup(() => {popover.remove();}); 76 assert_equals(invoker.popoverTargetElement,popover,'target element should be returned once it\'s in the document'); 77 assert_false(popover.matches(':popover-open')); 78 await testcase.invokeFn(invoker); 79 assert_equals(document.activeElement,invoker,'Focus should end up on the invoker'); 80 expectedBehavior = testcase.getExpectedLogic(action); 81 switch (expectedBehavior) { 82 case "toggle": 83 case "show": 84 assert_true(popover.matches(':popover-open'),'Toggle or show should show the popover'); 85 popover.hidePopover(); // Hide the popover 86 break; 87 case "hide": 88 case "none": 89 assert_false(popover.matches(':popover-open'),'Hide or none should leave the popover hidden'); 90 break; 91 default: 92 assert_unreached(); 93 } 94 if (expectedBehavior === "none") { 95 // If no behavior is expected, then there is nothing left to test. Even re-focusing 96 // a control that has no expected behavior may hide an open popover via light dismiss. 97 return; 98 } 99 assert_false(popover.matches(':popover-open')); 100 popover.showPopover(); // Show the popover directly 101 assert_equals(document.activeElement,invoker,'The popover should not shift focus'); 102 assert_true(popover.matches(':popover-open')); 103 await testcase.invokeFn(invoker); 104 switch (expectedBehavior) { 105 case "toggle": 106 case "hide": 107 assert_false(popover.matches(':popover-open'),'Toggle or hide should hide the popover'); 108 break; 109 case "show": 110 assert_true(popover.matches(':popover-open'),'Show should leave the popover showing'); 111 break; 112 default: 113 assert_unreached(); 114 } 115 },`Test ${testcase.name}, action=${action}, ${use_idl_for_target ? "popoverTarget IDL" : "popovertarget attr"}, ${use_idl_for_action ? "popoverTargetAction IDL" : "popovertargetaction attr"}, with popover=${type}`); 116 }); 117 }); 118 }); 119 }); 120 }); 121 }); 122 }