1 // Copyright 2015 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.
5 #include "base/callback.h"
6 #include "base/logging.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/path_service.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "components/dom_distiller/content/web_contents_main_frame_observer.h"
14 #include "content/public/browser/navigation_controller.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/web_contents_observer.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "content/shell/browser/shell.h"
19 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "ui/base/resource/resource_bundle.h"
24 // Helper class to know how far in the loading process the current WebContents
25 // has come. It will call the callback after DocumentLoadedInFrame is called for
27 class WebContentsMainFrameHelper
: public content::WebContentsObserver
{
29 WebContentsMainFrameHelper(content::WebContents
* web_contents
,
30 const base::Closure
& callback
)
31 : WebContentsObserver(web_contents
), callback_(callback
) {}
33 void DocumentLoadedInFrame(
34 content::RenderFrameHost
* render_frame_host
) override
{
35 if (!render_frame_host
->GetParent())
40 base::Closure callback_
;
45 namespace dom_distiller
{
47 const char* kExternalTestResourcesPath
=
48 "third_party/dom_distiller_js/dist/test/data";
49 // TODO(wychen) Remove filter when crbug.com/471854 is fixed.
50 const char* kTestFilePath
=
51 "/war/test.html?console_log=0&filter=-*.SchemaOrgParserAccessorTest.*";
52 const char* kRunJsTestsJs
=
53 "(function() {return org.chromium.distiller.JsTestEntry.run();})();";
55 class DomDistillerJsTest
: public content::ContentBrowserTest
{
57 DomDistillerJsTest() : result_(NULL
) {}
59 // content::ContentBrowserTest:
60 void SetUpOnMainThread() override
{
61 AddComponentsResources();
63 content::ContentBrowserTest::SetUpOnMainThread();
66 void OnJsTestExecutionDone(const base::Value
* value
) {
67 result_
= value
->DeepCopy();
68 js_test_execution_done_callback_
.Run();
72 base::Closure js_test_execution_done_callback_
;
73 const base::Value
* result_
;
76 void AddComponentsResources() {
77 base::FilePath pak_file
;
78 base::FilePath pak_dir
;
79 #if defined(OS_ANDROID)
80 CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA
, &pak_dir
));
81 pak_dir
= pak_dir
.Append(FILE_PATH_LITERAL("paks"));
83 PathService::Get(base::DIR_MODULE
, &pak_dir
);
86 pak_dir
.Append(FILE_PATH_LITERAL("components_tests_resources.pak"));
87 ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
88 pak_file
, ui::SCALE_FACTOR_NONE
);
91 void SetUpTestServer() {
93 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
94 path
= path
.AppendASCII(kExternalTestResourcesPath
);
95 embedded_test_server()->ServeFilesFromDirectory(path
);
96 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
100 IN_PROC_BROWSER_TEST_F(DomDistillerJsTest
, RunJsTests
) {
101 // Load the test file in content shell and wait until it has fully loaded.
102 content::WebContents
* web_contents
= shell()->web_contents();
103 dom_distiller::WebContentsMainFrameObserver::CreateForWebContents(
105 base::RunLoop url_loaded_runner
;
106 WebContentsMainFrameHelper
main_frame_loaded(web_contents
,
107 url_loaded_runner
.QuitClosure());
108 web_contents
->GetController().LoadURL(
109 embedded_test_server()->GetURL(kTestFilePath
),
111 ui::PAGE_TRANSITION_TYPED
,
113 url_loaded_runner
.Run();
115 // Execute the JS to run the tests, and wait until it has finished.
116 base::RunLoop run_loop
;
117 js_test_execution_done_callback_
= run_loop
.QuitClosure();
118 // Add timeout in case JS Test execution fails. It is safe to call the
119 // QuitClosure multiple times.
120 base::MessageLoop::current()->PostDelayedTask(
121 FROM_HERE
, run_loop
.QuitClosure(), base::TimeDelta::FromSeconds(15));
122 web_contents
->GetMainFrame()->ExecuteJavaScript(
123 base::UTF8ToUTF16(kRunJsTestsJs
),
124 base::Bind(&DomDistillerJsTest::OnJsTestExecutionDone
,
125 base::Unretained(this)));
128 // By now either the timeout has triggered, or there should be a result.
129 ASSERT_TRUE(result_
!= NULL
) << "No result found. Timeout?";
131 // Convert to dictionary and parse the results.
132 const base::DictionaryValue
* dict
;
133 result_
->GetAsDictionary(&dict
);
134 ASSERT_TRUE(result_
->GetAsDictionary(&dict
));
136 ASSERT_TRUE(dict
->HasKey("success"));
138 ASSERT_TRUE(dict
->GetBoolean("success", &success
));
140 ASSERT_TRUE(dict
->HasKey("numTests"));
142 ASSERT_TRUE(dict
->GetInteger("numTests", &num_tests
));
144 ASSERT_TRUE(dict
->HasKey("failed"));
146 ASSERT_TRUE(dict
->GetInteger("failed", &failed
));
148 ASSERT_TRUE(dict
->HasKey("skipped"));
150 ASSERT_TRUE(dict
->GetInteger("skipped", &skipped
));
152 VLOG(0) << "Ran " << num_tests
<< " tests. failed = " << failed
153 << " skipped = " << skipped
;
154 // Ensure that running the tests succeeded.
155 EXPECT_TRUE(success
);
157 // Only print the log if there was an error.
159 ASSERT_TRUE(dict
->HasKey("log"));
160 std::string console_log
;
161 ASSERT_TRUE(dict
->GetString("log", &console_log
));
162 VLOG(0) << "Console log:\n" << console_log
;
166 } // namespace dom_distiller