1// Copyright 2014 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 <string>
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/values.h"
10#include "chrome/common/url_constants.h"
11#include "chrome/test/base/ui_test_utils.h"
12#include "chrome/test/base/web_ui_browser_test.h"
13#include "content/public/browser/web_ui.h"
14#include "content/public/browser/web_ui_message_handler.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest-spi.h"
17
18using content::WebUIMessageHandler;
19
20// According to the interface for EXPECT_FATAL_FAILURE
21// (http://code.google.com/p/googletest/wiki/AdvancedGuide#Catching_Failures)
22// the statement must be statically available. Therefore, we make a static
23// global s_test_ which should point to |this| for the duration of the test run
24// and be cleared afterward.
25class WebUIBrowserExpectFailTest : public WebUIBrowserTest {
26 public:
27  WebUIBrowserExpectFailTest() {
28    EXPECT_FALSE(s_test_);
29    s_test_ = this;
30  }
31
32 protected:
33  virtual ~WebUIBrowserExpectFailTest() {
34    EXPECT_TRUE(s_test_);
35    s_test_ = NULL;
36  }
37
38  static void RunJavascriptTestNoReturn(const std::string& testname) {
39    EXPECT_TRUE(s_test_);
40    s_test_->RunJavascriptTest(testname);
41  }
42
43  static void RunJavascriptAsyncTestNoReturn(const std::string& testname) {
44    EXPECT_TRUE(s_test_);
45    s_test_->RunJavascriptAsyncTest(testname);
46  }
47
48 private:
49  static WebUIBrowserTest* s_test_;
50};
51
52WebUIBrowserTest* WebUIBrowserExpectFailTest::s_test_ = NULL;
53
54// Test that bogus javascript fails fast - no timeout waiting for result.
55IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestFailsFast) {
56  AddLibrary(base::FilePath(FILE_PATH_LITERAL("sample_downloads.js")));
57  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
58  EXPECT_FATAL_FAILURE(RunJavascriptTestNoReturn("DISABLED_BogusFunctionName"),
59                       "WebUITestHandler::JavaScriptComplete");
60}
61
62// Test that bogus javascript fails fast - no timeout waiting for result.
63IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestRuntimeErrorFailsFast) {
64  AddLibrary(base::FilePath(FILE_PATH_LITERAL("runtime_error.js")));
65  ui_test_utils::NavigateToURL(browser(), GURL(kDummyURL));
66  EXPECT_FATAL_FAILURE(RunJavascriptTestNoReturn("TestRuntimeErrorFailsFast"),
67                       "WebUITestHandler::JavaScriptComplete");
68}
69
70// Test that bogus javascript fails async test fast as well - no timeout waiting
71// for result.
72IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestFailsAsyncFast) {
73  AddLibrary(base::FilePath(FILE_PATH_LITERAL("sample_downloads.js")));
74  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
75  EXPECT_FATAL_FAILURE(
76      RunJavascriptAsyncTestNoReturn("DISABLED_BogusFunctionName"),
77      "WebUITestHandler::JavaScriptComplete");
78}
79
80// Tests that the async framework works.
81class WebUIBrowserAsyncTest : public WebUIBrowserTest {
82 public:
83  // Calls the testDone() function from test_api.js
84  void TestDone() {
85    RunJavascriptFunction("testDone");
86  }
87
88  // Starts a failing test.
89  void RunTestFailsAssert() {
90    RunJavascriptFunction("runAsync", new base::StringValue("testFailsAssert"));
91  }
92
93  // Starts a passing test.
94  void RunTestPasses() {
95    RunJavascriptFunction("runAsync", new base::StringValue("testPasses"));
96  }
97
98 protected:
99  WebUIBrowserAsyncTest() {}
100
101  // Class to synchronize asynchronous javascript activity with the tests.
102  class AsyncWebUIMessageHandler : public WebUIMessageHandler {
103   public:
104    AsyncWebUIMessageHandler() {}
105
106    MOCK_METHOD1(HandleTestContinues, void(const base::ListValue*));
107    MOCK_METHOD1(HandleTestFails, void(const base::ListValue*));
108    MOCK_METHOD1(HandleTestPasses, void(const base::ListValue*));
109
110   private:
111    virtual void RegisterMessages() OVERRIDE {
112      web_ui()->RegisterMessageCallback("startAsyncTest",
113          base::Bind(&AsyncWebUIMessageHandler::HandleStartAsyncTest,
114                     base::Unretained(this)));
115      web_ui()->RegisterMessageCallback("testContinues",
116          base::Bind(&AsyncWebUIMessageHandler::HandleTestContinues,
117                     base::Unretained(this)));
118      web_ui()->RegisterMessageCallback("testFails",
119          base::Bind(&AsyncWebUIMessageHandler::HandleTestFails,
120                     base::Unretained(this)));
121      web_ui()->RegisterMessageCallback("testPasses",
122          base::Bind(&AsyncWebUIMessageHandler::HandleTestPasses,
123                     base::Unretained(this)));
124    }
125
126    // Starts the test in |list_value|[0] with the runAsync wrapper.
127    void HandleStartAsyncTest(const base::ListValue* list_value) {
128      const base::Value* test_name;
129      ASSERT_TRUE(list_value->Get(0, &test_name));
130      web_ui()->CallJavascriptFunction("runAsync", *test_name);
131    }
132
133    DISALLOW_COPY_AND_ASSIGN(AsyncWebUIMessageHandler);
134  };
135
136  // Handler for this object.
137  ::testing::StrictMock<AsyncWebUIMessageHandler> message_handler_;
138
139 private:
140  // Provide this object's handler.
141  virtual WebUIMessageHandler* GetMockMessageHandler() OVERRIDE {
142    return &message_handler_;
143  }
144
145  // Set up and browse to kDummyURL for all tests.
146  virtual void SetUpOnMainThread() OVERRIDE {
147    WebUIBrowserTest::SetUpOnMainThread();
148    AddLibrary(base::FilePath(FILE_PATH_LITERAL("async.js")));
149    ui_test_utils::NavigateToURL(browser(), GURL(kDummyURL));
150  }
151
152  DISALLOW_COPY_AND_ASSIGN(WebUIBrowserAsyncTest);
153};
154
155// Test that assertions fail immediately after assertion fails (no testContinues
156// message). (Sync version).
157IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestSyncOkTestFail) {
158  ASSERT_FALSE(RunJavascriptTest("testFailsAssert"));
159}
160
161// Test that assertions fail immediately after assertion fails (no testContinues
162// message). (Async version).
163IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncFailsAssert) {
164  EXPECT_CALL(message_handler_, HandleTestFails(::testing::_));
165  ASSERT_FALSE(RunJavascriptAsyncTest(
166      "startAsyncTest", new base::StringValue("testFailsAssert")));
167}
168
169// Test that expectations continue the function, but fail the test.
170IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncFailsExpect) {
171  ::testing::InSequence s;
172  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
173  EXPECT_CALL(message_handler_, HandleTestFails(::testing::_));
174  ASSERT_FALSE(RunJavascriptAsyncTest(
175      "startAsyncTest", new base::StringValue("testFailsExpect")));
176}
177
178// Test that test continues and passes. (Sync version).
179IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestSyncPasses) {
180  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
181  ASSERT_TRUE(RunJavascriptTest("testPasses"));
182}
183
184// Test that test continues and passes. (Async version).
185IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncPasses) {
186  ::testing::InSequence s;
187  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
188  EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_))
189      .WillOnce(::testing::InvokeWithoutArgs(
190          this, &WebUIBrowserAsyncTest::TestDone));
191  ASSERT_TRUE(RunJavascriptAsyncTest(
192      "startAsyncTest", new base::StringValue("testPasses")));
193}
194
195// Test that two tests pass.
196IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncPassPass) {
197  ::testing::InSequence s;
198  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
199  EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_))
200      .WillOnce(::testing::InvokeWithoutArgs(
201          this, &WebUIBrowserAsyncTest::RunTestPasses));
202  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
203  EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_))
204      .WillOnce(::testing::InvokeWithoutArgs(
205          this, &WebUIBrowserAsyncTest::TestDone));
206  ASSERT_TRUE(RunJavascriptAsyncTest(
207      "startAsyncTest", new base::StringValue("testPasses")));
208}
209
210// Test that first test passes; second fails.
211IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncPassThenFail) {
212  ::testing::InSequence s;
213  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
214  EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_))
215      .WillOnce(::testing::InvokeWithoutArgs(
216          this, &WebUIBrowserAsyncTest::RunTestFailsAssert));
217  EXPECT_CALL(message_handler_, HandleTestFails(::testing::_));
218  ASSERT_FALSE(RunJavascriptAsyncTest(
219      "startAsyncTest", new base::StringValue("testPasses")));
220}
221
222// Test that testDone() with failure first then sync pass still fails.
223IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncDoneFailFirstSyncPass) {
224  ::testing::InSequence s;
225  EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_));
226  EXPECT_CALL(message_handler_, HandleTestFails(::testing::_));
227
228  // Call runAsync directly instead of deferring through startAsyncTest. It will
229  // call testDone() on failure, then return.
230  ASSERT_FALSE(RunJavascriptAsyncTest(
231      "runAsync", new base::StringValue("testAsyncDoneFailFirstSyncPass")));
232}
233
234// Test that calling testDone during RunJavascriptAsyncTest still completes
235// when waiting for async result. This is similar to the previous test, but call
236// testDone directly and expect pass result.
237IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestTestDoneEarlyPassesAsync) {
238  ASSERT_TRUE(RunJavascriptAsyncTest("testDone"));
239}
240
241// Test that calling testDone during RunJavascriptTest still completes when
242// waiting for async result.
243IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestTestDoneEarlyPasses) {
244  ASSERT_TRUE(RunJavascriptTest("testDone"));
245}
246