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