summaryrefslogtreecommitdiff
path: root/dom/html/test/test_fullscreen-api-race.html
blob: 6664e2ab526614d6ea0fa801bae7b287d8064c4c (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<!DOCTYPE html>
<html>
<head>
  <title>Test for race conditions of Fullscreen API</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/EventUtils.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script>

function Deferred() {
  this.promise = new Promise(resolve => {
    this.resolve = resolve;
  });
}

function checkIsChromeFullscreen(win, inFullscreen) {
  return SimpleTest.promiseWaitForCondition(
    () => win.fullScreen == inFullscreen,
    "The window should exit fullscreen state");
}

SimpleTest.waitForExplicitFinish();
// XXX This actually exposes a true race condition, but it could rarely
// happen in real world, because it only happens when requestFullscreen
// is called immediately after exiting fullscreen in certain condition,
// and in real life, requestFullscreen can only be called inside a user
// event handler. But we want to fix this race condition at some point,
// via queuing all exiting request as well as entering request together
// which we may eventually need to do for bug 1188256.
SimpleTest.requestFlakyTimeout(
  "Need to wait for potential fullscreen transition");
addLoadEvent(function () {
  SpecialPowers.pushPrefEnv({
    "set": [
      ["full-screen-api.unprefix.enabled", true],
      ["full-screen-api.allow-trusted-requests-only", false],
      // Use legacy data: URI behavior to run test.
      ["security.data_uri.block_toplevel_data_uri_navigations", false]
    ]
  }, next);
});

const OPEN_WINDOW_FUNCS = [
  function openNewTab() {
    return window.open("about:blank");
  },
  function openNewWindow() {
    return window.open("about:blank", "", "width=300,height=200");
  }
];

const ACTION_FUNCS = [
  function navigate(win) {
    info("About to navigate to another page");
    var deferred = new Deferred();
    win.location = "data:text/html,<html>";
    setTimeout(() => {
      SimpleTest.waitForFocus(() => {
        checkIsChromeFullscreen(win, false).then(() => {
          win.close();
          deferred.resolve();
        });
      }, win);
    }, 0);
    return deferred.promise;
  },
  function closeWindow(win) {
    info("About to close the window");
    win.close();
    return Promise.resolve();
  },
  function exitFullscreen(win) {
    info("About to cancel fullscreen");
    var deferred = new Deferred();
    function listener() {
      win.removeEventListener("fullscreenchange", listener);
      ok(!win.document.fullscreenElement, "Should exit fullscreen");
      checkIsChromeFullscreen(win, false).then(() => {
        win.close();
        deferred.resolve();
      });
    }
    win.addEventListener("fullscreenchange", listener);
    win.document.exitFullscreen();
    return deferred.promise;
  },
  function exitAndClose(win) {
    info("About to cancel fullscreen and close the window");
    win.document.exitFullscreen();
    win.close();
    return Promise.resolve();
  }
];

function* testGenerator() {
  for (var openWinFunc of OPEN_WINDOW_FUNCS) {
    for (var actionFunc of ACTION_FUNCS) {
      info(`Testing ${openWinFunc.name}, ${actionFunc.name}`);
      yield { openWinFunc: openWinFunc, actionFunc: actionFunc };
    }
  }
}

function runTest(test) {
  var win = test.openWinFunc();
  return new Promise(resolve => {
    SimpleTest.waitForFocus(resolve, win, true);
  }).then(() => {
    return new Promise((resolve, reject) => {
      var retried = false;
      function listener(evt) {
        if (!retried && evt.type == "fullscreenerror") {
          todo(false, "Failed to enter fullscreen, but try again");
          retried = true;
          SimpleTest.waitForFocus(() => {
            win.document.documentElement.requestFullscreen();
          }, win, true);
          return;
        }
        win.removeEventListener("fullscreenchange", listener);
        win.removeEventListener("fullscreenerror", listener);
        is(evt.type, "fullscreenchange", "Should get fullscreenchange");
        ok(win.document.fullscreenElement, "Should have entered fullscreen");
        ok(win.fullScreen, "The window should be in fullscreen");
        test.actionFunc(win).then(resolve);
      }
      if (win.fullScreen) {
        todo(false, "Should not open in fullscreen mode");
        win.close();
        reject();
        return;
      }
      info("About to enter fullscreen");
      win.addEventListener("fullscreenchange", listener);
      win.addEventListener("fullscreenerror", listener);
      win.document.documentElement.requestFullscreen();
    });
  }).then(() => {
    ok(win.closed, "The window should have been closed");
  });
}

var tests = testGenerator();

function next() {
  var test = tests.next().value;
  if (test) {
    runTest(test).catch(() => {
      return new Promise(resolve => {
        SimpleTest.waitForFocus(resolve);
      }).then(() => runTest(test));
    }).catch(() => {
      ok(false, "Fail to run test " +
         `${test.openWinFunc.name}, ${test.actionFunc.name}`);
    }).then(() => {
      setTimeout(() => SimpleTest.waitForFocus(next), 1000);
    });
  } else {
    SimpleTest.finish();
    return;
  }
}

</script>
</body>
</html>