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