summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/browsers/browsing-the-web/back-forward-cache/storage-events.html
blob: 6957496c3077acd5e87fa3127febfbcbbfb80099 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<!DOCTYPE HTML>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="resources/helper.sub.js"></script>
<script>
// When localStorage (`key1`) is modified when a page (`pageA`) is in BFCache,
// storage events should not be fired for the page after becoming active.
// https://github.com/whatwg/storage/issues/119#issuecomment-1115844532
promise_test(async t => {
  const pageA = new RemoteContext(token());
  const pageB = new RemoteContext(token());
  const pageC = new RemoteContext(token());

  const urlA = executorPath + pageA.context_id + '&events=pagehide,pageshow,load';
  const urlB = originCrossSite + executorPath + pageB.context_id;
  const urlC = executorPath + pageC.context_id + '&events=pagehide,pageshow,load';

  // localStorage key to set while pageA is in BFCache.
  const key1 = token();
  // localStorage key to set after pageA is restored from BFCache.
  const key2 = token();

  const startRecordingStorageEvent = (key1, key2) => {
    window.key1EventFired = new Promise(resolve => {
      window.addEventListener('storage', e => {
        if (e.key === key1) {
          recordEvent('storage1');
          resolve();
        }
      });
    });
    window.key2EventFired = new Promise(resolve => {
      window.addEventListener('storage', e => {
        if (e.key === key2) {
          recordEvent('storage2');
          resolve();
        }
      });
    });
  };

  window.open(urlA, '_blank', 'noopener');
  await pageA.execute_script(waitForPageShow);
  await pageA.execute_script(startRecordingStorageEvent, [key1, key2]);

  // Window C is an unrelated window kept open without navigation, to confirm
  // that storage events are fired as expected in non-BFCache-related scenario
  // and not blocked due to non-BFCache-related reasons.
  window.open(urlC, '_blank');
  await pageC.execute_script(waitForPageShow);
  await pageC.execute_script(startRecordingStorageEvent, [key1, key2]);

  // Navigate A to B.
  await pageA.execute_script((url) => {
    prepareNavigation(() => {
      location.href = url;
    });
  }, [urlB]);
  await pageB.execute_script(waitForPageShow);

  // Update `key1` while pageA is in BFCache.
  localStorage.setItem(key1, 'value');

  // Wait for a storage event is fired on PageC and a while,
  // to prevent race conditions between event processing
  // triggered by `setItem()` and the following operations.
  await pageC.execute_script(() => window.key1EventFired);
  await new Promise(resolve => t.step_timeout(resolve, 1000));

  // Back navigate to pageA, to be restored from BFCache.
  await pageB.execute_script(
    () => {
      prepareNavigation(() => { history.back(); });
    }
  );
  await pageA.execute_script(waitForPageShow);
  await assert_bfcached(pageA);

  // Update `key2` after pageA is restored from BFCache.
  localStorage.setItem(key2, 'value');

  // Wait for a storage event for `key2` is fired on PageA.
  await pageA.execute_script(() => window.key2EventFired);

  // Confirm that a storage event for `key1` is not fired on PageA.
  assert_array_equals(
    await pageA.execute_script(() => getRecordedEvents()),
    [
      'window.load',
      'window.pageshow',
      'window.pagehide.persisted',
      'window.pageshow.persisted',
      'storage2',
    ],
    'pageA should not receive storage events for updates while in BFCache');

}, 'Storage events should not be fired for BFCached pages after becoming active');
</script>