Skip to content

Commit

Permalink
prerender: Verify the order of extension WebNavigation events for
Browse files Browse the repository at this point in the history
prerendering.

This CL adds a test that verify the order of the extension events
of WebNavigation for prerendering.

Bug: 1278141
Change-Id: I87db71fffe8531aa8141d0e814f23fffa4d0ff00
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3715913
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Commit-Queue: Huanpo Lin <robertlin@chromium.org>
Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1034964}
  • Loading branch information
Robert Lin authored and Chromium LUCI CQ committed Aug 15, 2022
1 parent d7ab532 commit 0beff9e
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ class WebNavigationApiTest : public ExtensionApiTest {
// with deferred commits.
command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
}

content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
};

class WebNavigationApiBackForwardCacheTest : public WebNavigationApiTest {
Expand All @@ -249,30 +253,35 @@ class WebNavigationApiTestWithContextType
: public WebNavigationApiTest,
public testing::WithParamInterface<ContextType> {
public:
WebNavigationApiTestWithContextType()
: WebNavigationApiTest(GetParam()),
prerender_helper_(base::BindRepeating(
&WebNavigationApiTestWithContextType::GetWebContents,
base::Unretained(this))) {}
WebNavigationApiTestWithContextType() : WebNavigationApiTest(GetParam()) {}
~WebNavigationApiTestWithContextType() override = default;
WebNavigationApiTestWithContextType(
const WebNavigationApiTestWithContextType&) = delete;
WebNavigationApiTestWithContextType& operator=(
const WebNavigationApiTestWithContextType&) = delete;

content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}

protected:
[[nodiscard]] bool RunTest(const char* name,
bool allow_in_incognito = false) {
return RunExtensionTest(name, {},
{.allow_in_incognito = allow_in_incognito});
}
};

class WebNavigationApiPrerenderTestWithContextType
: public WebNavigationApiTest,
public testing::WithParamInterface<ContextType> {
public:
WebNavigationApiPrerenderTestWithContextType()
: WebNavigationApiTest(GetParam()) {}
~WebNavigationApiPrerenderTestWithContextType() override = default;
WebNavigationApiPrerenderTestWithContextType(
const WebNavigationApiPrerenderTestWithContextType&) = delete;
WebNavigationApiPrerenderTestWithContextType& operator=(
const WebNavigationApiPrerenderTestWithContextType&) = delete;

private:
content::test::PrerenderTestHelper prerender_helper_;
content::test::ScopedPrerenderFeatureList prerender_feature_list_;
};

IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, Api) {
Expand All @@ -284,6 +293,17 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, GetFrame) {
ASSERT_TRUE(RunExtensionTest("webnavigation/getFrame")) << message_;
}

IN_PROC_BROWSER_TEST_P(WebNavigationApiPrerenderTestWithContextType, GetFrame) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunExtensionTest("webnavigation/getFrame")) << message_;
}

IN_PROC_BROWSER_TEST_P(WebNavigationApiPrerenderTestWithContextType,
Prerendering) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunExtensionTest("webnavigation/prerendering")) << message_;
}

IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, GetFrameIncognito) {
ASSERT_TRUE(StartEmbeddedTestServer());

Expand All @@ -304,6 +324,12 @@ INSTANTIATE_TEST_SUITE_P(PersistentBackground,
INSTANTIATE_TEST_SUITE_P(ServiceWorker,
WebNavigationApiTestWithContextType,
testing::Values(ContextType::kServiceWorker));
INSTANTIATE_TEST_SUITE_P(PersistentBackground,
WebNavigationApiPrerenderTestWithContextType,
testing::Values(ContextType::kPersistentBackground));
INSTANTIATE_TEST_SUITE_P(ServiceWorker,
WebNavigationApiPrerenderTestWithContextType,
testing::Values(ContextType::kServiceWorker));

IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, ClientRedirect) {
ASSERT_TRUE(RunExtensionTest("webnavigation/clientRedirect")) << message_;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<html></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "webNavigation",
"version": "1.0",
"manifest_version": 2,
"description": "Tests the webNavigation API events - prerendering.",
"background": {
"scripts": ["test_prerendering.js"],
"persistent": false
},
"permissions": ["webNavigation", "tabs", "<all_urls>"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script type="speculationrules">
{
"prerender":[
{"source": "list",
"urls": ["a.html"]}
]
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

const inServiceWorker = 'ServiceWorkerGlobalScope' in self;
const scriptUrl = '_test_resources/api_test/webnavigation/framework.js';
let ready;
const onScriptLoad = chrome.test.loadScript(scriptUrl);

if (inServiceWorker) {
ready = onScriptLoad;
} else {
let onWindowLoad = new Promise((resolve) => {
window.onload = resolve;
});
ready = Promise.all([onWindowLoad, onScriptLoad]);
}

ready.then(async function() {
const config = await promise(chrome.test.getConfig);
const port = config.testServer.port;

// This test verifies the order of events of the first prerendering frame
// and the prerender activation. The order of the first prerendering
// navigation is onBeforeNavigate => onCommitted, and the one of the
// prerendering activation is onBeforeNavigate => onCommitted =>
// onDOMContentLoaded => onCompleted. DOMContentLoaded is dipatched on
// activation, because this is to avoid notifying observers about a load event
// triggered from an inactive RenderFrameHost.
chrome.test.runTests([
async function testVerifyPrerenderingFramesCallbackOrder() {
const urlPrefix =
`http://a.test:${port}/extensions/api_test/webnavigation/prerendering/`;
const prerenderTargetUrl = urlPrefix + 'a.html';
const initiatorUrl = urlPrefix + 'prerender.html';
let expectedEvents = [
// events
{
label: 'onBeforeNavigate-1',
event: 'onBeforeNavigate',
details: {
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: -1,
tabId: 0,
timeStamp: 0,
url: initiatorUrl
}
},
{
label: 'onCommitted-1',
event: 'onCommitted',
details: {
documentId: 1,
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 0,
tabId: 0,
timeStamp: 0,
transitionQualifiers:[],
transitionType:"link",
url: initiatorUrl
}
},
{
label: 'onDOMContentLoaded-1',
event: 'onDOMContentLoaded',
details: {
documentId: 1,
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 0,
tabId: 0,
timeStamp: 0,
url: initiatorUrl
}
},
{
label: 'onCompleted-1',
event: 'onCompleted',
details: {
documentId: 1,
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 0,
tabId: 0,
timeStamp: 0,
url: initiatorUrl
}
},
{
label: 'onBeforeNavigate-2',
event: 'onBeforeNavigate',
details: {
documentLifecycle: 'prerender',
frameId: 1,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: -1,
tabId: 0,
timeStamp: 0,
url: prerenderTargetUrl
}
},
{
label: 'onCommitted-2',
event: 'onCommitted',
details: {
documentId: 2,
documentLifecycle: 'prerender',
frameId: 1,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 1,
tabId: 0,
timeStamp: 0,
transitionQualifiers:[],
transitionType:"link",
url: prerenderTargetUrl
}
},
{
label: 'onBeforeNavigate-3',
event: 'onBeforeNavigate',
details: {
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: -1,
tabId: 0,
timeStamp: 0,
url: prerenderTargetUrl
}
},
{
label: 'onCommitted-3',
event: 'onCommitted',
details: {
documentId: 2,
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 1,
tabId: 0,
timeStamp: 0,
transitionQualifiers:[],
transitionType:"link",
url: prerenderTargetUrl
}
},
{
label: 'onDOMContentLoaded-3',
event: 'onDOMContentLoaded',
details: {
documentId: 2,
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 1,
tabId: 0,
timeStamp: 0,
url: prerenderTargetUrl
}
},
{
label: 'onCompleted-3',
event: 'onCompleted',
details: {
documentId: 2,
documentLifecycle: 'active',
frameId: 0,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 1,
tabId: 0,
timeStamp: 0,
url: prerenderTargetUrl
}
},
];

let expectedPrerenderedOrder = ['onBeforeNavigate-2', 'onCommitted-2'];

if (!inServiceWorker) {
expectedEvents.push(
// TODO(crbug.com/1349987): Remove this expectation when the crbug
// is fixed.
{
label: 'onCommitted-2-activation-callback',
event: 'onCommitted',
details: {
documentId: 2,
documentLifecycle: 'prerender',
frameId: 1,
frameType: 'outermost_frame',
parentFrameId: -1,
processId: 1,
tabId: 0,
timeStamp: 0,
transitionQualifiers:[],
transitionType:"link",
url: prerenderTargetUrl
}
});
expectedPrerenderedOrder.push('onCommitted-2-activation-callback');
}

expect(
expectedEvents,
[
// Events
// *-1: for navigate to the initiator page.
// *-2: for prerendering.
// *-3: for prerendering activation.
['onBeforeNavigate-1', 'onCommitted-1',
'onDOMContentLoaded-1', 'onCompleted-1'],
expectedPrerenderedOrder,
['onBeforeNavigate-3', 'onCommitted-3',
'onDOMContentLoaded-3', 'onCompleted-3'],
['onBeforeNavigate-1', 'onBeforeNavigate-2', 'onBeforeNavigate-3']
],
{ urls: ['<all_urls>'] }, // filter
[]);

const activationCallback = details => {
chrome.test.assertEq('prerender', details.documentLifecycle);
chrome.tabs.executeScript({
code: `location.href = '${prerenderTargetUrl}';`,
runAt: 'document_idle'
});
chrome.webNavigation.onCommitted.removeListener(activationCallback);
};

chrome.webNavigation.onCommitted.addListener(
activationCallback, {url: [{pathContains: '/a.html'}]});

// Navigate to a page that initiates prerendering "a.html".
let tab = await promise(chrome.tabs.create, {"url": initiatorUrl});
},
]);
});

0 comments on commit 0beff9e

Please sign in to comment.