Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: headless/public/util/dom_tree_extractor_browsertest.cc

Issue 2385653003: Add a utility class for extracting details of the DOM (Closed)
Patch Set: Support CSS dumps Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
43 std::vector<std::string> css_whitelist = {
44 "color", "display", "font-style", "margin-left",
45 "margin-right", "margin-top", "margin-bottom"};
46 extractor_->ExtractDomTree(
47 css_whitelist,
48 base::Bind(&DomTreeExtractorBrowserTest::OnDomTreeExtracted,
49 base::Unretained(this)));
50 }
51
52 void OnDomTreeExtracted(DomTreeExtractor::DomTree dom_tree) {
53 GURL::Replacements replace_port;
54 replace_port.SetPortStr("");
55
56 std::vector<std::unique_ptr<base::DictionaryValue>> dom_nodes(
57 dom_tree.dom_nodes_.size());
58
59 // For convenience flatten the dom tree into an array.
60 for (size_t i = 0; i < dom_tree.dom_nodes_.size(); i++) {
61 dom::Node* node = const_cast<dom::Node*>(dom_tree.dom_nodes_[i]);
62
63 dom_nodes[i].reset(
64 static_cast<base::DictionaryValue*>(node->Serialize().release()));
65
66 // Convert child & content document pointers into indexes.
67 if (node->HasChildren()) {
68 std::unique_ptr<base::ListValue> children(new base::ListValue());
69 for (const std::unique_ptr<dom::Node>& child : *node->GetChildren()) {
70 children->AppendInteger(
71 dom_tree.node_id_to_index_[child->GetNodeId()]);
72 }
73 dom_nodes[i]->Set("childIndices", std::move(children));
74 dom_nodes[i]->Remove("children", nullptr);
75 }
76
77 if (node->HasContentDocument()) {
78 dom_nodes[i]->SetInteger(
79 "contentDocumentIndex",
80 dom_tree
81 .node_id_to_index_[node->GetContentDocument()->GetNodeId()]);
82 dom_nodes[i]->Remove("contentDocument", nullptr);
83 }
84
85 dom_nodes[i]->Remove("childNodeCount", nullptr);
86
87 // Frame IDs are random.
88 if (dom_nodes[i]->HasKey("frameId"))
89 dom_nodes[i]->SetString("frameId", "?");
90
91 // Ports are random.
92 std::string url;
93 if (dom_nodes[i]->GetString("baseURL", &url)) {
94 dom_nodes[i]->SetString(
95 "baseURL", GURL(url).ReplaceComponents(replace_port).spec());
96 }
97
98 if (dom_nodes[i]->GetString("documentURL", &url)) {
99 dom_nodes[i]->SetString(
100 "documentURL", GURL(url).ReplaceComponents(replace_port).spec());
101 }
102 }
103
104 // Merge LayoutTreeNode data into the dictionaries.
105 for (const css::LayoutTreeNode* layout_node : dom_tree.layout_tree_nodes_) {
106 auto it =
107 dom_tree.node_id_to_index_.find(layout_node->GetBackendNodeId());
108 ASSERT_TRUE(it != dom_tree.node_id_to_index_.end());
109
110 base::DictionaryValue* node_dict = dom_nodes[it->second].get();
111 node_dict->Set("boundingBox", layout_node->GetBoundingBox()->Serialize());
112
113 if (layout_node->HasLayoutText())
114 node_dict->SetString("layoutText", layout_node->GetLayoutText());
115
116 if (layout_node->HasStyleIndex())
117 node_dict->SetInteger("styleIndex", layout_node->GetStyleIndex());
118
119 if (layout_node->HasInlineTextNodes()) {
120 std::unique_ptr<base::ListValue> inline_text_nodes(
121 new base::ListValue());
122 for (const std::unique_ptr<css::InlineTextBox>& inline_text_box :
123 *layout_node->GetInlineTextNodes()) {
124 size_t index = inline_text_nodes->GetSize();
125 inline_text_nodes->Set(index, inline_text_box->Serialize());
126 }
127 node_dict->Set("inlineTextNodes", std::move(inline_text_nodes));
128 }
129 }
130
131 std::vector<std::unique_ptr<base::DictionaryValue>> computed_styles(
132 dom_tree.computed_styles_.size());
133
134 for (size_t i = 0; i < dom_tree.computed_styles_.size(); i++) {
135 std::unique_ptr<base::DictionaryValue> style(new base::DictionaryValue());
136 for (const auto& style_proprty :
Eric Seckler 2016/10/20 08:43:58 nit: style_property
alex clarke (OOO till 29th) 2016/10/20 09:26:25 Done.
137 *dom_tree.computed_styles_[i]->GetProperties()) {
138 style->SetString(style_proprty->GetName(), style_proprty->GetValue());
139 }
140 computed_styles[i] = std::move(style);
141 }
142
143 const std::vector<std::string> expected_dom_nodes = {
144 "{\n"
145 " 'baseURL': 'http://127.0.0.1/dom_tree_test.html',\n"
146 " 'childIndices': [ 1 ],\n"
147 " 'documentURL': 'http://127.0.0.1/dom_tree_test.html',\n"
148 " 'localName': '',\n"
149 " 'nodeId': 1,\n"
150 " 'nodeName': '#document',\n"
151 " 'nodeType': 9,\n"
152 " 'nodeValue': '',\n"
153 " 'xmlVersion': ''\n"
154 "}\n",
155
156 "{\n"
157 " 'attributes': [ ],\n"
158 " 'childIndices': [ 2, 5 ],\n"
159 " 'frameId': '?',\n"
160 " 'localName': 'html',\n"
161 " 'nodeId': 2,\n"
162 " 'nodeName': 'HTML',\n"
163 " 'nodeType': 1,\n"
164 " 'nodeValue': ''\n"
165 "}\n",
166
167 "{\n"
168 " 'attributes': [ ],\n"
169 " 'boundingBox': {\n"
170 " 'height': 600.0,\n"
171 " 'width': 800.0,\n"
172 " 'x': 0.0,\n"
173 " 'y': 0.0\n"
174 " },\n"
175 " 'childIndices': [ 3 ],\n"
176 " 'localName': 'head',\n"
177 " 'nodeId': 3,\n"
178 " 'nodeName': 'HEAD',\n"
179 " 'nodeType': 1,\n"
180 " 'nodeValue': '',\n"
181 " 'styleIndex': 0\n"
182 "}\n",
183
184 "{\n"
185 " 'attributes': [ ],\n"
186 " 'boundingBox': {\n"
187 " 'height': 600.0,\n"
188 " 'width': 800.0,\n"
189 " 'x': 0.0,\n"
190 " 'y': 0.0\n"
191 " },\n"
192 " 'childIndices': [ 4 ],\n"
193 " 'localName': 'title',\n"
194 " 'nodeId': 4,\n"
195 " 'nodeName': 'TITLE',\n"
196 " 'nodeType': 1,\n"
197 " 'nodeValue': '',\n"
198 " 'styleIndex': 1\n"
199 "}\n",
200
201 "{\n"
202 " 'boundingBox': {\n"
203 " 'height': 584.0,\n"
204 " 'width': 784.0,\n"
205 " 'x': 8.0,\n"
206 " 'y': 8.0\n"
207 " },\n"
208 " 'localName': '',\n"
209 " 'nodeId': 5,\n"
210 " 'nodeName': '#text',\n"
211 " 'nodeType': 3,\n"
212 " 'nodeValue': 'Hello world!',\n"
213 " 'styleIndex': 2\n"
214 "}\n",
215
216 "{\n"
217 " 'attributes': [ ],\n"
218 " 'boundingBox': {\n"
219 " 'height': 367.0,\n"
220 " 'width': 784.0,\n"
221 " 'x': 8.0,\n"
222 " 'y': 8.0\n"
223 " },\n"
224 " 'childIndices': [ 6 ],\n"
225 " 'localName': 'body',\n"
226 " 'nodeId': 6,\n"
227 " 'nodeName': 'BODY',\n"
228 " 'nodeType': 1,\n"
229 " 'nodeValue': '',\n"
230 " 'styleIndex': 1\n"
231 "}\n",
232
233 "{\n"
234 " 'attributes': [ 'id', 'id1' ],\n"
235 " 'boundingBox': {\n"
236 " 'height': 37.0,\n"
237 " 'width': 784.0,\n"
238 " 'x': 8.0,\n"
239 " 'y': 8.0\n"
240 " },\n"
241 " 'childIndices': [ 7, 9, 16 ],\n"
242 " 'localName': 'div',\n"
243 " 'nodeId': 7,\n"
244 " 'nodeName': 'DIV',\n"
245 " 'nodeType': 1,\n"
246 " 'nodeValue': '',\n"
247 " 'styleIndex': 3\n"
248 "}\n",
249
250 "{\n"
251 " 'attributes': [ 'style', 'color: red' ],\n"
252 " 'boundingBox': {\n"
253 " 'height': 36.0,\n"
254 " 'width': 143.0,\n"
255 " 'x': 8.0,\n"
256 " 'y': 8.0\n"
257 " },\n"
258 " 'childIndices': [ 8 ],\n"
259 " 'inlineTextNodes': [ {\n"
260 " 'boundingBox': {\n"
261 " 'height': 36.0,\n"
262 " 'width': 142.171875,\n"
263 " 'x': 8.0,\n"
264 " 'y': 8.0\n"
265 " },\n"
266 " 'numCharacters': 10,\n"
267 " 'startCharacterIndex': 0\n"
268 " } ],\n"
269 " 'layoutText': 'Some text.',\n"
270 " 'localName': 'h1',\n"
271 " 'nodeId': 8,\n"
272 " 'nodeName': 'H1',\n"
273 " 'nodeType': 1,\n"
274 " 'nodeValue': '',\n"
275 " 'styleIndex': 3\n"
276 "}\n",
277
278 "{\n"
279 " 'boundingBox': {\n"
280 " 'height': 200.0,\n"
281 " 'width': 400.0,\n"
282 " 'x': 10.0,\n"
283 " 'y': 68.0\n"
284 " },\n"
285 " 'localName': '',\n"
286 " 'nodeId': 9,\n"
287 " 'nodeName': '#text',\n"
288 " 'nodeType': 3,\n"
289 " 'nodeValue': 'Some text.',\n"
290 " 'styleIndex': 1\n"
291 "}\n",
292
293 "{\n"
294 " 'attributes': [ 'src', '/iframe.html', 'width', '400', 'height', "
295 "'200' ],\n"
296 " 'boundingBox': {\n"
297 " 'height': 171.0,\n"
298 " 'width': 384.0,\n"
299 " 'x': 18.0,\n"
300 " 'y': 76.0\n"
301 " },\n"
302 " 'childIndices': [ ],\n"
303 " 'contentDocumentIndex': 10,\n"
304 " 'frameId': '?',\n"
305 " 'localName': 'iframe',\n"
306 " 'nodeId': 10,\n"
307 " 'nodeName': 'IFRAME',\n"
308 " 'nodeType': 1,\n"
309 " 'nodeValue': '',\n"
310 " 'styleIndex': 2\n"
311 "}\n",
312
313 "{\n"
314 " 'baseURL': 'http://127.0.0.1/iframe.html',\n"
315 " 'boundingBox': {\n"
316 " 'height': 37.0,\n"
317 " 'width': 384.0,\n"
318 " 'x': 18.0,\n"
319 " 'y': 76.0\n"
320 " },\n"
321 " 'childIndices': [ 11 ],\n"
322 " 'documentURL': 'http://127.0.0.1/iframe.html',\n"
323 " 'localName': '',\n"
324 " 'nodeId': 11,\n"
325 " 'nodeName': '#document',\n"
326 " 'nodeType': 9,\n"
327 " 'nodeValue': '',\n"
328 " 'styleIndex': 4,\n"
329 " 'xmlVersion': ''\n"
330 "}\n",
331
332 "{\n"
333 " 'attributes': [ ],\n"
334 " 'boundingBox': {\n"
335 " 'height': 36.0,\n"
336 " 'width': 308.0,\n"
337 " 'x': 8.0,\n"
338 " 'y': 8.0\n"
339 " },\n"
340 " 'childIndices': [ 12, 13 ],\n"
341 " 'frameId': '?',\n"
342 " 'inlineTextNodes': [ {\n"
343 " 'boundingBox': {\n"
344 " 'height': 36.0,\n"
345 " 'width': 307.734375,\n"
346 " 'x': 8.0,\n"
347 " 'y': 8.0\n"
348 " },\n"
349 " 'numCharacters': 22,\n"
350 " 'startCharacterIndex': 0\n"
351 " } ],\n"
352 " 'layoutText': 'Hello from the iframe!',\n"
353 " 'localName': 'html',\n"
354 " 'nodeId': 12,\n"
355 " 'nodeName': 'HTML',\n"
356 " 'nodeType': 1,\n"
357 " 'nodeValue': '',\n"
358 " 'styleIndex': 4\n"
359 "}\n",
360
361 "{\n"
362 " 'attributes': [ ],\n"
363 " 'boundingBox': {\n"
364 " 'height': 205.0,\n"
365 " 'width': 404.0,\n"
366 " 'x': 8.0,\n"
367 " 'y': 66.0\n"
368 " },\n"
369 " 'childIndices': [ ],\n"
370 " 'localName': 'head',\n"
371 " 'nodeId': 13,\n"
372 " 'nodeName': 'HEAD',\n"
373 " 'nodeType': 1,\n"
374 " 'nodeValue': '',\n"
375 " 'styleIndex': 5\n"
376 "}\n",
377
378 "{\n"
379 " 'attributes': [ ],\n"
380 " 'boundingBox': {\n"
381 " 'height': 0.0,\n"
382 " 'width': 0.0,\n"
383 " 'x': 0.0,\n"
384 " 'y': 0.0\n"
385 " },\n"
386 " 'childIndices': [ 14 ],\n"
387 " 'layoutText': '\\n',\n"
388 " 'localName': 'body',\n"
389 " 'nodeId': 14,\n"
390 " 'nodeName': 'BODY',\n"
391 " 'nodeType': 1,\n"
392 " 'nodeValue': '',\n"
393 " 'styleIndex': 1\n"
394 "}\n",
395
396 "{\n"
397 " 'attributes': [ ],\n"
398 " 'boundingBox': {\n"
399 " 'height': 105.0,\n"
400 " 'width': 784.0,\n"
401 " 'x': 8.0,\n"
402 " 'y': 270.0\n"
403 " },\n"
404 " 'childIndices': [ 15 ],\n"
405 " 'localName': 'h1',\n"
406 " 'nodeId': 15,\n"
407 " 'nodeName': 'H1',\n"
408 " 'nodeType': 1,\n"
409 " 'nodeValue': '',\n"
410 " 'styleIndex': 1\n"
411 "}\n",
412
413 "{\n"
414 " 'boundingBox': {\n"
415 " 'height': 105.0,\n"
416 " 'width': 784.0,\n"
417 " 'x': 8.0,\n"
418 " 'y': 270.0\n"
419 " },\n"
420 " 'localName': '',\n"
421 " 'nodeId': 16,\n"
422 " 'nodeName': '#text',\n"
423 " 'nodeType': 3,\n"
424 " 'nodeValue': 'Hello from the iframe!',\n"
425 " 'styleIndex': 1\n"
426 "}\n",
427
428 "{\n"
429 " 'attributes': [ 'id', 'id2' ],\n"
430 " 'boundingBox': {\n"
431 " 'height': 105.0,\n"
432 " 'width': 784.0,\n"
433 " 'x': 8.0,\n"
434 " 'y': 270.0\n"
435 " },\n"
436 " 'childIndices': [ 17 ],\n"
437 " 'localName': 'div',\n"
438 " 'nodeId': 17,\n"
439 " 'nodeName': 'DIV',\n"
440 " 'nodeType': 1,\n"
441 " 'nodeValue': '',\n"
442 " 'styleIndex': 1\n"
443 "}\n",
444
445 "{\n"
446 " 'attributes': [ 'id', 'id3' ],\n"
447 " 'boundingBox': {\n"
448 " 'height': 18.0,\n"
449 " 'width': 53.0,\n"
450 " 'x': 8.0,\n"
451 " 'y': 270.0\n"
452 " },\n"
453 " 'childIndices': [ 18 ],\n"
454 " 'localName': 'div',\n"
455 " 'nodeId': 18,\n"
456 " 'nodeName': 'DIV',\n"
457 " 'nodeType': 1,\n"
458 " 'nodeValue': '',\n"
459 " 'styleIndex': 6\n"
460 "}\n",
461
462 "{\n"
463 " 'attributes': [ 'id', 'id4' ],\n"
464 " 'boundingBox': {\n"
465 " 'height': 18.0,\n"
466 " 'width': 53.0,\n"
467 " 'x': 8.0,\n"
468 " 'y': 270.0\n"
469 " },\n"
470 " 'childIndices': [ 19, 21, 23, 24 ],\n"
471 " 'inlineTextNodes': [ {\n"
472 " 'boundingBox': {\n"
473 " 'height': 17.0,\n"
474 " 'width': 52.421875,\n"
475 " 'x': 8.0,\n"
476 " 'y': 270.4375\n"
477 " },\n"
478 " 'numCharacters': 7,\n"
479 " 'startCharacterIndex': 0\n"
480 " } ],\n"
481 " 'layoutText': 'Google!',\n"
482 " 'localName': 'div',\n"
483 " 'nodeId': 19,\n"
484 " 'nodeName': 'DIV',\n"
485 " 'nodeType': 1,\n"
486 " 'nodeValue': '',\n"
487 " 'styleIndex': 6\n"
488 "}\n",
489
490 "{\n"
491 " 'attributes': [ 'href', 'https://www.google.com' ],\n"
492 " 'boundingBox': {\n"
493 " 'height': 0.0,\n"
494 " 'width': 0.0,\n"
495 " 'x': 0.0,\n"
496 " 'y': 0.0\n"
497 " },\n"
498 " 'childIndices': [ 20 ],\n"
499 " 'layoutText': '\\n ',\n"
500 " 'localName': 'a',\n"
501 " 'nodeId': 20,\n"
502 " 'nodeName': 'A',\n"
503 " 'nodeType': 1,\n"
504 " 'nodeValue': '',\n"
505 " 'styleIndex': 1\n"
506 "}\n",
507
508 "{\n"
509 " 'boundingBox': {\n"
510 " 'height': 19.0,\n"
511 " 'width': 784.0,\n"
512 " 'x': 8.0,\n"
513 " 'y': 304.0\n"
514 " },\n"
515 " 'localName': '',\n"
516 " 'nodeId': 21,\n"
517 " 'nodeName': '#text',\n"
518 " 'nodeType': 3,\n"
519 " 'nodeValue': 'Google!',\n"
520 " 'styleIndex': 7\n"
521 "}\n",
522
523 "{\n"
524 " 'attributes': [ ],\n"
525 " 'boundingBox': {\n"
526 " 'height': 18.0,\n"
527 " 'width': 85.0,\n"
528 " 'x': 8.0,\n"
529 " 'y': 304.0\n"
530 " },\n"
531 " 'childIndices': [ 22 ],\n"
532 " 'inlineTextNodes': [ {\n"
533 " 'boundingBox': {\n"
534 " 'height': 17.0,\n"
535 " 'width': 84.84375,\n"
536 " 'x': 8.0,\n"
537 " 'y': 304.4375\n"
538 " },\n"
539 " 'numCharacters': 12,\n"
540 " 'startCharacterIndex': 0\n"
541 " } ],\n"
542 " 'layoutText': 'A paragraph!',\n"
543 " 'localName': 'p',\n"
544 " 'nodeId': 22,\n"
545 " 'nodeName': 'P',\n"
546 " 'nodeType': 1,\n"
547 " 'nodeValue': '',\n"
548 " 'styleIndex': 7\n"
549 "}\n",
550
551 "{\n"
552 " 'boundingBox': {\n"
553 " 'height': 0.0,\n"
554 " 'width': 0.0,\n"
555 " 'x': 0.0,\n"
556 " 'y': 0.0\n"
557 " },\n"
558 " 'inlineTextNodes': [ {\n"
559 " 'boundingBox': {\n"
560 " 'height': 17.0,\n"
561 " 'width': 0.0,\n"
562 " 'x': 8.0,\n"
563 " 'y': 338.4375\n"
564 " },\n"
565 " 'numCharacters': 1,\n"
566 " 'startCharacterIndex': 0\n"
567 " } ],\n"
568 " 'layoutText': '\\n',\n"
569 " 'localName': '',\n"
570 " 'nodeId': 23,\n"
571 " 'nodeName': '#text',\n"
572 " 'nodeType': 3,\n"
573 " 'nodeValue': 'A paragraph!',\n"
574 " 'styleIndex': 5\n"
575 "}\n",
576
577 "{\n"
578 " 'attributes': [ ],\n"
579 " 'boundingBox': {\n"
580 " 'height': 19.0,\n"
581 " 'width': 784.0,\n"
582 " 'x': 8.0,\n"
583 " 'y': 356.0\n"
584 " },\n"
585 " 'childIndices': [ ],\n"
586 " 'localName': 'br',\n"
587 " 'nodeId': 24,\n"
588 " 'nodeName': 'BR',\n"
589 " 'nodeType': 1,\n"
590 " 'nodeValue': '',\n"
591 " 'styleIndex': 8\n"
592 "}\n",
593
594 "{\n"
595 " 'attributes': [ 'style', 'color: green' ],\n"
596 " 'boundingBox': {\n"
597 " 'height': 18.0,\n"
598 " 'width': 41.0,\n"
599 " 'x': 8.0,\n"
600 " 'y': 356.0\n"
601 " },\n"
602 " 'childIndices': [ 25, 26, 28 ],\n"
603 " 'inlineTextNodes': [ {\n"
604 " 'boundingBox': {\n"
605 " 'height': 17.0,\n"
606 " 'width': 40.4375,\n"
607 " 'x': 8.0,\n"
608 " 'y': 356.4375\n"
609 " },\n"
610 " 'numCharacters': 5,\n"
611 " 'startCharacterIndex': 0\n"
612 " } ],\n"
613 " 'layoutText': 'Some ',\n"
614 " 'localName': 'div',\n"
615 " 'nodeId': 25,\n"
616 " 'nodeName': 'DIV',\n"
617 " 'nodeType': 1,\n"
618 " 'nodeValue': '',\n"
619 " 'styleIndex': 8\n"
620 "}\n",
621
622 "{\n"
623 " 'boundingBox': {\n"
624 " 'height': 18.0,\n"
625 " 'width': 37.0,\n"
626 " 'x': 48.0,\n"
627 " 'y': 356.0\n"
628 " },\n"
629 " 'localName': '',\n"
630 " 'nodeId': 26,\n"
631 " 'nodeName': '#text',\n"
632 " 'nodeType': 3,\n"
633 " 'nodeValue': 'Some ',\n"
634 " 'styleIndex': 9\n"
635 "}\n",
636
637 "{\n"
638 " 'attributes': [ ],\n"
639 " 'boundingBox': {\n"
640 " 'height': 18.0,\n"
641 " 'width': 37.0,\n"
642 " 'x': 48.0,\n"
643 " 'y': 356.0\n"
644 " },\n"
645 " 'childIndices': [ 27 ],\n"
646 " 'inlineTextNodes': [ {\n"
647 " 'boundingBox': {\n"
648 " 'height': 17.0,\n"
649 " 'width': 35.828125,\n"
650 " 'x': 48.4375,\n"
651 " 'y': 356.4375\n"
652 " },\n"
653 " 'numCharacters': 5,\n"
654 " 'startCharacterIndex': 0\n"
655 " } ],\n"
656 " 'layoutText': 'green',\n"
657 " 'localName': 'em',\n"
658 " 'nodeId': 27,\n"
659 " 'nodeName': 'EM',\n"
660 " 'nodeType': 1,\n"
661 " 'nodeValue': '',\n"
662 " 'styleIndex': 9\n"
663 "}\n",
664
665 "{\n"
666 " 'boundingBox': {\n"
667 " 'height': 18.0,\n"
668 " 'width': 41.0,\n"
669 " 'x': 84.0,\n"
670 " 'y': 356.0\n"
671 " },\n"
672 " 'inlineTextNodes': [ {\n"
673 " 'boundingBox': {\n"
674 " 'height': 17.0,\n"
675 " 'width': 39.984375,\n"
676 " 'x': 84.265625,\n"
677 " 'y': 356.4375\n"
678 " },\n"
679 " 'numCharacters': 8,\n"
680 " 'startCharacterIndex': 0\n"
681 " } ],\n"
682 " 'layoutText': ' text...',\n"
683 " 'localName': '',\n"
684 " 'nodeId': 28,\n"
685 " 'nodeName': '#text',\n"
686 " 'nodeType': 3,\n"
687 " 'nodeValue': 'green',\n"
688 " 'styleIndex': 8\n"
689 "}\n",
690
691 "{\n"
692 " 'localName': '',\n"
693 " 'nodeId': 29,\n"
694 " 'nodeName': '#text',\n"
695 " 'nodeType': 3,\n"
696 " 'nodeValue': ' text...'\n"
697 "}\n"};
698
699 EXPECT_EQ(expected_dom_nodes.size(), dom_nodes.size());
700
701 for (size_t i = 0; i < dom_nodes.size(); i++) {
702 std::string result_json;
703 base::JSONWriter::WriteWithOptions(
704 *dom_nodes[i], base::JSONWriter::OPTIONS_PRETTY_PRINT, &result_json);
705
706 base::ReplaceChars(result_json, "\"", "'", &result_json);
707
708 ASSERT_LT(i, expected_dom_nodes.size());
709 EXPECT_EQ(expected_dom_nodes[i], result_json) << " Node # " << i;
710 }
711
712 const std::vector<std::string> expected_styles = {
713 "{\n"
714 " 'color': '',\n"
715 " 'display': '',\n"
716 " 'font-style': '',\n"
717 " 'margin-bottom': '',\n"
718 " 'margin-left': '',\n"
719 " 'margin-right': '',\n"
720 " 'margin-top': ''\n"
721 "}\n",
722
723 "{\n"
724 " 'color': 'rgb(0, 0, 0)',\n"
725 " 'display': 'block',\n"
726 " 'font-style': 'normal',\n"
727 " 'margin-bottom': '0px',\n"
728 " 'margin-left': '0px',\n"
729 " 'margin-right': '0px',\n"
730 " 'margin-top': '0px'\n"
731 "}\n",
732
733 "{\n"
734 " 'color': 'rgb(0, 0, 0)',\n"
735 " 'display': 'block',\n"
736 " 'font-style': 'normal',\n"
737 " 'margin-bottom': '8px',\n"
738 " 'margin-left': '8px',\n"
739 " 'margin-right': '8px',\n"
740 " 'margin-top': '8px'\n"
741 "}\n",
742
743 "{\n"
744 " 'color': 'rgb(255, 0, 0)',\n"
745 " 'display': 'block',\n"
746 " 'font-style': 'normal',\n"
747 " 'margin-bottom': '21.44px',\n"
748 " 'margin-left': '0px',\n"
749 " 'margin-right': '0px',\n"
750 " 'margin-top': '21.44px'\n"
751 "}\n",
752
753 "{\n"
754 " 'color': 'rgb(0, 0, 0)',\n"
755 " 'display': 'block',\n"
756 " 'font-style': 'normal',\n"
757 " 'margin-bottom': '21.44px',\n"
758 " 'margin-left': '0px',\n"
759 " 'margin-right': '0px',\n"
760 " 'margin-top': '21.44px'\n"
761 "}\n",
762
763 "{\n"
764 " 'color': 'rgb(0, 0, 0)',\n"
765 " 'display': 'inline',\n"
766 " 'font-style': 'normal',\n"
767 " 'margin-bottom': '0px',\n"
768 " 'margin-left': '0px',\n"
769 " 'margin-right': '0px',\n"
770 " 'margin-top': '0px'\n"
771 "}\n",
772
773 "{\n"
774 " 'color': 'rgb(0, 0, 238)',\n"
775 " 'display': 'inline',\n"
776 " 'font-style': 'normal',\n"
777 " 'margin-bottom': '0px',\n"
778 " 'margin-left': '0px',\n"
779 " 'margin-right': '0px',\n"
780 " 'margin-top': '0px'\n"
781 "}\n",
782
783 "{\n"
784 " 'color': 'rgb(0, 0, 0)',\n"
785 " 'display': 'block',\n"
786 " 'font-style': 'normal',\n"
787 " 'margin-bottom': '16px',\n"
788 " 'margin-left': '0px',\n"
789 " 'margin-right': '0px',\n"
790 " 'margin-top': '16px'\n"
791 "}\n",
792
793 "{\n"
794 " 'color': 'rgb(0, 128, 0)',\n"
795 " 'display': 'block',\n"
796 " 'font-style': 'normal',\n"
797 " 'margin-bottom': '0px',\n"
798 " 'margin-left': '0px',\n"
799 " 'margin-right': '0px',\n"
800 " 'margin-top': '0px'\n"
801 "}\n",
802
803 "{\n"
804 " 'color': 'rgb(0, 128, 0)',\n"
805 " 'display': 'inline',\n"
806 " 'font-style': 'italic',\n"
807 " 'margin-bottom': '0px',\n"
808 " 'margin-left': '0px',\n"
809 " 'margin-right': '0px',\n"
810 " 'margin-top': '0px'\n"
811 "}\n"};
812
813 for (size_t i = 0; i < computed_styles.size(); i++) {
814 std::string result_json;
815 base::JSONWriter::WriteWithOptions(*computed_styles[i],
816 base::JSONWriter::OPTIONS_PRETTY_PRINT,
817 &result_json);
818
819 base::ReplaceChars(result_json, "\"", "'", &result_json);
820
821 ASSERT_LT(i, expected_styles.size());
822 EXPECT_EQ(expected_styles[i], result_json) << " Style # " << i;
823 }
824
825 FinishAsynchronousTest();
826 }
827
828 std::unique_ptr<DomTreeExtractor> extractor_;
829 };
830
831 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DomTreeExtractorBrowserTest);
832
833 } // namespace headless
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698