blob: 6d1f0de56509d50823b46566c1478ba3ed60477c [file] [log] [blame]
// Copyright 2018 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.
#include <string>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/platform_notification_context.h"
#include "content/public/browser/service_worker_context_observer.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/service_worker_test_helpers.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_content_browser_client.h"
#include "content/test/test_content_browser_client.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
#include "url/gurl.h"
namespace content {
// Tests for the service worker Clients API.
class ServiceWorkerClientsApiBrowserTest : public ContentBrowserTest {
public:
ServiceWorkerClientsApiBrowserTest() = default;
void SetUp() override {
ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
ContentBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
embedded_test_server()->StartAcceptingConnections();
StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
shell()->web_contents()->GetBrowserContext());
wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
partition->GetServiceWorkerContext());
}
ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
private:
scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerClientsApiBrowserTest);
};
// Tests a successful WindowClient.navigate() call.
IN_PROC_BROWSER_TEST_F(ServiceWorkerClientsApiBrowserTest, Navigate) {
// Load a page that registers a service worker.
EXPECT_TRUE(NavigateToURL(shell(),
embedded_test_server()->GetURL(
"/service_worker/create_service_worker.html")));
EXPECT_EQ("DONE", EvalJs(shell(), "register('client_api_worker.js');"));
// Load the page again so we are controlled.
EXPECT_TRUE(NavigateToURL(shell(),
embedded_test_server()->GetURL(
"/service_worker/create_service_worker.html")));
EXPECT_EQ(true, EvalJs(shell(), "!!navigator.serviceWorker.controller"));
// Have the service worker call client.navigate() on the page.
const std::string navigate_script = R"(
(async () => {
const registration = await navigator.serviceWorker.ready;
registration.active.postMessage({command: 'navigate', url: 'empty.html'});
return true;
})();
)";
EXPECT_EQ(true, EvalJs(shell(), navigate_script));
// The page should be navigated to empty.html.
const base::string16 title =
base::ASCIIToUTF16("ServiceWorker test - empty page");
TitleWatcher title_watcher(shell()->web_contents(), title);
EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
}
// Tests a WindowClient.navigate() call during a browser-initiated navigation.
// Regression test for https://crbug.com/930154.
IN_PROC_BROWSER_TEST_F(ServiceWorkerClientsApiBrowserTest,
NavigateDuringBrowserNavigation) {
// Load a page that registers a service worker.
EXPECT_TRUE(NavigateToURL(shell(),
embedded_test_server()->GetURL(
"/service_worker/create_service_worker.html")));
EXPECT_EQ("DONE", EvalJs(shell(), "register('client_api_worker.js');"));
// Load the test page.
EXPECT_TRUE(NavigateToURL(
shell(),
embedded_test_server()->GetURL("/service_worker/request_navigate.html")));
// Start a browser-initiated navigation.
GURL url(embedded_test_server()->GetURL("/title1.html"));
TestNavigationManager navigation(shell()->web_contents(), url);
shell()->LoadURL(url);
EXPECT_TRUE(navigation.WaitForRequestStart());
// Have the service worker call client.navigate() to try to go to another
// URL. It should fail.
EXPECT_EQ("navigate failed", EvalJs(shell(), "requestToNavigate();"));
// The browser-initiated navigation should finish.
navigation.WaitForNavigationFinished(); // Resume navigation.
EXPECT_TRUE(navigation.was_successful());
}
// Tests a successful Clients.openWindow() call.
IN_PROC_BROWSER_TEST_F(ServiceWorkerClientsApiBrowserTest, OpenWindow) {
// Load a page that registers a service worker.
GURL page_url = embedded_test_server()->GetURL(
"/service_worker/create_service_worker.html");
EXPECT_TRUE(NavigateToURL(shell(), page_url));
EXPECT_EQ("DONE", EvalJs(shell(), "register('client_api_worker.js');"));
// Tell the service worker to call clients.openWindow(target_url). Do it from
// a notification click event so it has a user interaction token that allows
// popups.
content::WebContents* new_window = nullptr;
GURL target_url =
embedded_test_server()->GetURL("/service_worker/empty.html");
{
GURL scope_url = embedded_test_server()->GetURL("/service_worker/");
blink::PlatformNotificationData notification_data;
notification_data.body = base::UTF8ToUTF16(target_url.spec());
content::WebContentsAddedObserver new_window_observer;
content::DispatchServiceWorkerNotificationClick(wrapper(), scope_url,
notification_data);
new_window = new_window_observer.GetWebContents();
}
// Verify that the new window has navigated successfully.
content::TestNavigationObserver nav_observer(new_window, 1);
nav_observer.Wait();
EXPECT_TRUE(nav_observer.last_navigation_succeeded());
EXPECT_EQ(target_url, nav_observer.last_navigation_url());
}
} // namespace content