browser_net_ws-sse-persist-columns.js (7017B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 /** 7 * Test columns' state for WS and SSE connection. 8 */ 9 10 function shallowArrayEqual(arr1, arr2) { 11 if (arr1.length !== arr2.length) { 12 return false; 13 } 14 for (let i = 0; i < arr1.length; i++) { 15 if ( 16 (arr2[i] instanceof RegExp && !arr2[i].test(arr1[i])) || 17 (typeof arr2[i] === "string" && arr2[i] !== arr1[i]) 18 ) { 19 return false; 20 } 21 } 22 return true; 23 } 24 25 function shallowObjectEqual(obj1, obj2) { 26 const k1 = Object.keys(obj1); 27 const k2 = Object.keys(obj2); 28 29 if (k1.length !== k2.length) { 30 return false; 31 } 32 33 for (const key of k1) { 34 if (obj1[key] !== obj2[key]) { 35 return false; 36 } 37 } 38 39 return true; 40 } 41 42 function shallowEqual(obj1, obj2) { 43 if (Array.isArray(obj1) && Array.isArray(obj2)) { 44 return shallowArrayEqual(obj1, obj2); 45 } 46 return shallowObjectEqual(obj1, obj2); 47 } 48 49 add_task(async function () { 50 const { tab, monitor } = await initNetMonitor( 51 "http://mochi.test:8888/browser/devtools/client/netmonitor/test/websockets/html_ws-sse-test-page.html", 52 { 53 requestCount: 1, 54 } 55 ); 56 info("Starting test... "); 57 58 const { document, store, windowRequire } = monitor.panelWin; 59 const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); 60 61 store.dispatch(Actions.batchEnable(false)); 62 63 const onNetworkEvents = waitForNetworkEvents(monitor, 2); 64 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 65 await content.wrappedJSObject.openWsConnection(1); 66 // Running openSseConnection() here causes intermittent behavior. 67 }); 68 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 69 await content.wrappedJSObject.openSseConnection(); 70 }); 71 await onNetworkEvents; 72 73 const requests = document.querySelectorAll(".request-list-item"); 74 is(requests.length, 2, "There should be two requests"); 75 76 // Select the WS request. 77 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]); 78 79 store.dispatch(Actions.toggleMessageColumn("size")); 80 store.dispatch(Actions.toggleMessageColumn("opCode")); 81 store.dispatch(Actions.toggleMessageColumn("maskBit")); 82 store.dispatch(Actions.toggleMessageColumn("finBit")); 83 clickOnSidebarTab(document, "response"); 84 85 // Get all messages present in the "Response" panel 86 let frames = await waitFor(() => { 87 const nodeList = document.querySelectorAll( 88 "#messages-view .message-list-table .message-list-item" 89 ); 90 return nodeList.length === 2 ? nodeList : null; 91 }); 92 93 // Check expected results 94 95 is(frames.length, 2, "There should be two frames"); 96 97 let columnHeaders = Array.prototype.map.call( 98 document.querySelectorAll( 99 "#messages-view .message-list-headers .button-text" 100 ), 101 node => node.textContent 102 ); 103 104 is( 105 shallowEqual(columnHeaders, [ 106 "Data", 107 "Size", 108 "OpCode", 109 "MaskBit", 110 "FinBit", 111 "Time", 112 ]), 113 true, 114 "WS Column headers are in correct order" 115 ); 116 117 // Get column values of first row for WS. 118 let columnValues = Array.prototype.map.call(frames, frame => 119 Array.prototype.map.call( 120 frame.querySelectorAll(".message-list-column"), 121 column => column.textContent.trim() 122 ) 123 )[0]; 124 125 is( 126 shallowEqual(columnValues, [ 127 "Payload 0", 128 "9 B", 129 "1", 130 "true", 131 "true", 132 // Time format is "hh:mm:ss.mmm". 133 /\d+:\d+:\d+\.\d+/, 134 ]), 135 true, 136 "WS Column values are in correct order" 137 ); 138 139 // Select the SSE request. 140 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[1]); 141 142 store.dispatch(Actions.toggleMessageColumn("lastEventId")); 143 store.dispatch(Actions.toggleMessageColumn("eventName")); 144 store.dispatch(Actions.toggleMessageColumn("retry")); 145 146 await waitFor( 147 () => 148 document.querySelectorAll( 149 "#messages-view .message-list-headers .button-text" 150 ).length === 5 151 ); 152 frames = document.querySelectorAll( 153 "#messages-view .message-list-table .message-list-item" 154 ); 155 156 columnHeaders = Array.prototype.map.call( 157 document.querySelectorAll( 158 "#messages-view .message-list-headers .button-text" 159 ), 160 node => node.textContent 161 ); 162 163 is( 164 shallowEqual(columnHeaders, [ 165 "Data", 166 "Time", 167 "Event Name", 168 "Last Event ID", 169 "Retry", 170 ]), 171 true, 172 "SSE Column headers are in correct order" 173 ); 174 175 // Get column values of first row for SSE. 176 columnValues = Array.prototype.map.call(frames, frame => 177 Array.prototype.map.call( 178 frame.querySelectorAll(".message-list-column"), 179 column => column.textContent.trim() 180 ) 181 )[0]; 182 183 is( 184 shallowEqual(columnValues, [ 185 "Why so serious?", 186 /\d+:\d+:\d+\.\d+/, 187 "message", 188 "", 189 "5000", 190 ]), 191 true, 192 "SSE Column values are in correct order" 193 ); 194 195 // Select the WS request again. 196 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]); 197 is( 198 shallowEqual(store.getState().messages.columns, { 199 data: true, 200 time: true, 201 size: true, 202 opCode: true, 203 maskBit: true, 204 finBit: true, 205 }), 206 true, 207 "WS columns should persist after request switch" 208 ); 209 210 // Select the SSE request again. 211 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[1]); 212 is( 213 shallowEqual(store.getState().messages.columns, { 214 data: true, 215 time: true, 216 size: false, 217 lastEventId: true, 218 eventName: true, 219 retry: true, 220 }), 221 true, 222 "SSE columns should persist after request switch" 223 ); 224 225 // Reset SSE columns. 226 store.dispatch(Actions.resetMessageColumns()); 227 228 // Switch to WS request again. 229 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]); 230 is( 231 shallowEqual(store.getState().messages.columns, { 232 data: true, 233 time: true, 234 size: true, 235 opCode: true, 236 maskBit: true, 237 finBit: true, 238 }), 239 true, 240 "WS columns should not reset after resetting SSE columns" 241 ); 242 243 // Reset WS columns. 244 store.dispatch(Actions.resetMessageColumns()); 245 246 // Switch to SSE request again. 247 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[1]); 248 is( 249 shallowEqual(store.getState().messages.columns, { 250 data: true, 251 time: true, 252 size: false, 253 lastEventId: false, 254 eventName: false, 255 retry: false, 256 }), 257 true, 258 "SSE columns' reset state should persist after request switch" 259 ); 260 261 // Switch to WS request again. 262 EventUtils.sendMouseEvent({ type: "mousedown" }, requests[0]); 263 is( 264 shallowEqual(store.getState().messages.columns, { 265 data: true, 266 time: true, 267 size: false, 268 opCode: false, 269 maskBit: false, 270 finBit: false, 271 }), 272 true, 273 "WS columns' reset state should persist after request switch" 274 ); 275 276 // Close WS connection. 277 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 278 await content.wrappedJSObject.closeWsConnection(); 279 }); 280 281 return teardown(monitor); 282 });