storage-events.html (3626B)
1 <!DOCTYPE HTML> 2 <meta name="timeout" content="long"> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script src="/common/utils.js"></script> 6 <script src="/common/dispatcher/dispatcher.js"></script> 7 <script src="resources/helper.sub.js"></script> 8 <script> 9 // When localStorage (`key1`) is modified when a page (`pageA`) is in BFCache, 10 // storage events should not be fired for the page after becoming active. 11 // https://github.com/whatwg/storage/issues/119#issuecomment-1115844532 12 promise_test(async t => { 13 const pageA = new RemoteContext(token()); 14 const pageB = new RemoteContext(token()); 15 const pageC = new RemoteContext(token()); 16 17 const urlA = executorPath + pageA.context_id + '&events=pagehide,pageshow,load'; 18 const urlB = originCrossSite + executorPath + pageB.context_id; 19 const urlC = executorPath + pageC.context_id + '&events=pagehide,pageshow,load'; 20 21 // localStorage key to set while pageA is in BFCache. 22 const key1 = token(); 23 // localStorage key to set after pageA is restored from BFCache. 24 const key2 = token(); 25 26 const startRecordingStorageEvent = (key1, key2) => { 27 window.key1EventFired = new Promise(resolve => { 28 window.addEventListener('storage', e => { 29 if (e.key === key1) { 30 recordEvent('storage1'); 31 resolve(); 32 } 33 }); 34 }); 35 window.key2EventFired = new Promise(resolve => { 36 window.addEventListener('storage', e => { 37 if (e.key === key2) { 38 recordEvent('storage2'); 39 resolve(); 40 } 41 }); 42 }); 43 }; 44 45 window.open(urlA, '_blank', 'noopener'); 46 await pageA.execute_script(waitForPageShow); 47 await pageA.execute_script(startRecordingStorageEvent, [key1, key2]); 48 49 // Window C is an unrelated window kept open without navigation, to confirm 50 // that storage events are fired as expected in non-BFCache-related scenario 51 // and not blocked due to non-BFCache-related reasons. 52 window.open(urlC, '_blank'); 53 await pageC.execute_script(waitForPageShow); 54 await pageC.execute_script(startRecordingStorageEvent, [key1, key2]); 55 56 // Navigate A to B. 57 await pageA.execute_script((url) => { 58 prepareNavigation(() => { 59 location.href = url; 60 }); 61 }, [urlB]); 62 await pageB.execute_script(waitForPageShow); 63 64 // Update `key1` while pageA is in BFCache. 65 localStorage.setItem(key1, 'value'); 66 67 // Wait for a storage event is fired on PageC and a while, 68 // to prevent race conditions between event processing 69 // triggered by `setItem()` and the following operations. 70 await pageC.execute_script(() => window.key1EventFired); 71 await new Promise(resolve => t.step_timeout(resolve, 1000)); 72 73 // Back navigate to pageA, to be restored from BFCache. 74 await pageB.execute_script( 75 () => { 76 prepareNavigation(() => { history.back(); }); 77 } 78 ); 79 await pageA.execute_script(waitForPageShow); 80 await assert_bfcached(pageA); 81 82 // Update `key2` after pageA is restored from BFCache. 83 localStorage.setItem(key2, 'value'); 84 85 // Wait for a storage event for `key2` is fired on PageA. 86 await pageA.execute_script(() => window.key2EventFired); 87 88 // Confirm that a storage event for `key1` is not fired on PageA. 89 assert_array_equals( 90 await pageA.execute_script(() => getRecordedEvents()), 91 [ 92 'window.load', 93 'window.pageshow', 94 'window.pagehide.persisted', 95 'window.pageshow.persisted', 96 'storage2', 97 ], 98 'pageA should not receive storage events for updates while in BFCache'); 99 100 }, 'Storage events should not be fired for BFCached pages after becoming active'); 101 </script>