File: largest_contentful_paint.html

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (175 lines) | stat: -rw-r--r-- 5,545 bytes parent folder | download | duplicates (7)
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
169
170
171
172
173
174
175
<script src="resources/testharness.js"></script>
<script>
// Tell testharness.js to not wait for 'real' tests; we only want
// testharness.js for its assertion helpers.
setup({'output': false});
</script>

<script>
  // 'AsyncBuffer' serves as a helper to buffer LCP reports asynchronously.
  class AsyncBuffer {
    constructor() {
      // 'pending' is an array that will buffer entries reported through the
      // PerformanceObserver and can be collected with 'pop'.
      this.pending = [];

      // 'resolve_fn' is a reference to the 'resolve' function of a
      // Promise that blocks for new entries to arrive via 'push()'. Calling
      // the function resolves the promise and unblocks calls to 'pop()'.
      this.resolve_fn = null;
    }

    // Concatenates the given 'entries' list to this AsyncBuffer.
    push(entries) {
      if (entries.length == 0) {
        throw new Error("Must not push an empty list of entries!");
      }
      this.pending = this.pending.concat(entries);

      // If there are calls to 'pop' that are blocked waiting for items, signal
      // that they can continue.
      if (this.resolve_fn != null) {
        this.resolve_fn();
        this.resolve_fn = null;
      }
    }

    // Takes the current pending entries from this AsyncBuffer. If there are no
    // entries queued already, this will block until some show up.
    async pop() {
      if (this.pending.length == 0) {
        // Need to instantiate a promise to block on. The next call to 'push'
        // will resolve the promise once it has queued the entries.
        await new Promise(resolve => {
          this.resolve_fn = resolve;
        });
      }
      assert_true(this.pending.length > 0);

      const result = this.pending;
      this.pending = [];
      return result;
    }
  }

  const buffer = new AsyncBuffer();
  const po = new PerformanceObserver(entryList => {
    buffer.push(entryList.getEntries());
  });
  po.observe({type: 'largest-contentful-paint', buffered: true});
</script>

<div id="content_div_1"></div>
<div id="content_div_2"></div>

<script>
  const block_for_next_lcp = async () => {
    return buffer.pop().then(seen_events => {
      // This test case assumes each LCP entry is handled before the next could
      // possibly be generated.
      assert_equals(seen_events.length, 1);
      return seen_events[0];
    });
  };

  // Adds the first image "lcp-16x16.png" to "content_div_1". We expect this
  // operation to trigger a new LCP entry.
  const add_first_image = () => {
    let img = document.createElement("img");
    content_div_1.appendChild(img);
    img.src = "images/lcp-16x16.png";
  };

  // Adds another image that is larger than "lcp-16x16.png". We expect this
  // operation to trigger a new LCP entry.
  const add_larger_image = () => {
    let new_img = document.createElement("img");
    content_div_2.appendChild(new_img);
    new_img.src = "images/lcp-96x96.png";
    new_img.id = "larger_image";
  };

  // Adds the largest image. We expect this
  // operation to trigger a new LCP entry.
  const add_largest_image = () => {
    let new_img = document.createElement("img");
    content_div_2.appendChild(new_img);
    new_img.src = "images/lcp-256x256.png";
  };

  // Removes the image added by 'add_larger_image'. We expect this operation to
  // not trigger a new LCP entry.
  const remove_larger_image = () => {
    const larger_image = document.getElementById("larger_image");
    assert_not_equals(larger_image, null);
    content_div_2.removeChild(larger_image);
  };

  const waitForAnimationFrames = frameCount => {
    return new Promise(resolve => {
      const handleFrame = () => {
        if (--frameCount <= 0)
          resolve();
        else
          requestAnimationFrame(handleFrame);
      };
      requestAnimationFrame(handleFrame);
    });
  };

  const test_first_image = async () => {
    // This test exercises the following scenario
    //  - have an initial page load with an image
    //  - assert that LCP fires for that image
    add_first_image();
    const lcp = await block_for_next_lcp();

    // Now that we've run through the scenario and collected our measurements,
    // return them in a structure that the C++ side can easily query.
    let output = [
    // lcp
    {
      url: lcp.url,
      time: lcp.startTime
    }];
    return output;
  };
  const test_larger_image = async () => {
    // This test exercises the following scenario
    //  - add a larger image to the page
    //  - assert that LCP fires for the new image
    //  - remove the larger image
    //  - wait for some rAFs
    add_larger_image();
    const lcp = await block_for_next_lcp();
    remove_larger_image();
    await waitForAnimationFrames(3);

    // Now that we've run through the scenario and collected our measurements,
    // return them in a structure that the C++ side can easily query.
    let output = [
    // lcp
    {
      url: lcp.url,
      time: lcp.startTime
    }];
    return output;
  };
  const test_largest_image = async () => {
    // This test exercises the following scenario
    //  - add the largest image to the page
    //  - assert that the new LCP is for the largest
    add_largest_image();
    const lcp = await block_for_next_lcp();

    // Now that we've run through the scenario and collected our measurements,
    // return them in a structure that the C++ side can easily query.
    let output = [
    // lcp
    {
      url: lcp.url,
      time: lcp.startTime
    }];
    return output;
  };
</script>