OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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. |
| 4 |
| 5 #include "headless/public/util/dom_tree_extractor.h" |
| 6 |
| 7 #include <memory> |
| 8 #include "base/json/json_writer.h" |
| 9 #include "base/strings/string_util.h" |
| 10 #include "content/public/browser/render_widget_host_view.h" |
| 11 #include "content/public/browser/web_contents.h" |
| 12 #include "content/public/test/browser_test.h" |
| 13 #include "headless/lib/browser/headless_web_contents_impl.h" |
| 14 #include "headless/public/domains/browser.h" |
| 15 #include "headless/public/domains/emulation.h" |
| 16 #include "headless/public/domains/network.h" |
| 17 #include "headless/public/domains/page.h" |
| 18 #include "headless/public/headless_browser.h" |
| 19 #include "headless/public/headless_devtools_client.h" |
| 20 #include "headless/public/headless_devtools_target.h" |
| 21 #include "headless/test/headless_browser_test.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" |
| 23 #include "url/gurl.h" |
| 24 |
| 25 namespace headless { |
| 26 |
| 27 class DomTreeExtractorBrowserTest : public HeadlessAsyncDevTooledBrowserTest, |
| 28 public page::Observer { |
| 29 public: |
| 30 void RunDevTooledTest() override { |
| 31 EXPECT_TRUE(embedded_test_server()->Start()); |
| 32 devtools_client_->GetPage()->AddObserver(this); |
| 33 devtools_client_->GetPage()->Enable(); |
| 34 devtools_client_->GetPage()->Navigate( |
| 35 embedded_test_server()->GetURL("/dom_tree_test.html").spec()); |
| 36 } |
| 37 |
| 38 void OnLoadEventFired(const page::LoadEventFiredParams& params) override { |
| 39 devtools_client_->GetPage()->RemoveObserver(this); |
| 40 |
| 41 extractor_.reset(new DomTreeExtractor(devtools_client_.get())); |
| 42 extractor_->ExtractDom( |
| 43 base::Bind(&DomTreeExtractorBrowserTest::OnDomTreeExtracted, |
| 44 base::Unretained(this))); |
| 45 } |
| 46 |
| 47 void OnDomTreeExtracted( |
| 48 std::vector<std::unique_ptr<base::DictionaryValue>> dom_tree) { |
| 49 std::vector<std::string> expected_results = { |
| 50 "{'baseURL':'http://127.0.0.1/dom_tree_test.html','childIndicies':[1]," |
| 51 "'documentURL':'http://127.0.0.1/dom_tree_test.html','localName':''," |
| 52 "'nodeId':1,'nodeName':'#document','nodeType':9,'nodeValue':''," |
| 53 "'xmlVersion':''}", |
| 54 |
| 55 "{'attributes':[],'childIndicies':[2,5],'frameId':'?','localName'" |
| 56 ":'html','nodeId':2,'nodeName':'HTML','nodeType':1,'nodeValue':''}", |
| 57 |
| 58 "{'attributes':[],'boundingBox':{'height':600.0,'width':800.0,'x':0.0,'" |
| 59 "y':0.0},'childIndicies':[3],'localName':'head','nodeId':3,'nodeName':'" |
| 60 "HEAD','nodeType':1,'nodeValue':''}", |
| 61 |
| 62 "{'attributes':[],'boundingBox':{'height':584.0,'width':784.0,'x':8.0,'" |
| 63 "y':8.0},'childIndicies':[4],'localName':'title','nodeId':5,'nodeName':" |
| 64 "'TITLE','nodeType':1,'nodeValue':''}", |
| 65 |
| 66 "{'boundingBox':{'height':226.0,'width':784.0,'x':8.0,'y':8.0},'" |
| 67 "localName':'','nodeId':6,'nodeName':'#text','nodeType':3,'nodeValue':'" |
| 68 "Hello world!'}", |
| 69 |
| 70 "{'attributes':[],'boundingBox':{'height':600.0,'width':800.0,'x':0.0,'" |
| 71 "y':0.0},'childIndicies':[6],'localName':'body','nodeId':4,'nodeName':'" |
| 72 "BODY','nodeType':1,'nodeValue':''}", |
| 73 |
| 74 "{'attributes':['id','id1'],'boundingBox':{'height':17.0,'width':73.0,'" |
| 75 "x':8.0,'y':198.0},'childIndicies':[7,8,15],'inlineTextNodes':[{'" |
| 76 "boundingBox':{'height':17.0,'width':72.4375,'x':8.0,'y':198.0},'" |
| 77 "numCharacters':11,'startCharacterIndex':1}],'layoutText':'\\nSome " |
| 78 "text.\\n','localName':'div','nodeId':7,'nodeName':'DIV','nodeType':1,'" |
| 79 "nodeValue':''}", |
| 80 |
| 81 "{'boundingBox':{'height':200.0,'width':400.0,'x':82.0,'y':10.0},'" |
| 82 "localName':'','nodeId':8,'nodeName':'#text','nodeType':3,'nodeValue':'" |
| 83 "\\nSome text.\\n'}", |
| 84 |
| 85 "{'attributes':['src','/iframe.html','width','400','height','200']," |
| 86 "'boundingBox':{'height':171.0,'width':384.0,'x':90.0,'y':18.0}," |
| 87 "'childIndicies':[],'contentDocumentIndex':9,'frameId':'?'," |
| 88 "'localName':'iframe','nodeId':9,'nodeName':'IFRAME','nodeType':1," |
| 89 "'nodeValue':''}", |
| 90 |
| 91 "{'baseURL':'http://127.0.0.1/iframe.html','boundingBox':{" |
| 92 "'height':37.0,'width':384.0,'x':90.0,'y':18.0},'childIndicies':[10]," |
| 93 "'documentURL':'http://127.0.0.1/iframe.html','localName':''," |
| 94 "'nodeId':10,'nodeName':'#document','nodeType':9,'nodeValue':''," |
| 95 "'xmlVersion':''}", |
| 96 |
| 97 "{'attributes':[],'boundingBox':{'height':36.0,'width':308.0,'x':8.0,'" |
| 98 "y':8.0},'childIndicies':[11,12],'frameId':'?','inlineTextNodes':" |
| 99 "[{'boundingBox':{'height':36.0,'width':307.734375,'x':8.0,'y':8.0},'" |
| 100 "numCharacters':22,'startCharacterIndex':0}],'layoutText':'Hello from " |
| 101 "the iframe!','localName':'html','nodeId':11,'nodeName':'HTML'," |
| 102 "'nodeType':1,'nodeValue':''}", |
| 103 |
| 104 "{'attributes':[],'boundingBox':{'height':204.0,'width':405.0,'x':80.0," |
| 105 "'y':8.0},'childIndicies':[],'localName':'head','nodeId':12,'nodeName':" |
| 106 "'HEAD','nodeType':1,'nodeValue':''}", |
| 107 |
| 108 "{'attributes':[],'boundingBox':{'height':0.0,'width':0.0,'x':0.0,'y':" |
| 109 "0.0},'childIndicies':[13],'layoutText':'\\n','localName':'body','" |
| 110 "nodeId':13,'nodeName':'BODY','nodeType':1,'nodeValue':''}", |
| 111 |
| 112 "{'attributes':[],'boundingBox':{'height':18.0,'width':784.0,'x':8.0,'" |
| 113 "y':216.0},'childIndicies':[14],'localName':'h1','nodeId':14,'nodeName'" |
| 114 ":'H1','nodeType':1,'nodeValue':''}", |
| 115 |
| 116 "{'boundingBox':{'height':18.0,'width':784.0,'x':8.0,'y':216.0},'" |
| 117 "localName':'','nodeId':15,'nodeName':'#text','nodeType':3,'nodeValue':" |
| 118 "'Hello from the iframe!'}", |
| 119 |
| 120 "{'attributes':['id','id2'],'boundingBox':{'height':18.0,'width':784.0," |
| 121 "'x':8.0,'y':216.0},'childIndicies':[16],'localName':'div','nodeId':16," |
| 122 "'nodeName':'DIV','nodeType':1,'nodeValue':''}", |
| 123 |
| 124 "{'attributes':['id','id3'],'boundingBox':{'height':17.0,'width':53.0,'" |
| 125 "x':8.0,'y':216.0},'childIndicies':[17],'localName':'div','nodeId':17,'" |
| 126 "nodeName':'DIV','nodeType':1,'nodeValue':''}", |
| 127 |
| 128 "{'attributes':['id','id4'],'boundingBox':{'height':17.0,'width':53.0,'" |
| 129 "x':8.0,'y':216.0},'childIndicies':[18],'inlineTextNodes':[{'" |
| 130 "boundingBox':{'height':17.0,'width':52.421875,'x':8.0,'y':216.0},'" |
| 131 "numCharacters':7,'startCharacterIndex':0}],'layoutText':'Google!','" |
| 132 "localName':'div','nodeId':18,'nodeName':'DIV','nodeType':1,'nodeValue'" |
| 133 ":''}", |
| 134 |
| 135 "{'attributes':['href','https://www.google.com'],'boundingBox':{" |
| 136 "'height':0.0,'width':0.0,'x':0.0,'y':0.0},'childIndicies':[19]," |
| 137 "'layoutText':'\\n ','localName':'a','nodeId':19,'nodeName':'A'," |
| 138 "'nodeType':1,'nodeValue':''}", |
| 139 |
| 140 "{'localName':'','nodeId':20,'nodeName':'#text','nodeType':3,'" |
| 141 "nodeValue':'Google!'}"}; |
| 142 |
| 143 GURL::Replacements replace_port; |
| 144 replace_port.SetPortStr(""); |
| 145 for (size_t i = 0; i < dom_tree.size(); i++) { |
| 146 // Frame IDs are random. |
| 147 if (dom_tree[i]->HasKey("frameId")) |
| 148 dom_tree[i]->SetString("frameId", "?"); |
| 149 |
| 150 // Ports are random. |
| 151 std::string url; |
| 152 if (dom_tree[i]->GetString("baseURL", &url)) { |
| 153 dom_tree[i]->SetString( |
| 154 "baseURL", GURL(url).ReplaceComponents(replace_port).spec()); |
| 155 } |
| 156 |
| 157 if (dom_tree[i]->GetString("documentURL", &url)) { |
| 158 dom_tree[i]->SetString( |
| 159 "documentURL", GURL(url).ReplaceComponents(replace_port).spec()); |
| 160 } |
| 161 |
| 162 std::string result_json; |
| 163 base::JSONWriter::Write(*dom_tree[i], &result_json); |
| 164 |
| 165 // Not allowed to use C++11 string literals so we make do as best we can. |
| 166 base::ReplaceChars(result_json, "\"", "'", &result_json); |
| 167 |
| 168 ASSERT_LT(i, expected_results.size()); |
| 169 EXPECT_EQ(expected_results[i], result_json) << " Node # " << i; |
| 170 } |
| 171 |
| 172 FinishAsynchronousTest(); |
| 173 } |
| 174 |
| 175 std::unique_ptr<DomTreeExtractor> extractor_; |
| 176 }; |
| 177 |
| 178 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DomTreeExtractorBrowserTest); |
| 179 |
| 180 } // namespace headless |
OLD | NEW |