events_input_sources_change.https.html (4326B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script src="resources/webxr_util.js"></script> 5 <script src="resources/webxr_test_constants.js"></script> 6 7 <script> 8 "use strict" 9 let testName = "Transient input sources fire events in the right order"; 10 11 let watcherDone = new Event("watcherdone"); 12 13 let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE; 14 15 let testFunction = function(session, fakeDeviceController, t) { 16 let eventWatcher = new EventWatcher( 17 t, session, ["inputsourceschange", "selectstart", "select", "selectend", "watcherdone"]); 18 let eventPromise = eventWatcher.wait_for( 19 ["inputsourceschange", "selectstart", "select", "selectend", "inputsourceschange", "watcherdone"]); 20 21 let inputChangeEvents = 0; 22 let cached_input_source = null; 23 function onInputSourcesChange(event) { 24 t.step(() => { 25 inputChangeEvents++; 26 assert_equals(event.session, session); 27 validateSameObject(event); 28 29 assert_throws_js( 30 TypeError, 31 () => { event.added[0] = "test"; }, 32 "added array must be frozen" 33 ); 34 assert_throws_js( 35 TypeError, 36 () => { event.removed[0] = "test"; }, 37 "removed array must be frozen" 38 ); 39 40 // The first change event should be adding our controller. 41 if (inputChangeEvents === 1) { 42 validateAdded(event.added, 1); 43 validateRemoved(event.removed, 0); 44 cached_input_source = session.inputSources[0]; 45 assert_not_equals(cached_input_source, null); 46 } else if (inputChangeEvents === 2) { 47 // The second event should be removing our controller. 48 validateAdded(event.added, 0); 49 validateRemoved(event.removed, 1); 50 assert_true(event.removed.includes(cached_input_source)); 51 session.dispatchEvent(watcherDone); 52 } 53 }); 54 } 55 56 function validateAdded(added, length) { 57 t.step(() => { 58 assert_not_equals(added, null); 59 assert_equals(added.length, length, 60 "Added length matches expectations"); 61 62 let currentSources = Array.from(session.inputSources.values()); 63 added.forEach((source) => { 64 assert_true(currentSources.includes(source), 65 "Every element in added should be in the input source list"); 66 }); 67 }); 68 } 69 70 function validateRemoved(removed, length) { 71 t.step(() => { 72 assert_not_equals(removed, null); 73 assert_equals(removed.length, length, 74 "Removed length matches expectations"); 75 76 let currentSources = Array.from(session.inputSources.values()); 77 removed.forEach((source) => { 78 assert_false(currentSources.includes(source), 79 "No element in removed should be in the input source list"); 80 }); 81 }); 82 } 83 84 // Verifies that the same object is returned each time attributes are accessed 85 // on an XRInputSourcesChangeEvent, as required by the spec. 86 function validateSameObject(event) { 87 let eventSession = event.session; 88 let added = event.added; 89 let removed = event.removed; 90 91 t.step(() => { 92 assert_equals(eventSession, event.session, 93 "XRInputSourcesChangeEvent.session returns the same object."); 94 assert_equals(added, event.added, 95 "XRInputSourcesChangeEvent.added returns the same object."); 96 assert_equals(removed, event.removed, 97 "XRInputSourcesChangeEvent.removed returns the same object."); 98 }); 99 } 100 101 session.addEventListener('inputsourceschange', onInputSourcesChange, false); 102 103 // Create our input source and immediately toggle the primary input so that 104 // it appears as already needing to send a click event when it appears. 105 let input_source = fakeDeviceController.simulateInputSourceConnection({ 106 handedness: "right", 107 targetRayMode: "tracked-pointer", 108 pointerOrigin: VALID_POINTER_TRANSFORM, 109 profiles: [], 110 selectionClicked: true 111 }); 112 113 // Make our input source disappear after one frame, and wait an additional 114 // frame for that disappearance to propogate. 115 requestSkipAnimationFrame(session, (time, xrFrame) => { 116 input_source.disconnect(); 117 session.requestAnimationFrame((time, xrFrame) => {}); 118 }); 119 120 return eventPromise; 121 }; 122 123 xr_session_promise_test( 124 testName, testFunction, fakeDeviceInitParams, 'immersive-vr'); 125 </script>