1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/path_service.h"
7 #include "content/public/browser/web_contents.h"
8 #include "content/public/common/content_switches.h"
9 #include "content/public/common/manifest.h"
10 #include "content/public/test/browser_test_utils.h"
11 #include "content/public/test/content_browser_test.h"
12 #include "content/public/test/content_browser_test_utils.h"
13 #include "content/public/test/test_navigation_observer.h"
14 #include "content/shell/browser/shell.h"
15 #include "net/test/embedded_test_server/embedded_test_server.h"
19 class ManifestBrowserTest
;
21 // Mock of a WebContentsDelegate that catches messages sent to the console.
22 class MockWebContentsDelegate
: public WebContentsDelegate
{
24 MockWebContentsDelegate(WebContents
* web_contents
, ManifestBrowserTest
* test
)
25 : web_contents_(web_contents
),
29 bool AddMessageToConsole(WebContents
* source
,
31 const base::string16
& message
,
33 const base::string16
& source_id
) override
;
36 WebContents
* web_contents_
;
37 ManifestBrowserTest
* test_
;
40 class ManifestBrowserTest
: public ContentBrowserTest
{
42 friend MockWebContentsDelegate
;
45 : console_error_count_(0) {
46 cors_embedded_test_server_
.reset(new net::test_server::EmbeddedTestServer
);
47 base::FilePath test_data_dir
;
48 CHECK(PathService::Get(base::DIR_SOURCE_ROOT
, &test_data_dir
));
49 cors_embedded_test_server_
->ServeFilesFromDirectory(
50 test_data_dir
.AppendASCII("content/test/data/"));
53 ~ManifestBrowserTest() override
{}
55 void SetUpOnMainThread() override
{
56 ContentBrowserTest::SetUpOnMainThread();
57 DCHECK(shell()->web_contents());
59 mock_web_contents_delegate_
.reset(
60 new MockWebContentsDelegate(shell()->web_contents(), this));
61 shell()->web_contents()->SetDelegate(mock_web_contents_delegate_
.get());
64 void GetManifestAndWait() {
65 shell()->web_contents()->GetManifest(
66 base::Bind(&ManifestBrowserTest::OnGetManifest
,
67 base::Unretained(this)));
69 message_loop_runner_
= new MessageLoopRunner();
70 message_loop_runner_
->Run();
73 void OnGetManifest(const Manifest
& manifest
) {
75 message_loop_runner_
->Quit();
78 const Manifest
& manifest() const {
82 unsigned int console_error_count() const {
83 return console_error_count_
;
86 void OnReceivedConsoleError() {
87 console_error_count_
++;
90 net::test_server::EmbeddedTestServer
* cors_embedded_test_server() const {
91 return cors_embedded_test_server_
.get();
95 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
96 scoped_ptr
<MockWebContentsDelegate
> mock_web_contents_delegate_
;
97 scoped_ptr
<net::test_server::EmbeddedTestServer
> cors_embedded_test_server_
;
99 int console_error_count_
;
101 DISALLOW_COPY_AND_ASSIGN(ManifestBrowserTest
);
104 // The implementation of AddMessageToConsole isn't inlined because it needs
105 // to know about |test_|.
106 bool MockWebContentsDelegate::AddMessageToConsole(
109 const base::string16
& message
,
111 const base::string16
& source_id
) {
112 DCHECK(source
== web_contents_
);
114 if (level
== logging::LOG_ERROR
)
115 test_
->OnReceivedConsoleError();
119 // If a page has no manifest, requesting a manifest should return the empty
121 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, NoManifest
) {
122 GURL test_url
= GetTestUrl("manifest", "no-manifest.html");
124 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
125 shell()->LoadURL(test_url
);
126 navigation_observer
.Wait();
128 GetManifestAndWait();
129 EXPECT_TRUE(manifest().IsEmpty());
130 EXPECT_EQ(0u, console_error_count());
133 // If a page manifest points to a 404 URL, requesting the manifest should return
134 // the empty manifest.
135 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, 404Manifest
) {
136 GURL test_url
= GetTestUrl("manifest", "404-manifest.html");
138 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
139 shell()->LoadURL(test_url
);
140 navigation_observer
.Wait();
142 GetManifestAndWait();
143 EXPECT_TRUE(manifest().IsEmpty());
144 EXPECT_EQ(0u, console_error_count());
147 // If a page has an empty manifest, requesting the manifest should return the
149 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, EmptyManifest
) {
150 GURL test_url
= GetTestUrl("manifest", "empty-manifest.html");
152 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
153 shell()->LoadURL(test_url
);
154 navigation_observer
.Wait();
156 GetManifestAndWait();
157 EXPECT_TRUE(manifest().IsEmpty());
158 EXPECT_EQ(0u, console_error_count());
161 // If a page's manifest can't be parsed correctly, requesting the manifest
162 // should return an empty manifest.
163 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, ParseErrorManifest
) {
164 GURL test_url
= GetTestUrl("manifest", "parse-error-manifest.html");
166 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
167 shell()->LoadURL(test_url
);
168 navigation_observer
.Wait();
170 GetManifestAndWait();
171 EXPECT_TRUE(manifest().IsEmpty());
172 EXPECT_EQ(1u, console_error_count());
175 // If a page has a manifest that can be fetched and parsed, requesting the
176 // manifest should return a properly filled manifest.
177 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, DummyManifest
) {
178 GURL test_url
= GetTestUrl("manifest", "dummy-manifest.html");
180 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
181 shell()->LoadURL(test_url
);
182 navigation_observer
.Wait();
184 GetManifestAndWait();
185 EXPECT_FALSE(manifest().IsEmpty());
186 EXPECT_EQ(0u, console_error_count());
189 // If a page changes manifest during its life-time, requesting the manifest
190 // should return the current manifest.
191 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, DynamicManifest
) {
192 GURL test_url
= GetTestUrl("manifest", "dynamic-manifest.html");
194 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
195 shell()->LoadURL(test_url
);
196 navigation_observer
.Wait();
199 GetManifestAndWait();
200 EXPECT_TRUE(manifest().IsEmpty());
204 std::string manifest_url
=
205 GetTestUrl("manifest", "dummy-manifest.json").spec();
206 ASSERT_TRUE(content::ExecuteScript(
207 shell()->web_contents(), "setManifestTo('" + manifest_url
+ "')"));
209 GetManifestAndWait();
210 EXPECT_FALSE(manifest().IsEmpty());
214 std::string manifest_url
=
215 GetTestUrl("manifest", "empty-manifest.json").spec();
216 ASSERT_TRUE(content::ExecuteScript(
217 shell()->web_contents(), "setManifestTo('" + manifest_url
+ "')"));
219 GetManifestAndWait();
220 EXPECT_TRUE(manifest().IsEmpty());
223 EXPECT_EQ(0u, console_error_count());
226 // If a page's manifest lives in a different origin, it should follow the CORS
227 // rules and requesting the manifest should return an empty manifest (unless the
228 // response contains CORS headers).
229 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, CORSManifest
) {
230 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
231 ASSERT_TRUE(cors_embedded_test_server()->InitializeAndWaitUntilReady());
232 ASSERT_NE(embedded_test_server()->port(),
233 cors_embedded_test_server()->port());
236 embedded_test_server()->GetURL("/manifest/dynamic-manifest.html");
238 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
239 shell()->LoadURL(test_url
);
240 navigation_observer
.Wait();
242 std::string manifest_url
= cors_embedded_test_server()->GetURL(
243 "/manifest/dummy-manifest.json").spec();
244 ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
245 "setManifestTo('" + manifest_url
+ "')"));
247 GetManifestAndWait();
248 EXPECT_TRUE(manifest().IsEmpty());
250 EXPECT_EQ(0u, console_error_count());
253 // If a page's manifest lives in a different origin, it should be accessible if
254 // it has valid access controls headers.
255 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, CORSManifestWithAcessControls
) {
256 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
257 ASSERT_TRUE(cors_embedded_test_server()->InitializeAndWaitUntilReady());
258 ASSERT_NE(embedded_test_server()->port(),
259 cors_embedded_test_server()->port());
262 embedded_test_server()->GetURL("/manifest/dynamic-manifest.html");
264 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
265 shell()->LoadURL(test_url
);
266 navigation_observer
.Wait();
268 std::string manifest_url
= cors_embedded_test_server()->GetURL(
269 "/manifest/manifest-cors.json").spec();
270 ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
271 "setManifestTo('" + manifest_url
+ "')"));
273 GetManifestAndWait();
274 EXPECT_FALSE(manifest().IsEmpty());
276 EXPECT_EQ(0u, console_error_count());
279 // If a page's manifest is in an insecure origin while the page is in a secure
280 // origin, requesting the manifest should return the empty manifest.
281 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, MixedContentManifest
) {
282 scoped_ptr
<net::SpawnedTestServer
> https_server(new net::SpawnedTestServer(
283 net::SpawnedTestServer::TYPE_HTTPS
,
284 net::BaseTestServer::SSLOptions(net::BaseTestServer::SSLOptions::CERT_OK
),
285 base::FilePath(FILE_PATH_LITERAL("content/test/data"))));
287 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
288 ASSERT_TRUE(https_server
->Start());
291 embedded_test_server()->GetURL("/manifest/dynamic-manifest.html");
293 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
294 shell()->LoadURL(test_url
);
295 navigation_observer
.Wait();
297 std::string manifest_url
=
298 https_server
->GetURL("/manifest/dummy-manifest.json").spec();
299 ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
300 "setManifestTo('" + manifest_url
+ "')"));
302 GetManifestAndWait();
303 EXPECT_TRUE(manifest().IsEmpty());
305 EXPECT_EQ(0u, console_error_count());
308 // If a page's manifest has some parsing errors, they should show up in the
309 // developer console.
310 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, ParsingErrorsManifest
) {
311 GURL test_url
= GetTestUrl("manifest", "parsing-errors.html");
313 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
314 shell()->LoadURL(test_url
);
315 navigation_observer
.Wait();
317 GetManifestAndWait();
318 EXPECT_TRUE(manifest().IsEmpty());
319 EXPECT_EQ(6u, console_error_count());
322 // If a page has a manifest and the page is navigated to a page without a
323 // manifest, the page's manifest should be updated.
324 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, Navigation
) {
325 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
328 embedded_test_server()->GetURL("/manifest/dummy-manifest.html");
330 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
331 shell()->LoadURL(test_url
);
332 navigation_observer
.Wait();
334 GetManifestAndWait();
335 EXPECT_FALSE(manifest().IsEmpty());
336 EXPECT_EQ(0u, console_error_count());
341 embedded_test_server()->GetURL("/manifest/no-manifest.html");
343 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
344 shell()->LoadURL(test_url
);
345 navigation_observer
.Wait();
347 GetManifestAndWait();
348 EXPECT_TRUE(manifest().IsEmpty());
349 EXPECT_EQ(0u, console_error_count());
353 // If a page has a manifest and the page is navigated using pushState (ie. same
354 // page), it should keep its manifest state.
355 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, PushStateNavigation
) {
356 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
358 embedded_test_server()->GetURL("/manifest/dummy-manifest.html");
361 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
362 shell()->LoadURL(test_url
);
363 navigation_observer
.Wait();
367 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
368 ASSERT_TRUE(content::ExecuteScript(
369 shell()->web_contents(),
370 "history.pushState({foo: \"bar\"}, 'page', 'page.html');"));
371 navigation_observer
.Wait();
374 GetManifestAndWait();
375 EXPECT_FALSE(manifest().IsEmpty());
376 EXPECT_EQ(0u, console_error_count());
379 // If a page has a manifest and is navigated using an anchor (ie. same page), it
380 // should keep its manifest state.
381 IN_PROC_BROWSER_TEST_F(ManifestBrowserTest
, AnchorNavigation
) {
382 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
384 embedded_test_server()->GetURL("/manifest/dummy-manifest.html");
387 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
388 shell()->LoadURL(test_url
);
389 navigation_observer
.Wait();
393 TestNavigationObserver
navigation_observer(shell()->web_contents(), 1);
394 ASSERT_TRUE(content::ExecuteScript(
395 shell()->web_contents(),
396 "var a = document.createElement('a'); a.href='#foo';"
397 "document.body.appendChild(a); a.click();"));
398 navigation_observer
.Wait();
401 GetManifestAndWait();
402 EXPECT_FALSE(manifest().IsEmpty());
403 EXPECT_EQ(0u, console_error_count());
406 } // namespace content