summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/long-animation-frame/tentative/resources/utils.js
blob: 8781252e9411fcb3bf2423347e185e2633ef0140 (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
const windowLoaded = new Promise(resolve => window.addEventListener('load', resolve));
setup(() =>
  assert_implements(window.PerformanceLongAnimationFrameTiming,
    'Long animation frames are not supported.'));

const very_long_frame_duration = 360;
const no_long_frame_timeout = very_long_frame_duration * 3;
const waiting_for_long_frame_timeout = very_long_frame_duration * 10;

function loaf_promise(t) {
  return new Promise(resolve => {
      const observer = new PerformanceObserver(entries => {
          const entry = entries.getEntries()[0];
          // TODO: understand why we need this 5ms epsilon.
          if (entry.duration > very_long_frame_duration - 5) {
            observer.disconnect();
            resolve(entry);
          }
      });

      t.add_cleanup(() => observer.disconnect());

      observer.observe({entryTypes: ['long-animation-frame']});
  });
}

function busy_wait(ms_delay = very_long_frame_duration) {
  const deadline = performance.now() + ms_delay;
  while (performance.now() < deadline) {}
}

async function expect_long_frame(cb, t) {
  await windowLoaded;
  await new Promise(resolve => t.step_timeout(resolve, 0));
  const timeout = new Promise((resolve, reject) =>
    t.step_timeout(() => resolve("timeout"), waiting_for_long_frame_timeout));
  const receivedLongFrame = loaf_promise(t);
  await cb(t);
  const entry = await Promise.race([
    receivedLongFrame,
    timeout
  ]);
  return entry;
}

async function expect_long_frame_with_script(cb, predicate, t) {
  for (let i = 0; i < 10; ++i) {
      const entry = await expect_long_frame(cb, t);
      if (entry === "timeout" || !entry.scripts.length)
        continue;
      for (const script of entry.scripts) {
        if (predicate(script))
          return [entry, script];
      }
  }

  return [];
}

async function expect_no_long_frame(cb, t) {
  await windowLoaded;
  for (let i = 0; i < 5; ++i) {
    const receivedLongFrame = loaf_promise(t);
    await cb();
    const result = await Promise.race([receivedLongFrame,
        new Promise(resolve => t.step_timeout(() => resolve("timeout"),
        no_long_frame_timeout))]);
    if (result === "timeout")
      return false;
  }

  throw new Error("Consistently creates long frame");
}

async function prepare_exec_iframe(t, origin) {
  const iframe = document.createElement("iframe");
  t.add_cleanup(() => iframe.remove());
  const url = new URL("/common/dispatcher/remote-executor.html", origin);
  const uuid = token();
  url.searchParams.set("uuid", uuid);
  iframe.src = url.href;
  document.body.appendChild(iframe);
  await new Promise(resolve => iframe.addEventListener("load", resolve));
  return [new RemoteContext(uuid), iframe];
}


async function prepare_exec_popup(t, origin) {
  const url = new URL("/common/dispatcher/remote-executor.html", origin);
  const uuid = token();
  url.searchParams.set("uuid", uuid);
  const popup = window.open(url);
  t.add_cleanup(() => popup.close());
  return [new RemoteContext(uuid), popup];
}
function test_loaf_script(cb, name, type, label) {
  promise_test(async t => {
    let [entry, script] = [];
    [entry, script] = await expect_long_frame_with_script(cb,
      script => (
        script.type === type &&
        script.name.startsWith(name) &&
        script.duration >= very_long_frame_duration), t);

    assert_true(!!entry, "Entry detected");
    assert_greater_than_equal(script.duration, very_long_frame_duration);
    assert_greater_than_equal(entry.duration, script.duration);
    assert_greater_than_equal(script.executionStart, script.startTime);
    assert_greater_than_equal(script.startTime, entry.startTime)
    assert_equals(script.window, window);
    assert_equals(script.forcedStyleAndLayoutDuration, 0);
    assert_equals(script.windowAttribution, "self");
}, `LoAF script: ${name} ${type},${label ? ` ${label}` : ''}`);

}

function test_self_user_callback(cb, name, label) {
    test_loaf_script(cb, name, "user-callback", label);
}

function test_self_event_listener(cb, name) {
  test_loaf_script(cb, name, "event-listener");
}

function test_promise_script(cb, resolve_or_reject, name, label) {
  test_loaf_script(cb, name, `${resolve_or_reject}-promise`, label);
}

function test_self_script_block(cb, name, type) {
  test_loaf_script(cb, name, type);
}