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 "testing/gtest/include/gtest/gtest.h"
14
15namespace {
16
17void AssertPendingState(NavigationTracker* tracker,
18                        const std::string& frame_id,
19                        bool expected_is_pending) {
20  bool is_pending = !expected_is_pending;
21  ASSERT_EQ(kOk, tracker->IsPendingNavigation(frame_id, &is_pending).code());
22  ASSERT_EQ(expected_is_pending, is_pending);
23}
24
25}  // namespace
26
27TEST(NavigationTracker, FrameLoadStartStop) {
28  StubDevToolsClient client;
29  NavigationTracker tracker(&client);
30
31  base::DictionaryValue params;
32  ASSERT_EQ(
33      kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
34  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
35  ASSERT_EQ(
36      kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
37  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
38}
39
40TEST(NavigationTracker, NavigationScheduledThenLoaded) {
41  StubDevToolsClient client;
42  NavigationTracker tracker(&client, NavigationTracker::kNotLoading);
43  base::DictionaryValue params;
44  params.SetString("frameId", "f");
45  base::DictionaryValue params_scheduled;
46  params_scheduled.SetInteger("delay", 0);
47  params_scheduled.SetString("frameId", "f");
48
49  ASSERT_EQ(
50      kOk,
51      tracker.OnEvent(
52          &client, "Page.frameScheduledNavigation", params_scheduled).code());
53  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
54  ASSERT_EQ(
55      kOk, tracker.OnEvent(&client, "Page.frameStartedLoading", params).code());
56  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
57  ASSERT_EQ(
58      kOk,
59      tracker.OnEvent(&client, "Page.frameClearedScheduledNavigation", params)
60          .code());
61  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
62  ASSERT_EQ(
63      kOk, tracker.OnEvent(&client, "Page.frameStoppedLoading", params).code());
64  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
65}
66
67TEST(NavigationTracker, NavigationScheduledForOtherFrame) {
68  StubDevToolsClient client;
69  NavigationTracker tracker(&client, NavigationTracker::kNotLoading);
70  base::DictionaryValue params_scheduled;
71  params_scheduled.SetInteger("delay", 0);
72  params_scheduled.SetString("frameId", "other");
73
74  ASSERT_EQ(
75      kOk,
76      tracker.OnEvent(
77          &client, "Page.frameScheduledNavigation", params_scheduled).code());
78  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
79}
80
81TEST(NavigationTracker, NavigationScheduledThenCancelled) {
82  StubDevToolsClient client;
83  NavigationTracker tracker(&client, NavigationTracker::kNotLoading);
84  base::DictionaryValue params;
85  params.SetString("frameId", "f");
86  base::DictionaryValue params_scheduled;
87  params_scheduled.SetInteger("delay", 0);
88  params_scheduled.SetString("frameId", "f");
89
90  ASSERT_EQ(
91      kOk,
92      tracker.OnEvent(
93          &client, "Page.frameScheduledNavigation", params_scheduled).code());
94  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
95  ASSERT_EQ(
96      kOk,
97      tracker.OnEvent(&client, "Page.frameClearedScheduledNavigation", params)
98          .code());
99  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
100}
101
102TEST(NavigationTracker, NavigationScheduledTooFarAway) {
103  StubDevToolsClient client;
104  NavigationTracker tracker(&client, NavigationTracker::kNotLoading);
105
106  base::DictionaryValue params_scheduled;
107  params_scheduled.SetInteger("delay", 10);
108  params_scheduled.SetString("frameId", "f");
109  ASSERT_EQ(
110      kOk,
111      tracker.OnEvent(
112          &client, "Page.frameScheduledNavigation", params_scheduled).code());
113  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
114}
115
116TEST(NavigationTracker, DiscardScheduledNavigationsOnMainFrameCommit) {
117  StubDevToolsClient client;
118  NavigationTracker tracker(&client, NavigationTracker::kNotLoading);
119
120  base::DictionaryValue params_scheduled;
121  params_scheduled.SetString("frameId", "subframe");
122  params_scheduled.SetInteger("delay", 0);
123  ASSERT_EQ(
124      kOk,
125      tracker.OnEvent(
126          &client, "Page.frameScheduledNavigation", params_scheduled).code());
127  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "subframe", true));
128
129  base::DictionaryValue params_navigated;
130  params_navigated.SetString("frame.parentId", "something");
131  ASSERT_EQ(
132      kOk,
133      tracker.OnEvent(&client, "Page.frameNavigated", params_navigated).code());
134  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "subframe", true));
135  params_navigated.Clear();
136  ASSERT_EQ(
137      kOk,
138      tracker.OnEvent(&client, "Page.frameNavigated", params_navigated).code());
139  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "subframe", false));
140}
141
142namespace {
143
144class FailToEvalScriptDevToolsClient : public StubDevToolsClient {
145 public:
146  virtual ~FailToEvalScriptDevToolsClient() {}
147
148  virtual Status SendCommandAndGetResult(
149      const std::string& method,
150      const base::DictionaryValue& params,
151      scoped_ptr<base::DictionaryValue>* result) OVERRIDE {
152    EXPECT_STREQ("Runtime.evaluate", method.c_str());
153    return Status(kUnknownError, "failed to eval script");
154  }
155};
156
157}  // namespace
158
159TEST(NavigationTracker, UnknownStateFailsToDetermineState) {
160  FailToEvalScriptDevToolsClient client;
161  NavigationTracker tracker(&client);
162  bool is_pending;
163  ASSERT_EQ(kUnknownError,
164            tracker.IsPendingNavigation("f", &is_pending).code());
165}
166
167namespace {
168
169class DeterminingLoadStateDevToolsClient : public StubDevToolsClient {
170 public:
171  DeterminingLoadStateDevToolsClient(
172      bool is_loading,
173      const std::string& send_event_first,
174      base::DictionaryValue* send_event_first_params)
175      : is_loading_(is_loading),
176        send_event_first_(send_event_first),
177        send_event_first_params_(send_event_first_params) {}
178
179  virtual ~DeterminingLoadStateDevToolsClient() {}
180
181  virtual Status SendCommandAndGetResult(
182      const std::string& method,
183      const base::DictionaryValue& params,
184      scoped_ptr<base::DictionaryValue>* result) OVERRIDE {
185    if (send_event_first_.length()) {
186      Status status = listeners_.front()
187          ->OnEvent(this, send_event_first_, *send_event_first_params_);
188      if (status.IsError())
189        return status;
190    }
191
192    base::DictionaryValue result_dict;
193    result_dict.SetBoolean("result.value", is_loading_);
194    result->reset(result_dict.DeepCopy());
195    return Status(kOk);
196  }
197
198 private:
199  bool is_loading_;
200  std::string send_event_first_;
201  base::DictionaryValue* send_event_first_params_;
202};
203
204}  // namespace
205
206TEST(NavigationTracker, UnknownStateForcesStart) {
207  base::DictionaryValue params;
208  DeterminingLoadStateDevToolsClient client(true, std::string(), &params);
209  NavigationTracker tracker(&client);
210  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
211}
212
213TEST(NavigationTracker, UnknownStateForcesStartReceivesStop) {
214  base::DictionaryValue params;
215  DeterminingLoadStateDevToolsClient client(
216      true, "Page.frameStoppedLoading", &params);
217  NavigationTracker tracker(&client);
218  ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
219}
220