source-attribute-retargeting.html (4794B)
1 <!DOCTYPE html> 2 <link rel=author href="mailto:jarhar@chromium.org"> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 6 <div id=popover popover=auto>popover</div> 7 <div id=host> 8 <template shadowrootmode=open> 9 <button id=shadow-button command=show-popover>button in shadowroot</button> 10 </template> 11 </div> 12 13 <script> 14 promise_test(async () => { 15 const popover = document.getElementById('popover'); 16 const host = document.getElementById('host'); 17 const shadowButton = host.shadowRoot.getElementById('shadow-button'); 18 shadowButton.commandForElement = popover; 19 20 const eventNames = ['beforetoggle', 'toggle', 'command']; 21 const eventNameToEvent = {}; 22 const eventNameToCaptureSource = {}; 23 const eventNameToBubbleSource = {}; 24 25 for (const eventName of eventNames) { 26 popover.addEventListener(eventName, event => { 27 eventNameToEvent[eventName] = event; 28 eventNameToBubbleSource[eventName] = event.source; 29 }); 30 popover.addEventListener(eventName, event => { 31 eventNameToCaptureSource[eventName] = event.source; 32 }, {capture: true}); 33 } 34 35 shadowButton.click(); 36 await new Promise(requestAnimationFrame); 37 await new Promise(requestAnimationFrame); 38 39 for (const eventName of eventNames) { 40 const event = eventNameToEvent[eventName]; 41 assert_true(!!event, `A ${eventName} event should have been fired.`); 42 assert_equals(eventNameToCaptureSource[eventName], host, 43 `${eventName}.source during capture.`); 44 assert_equals(eventNameToBubbleSource[eventName], host, 45 `${eventName}.source during bubble.`); 46 assert_not_equals(event.source, shadowButton, 47 `${eventName}.source shouldn't leak the shadow button.`); 48 assert_equals(event.source, host, 49 `${eventName}.source after dispatch.`); 50 } 51 }, 'CommandEvent.source and ToggleEvent.source should be retargeted during and after event dispatch.'); 52 </script> 53 54 <div id=host2> 55 <template shadowrootmode=open> 56 <div id=source>source</div> 57 <div id=innerhost> 58 <template shadowrootmode=open> 59 <div id=target>target</div> 60 </template> 61 </div> 62 </template> 63 </div> 64 65 <script> 66 // This does not test ToggleEvent because ToggleEventInit does not have a source attribute. 67 promise_test(async () => { 68 const host2 = document.getElementById('host2'); 69 const source = host2.shadowRoot.getElementById('source'); 70 const innerhost = host2.shadowRoot.getElementById('innerhost'); 71 const target = innerhost.shadowRoot.getElementById('target'); 72 73 const targets = [host2, innerhost, target]; 74 const targetToEvent = new Map(); 75 const targetToCaptureSource = new Map(); 76 const targetToBubbleSource = new Map(); 77 78 for (const target of targets) { 79 target.addEventListener('command', event => { 80 targetToEvent.set(target, event); 81 targetToBubbleSource.set(target, event.source); 82 }); 83 target.addEventListener('command', event => { 84 targetToCaptureSource.set(target, event.source); 85 }, {capture: true}); 86 } 87 88 const commandEvent = new CommandEvent('command', {composed: true, source}); 89 target.dispatchEvent(commandEvent); 90 91 for (const target of targets) { 92 const expectedSource = target == host2 ? host2 : source; 93 assert_true(targetToEvent.has(target), 94 `${target.id}: event should have fired.`); 95 assert_equals(targetToCaptureSource.get(target), expectedSource, 96 `${target.id}: event.source at capture.`); 97 assert_equals(targetToBubbleSource.get(target), expectedSource, 98 `${target.id}: event.source at bubble.`); 99 assert_equals(targetToEvent.get(target).source, host2, 100 `${target.id}: event.source after dispatch.`); 101 } 102 }, 'CommandEvent.source should be retargeted when manually dispatched with composed set to true.'); 103 </script> 104 105 <div id=popover3 popover=auto>popover 3</div> 106 <button id=button3 commandfor=popover3 command=show-popover>show popover 3</button> 107 108 <script> 109 promise_test(async () => { 110 const button = document.getElementById('button3'); 111 const popover = document.getElementById('popover3'); 112 113 const eventNames = ['beforetoggle', 'toggle', 'command']; 114 const eventNameToEvent = {}; 115 for (const eventName of eventNames) { 116 popover.addEventListener(eventName, event => { 117 eventNameToEvent[eventName] = event; 118 }); 119 } 120 121 button.click(); 122 await new Promise(requestAnimationFrame); 123 await new Promise(requestAnimationFrame); 124 125 for (const eventName of eventNames) { 126 const event = eventNameToEvent[eventName]; 127 assert_true(!!event, `${eventName} should have been fired.`); 128 assert_equals(event.source, button, 129 `${eventName}.source should be the invoker button after dispatch.`); 130 } 131 }, 'CommandEvent.source and ToggleEvent.source should not be set to null after dispatch without ShadowDOM.'); 132 </script>