| // Copyright 2017 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 <functional> |
| #include <strstream> |
| |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "content/public/test/browser_test.h" |
| #include "headless/public/devtools/domains/dom_snapshot.h" |
| #include "headless/public/devtools/domains/page.h" |
| #include "headless/public/devtools/domains/runtime.h" |
| #include "headless/public/headless_devtools_client.h" |
| #include "headless/test/headless_render_test.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #define HEADLESS_RENDER_BROWSERTEST(clazz) \ |
| class HeadlessRenderBrowserTest##clazz : public clazz {}; \ |
| HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessRenderBrowserTest##clazz) |
| |
| // TODO(dats): For some reason we are missing all HTTP redirects. |
| // crbug.com/789298 |
| #define DISABLE_HTTP_REDIRECTS_CHECKS |
| |
| namespace headless { |
| |
| namespace { |
| |
| const std::string SOME_HOST = "http://www.example.com"; |
| constexpr char SOME_URL[] = "http://example.com/foobar"; |
| constexpr char TEXT_HTML[] = "text/html"; |
| |
| using dom_snapshot::GetSnapshotResult; |
| using dom_snapshot::DOMNode; |
| using dom_snapshot::LayoutTreeNode; |
| using net::test_server::HttpRequest; |
| using net::test_server::HttpResponse; |
| using net::test_server::BasicHttpResponse; |
| using net::test_server::RawHttpResponse; |
| using page::FrameScheduledNavigationReason; |
| using testing::ElementsAre; |
| using testing::UnorderedElementsAre; |
| using testing::Eq; |
| using testing::Ne; |
| using testing::StartsWith; |
| |
| template <typename T, typename V> |
| std::vector<T> ElementsView(const std::vector<std::unique_ptr<V>>& elements, |
| std::function<bool(const V&)> filter, |
| std::function<T(const V&)> transform) { |
| std::vector<T> result; |
| for (const auto& element : elements) { |
| if (filter(*element)) |
| result.push_back(transform(*element)); |
| } |
| return result; |
| } |
| |
| bool HasType(int type, const DOMNode& node) { |
| return node.GetNodeType() == type; |
| } |
| bool HasName(const char* name, const DOMNode& node) { |
| return node.GetNodeName() == name; |
| } |
| bool IsTag(const DOMNode& node) { |
| return HasType(1, node); |
| } |
| bool IsText(const DOMNode& node) { |
| return HasType(3, node); |
| } |
| |
| std::vector<std::string> TextLayout(const GetSnapshotResult* snapshot) { |
| return ElementsView<std::string, LayoutTreeNode>( |
| *snapshot->GetLayoutTreeNodes(), |
| [](const auto& node) { return node.HasLayoutText(); }, |
| [](const auto& node) { return node.GetLayoutText(); }); |
| } |
| |
| std::vector<const DOMNode*> FilterDOM( |
| const GetSnapshotResult* snapshot, |
| std::function<bool(const DOMNode&)> filter) { |
| return ElementsView<const DOMNode*, DOMNode>( |
| *snapshot->GetDomNodes(), filter, [](const auto& n) { return &n; }); |
| } |
| |
| std::vector<const DOMNode*> FindTags(const GetSnapshotResult* snapshot, |
| const char* name = nullptr) { |
| return FilterDOM(snapshot, [name](const auto& n) { |
| return IsTag(n) && (!name || HasName(name, n)); |
| }); |
| } |
| |
| size_t IndexInDOM(const GetSnapshotResult* snapshot, const DOMNode* node) { |
| for (size_t i = 0; i < snapshot->GetDomNodes()->size(); ++i) { |
| if (snapshot->GetDomNodes()->at(i).get() == node) |
| return i; |
| } |
| CHECK(false); |
| return static_cast<size_t>(-1); |
| } |
| |
| const DOMNode* GetAt(const GetSnapshotResult* snapshot, size_t index) { |
| CHECK_LE(index, snapshot->GetDomNodes()->size()); |
| return snapshot->GetDomNodes()->at(index).get(); |
| } |
| |
| const DOMNode* NextNode(const GetSnapshotResult* snapshot, |
| const DOMNode* node) { |
| return GetAt(snapshot, IndexInDOM(snapshot, node) + 1); |
| } |
| |
| MATCHER_P(NodeName, expected, "") { |
| return arg->GetNodeName() == expected; |
| } |
| MATCHER_P(NodeValue, expected, "") { |
| return arg->GetNodeValue() == expected; |
| } |
| MATCHER_P(NodeType, expected, 0) { |
| return arg->GetNodeType() == expected; |
| } |
| |
| MATCHER_P(RemoteString, expected, "") { |
| return arg->GetType() == runtime::RemoteObjectType::STRING && |
| arg->GetValue()->GetString() == expected; |
| } |
| |
| MATCHER_P(RequestPath, expected, "") { |
| return arg.relative_url == expected; |
| } |
| |
| MATCHER_P(RedirectUrl, expected, "") { |
| return arg.first == expected; |
| } |
| |
| MATCHER_P(RedirectReason, expected, "") { |
| return arg.second == expected; |
| } |
| |
| MATCHER_P(CookieValue, expected, "") { |
| return arg->GetValue() == expected; |
| } |
| |
| const DOMNode* FindTag(const GetSnapshotResult* snapshot, const char* name) { |
| auto tags = FindTags(snapshot, name); |
| if (tags.empty()) |
| return nullptr; |
| EXPECT_THAT(tags, ElementsAre(NodeName(name))); |
| return tags[0]; |
| } |
| |
| TestInMemoryProtocolHandler::Response HttpRedirect( |
| int code, |
| const std::string& url, |
| const std::string& status = "Moved") { |
| CHECK(code >= 300 && code < 400); |
| std::stringstream str; |
| str << "HTTP/1.1 " << code << " " << status << "\r\nLocation: " << url |
| << "\r\n\r\n"; |
| return TestInMemoryProtocolHandler::Response(str.str()); |
| } |
| |
| TestInMemoryProtocolHandler::Response HttpOk(const std::string& html) { |
| return TestInMemoryProtocolHandler::Response(html, TEXT_HTML); |
| } |
| |
| } // namespace |
| |
| class HelloWorldTest : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse(SOME_URL, HttpOk(R"|(<!doctype html> |
| <h1>Hello headless world!</h1> |
| )|")); |
| return GURL(SOME_URL); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(FindTags(dom_snapshot), |
| ElementsAre(NodeName("HTML"), NodeName("HEAD"), |
| NodeName("BODY"), NodeName("H1"))); |
| EXPECT_THAT( |
| FilterDOM(dom_snapshot, IsText), |
| ElementsAre(NodeValue("Hello headless world!"), NodeValue("\n"))); |
| EXPECT_THAT(TextLayout(dom_snapshot), ElementsAre("Hello headless world!")); |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), ElementsAre(SOME_URL)); |
| EXPECT_FALSE(main_frame_.empty()); |
| EXPECT_TRUE(unconfirmed_frame_redirects_.empty()); |
| EXPECT_TRUE(confirmed_frame_redirects_.empty()); |
| EXPECT_THAT(frames_[main_frame_].size(), Eq(1u)); |
| const auto& frame = frames_[main_frame_][0]; |
| EXPECT_THAT(frame->GetUrl(), Eq(SOME_URL)); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(HelloWorldTest); |
| |
| class TimeoutTest : public HelloWorldTest { |
| private: |
| void OnPageRenderCompleted() override { |
| // Never complete. |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| FAIL() << "Should not reach here"; |
| } |
| |
| void OnTimeout() override { SetTestCompleted(); } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(TimeoutTest); |
| |
| class JavaScriptOverrideTitle_JsEnabled : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse(SOME_URL, HttpOk(R"|( |
| <html> |
| <head> |
| <title>JavaScript is off</title> |
| <script language="JavaScript"> |
| <!-- Begin |
| document.title = 'JavaScript is on'; |
| // End --> |
| </script> |
| </head> |
| <body onload="settitle()"> |
| Hello, World! |
| </body> |
| </html> |
| )|")); |
| return GURL(SOME_URL); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| const DOMNode* value = |
| NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE")); |
| EXPECT_THAT(value, NodeValue("JavaScript is on")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(JavaScriptOverrideTitle_JsEnabled); |
| |
| class JavaScriptOverrideTitle_JsDisabled |
| : public JavaScriptOverrideTitle_JsEnabled { |
| private: |
| void OverrideWebPreferences(WebPreferences* preferences) override { |
| JavaScriptOverrideTitle_JsEnabled::OverrideWebPreferences(preferences); |
| preferences->javascript_enabled = false; |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| const DOMNode* value = |
| NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE")); |
| EXPECT_THAT(value, NodeValue("JavaScript is off")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(JavaScriptOverrideTitle_JsDisabled); |
| |
| class JavaScriptConsoleErrors : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse(SOME_URL, HttpOk(R"|( |
| <html> |
| <head> |
| <script language="JavaScript"> |
| <![CDATA[ |
| function image() { |
| window.open('<xsl:value-of select="/IMAGE/@href" />'); |
| } |
| ]]> |
| </script> |
| </head> |
| <body onload="func3()"> |
| <script type="text/javascript"> |
| func1() |
| </script> |
| <script type="text/javascript"> |
| func2(); |
| </script> |
| <script type="text/javascript"> |
| console.log("Hello, Script!"); |
| </script> |
| </body> |
| </html> |
| )|")); |
| return GURL(SOME_URL); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(console_log_, ElementsAre("L Hello, Script!")); |
| EXPECT_THAT(js_exceptions_, |
| ElementsAre(StartsWith("Uncaught SyntaxError:"), |
| StartsWith("Uncaught ReferenceError: func1"), |
| StartsWith("Uncaught ReferenceError: func2"), |
| StartsWith("Uncaught ReferenceError: func3"))); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(JavaScriptConsoleErrors); |
| |
| class DelayedCompletion : public HeadlessRenderTest { |
| private: |
| base::TimeTicks start_; |
| |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse(SOME_URL, HttpOk(R"|( |
| <html> |
| <body> |
| <script type="text/javascript"> |
| setTimeout(() => { |
| var div = document.getElementById('content'); |
| var p = document.createElement('p'); |
| p.textContent = 'delayed text'; |
| div.appendChild(p); |
| }, 3000); |
| </script> |
| <div id="content"/> |
| </body> |
| </html> |
| )|")); |
| start_ = base::TimeTicks::Now(); |
| return GURL(SOME_URL); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| base::TimeTicks end = base::TimeTicks::Now(); |
| EXPECT_THAT( |
| FindTags(dom_snapshot), |
| ElementsAre(NodeName("HTML"), NodeName("HEAD"), NodeName("BODY"), |
| NodeName("SCRIPT"), NodeName("DIV"), NodeName("P"))); |
| const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P")); |
| EXPECT_THAT(value, NodeValue("delayed text")); |
| // The page delays output for 3 seconds. Due to virtual time this should |
| // take significantly less actual time. |
| base::TimeDelta passed = end - start_; |
| EXPECT_THAT(passed.InSecondsF(), testing::Le(2.9f)); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(DelayedCompletion); |
| |
| class ClientRedirectChain : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <head> |
| <meta http-equiv="refresh" content="0; url=http://www.example.com/1"/> |
| <title>Hello, World 0</title> |
| </head> |
| <body>http://www.example.com/</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", HttpOk(R"|( |
| <html> |
| <head> |
| <title>Hello, World 1</title> |
| <script> |
| document.location='http://www.example.com/2'; |
| </script> |
| </head> |
| <body>http://www.example.com/1</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", HttpOk(R"|( |
| <html> |
| <head> |
| <title>Hello, World 2</title> |
| <script> |
| setTimeout("document.location='http://www.example.com/3'", 1000); |
| </script> |
| </head> |
| <body>http://www.example.com/2</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/3", HttpOk(R"|( |
| <html> |
| <head> |
| <title>Pass</title> |
| </head> |
| <body> |
| http://www.example.com/3 |
| <img src="pass"> |
| </body> |
| </html> |
| )|")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2", "http://www.example.com/3", |
| "http://www.example.com/pass")); |
| const DOMNode* value = |
| NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE")); |
| EXPECT_THAT(value, NodeValue("Pass")); |
| EXPECT_THAT( |
| confirmed_frame_redirects_[main_frame_], |
| ElementsAre( |
| RedirectReason(FrameScheduledNavigationReason::META_TAG_REFRESH), |
| RedirectReason(FrameScheduledNavigationReason::SCRIPT_INITIATED), |
| RedirectReason(FrameScheduledNavigationReason::SCRIPT_INITIATED))); |
| EXPECT_THAT(frames_[main_frame_].size(), Eq(4u)); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(ClientRedirectChain); |
| |
| class ClientRedirectChain_NoJs : public ClientRedirectChain { |
| private: |
| void OverrideWebPreferences(WebPreferences* preferences) override { |
| ClientRedirectChain::OverrideWebPreferences(preferences); |
| preferences->javascript_enabled = false; |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1")); |
| const DOMNode* value = |
| NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE")); |
| EXPECT_THAT(value, NodeValue("Hello, World 1")); |
| EXPECT_THAT(confirmed_frame_redirects_[main_frame_], |
| ElementsAre(RedirectReason( |
| FrameScheduledNavigationReason::META_TAG_REFRESH))); |
| EXPECT_THAT(frames_[main_frame_].size(), Eq(2u)); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(ClientRedirectChain_NoJs); |
| |
| class ServerRedirectChain : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| HttpRedirect(302, "http://www.example.com/1")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/1", |
| HttpRedirect(301, "http://www.example.com/2")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/2", |
| HttpRedirect(302, "http://www.example.com/3")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/3", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2", "http://www.example.com/3")); |
| const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P")); |
| EXPECT_THAT(value, NodeValue("Pass")); |
| #ifndef DISABLE_HTTP_REDIRECTS_CHECKS |
| EXPECT_THAT( |
| confirmed_frame_redirects_[main_frame_], |
| ElementsAre( |
| RedirectReason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH), |
| RedirectReason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH), |
| RedirectReason( |
| FrameScheduledNavigationReason::HTTP_HEADER_REFRESH))); |
| EXPECT_THAT(frames_[main_frame_].size(), Eq(4u)); |
| #endif // #ifndef DISABLE_HTTP_REDIRECTS_CHECKS |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(ServerRedirectChain); |
| |
| class ServerRedirectToFailure : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| HttpRedirect(302, "http://www.example.com/1")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/1", |
| HttpRedirect(301, "http://www.example.com/FAIL")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/FAIL")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(ServerRedirectToFailure); |
| |
| class ServerRedirectRelativeChain : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| HttpRedirect(302, "http://www.mysite.com/1")); |
| GetProtocolHandler()->InsertResponse("http://www.mysite.com/1", |
| HttpRedirect(301, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.mysite.com/2", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.mysite.com/1", |
| "http://www.mysite.com/2")); |
| const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P")); |
| EXPECT_THAT(value, NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(ServerRedirectRelativeChain); |
| |
| class MixedRedirectChain : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <head> |
| <meta http-equiv="refresh" content="0; url=http://www.example.com/1"/> |
| <title>Hello, World 0</title> |
| </head> |
| <body>http://www.example.com/</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", HttpOk(R"|( |
| <html> |
| <head> |
| <title>Hello, World 1</title> |
| <script> |
| document.location='http://www.example.com/2'; |
| </script> |
| </head> |
| <body>http://www.example.com/1</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", |
| HttpRedirect(302, "3")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/3", |
| HttpRedirect(301, "http://www.example.com/4")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/4", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2", "http://www.example.com/3", |
| "http://www.example.com/4")); |
| const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P")); |
| EXPECT_THAT(value, NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(MixedRedirectChain); |
| |
| class FramesRedirectChain : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| HttpRedirect(302, "http://www.example.com/1")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", HttpOk(R"|( |
| <html> |
| <frameset> |
| <frame src="http://www.example.com/frameA/"> |
| <frame src="http://www.example.com/frameB/"> |
| </frameset> |
| </html> |
| )|")); |
| |
| // Frame A |
| GetProtocolHandler()->InsertResponse("http://www.example.com/frameA/", |
| HttpOk(R"|( |
| <html> |
| <head> |
| <script>document.location='http://www.example.com/frameA/1'</script> |
| </head> |
| <body>HELLO WORLD 1</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/frameA/1", |
| HttpRedirect(301, "/frameA/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/frameA/2", |
| HttpOk("<p>FRAME A</p>")); |
| |
| // Frame B |
| GetProtocolHandler()->InsertResponse("http://www.example.com/frameB/", |
| HttpOk(R"|( |
| <html> |
| <head><title>HELLO WORLD 2</title></head> |
| <body> |
| <iframe src="http://www.example.com/iframe/"></iframe> |
| </body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/iframe/", |
| HttpOk(R"|( |
| <html> |
| <head> |
| <script>document.location='http://www.example.com/iframe/1'</script> |
| </head> |
| <body>HELLO WORLD 1</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/iframe/1", |
| HttpRedirect(302, "/iframe/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/iframe/2", |
| HttpRedirect(301, "3")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/iframe/3", |
| HttpOk("<p>IFRAME B</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| UnorderedElementsAre( |
| "http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/frameA/", "http://www.example.com/frameA/1", |
| "http://www.example.com/frameA/2", "http://www.example.com/frameB/", |
| "http://www.example.com/iframe/", "http://www.example.com/iframe/1", |
| "http://www.example.com/iframe/2", |
| "http://www.example.com/iframe/3")); |
| auto dom = FindTags(dom_snapshot, "P"); |
| EXPECT_THAT(dom, ElementsAre(NodeName("P"), NodeName("P"))); |
| EXPECT_THAT(NextNode(dom_snapshot, dom[0]), NodeValue("FRAME A")); |
| EXPECT_THAT(NextNode(dom_snapshot, dom[1]), NodeValue("IFRAME B")); |
| |
| const page::Frame* main_frame = nullptr; |
| const page::Frame* a_frame = nullptr; |
| const page::Frame* b_frame = nullptr; |
| const page::Frame* i_frame = nullptr; |
| EXPECT_THAT(frames_.size(), Eq(4u)); |
| for (const auto& it : frames_) { |
| if (it.second.back()->GetUrl() == "http://www.example.com/1") |
| main_frame = it.second.back().get(); |
| else if (it.second.back()->GetUrl() == "http://www.example.com/frameA/2") |
| a_frame = it.second.back().get(); |
| else if (it.second.back()->GetUrl() == "http://www.example.com/frameB/") |
| b_frame = it.second.back().get(); |
| else if (it.second.back()->GetUrl() == "http://www.example.com/iframe/3") |
| i_frame = it.second.back().get(); |
| else |
| ADD_FAILURE() << "Unexpected frame URL: " << it.second.back()->GetUrl(); |
| } |
| |
| #ifndef DISABLE_HTTP_REDIRECTS_CHECKS |
| EXPECT_THAT(frames_[main_frame->GetId()].size(), Eq(2u)); |
| EXPECT_THAT(frames_[a_frame->GetId()].size(), Eq(3u)); |
| EXPECT_THAT(frames_[b_frame->GetId()].size(), Eq(1u)); |
| EXPECT_THAT(frames_[i_frame->GetId()].size(), Eq(4u)); |
| EXPECT_THAT(confirmed_frame_redirects_[main_frame->GetId()], |
| ElementsAre(RedirectReason( |
| FrameScheduledNavigationReason::HTTP_HEADER_REFRESH))); |
| EXPECT_THAT( |
| confirmed_frame_redirects_[a_frame->GetId()], |
| ElementsAre( |
| RedirectReason(FrameScheduledNavigationReason::SCRIPT_INITIATED), |
| RedirectReason( |
| FrameScheduledNavigationReason::HTTP_HEADER_REFRESH))); |
| EXPECT_THAT( |
| confirmed_frame_redirects_[i_frame->GetId()], |
| ElementsAre( |
| RedirectReason(FrameScheduledNavigationReason::SCRIPT_INITIATED), |
| RedirectReason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH), |
| RedirectReason( |
| FrameScheduledNavigationReason::HTTP_HEADER_REFRESH))); |
| #endif // #ifndef DISABLE_HTTP_REDIRECTS_CHECKS |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(FramesRedirectChain); |
| |
| class DoubleRedirect : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <head> |
| <title>Hello, World 1</title> |
| <script> |
| document.location='http://www.example.com/1'; |
| document.location='http://www.example.com/2'; |
| </script> |
| </head> |
| <body>http://www.example.com/1</body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/2")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| EXPECT_THAT(confirmed_frame_redirects_[main_frame_], |
| ElementsAre(RedirectReason( |
| FrameScheduledNavigationReason::SCRIPT_INITIATED))); |
| EXPECT_THAT(frames_[main_frame_].size(), Eq(2u)); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(DoubleRedirect); |
| |
| class RedirectAfterCompletion : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <head> |
| <meta http-equiv='refresh' content='120; url=http://www.example.com/1'> |
| </head> |
| <body><p>Pass</p></body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", |
| HttpOk("<p>Fail</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| EXPECT_THAT(confirmed_frame_redirects_[main_frame_], ElementsAre()); |
| EXPECT_THAT(frames_[main_frame_].size(), Eq(1u)); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectAfterCompletion); |
| |
| class Redirect307PostMethod : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <body onload='document.forms[0].submit();'> |
| <form action='1' method='post'> |
| <input name='foo' value='bar'> |
| </form> |
| </body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", |
| HttpRedirect(307, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2")); |
| EXPECT_THAT(GetProtocolHandler()->methods_requested(), |
| ElementsAre("GET", "POST", "POST")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(Redirect307PostMethod); |
| |
| class RedirectPostChain : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <body onload='document.forms[0].submit();'> |
| <form action='1' method='post'> |
| <input name='foo' value='bar'> |
| </form> |
| </body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", |
| HttpRedirect(307, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", HttpOk(R"|( |
| <html> |
| <body onload='document.forms[0].submit();'> |
| <form action='3' method='post'> |
| </form> |
| </body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/3", |
| HttpRedirect(307, "/4")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/4", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2", "http://www.example.com/3", |
| "http://www.example.com/4")); |
| EXPECT_THAT(GetProtocolHandler()->methods_requested(), |
| ElementsAre("GET", "POST", "POST", "POST", "POST")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectPostChain); |
| |
| class Redirect307PutMethod : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <head> |
| <script> |
| function doPut() { |
| var xhr = new XMLHttpRequest(); |
| xhr.open('PUT', 'http://www.example.com/1'); |
| xhr.setRequestHeader('Content-Type', 'text/plain'); |
| xhr.addEventListener('load', function() { |
| document.getElementById('content').textContent = this.responseText; |
| }); |
| xhr.send('some data'); |
| } |
| </script> |
| </head> |
| <body onload='doPut();'> |
| <p id="content"></p> |
| </body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", |
| HttpRedirect(307, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", |
| {"Pass", "text/plain"}); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2")); |
| EXPECT_THAT(GetProtocolHandler()->methods_requested(), |
| ElementsAre("GET", "PUT", "PUT")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(Redirect307PutMethod); |
| |
| class Redirect303PutGet : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html> |
| <head> |
| <script> |
| function doPut() { |
| var xhr = new XMLHttpRequest(); |
| xhr.open('PUT', 'http://www.example.com/1'); |
| xhr.setRequestHeader('Content-Type', 'text/plain'); |
| xhr.addEventListener('load', function() { |
| document.getElementById('content').textContent = this.responseText; |
| }); |
| xhr.send('some data'); |
| } |
| </script> |
| </head> |
| <body onload='doPut();'> |
| <p id="content"></p> |
| </body> |
| </html> |
| )|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1", |
| HttpRedirect(303, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2", |
| {"Pass", "text/plain"}); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1", |
| "http://www.example.com/2")); |
| EXPECT_THAT(GetProtocolHandler()->methods_requested(), |
| ElementsAre("GET", "PUT", "GET")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(Redirect303PutGet); |
| |
| class RedirectBaseUrl : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://foo.com/", |
| HttpRedirect(302, "http://bar.com/")); |
| GetProtocolHandler()->InsertResponse("http://bar.com/", |
| HttpOk("<img src=\"pass\">")); |
| return GURL("http://foo.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://foo.com/", "http://bar.com/", |
| "http://bar.com/pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectBaseUrl); |
| |
| class RedirectNonAsciiUrl : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| // "ä¸æ–‡" is 0xE4 0xB8 0xAD, 0xE6 0x96 0x87 |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| HttpRedirect(302, "http://www.example.com/ä¸æ–‡")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/%E4%B8%AD%E6%96%87", |
| HttpRedirect(303, "http://www.example.com/pass#ä¸æ–‡")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/pass#%E4%B8%AD%E6%96%87", |
| HttpOk("<p>Pass</p>")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/%C3%A4%C2%B8%C2%AD%C3%A6%C2%96%C2%87", |
| {"HTTP/1.1 500 Bad Response\r\nContent-Type: text/html\r\n\r\nFail"}); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", |
| "http://www.example.com/%E4%B8%AD%E6%96%87", |
| "http://www.example.com/pass#%E4%B8%AD%E6%96%87")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectNonAsciiUrl); |
| |
| class RedirectEmptyUrl : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| {"HTTP/1.1 302 Found\r\nLocation: \r\n\r\n<!DOCTYPE html><p>Pass</p>"}); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectEmptyUrl); |
| |
| class RedirectInvalidUrl : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/", |
| {"HTTP/1.1 302 Found\r\nLocation: http://\r\n\r\n" |
| "<!DOCTYPE html><p>Pass</p>"}); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectInvalidUrl); |
| |
| class RedirectKeepsFragment : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/#foo", |
| HttpRedirect(302, "/1")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1#foo", |
| HttpRedirect(302, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2#foo", |
| HttpOk(R"|( |
| <body> |
| <p id="content"></p> |
| <script> |
| document.getElementById('content').textContent = window.location.href; |
| </script> |
| </body> |
| )|")); |
| return GURL("http://www.example.com/#foo"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/#foo", |
| "http://www.example.com/1#foo", |
| "http://www.example.com/2#foo")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("http://www.example.com/2#foo")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectKeepsFragment); |
| |
| class RedirectReplacesFragment : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/#foo", |
| HttpRedirect(302, "/1#bar")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1#bar", |
| HttpRedirect(302, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2#bar", |
| HttpOk(R"|( |
| <body> |
| <p id="content"></p> |
| <script> |
| document.getElementById('content').textContent = window.location.href; |
| </script> |
| </body> |
| )|")); |
| return GURL("http://www.example.com/#foo"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/#foo", |
| "http://www.example.com/1#bar", |
| "http://www.example.com/2#bar")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("http://www.example.com/2#bar")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectReplacesFragment); |
| |
| class RedirectNewFragment : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", |
| HttpRedirect(302, "/1#foo")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/1#foo", |
| HttpRedirect(302, "/2")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/2#foo", |
| HttpOk(R"|( |
| <body> |
| <p id="content"></p> |
| <script> |
| document.getElementById('content').textContent = window.location.href; |
| </script> |
| </body> |
| )|")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT( |
| GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", "http://www.example.com/1#foo", |
| "http://www.example.com/2#foo")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("http://www.example.com/2#foo")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(RedirectNewFragment); |
| |
| class WindowLocationFragments : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/#fragment1", |
| HttpOk(R"|( |
| <script> |
| if (window.location.hash == '#fragment1') { |
| document.write('<iframe src="iframe#fragment2"></iframe>'); |
| } |
| </script>)|")); |
| GetProtocolHandler()->InsertResponse( |
| "http://www.example.com/iframe#fragment2", HttpOk(R"|( |
| <script> |
| if (window.location.hash == '#fragment2') { |
| document.location = 'http://www.example.com/pass'; |
| } |
| </script>)|")); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/pass", |
| HttpOk("<p>Pass</p>")); |
| return GURL("http://www.example.com/#fragment1"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/#fragment1", |
| "http://www.example.com/iframe#fragment2", |
| "http://www.example.com/pass")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(WindowLocationFragments); |
| |
| class CookieSetFromJs : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html><head><script> |
| document.cookie = 'SessionID=123'; |
| n = document.cookie.indexOf('SessionID'); |
| if (n < 0) { |
| top.location = '/epicfail'; |
| } |
| </script></head><body>Pass</body></html>)|")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/")); |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "BODY")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs); |
| |
| class CookieSetFromJs_NoCookies : public CookieSetFromJs { |
| private: |
| void OverrideWebPreferences(WebPreferences* preferences) override { |
| HeadlessRenderTest::OverrideWebPreferences(preferences); |
| preferences->cookie_enabled = false; |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(GetProtocolHandler()->urls_requested(), |
| ElementsAre("http://www.example.com/", |
| "http://www.example.com/epicfail")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs_NoCookies); |
| |
| class CookieUpdatedFromJs : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| client->GetNetwork()->SetCookie(network::SetCookieParams::Builder() |
| .SetUrl("http://www.example.com/") |
| .SetName("foo") |
| .SetValue("bar") |
| .Build()); |
| GetProtocolHandler()->InsertResponse("http://www.example.com/", HttpOk(R"|( |
| <html><head><script> |
| var x = document.cookie; |
| document.cookie = x + 'baz'; |
| </script></head><body>Pass</body></html>)|")); |
| return GURL("http://www.example.com/"); |
| } |
| |
| void OnPageRenderCompleted() override { |
| devtools_client_->GetNetwork()->GetCookies( |
| network::GetCookiesParams::Builder() |
| .SetUrls({"http://www.example.com/"}) |
| .Build(), |
| base::Bind(&CookieUpdatedFromJs::OnGetCookies, base::Unretained(this))); |
| } |
| |
| void OnGetCookies(std::unique_ptr<network::GetCookiesResult> result) { |
| const auto& cookies = *result->GetCookies(); |
| EXPECT_THAT(cookies, ElementsAre(CookieValue("barbaz"))); |
| HeadlessRenderTest::OnPageRenderCompleted(); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "BODY")), |
| NodeValue("Pass")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(CookieUpdatedFromJs); |
| |
| class InCrossOriginObject : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse("http://foo.com/", HttpOk(R"|( |
| <html><body> |
| <iframe id='myframe' src='http://bar.com/'></iframe> |
| <script> |
| window.onload = function() { |
| try { |
| var a = 0 in document.getElementById('myframe').contentWindow; |
| } catch (e) { |
| console.log(e.message); |
| } |
| }; |
| </script><p>Pass</p></body></html>)|")); |
| GetProtocolHandler()->InsertResponse("http://bar.com/", |
| HttpOk(R"|(<html></html>)|")); |
| return GURL("http://foo.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")), |
| NodeValue("Pass")); |
| EXPECT_THAT(console_log_, |
| ElementsAre(StartsWith("L Blocked a frame with origin " |
| "\"http://foo.com\" from accessing"))); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(InCrossOriginObject); |
| |
| class ContentSecurityPolicy : public HeadlessRenderTest { |
| private: |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| // Only first 3 scripts of 4 on the page are whitelisted for execution. |
| // Therefore only 3 lines in the log are expected. |
| GetProtocolHandler()->InsertResponse( |
| "http://example.com/", |
| {"HTTP/1.1 200 OK\r\n" |
| "Content-Type: text/html\r\n" |
| "Content-Security-Policy: script-src" |
| " 'sha256-INSsCHXoo4K3+jDRF8FSvl13GP22I9vcqcJjkq35Y20='" |
| " 'sha384-77lSn5Q6V979pJ8W2TXc6Lrj98LughR0ofkFwa+" |
| "qOEtlcofEdLPkOPtpJF8QQMev'" |
| " 'sha512-" |
| "2cS3KZwfnxFo6lvBvAl113f5N3QCRgtRJBbtFaQHKOhk36sdYYKFvhCqGTvbN7pBKUfsj" |
| "fCQgFF4MSbCQuvT8A=='\r\n\r\n" |
| "<!DOCTYPE html>\n" |
| "<script>console.log('pass256');</script>\n" |
| "<script>console.log('pass384');</script>\n" |
| "<script>console.log('pass512');</script>\n" |
| "<script>console.log('fail');</script>"}); |
| // For example, regenerate sha256 hash with: |
| // echo -n "console.log('pass256');" \ |
| // | openssl sha256 -binary \ |
| // | openssl base64 |
| return GURL("http://example.com/"); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| EXPECT_THAT(console_log_, |
| ElementsAre("L pass256", "L pass384", "L pass512")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(ContentSecurityPolicy); |
| |
| class FrameLoadEvents : public HeadlessRenderTest { |
| private: |
| std::map<std::string, std::string> frame_navigated_; |
| std::map<std::string, std::string> frame_scheduled_; |
| |
| GURL GetPageUrl(HeadlessDevToolsClient* client) override { |
| GetProtocolHandler()->InsertResponse( |
| "http://example.com/", HttpRedirect(302, "http://example.com/1")); |
| |
| GetProtocolHandler()->InsertResponse("http://example.com/1", HttpOk(R"|( |
| <html><frameset> |
| <frame src="http://example.com/frameA/" id="frameA"> |
| <frame src="http://example.com/frameB/" id="frameB"> |
| </frameset></html> |
| )|")); |
| |
| GetProtocolHandler()->InsertResponse("http://example.com/frameA/", |
| HttpOk(R"|( |
| <html><head><script> |
| document.location="http://example.com/frameA/1" |
| </script></head></html> |
| )|")); |
| |
| GetProtocolHandler()->InsertResponse("http://example.com/frameB/", |
| HttpOk(R"|( |
| <html><head><script> |
| document.location="http://example.com/frameB/1" |
| </script></head></html> |
| )|")); |
| |
| GetProtocolHandler()->InsertResponse( |
| "http://example.com/frameA/1", |
| HttpOk("<html><body>FRAME A 1</body></html>")); |
| |
| GetProtocolHandler()->InsertResponse("http://example.com/frameB/1", |
| HttpOk(R"|( |
| <html><body>FRAME B 1 |
| <iframe src="http://example.com/frameB/1/iframe/" id="iframe"></iframe> |
| </body></html> |
| )|")); |
| |
| GetProtocolHandler()->InsertResponse("http://example.com/frameB/1/iframe/", |
| HttpOk(R"|( |
| <html><head><script> |
| document.location="http://example.com/frameB/1/iframe/1" |
| </script></head></html> |
| )|")); |
| |
| GetProtocolHandler()->InsertResponse( |
| "http://example.com/frameB/1/iframe/1", |
| HttpOk("<html><body>IFRAME 1</body><html>")); |
| |
| return GURL("http://example.com/"); |
| } |
| |
| void OnFrameNavigated(const page::FrameNavigatedParams& params) override { |
| frame_navigated_.insert(std::make_pair(params.GetFrame()->GetId(), |
| params.GetFrame()->GetUrl())); |
| HeadlessRenderTest::OnFrameNavigated(params); |
| } |
| |
| void OnFrameScheduledNavigation( |
| const page::FrameScheduledNavigationParams& params) override { |
| frame_scheduled_.insert( |
| std::make_pair(params.GetFrameId(), params.GetUrl())); |
| HeadlessRenderTest::OnFrameScheduledNavigation(params); |
| } |
| |
| void VerifyDom(GetSnapshotResult* dom_snapshot) override { |
| std::vector<std::string> urls; |
| for (const auto& kv : frame_navigated_) { |
| urls.push_back(kv.second); |
| } |
| EXPECT_THAT(urls, UnorderedElementsAre( |
| "http://example.com/1", "http://example.com/frameA/", |
| "http://example.com/frameB/", |
| "http://example.com/frameB/1/iframe/")); |
| urls.clear(); |
| for (const auto& kv : frame_scheduled_) { |
| urls.push_back(kv.second); |
| } |
| EXPECT_THAT(urls, |
| UnorderedElementsAre("http://example.com/frameA/1", |
| "http://example.com/frameB/1", |
| "http://example.com/frameB/1/iframe/1")); |
| } |
| }; |
| HEADLESS_RENDER_BROWSERTEST(FrameLoadEvents); |
| |
| } // namespace headless |