1 // Copyright (c) 2012 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/compiler_specific.h"
8 #include "base/json/json_reader.h"
9 #include "base/values.h"
10 #include "chrome/test/chromedriver/chrome/navigation_tracker.h"
11 #include "chrome/test/chromedriver/chrome/status.h"
12 #include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
13 #include "chrome/test/chromedriver/chrome/version.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace {
17
AssertPendingState(NavigationTracker * tracker,const std::string & frame_id,bool expected_is_pending)18 void AssertPendingState(NavigationTracker* tracker,
19 const std::string& frame_id,
20 bool expected_is_pending) {
21 bool is_pending = !expected_is_pending;
22 ASSERT_EQ(kOk, tracker->IsPendingNavigation(frame_id, &is_pending).code());
23 ASSERT_EQ(expected_is_pending, is_pending);
24 }
25
AssertTrackerExpectsSingleStopEvent(BrowserInfo * browser_info)26 void AssertTrackerExpectsSingleStopEvent(BrowserInfo* browser_info) {
27 StubDevToolsClient client;
28 NavigationTracker tracker(&client, browser_info);
29 base::DictionaryValue params;
30
31 // num_frames_pending_ == 0
32 ASSERT_EQ(
33 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
34 // num_frames_pending_ == 1
35 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
36 ASSERT_EQ(
37 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
38 // num_frames_pending_ == 2
39 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
40 ASSERT_EQ(
41 kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
42 // num_frames_pending_ == 0
43 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
44 }
45
AssertTrackerExpectsMultipleStopEvents(BrowserInfo * browser_info)46 void AssertTrackerExpectsMultipleStopEvents(BrowserInfo* browser_info) {
47 StubDevToolsClient client;
48 NavigationTracker tracker(&client, browser_info);
49 base::DictionaryValue params;
50
51 // num_frames_pending_ == 0
52 ASSERT_EQ(
53 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
54 // num_frames_pending_ == 1
55 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
56 ASSERT_EQ(
57 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
58 // num_frames_pending_ == 2
59 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
60 ASSERT_EQ(
61 kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
62 // num_frames_pending_ == 1
63 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
64 ASSERT_EQ(
65 kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
66 // num_frames_pending_ == 0
67 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
68 ASSERT_EQ(
69 kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
70 // num_frames_pending_ == 0
71 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
72 ASSERT_EQ(
73 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
74 // num_frames_pending_ == 1
75 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
76 }
77
78 } // namespace
79
TEST(NavigationTracker,FrameLoadStartStop)80 TEST(NavigationTracker, FrameLoadStartStop) {
81 StubDevToolsClient client;
82 BrowserInfo browser_info;
83 NavigationTracker tracker(&client, &browser_info);
84
85 base::DictionaryValue params;
86 ASSERT_EQ(
87 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
88 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
89 ASSERT_EQ(
90 kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
91 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
92 }
93
94 // NavigationTracker::OnEvent handles the Page.frameStoppedLoading event
95 // differently, depending on the browser and blink version. See the comment in
96 // NavigationTracker::OnEvent for details.
97
TEST(NavigationTracker,MultipleFramesLoadOldDevtools)98 TEST(NavigationTracker, MultipleFramesLoadOldDevtools) {
99 BrowserInfo kOldChromeWithNewBlink("chrome", std::string(), 1916, 170248);
100 AssertTrackerExpectsSingleStopEvent(&kOldChromeWithNewBlink);
101
102 BrowserInfo kWebViewWithOldBlink("webview", std::string(), 9999, 170247);
103 AssertTrackerExpectsSingleStopEvent(&kWebViewWithOldBlink);
104 }
105
TEST(NavigationTracker,MultipleFramesLoad)106 TEST(NavigationTracker, MultipleFramesLoad) {
107 BrowserInfo kNewChromeWithNewBlink("chrome", std::string(), 1917, 170248);
108 AssertTrackerExpectsMultipleStopEvents(&kNewChromeWithNewBlink);
109
110 BrowserInfo kWebViewWithNewBlink("webview", std::string(), 9999, 170248);
111 AssertTrackerExpectsMultipleStopEvents(&kWebViewWithNewBlink);
112 }
113
TEST(NavigationTracker,NavigationScheduledThenLoaded)114 TEST(NavigationTracker, NavigationScheduledThenLoaded) {
115 StubDevToolsClient client;
116 BrowserInfo browser_info;
117 NavigationTracker tracker(
118 &client, NavigationTracker::kNotLoading, &browser_info);
119 base::DictionaryValue params;
120 params.SetString("frameId", "f");
121 base::DictionaryValue params_scheduled;
122 params_scheduled.SetInteger("delay", 0);
123 params_scheduled.SetString("frameId", "f");
124
125 ASSERT_EQ(
126 kOk,
127 tracker.OnEvent(
128 &client, "Page.frameScheduledNavigation", params_scheduled).code());
129 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
130 ASSERT_EQ(
131 kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
132 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
133 ASSERT_EQ(
134 kOk,
135 tracker.OnEvent(&client, "Page.frameClearedScheduledNavigation", params)
136 .code());
137 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
138 ASSERT_EQ(
139 kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
140 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
141 }
142
TEST(NavigationTracker,NavigationScheduledForOtherFrame)143 TEST(NavigationTracker, NavigationScheduledForOtherFrame) {
144 StubDevToolsClient client;
145 BrowserInfo browser_info;
146 NavigationTracker tracker(
147 &client, NavigationTracker::kNotLoading, &browser_info);
148 base::DictionaryValue params_scheduled;
149 params_scheduled.SetInteger("delay", 0);
150 params_scheduled.SetString("frameId", "other");
151
152 ASSERT_EQ(
153 kOk,
154 tracker.OnEvent(
155 &client, "Page.frameScheduledNavigation", params_scheduled).code());
156 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
157 }
158
TEST(NavigationTracker,NavigationScheduledThenCancelled)159 TEST(NavigationTracker, NavigationScheduledThenCancelled) {
160 StubDevToolsClient client;
161 BrowserInfo browser_info;
162 NavigationTracker tracker(
163 &client, NavigationTracker::kNotLoading, &browser_info);
164 base::DictionaryValue params;
165 params.SetString("frameId", "f");
166 base::DictionaryValue params_scheduled;
167 params_scheduled.SetInteger("delay", 0);
168 params_scheduled.SetString("frameId", "f");
169
170 ASSERT_EQ(
171 kOk,
172 tracker.OnEvent(
173 &client, "Page.frameScheduledNavigation", params_scheduled).code());
174 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
175 ASSERT_EQ(
176 kOk,
177 tracker.OnEvent(&client, "Page.frameClearedScheduledNavigation", params)
178 .code());
179 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
180 }
181
TEST(NavigationTracker,NavigationScheduledTooFarAway)182 TEST(NavigationTracker, NavigationScheduledTooFarAway) {
183 StubDevToolsClient client;
184 BrowserInfo browser_info;
185 NavigationTracker tracker(
186 &client, NavigationTracker::kNotLoading, &browser_info);
187
188 base::DictionaryValue params_scheduled;
189 params_scheduled.SetInteger("delay", 10);
190 params_scheduled.SetString("frameId", "f");
191 ASSERT_EQ(
192 kOk,
193 tracker.OnEvent(
194 &client, "Page.frameScheduledNavigation", params_scheduled).code());
195 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
196 }
197
TEST(NavigationTracker,DiscardScheduledNavigationsOnMainFrameCommit)198 TEST(NavigationTracker, DiscardScheduledNavigationsOnMainFrameCommit) {
199 StubDevToolsClient client;
200 BrowserInfo browser_info;
201 NavigationTracker tracker(
202 &client, NavigationTracker::kNotLoading, &browser_info);
203
204 base::DictionaryValue params_scheduled;
205 params_scheduled.SetString("frameId", "subframe");
206 params_scheduled.SetInteger("delay", 0);
207 ASSERT_EQ(
208 kOk,
209 tracker.OnEvent(
210 &client, "Page.frameScheduledNavigation", params_scheduled).code());
211 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "subframe", true));
212
213 base::DictionaryValue params_navigated;
214 params_navigated.SetString("frame.parentId", "something");
215 ASSERT_EQ(
216 kOk,
217 tracker.OnEvent(&client, "Page.frameNavigated", params_navigated).code());
218 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "subframe", true));
219 params_navigated.Clear();
220 ASSERT_EQ(
221 kOk,
222 tracker.OnEvent(&client, "Page.frameNavigated", params_navigated).code());
223 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "subframe", false));
224 }
225
226 namespace {
227
228 class FailToEvalScriptDevToolsClient : public StubDevToolsClient {
229 public:
~FailToEvalScriptDevToolsClient()230 virtual ~FailToEvalScriptDevToolsClient() {}
231
SendCommandAndGetResult(const std::string & method,const base::DictionaryValue & params,scoped_ptr<base::DictionaryValue> * result)232 virtual Status SendCommandAndGetResult(
233 const std::string& method,
234 const base::DictionaryValue& params,
235 scoped_ptr<base::DictionaryValue>* result) OVERRIDE {
236 EXPECT_STREQ("Runtime.evaluate", method.c_str());
237 return Status(kUnknownError, "failed to eval script");
238 }
239 };
240
241 } // namespace
242
TEST(NavigationTracker,UnknownStateFailsToDetermineState)243 TEST(NavigationTracker, UnknownStateFailsToDetermineState) {
244 FailToEvalScriptDevToolsClient client;
245 BrowserInfo browser_info;
246 NavigationTracker tracker(&client, &browser_info);
247 bool is_pending;
248 ASSERT_EQ(kUnknownError,
249 tracker.IsPendingNavigation("f", &is_pending).code());
250 }
251
252 namespace {
253
254 class DeterminingLoadStateDevToolsClient : public StubDevToolsClient {
255 public:
DeterminingLoadStateDevToolsClient(bool is_loading,const std::string & send_event_first,base::DictionaryValue * send_event_first_params)256 DeterminingLoadStateDevToolsClient(
257 bool is_loading,
258 const std::string& send_event_first,
259 base::DictionaryValue* send_event_first_params)
260 : is_loading_(is_loading),
261 send_event_first_(send_event_first),
262 send_event_first_params_(send_event_first_params) {}
263
~DeterminingLoadStateDevToolsClient()264 virtual ~DeterminingLoadStateDevToolsClient() {}
265
SendCommandAndGetResult(const std::string & method,const base::DictionaryValue & params,scoped_ptr<base::DictionaryValue> * result)266 virtual Status SendCommandAndGetResult(
267 const std::string& method,
268 const base::DictionaryValue& params,
269 scoped_ptr<base::DictionaryValue>* result) OVERRIDE {
270 if (send_event_first_.length()) {
271 Status status = listeners_.front()
272 ->OnEvent(this, send_event_first_, *send_event_first_params_);
273 if (status.IsError())
274 return status;
275 }
276
277 base::DictionaryValue result_dict;
278 result_dict.SetBoolean("result.value", is_loading_);
279 result->reset(result_dict.DeepCopy());
280 return Status(kOk);
281 }
282
283 private:
284 bool is_loading_;
285 std::string send_event_first_;
286 base::DictionaryValue* send_event_first_params_;
287 };
288
289 } // namespace
290
TEST(NavigationTracker,UnknownStateForcesStart)291 TEST(NavigationTracker, UnknownStateForcesStart) {
292 base::DictionaryValue params;
293 DeterminingLoadStateDevToolsClient client(true, std::string(), ¶ms);
294 BrowserInfo browser_info;
295 NavigationTracker tracker(&client, &browser_info);
296 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
297 }
298
TEST(NavigationTracker,UnknownStateForcesStartReceivesStop)299 TEST(NavigationTracker, UnknownStateForcesStartReceivesStop) {
300 base::DictionaryValue params;
301 DeterminingLoadStateDevToolsClient client(
302 true, "Page.frameStoppedLoading", ¶ms);
303 BrowserInfo browser_info;
304 NavigationTracker tracker(&client, &browser_info);
305 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
306 }
307
TEST(NavigationTracker,OnSuccessfulNavigate)308 TEST(NavigationTracker, OnSuccessfulNavigate) {
309 base::DictionaryValue params;
310 DeterminingLoadStateDevToolsClient client(
311 true, "Page.frameStoppedLoading", ¶ms);
312 BrowserInfo browser_info;
313 NavigationTracker tracker(
314 &client, NavigationTracker::kNotLoading, &browser_info);
315 tracker.OnCommandSuccess(&client, "Page.navigate");
316 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
317 }
318
TEST(NavigationTracker,OnSuccessfulNavigateStillWaiting)319 TEST(NavigationTracker, OnSuccessfulNavigateStillWaiting) {
320 base::DictionaryValue params;
321 DeterminingLoadStateDevToolsClient client(true, std::string(), ¶ms);
322 BrowserInfo browser_info;
323 NavigationTracker tracker(
324 &client, NavigationTracker::kNotLoading, &browser_info);
325 tracker.OnCommandSuccess(&client, "Page.navigate");
326 ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
327 }
328