overwriting-text.html (3731B)
1 <!DOCTYPE html> 2 <meta charset="utf-8" /> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script src="/resources/testdriver.js"></script> 6 <script src="/resources/testdriver-vendor.js"></script> 7 <script src="/soft-navigation-heuristics/resources/soft-navigation-test-helper.js"></script> 8 9 <button id="navigateButton">Click here!</button> 10 <h1>Heading!</h1> 11 <div id="content" elementtiming="content-text">Initial Text</div> 12 <div id="container"></div> 13 14 <script> 15 async function waitForExactlyOneElementTimingEntry(id, buffered) { 16 let entries = await new Promise(resolve => { 17 new PerformanceObserver((list, observer) => { 18 resolve(list.getEntries()); 19 observer.disconnect(); 20 }).observe({type: 'element', buffered}); 21 }); 22 assert_equals( 23 entries.length, 1, 24 `Expected exactly one ElementTiming entry for "${id}"`); 25 assert_equals( 26 entries[0].identifier, id, 27 `Unexpected ElementTiming entry: expected "${id}"`); 28 } 29 30 async function runTest(t, url, text) { 31 navigateButton.addEventListener('click', async () => { 32 // We expect to get a timing entry for this, but not a soft nav ICP entry. 33 // This lets us check that we don't get more than the initial timing entry 34 // for `content`. 35 const div = document.createElement("div"); 36 div.innerHTML = `<div id="additional" elementtiming="${url}">hi</div>`; 37 container.appendChild(div); 38 39 content.innerText = text; 40 41 history.pushState({}, '', url); 42 }, {once: true}); 43 44 // Set up the PerformanceObservers before clicking to avoid races, 45 // and use unbuffered here so we don't get duplicate entries. 46 const elementTimingPromise = 47 waitForExactlyOneElementTimingEntry(url, /*buffered=*/false); 48 const softNavPromise = 49 SoftNavigationTestHelper.getPerformanceEntries("soft-navigation"); 50 const icpPromise = 51 SoftNavigationTestHelper.getPerformanceEntries("interaction-contentful-paint"); 52 53 if (test_driver) { 54 test_driver.click(navigateButton); 55 } 56 57 const helper = new SoftNavigationTestHelper(t); 58 59 // Check if we detected a soft nav. 60 const softNavs = await helper.withTimeoutMessage( 61 softNavPromise, "Soft navigation not detected.", /*timeout=*/ 3000); 62 assert_equals(softNavs.length, 1, 'Expected exactly one soft navigation.'); 63 assert_true( 64 softNavs[0].name.endsWith(url), 65 `Unexpected Soft Navigation URL. Expected url to end with ${url} but got ${softNavs[0].name}`); 66 67 // Check that we only get one ICP entry, and that it's for the node whose 68 // text we overwrote. 69 const icps = await helper.withTimeoutMessage( 70 icpPromise, 'ICP not detected.', /*timeout=*/ 3000); 71 assert_equals(icps.length, 1, 'Expected exactly one ICP entry.'); 72 assert_equals(icps[0].id, 'content', 'Expected ICP candidate to be "content"'); 73 74 // Finally, check to make sure we don't get an additional timing entry. 75 return elementTimingPromise; 76 } 77 78 // Wait for the initial text load and make its way through the text timing 79 // pipeline before changing its contents. 80 promise_setup(() => waitForExactlyOneElementTimingEntry('content-text', /*buffered=*/true)); 81 82 promise_test(t => { 83 const url = 'soft-nav-1'; 84 const text = 'The initial text has been replaced!'; 85 return runTest(t, url, text); 86 }, 'Soft Navigation Detection supports replacing existing text'); 87 88 promise_test(t => { 89 const url = 'soft-nav-2'; 90 const text = 'The initial text has been replaced again!'; 91 return runTest(t, url, text); 92 }, 'Soft Navigation Detection supports replacing existing text in multiple interactions'); 93 </script>