• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(), &params);
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", &params);
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", &params);
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(), &params);
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