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