[go: nahoru, domu]

blob: f0d0e8430e15c5bbef8d0a10d07cde478e38f27a [file] [log] [blame]
Avi Drissman4a8573c2022-09-09 19:35:541// Copyright 2013 The Chromium Authors
chrisgao@chromium.org584ae1f2013-02-11 20:18:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dchengba062652016-04-13 01:34:355#include "chrome/test/chromedriver/chrome/web_view_impl.h"
6
chrisgao@chromium.org584ae1f2013-02-11 20:18:517#include <list>
dchengba062652016-04-13 01:34:358#include <memory>
Vladimir Nechaev355dc822022-08-08 12:12:339#include <queue>
chrisgao@chromium.org584ae1f2013-02-11 20:18:5110#include <string>
11
12#include "base/compiler_specific.h"
Avi Drissman69ba0cc2023-01-09 20:56:0313#include "base/functional/bind.h"
Vladimir Nechaev355dc822022-08-08 12:12:3314#include "base/json/json_reader.h"
15#include "base/json/json_writer.h"
Vladimir Nechaeva94351f2023-03-08 10:31:4216#include "base/logging.h"
Vladimir Nechaev355dc822022-08-08 12:12:3317#include "base/memory/raw_ptr.h"
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:1218#include "base/strings/string_number_conversions.h"
Rohan Pavone60bf0042019-05-23 17:18:5019#include "base/time/time.h"
chrisgao@chromium.org584ae1f2013-02-11 20:18:5120#include "base/values.h"
Tricia Crichton82d78842019-11-19 21:50:4521#include "chrome/test/chromedriver/chrome/browser_info.h"
Tricia Crichton82d78842019-11-19 21:50:4522#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:1223#include "chrome/test/chromedriver/chrome/frame_tracker.h"
Tricia Crichton82d78842019-11-19 21:50:4524#include "chrome/test/chromedriver/chrome/page_load_strategy.h"
chrisgao@chromium.org1a7771f42013-03-15 16:20:0225#include "chrome/test/chromedriver/chrome/status.h"
John Chenae9b9ff02020-06-30 22:28:1726#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
Tricia Crichton82d78842019-11-19 21:50:4527#include "chrome/test/chromedriver/net/sync_websocket.h"
28#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
29#include "chrome/test/chromedriver/net/timeout.h"
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:1230#include "testing/gmock/include/gmock/gmock.h"
chrisgao@chromium.org584ae1f2013-02-11 20:18:5131#include "testing/gtest/include/gtest/gtest.h"
32
33namespace {
34
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:1235const char kElementKey[] = "ELEMENT";
36const char kElementKeyW3C[] = "element-6066-11e4-a52e-4f735466cecf";
37const char kShadowRootKey[] = "shadow-6066-11e4-a52e-4f735466cecf";
38
39using testing::Eq;
40using testing::Pointee;
41
42template <int Code>
43testing::AssertionResult StatusCodeIs(const Status& status) {
44 if (status.code() == Code) {
45 return testing::AssertionSuccess();
46 } else {
47 return testing::AssertionFailure() << status.message();
48 }
49}
50
51testing::AssertionResult StatusOk(const Status& status) {
52 return StatusCodeIs<kOk>(status);
53}
54
Vladimir Nechaeva94351f2023-03-08 10:31:4255base::Value::Dict GenerateResponse(int backend_node_id) {
56 base::Value::Dict result;
57 result.SetByDottedPath(std::string("value.") + kElementKeyW3C, 0);
58 result.Set("status", 0);
59 std::string json;
60 base::JSONWriter::Write(result, &json);
61 base::Value::Dict dict;
62 dict.Set("value", std::move(json));
63 base::Value::Dict node;
64 node.SetByDottedPath("value.backendNodeId", backend_node_id);
65 base::Value::List serialized_list;
66 serialized_list.Append(std::move(dict));
67 serialized_list.Append(std::move(node));
68 base::Value::Dict response;
69 response.SetByDottedPath("result.webDriverValue.value",
70 std::move(serialized_list));
71 return response;
72}
73
74base::Value::Dict GenerateResponseWithScriptArguments(
75 base::Value::List args,
76 const std::string& element_key) {
77 base::Value::List arr;
78 base::Value::List nodes;
79 for (base::Value& arg : args) {
80 if (!arg.is_dict()) {
81 arr.Append(std::move(arg));
82 continue;
83 }
84 std::string* maybe_object_id = arg.GetDict().FindString("objectId");
85 int object_id = 0xdeadbeef;
86 if (!maybe_object_id || !base::StringToInt(*maybe_object_id, &object_id)) {
87 arr.Append(std::move(arg));
88 continue;
89 }
90
91 base::Value::Dict node;
92 base::Value::Dict ref;
93 ref.Set(element_key, static_cast<int>(nodes.size()));
94 arr.Append(std::move(ref));
95 node.SetByDottedPath("value.backendNodeId", object_id);
96 nodes.Append(std::move(node));
97 }
98
99 base::Value::Dict result;
100 result.Set("value", std::move(arr));
101 result.Set("status", 0);
102 std::string json;
103 base::JSONWriter::Write(result, &json);
104 base::Value::Dict dict;
105 dict.Set("value", std::move(json));
106 base::Value::List serialized_list;
107 serialized_list.Append(std::move(dict));
108
109 for (base::Value& node : nodes) {
110 serialized_list.Append(std::move(node));
111 }
112
113 base::Value::Dict response;
114 response.SetByDottedPath("result.webDriverValue.value",
115 std::move(serialized_list));
116 return response;
117}
118
John Chenae9b9ff02020-06-30 22:28:17119class FakeDevToolsClient : public StubDevToolsClient {
chrisgao@chromium.org584ae1f2013-02-11 20:18:51120 public:
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12121 explicit FakeDevToolsClient(std::string id)
122 : StubDevToolsClient(id), status_(kOk) {}
John Chenae9b9ff02020-06-30 22:28:17123 FakeDevToolsClient() : status_(kOk) {}
124 ~FakeDevToolsClient() override = default;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51125
Vladimir Nechaeva94351f2023-03-08 10:31:42126 void SetStatus(const Status& status) { status_ = status; }
127 void SetResult(const base::Value::Dict& result) { result_ = result.Clone(); }
128
129 void SetElementKey(std::string element_key) {
130 element_key_ = std::move(element_key);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51131 }
chrisgao@chromium.org584ae1f2013-02-11 20:18:51132
133 // Overridden from DevToolsClient:
Minoru Chikamunea5117de62021-12-20 08:59:47134 Status SendCommandAndGetResult(const std::string& method,
Maks Orloviche0cc69b2022-09-27 14:49:34135 const base::Value::Dict& params,
Marijn Kruisselbrink3a1fd6caf2022-12-13 18:49:03136 base::Value::Dict* result) override {
chrisgao@chromium.org584ae1f2013-02-11 20:18:51137 if (status_.IsError())
138 return status_;
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12139
140 if (method == "Page.getFrameTree") {
141 // Unused padding frame
142 base::Value::Dict unused_child;
143 unused_child.SetByDottedPath("frame.id", "unused");
144 unused_child.SetByDottedPath("frame.loaderId", "unused_loader");
145 // Used by the dedicated tests
146 base::Value::Dict good_child;
147 good_child.SetByDottedPath("frame.id", "good");
148 good_child.SetByDottedPath("frame.loaderId", "good_loader");
149 // Default constructed WebViewImpl will point here
150 // Needed for the tests that are neutral to getFramTree
151 base::Value::Dict default_child;
152 default_child.SetByDottedPath("frame.id", GetOwner()->GetId());
153 default_child.SetByDottedPath("frame.loaderId", "default_loader");
154 // root
155 base::Value::List children;
156 children.Append(std::move(good_child));
157 children.Append(std::move(default_child));
158 for (base::Value& frame : extra_child_frames_) {
159 children.Append(frame.Clone());
160 }
161 result->SetByDottedPath("frameTree.frame.id", "root");
162 result->SetByDottedPath("frameTree.frame.loaderId", "root_loader");
163 result->SetByDottedPath("frameTree.childFrames", std::move(children));
164 } else if (method == "DOM.resolveNode") {
165 absl::optional<int> maybe_backend_node_id =
166 params.FindInt("backendNodeId");
167 if (!maybe_backend_node_id) {
168 return Status{
169 kUnknownError,
170 "backend node id is missing in DOM.resolveNode parameters"};
171 }
172 result->SetByDottedPath("object.objectId",
173 base::NumberToString(*maybe_backend_node_id));
Vladimir Nechaeva94351f2023-03-08 10:31:42174 } else if (method == "Runtime.callFunctionOn" && result_.empty()) {
175 const base::Value::List* args = params.FindList("arguments");
176 if (args == nullptr) {
177 return Status{kInvalidArgument,
178 "arguments are not provided to Runtime.callFunctionOn"};
179 }
180 *result =
181 GenerateResponseWithScriptArguments(args->Clone(), element_key_);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12182 } else {
183 *result = result_.Clone();
184 }
185
chrisgao@chromium.org584ae1f2013-02-11 20:18:51186 return Status(kOk);
187 }
chrisgao@chromium.org584ae1f2013-02-11 20:18:51188
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12189 void AddExtraChildFrame(base::Value::Dict frame) {
190 extra_child_frames_.Append(std::move(frame));
191 }
192
193 void ClearExtraChildFrames() { extra_child_frames_.clear(); }
194
chrisgao@chromium.org584ae1f2013-02-11 20:18:51195 private:
196 Status status_;
Matt Menkeb24aeee2022-11-04 12:18:06197 base::Value::Dict result_;
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12198 base::Value::List extra_child_frames_;
Vladimir Nechaeva94351f2023-03-08 10:31:42199 std::string element_key_ = kElementKeyW3C;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51200};
201
Matt Menkeb24aeee2022-11-04 12:18:06202void AssertEvalFails(const base::Value::Dict& command_result) {
203 base::Value::Dict result;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51204 FakeDevToolsClient client;
Vladimir Nechaeva94351f2023-03-08 10:31:42205 client.SetResult(command_result);
Shengfa Lin7d204c82020-04-25 01:06:14206 Status status = internal::EvaluateScript(
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12207 &client, "context", std::string(), base::TimeDelta::Max(), false, result);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51208 ASSERT_EQ(kUnknownError, status.code());
Matt Menkeb24aeee2022-11-04 12:18:06209 ASSERT_TRUE(result.empty());
chrisgao@chromium.org584ae1f2013-02-11 20:18:51210}
211
212} // namespace
213
214TEST(EvaluateScript, CommandError) {
Matt Menkeb24aeee2022-11-04 12:18:06215 base::Value::Dict result;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51216 FakeDevToolsClient client;
Vladimir Nechaeva94351f2023-03-08 10:31:42217 client.SetStatus(Status(kUnknownError));
Shengfa Lin7d204c82020-04-25 01:06:14218 Status status = internal::EvaluateScript(
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12219 &client, "context", std::string(), base::TimeDelta::Max(), false, result);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51220 ASSERT_EQ(kUnknownError, status.code());
Matt Menkeb24aeee2022-11-04 12:18:06221 ASSERT_TRUE(result.empty());
chrisgao@chromium.org584ae1f2013-02-11 20:18:51222}
223
chrisgao@chromium.org584ae1f2013-02-11 20:18:51224TEST(EvaluateScript, MissingResult) {
Matt Menkeb24aeee2022-11-04 12:18:06225 base::Value::Dict dict;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51226 ASSERT_NO_FATAL_FAILURE(AssertEvalFails(dict));
227}
228
229TEST(EvaluateScript, Throws) {
Matt Menkeb24aeee2022-11-04 12:18:06230 base::Value::Dict dict;
231 dict.SetByDottedPath("exceptionDetails.exception.className", "SyntaxError");
232 dict.SetByDottedPath("result.type", "object");
chrisgao@chromium.org584ae1f2013-02-11 20:18:51233 ASSERT_NO_FATAL_FAILURE(AssertEvalFails(dict));
234}
235
236TEST(EvaluateScript, Ok) {
Matt Menkeb24aeee2022-11-04 12:18:06237 base::Value::Dict result;
238 base::Value::Dict dict;
239 dict.SetByDottedPath("result.key", 100);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51240 FakeDevToolsClient client;
Vladimir Nechaeva94351f2023-03-08 10:31:42241 client.SetResult(dict);
Vladimir Nechaevae1c317f2022-05-23 09:10:49242 ASSERT_TRUE(internal::EvaluateScript(&client, "context", std::string(),
Matt Menkeb24aeee2022-11-04 12:18:06243 base::TimeDelta::Max(), false, result)
Rohan Pavone60bf0042019-05-23 17:18:50244 .IsOk());
Matt Menkeb24aeee2022-11-04 12:18:06245 ASSERT_TRUE(result.contains("key"));
chrisgao@chromium.org584ae1f2013-02-11 20:18:51246}
247
248TEST(EvaluateScriptAndGetValue, MissingType) {
dchengba062652016-04-13 01:34:35249 std::unique_ptr<base::Value> result;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51250 FakeDevToolsClient client;
Matt Menkeb24aeee2022-11-04 12:18:06251 base::Value::Dict dict;
252 dict.SetByDottedPath("result.value", 1);
Vladimir Nechaeva94351f2023-03-08 10:31:42253 client.SetResult(dict);
Vladimir Nechaevae1c317f2022-05-23 09:10:49254 ASSERT_TRUE(internal::EvaluateScriptAndGetValue(
255 &client, "context", std::string(), base::TimeDelta::Max(),
256 false, &result)
Rohan Pavone60bf0042019-05-23 17:18:50257 .IsError());
chrisgao@chromium.org584ae1f2013-02-11 20:18:51258}
259
260TEST(EvaluateScriptAndGetValue, Undefined) {
dchengba062652016-04-13 01:34:35261 std::unique_ptr<base::Value> result;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51262 FakeDevToolsClient client;
Matt Menkeb24aeee2022-11-04 12:18:06263 base::Value::Dict dict;
264 dict.SetByDottedPath("result.type", "undefined");
Vladimir Nechaeva94351f2023-03-08 10:31:42265 client.SetResult(dict);
Rohan Pavone60bf0042019-05-23 17:18:50266 Status status = internal::EvaluateScriptAndGetValue(
Vladimir Nechaevae1c317f2022-05-23 09:10:49267 &client, "context", std::string(), base::TimeDelta::Max(), false,
268 &result);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51269 ASSERT_EQ(kOk, status.code());
jdoerrie1f536b22017-10-23 17:15:11270 ASSERT_TRUE(result && result->is_none());
chrisgao@chromium.org584ae1f2013-02-11 20:18:51271}
272
273TEST(EvaluateScriptAndGetValue, Ok) {
dchengba062652016-04-13 01:34:35274 std::unique_ptr<base::Value> result;
chrisgao@chromium.org584ae1f2013-02-11 20:18:51275 FakeDevToolsClient client;
Matt Menkeb24aeee2022-11-04 12:18:06276 base::Value::Dict dict;
277 dict.SetByDottedPath("result.type", "integer");
278 dict.SetByDottedPath("result.value", 1);
Vladimir Nechaeva94351f2023-03-08 10:31:42279 client.SetResult(dict);
Rohan Pavone60bf0042019-05-23 17:18:50280 Status status = internal::EvaluateScriptAndGetValue(
Vladimir Nechaevae1c317f2022-05-23 09:10:49281 &client, "context", std::string(), base::TimeDelta::Max(), false,
282 &result);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51283 ASSERT_EQ(kOk, status.code());
Minoru Chikamune8b25dd62021-04-17 02:26:49284 ASSERT_TRUE(result && result->is_int());
285 ASSERT_EQ(1, result->GetInt());
chrisgao@chromium.org584ae1f2013-02-11 20:18:51286}
287
chrisgao@chromium.org584ae1f2013-02-11 20:18:51288TEST(ParseCallFunctionResult, NotDict) {
dchengba062652016-04-13 01:34:35289 std::unique_ptr<base::Value> result;
jdoerrie239723572017-03-02 12:09:19290 base::Value value(1);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51291 ASSERT_NE(kOk, internal::ParseCallFunctionResult(value, &result).code());
292}
293
294TEST(ParseCallFunctionResult, Ok) {
dchengba062652016-04-13 01:34:35295 std::unique_ptr<base::Value> result;
Matt Menkeb24aeee2022-11-04 12:18:06296 base::Value::Dict dict;
297 dict.Set("status", 0);
298 dict.Set("value", 1);
299 Status status =
300 internal::ParseCallFunctionResult(base::Value(std::move(dict)), &result);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51301 ASSERT_EQ(kOk, status.code());
Minoru Chikamune8b25dd62021-04-17 02:26:49302 ASSERT_TRUE(result && result->is_int());
303 ASSERT_EQ(1, result->GetInt());
chrisgao@chromium.org584ae1f2013-02-11 20:18:51304}
305
306TEST(ParseCallFunctionResult, ScriptError) {
dchengba062652016-04-13 01:34:35307 std::unique_ptr<base::Value> result;
Matt Menkeb24aeee2022-11-04 12:18:06308 base::Value::Dict dict;
309 dict.Set("status", 1);
310 dict.Set("value", 1);
311 Status status =
312 internal::ParseCallFunctionResult(base::Value(std::move(dict)), &result);
chrisgao@chromium.org584ae1f2013-02-11 20:18:51313 ASSERT_EQ(1, status.code());
314 ASSERT_FALSE(result);
315}
Tricia Crichton82d78842019-11-19 21:50:45316
317namespace {
318
319class MockSyncWebSocket : public SyncWebSocket {
320 public:
321 explicit MockSyncWebSocket(SyncWebSocket::StatusCode next_status)
Vladimir Nechaev355dc822022-08-08 12:12:33322 : connected_(false), id_(-1), next_status_(next_status) {}
323 MockSyncWebSocket() : MockSyncWebSocket(SyncWebSocket::StatusCode::kOk) {}
324 ~MockSyncWebSocket() override = default;
325
Lei Zhang22a73ec32022-11-03 19:15:12326 void SetNexStatusCode(SyncWebSocket::StatusCode status_code) {
327 next_status_ = status_code;
Vladimir Nechaev355dc822022-08-08 12:12:33328 }
Tricia Crichton82d78842019-11-19 21:50:45329
330 bool IsConnected() override { return connected_; }
331
332 bool Connect(const GURL& url) override {
333 EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
334 connected_ = true;
335 return true;
336 }
337
Vladimir Nechaev355dc822022-08-08 12:12:33338 bool Send(const std::string& message) override {
339 absl::optional<base::Value> value = base::JSONReader::Read(message);
340 if (!value) {
341 return false;
342 }
343
344 absl::optional<int> id = value->GetDict().FindInt("id");
345 if (!id) {
346 return false;
347 }
348
Lei Zhang22a73ec32022-11-03 19:15:12349 std::string response_str;
Vladimir Nechaev355dc822022-08-08 12:12:33350 base::Value::Dict response;
351 response.Set("id", *id);
Matt Menkeb24aeee2022-11-04 12:18:06352 base::Value::Dict result;
353 result.Set("param", 1);
354 response.Set("result", std::move(result));
355 base::JSONWriter::Write(response, &response_str);
Lei Zhang22a73ec32022-11-03 19:15:12356 messages_.push(response_str);
Vladimir Nechaev355dc822022-08-08 12:12:33357 return true;
358 }
Tricia Crichton82d78842019-11-19 21:50:45359
360 SyncWebSocket::StatusCode ReceiveNextMessage(
361 std::string* message,
362 const Timeout& timeout) override {
Vladimir Nechaev355dc822022-08-08 12:12:33363 if (next_status_ == SyncWebSocket::StatusCode::kOk && !messages_.empty()) {
364 *message = messages_.front();
365 messages_.pop();
366 }
Tricia Crichton82d78842019-11-19 21:50:45367 return next_status_;
368 }
369
Vladimir Nechaev355dc822022-08-08 12:12:33370 bool HasNextMessage() override { return !messages_.empty(); }
Tricia Crichton82d78842019-11-19 21:50:45371
372 protected:
373 bool connected_;
374 int id_;
Vladimir Nechaev355dc822022-08-08 12:12:33375 std::queue<std::string> messages_;
Tricia Crichton82d78842019-11-19 21:50:45376 SyncWebSocket::StatusCode next_status_;
377};
378
379std::unique_ptr<SyncWebSocket> CreateMockSyncWebSocket(
380 SyncWebSocket::StatusCode next_status) {
381 return std::make_unique<MockSyncWebSocket>(next_status);
382}
383
Vladimir Nechaev355dc822022-08-08 12:12:33384class SyncWebSocketWrapper : public SyncWebSocket {
385 public:
386 explicit SyncWebSocketWrapper(SyncWebSocket* socket) : socket_(socket) {}
387 ~SyncWebSocketWrapper() override = default;
388
389 bool IsConnected() override { return socket_->IsConnected(); }
390
391 bool Connect(const GURL& url) override { return socket_->Connect(url); }
392
393 bool Send(const std::string& message) override {
394 return socket_->Send(message);
395 }
396
397 SyncWebSocket::StatusCode ReceiveNextMessage(
398 std::string* message,
399 const Timeout& timeout) override {
400 return socket_->ReceiveNextMessage(message, timeout);
401 }
402
403 bool HasNextMessage() override { return socket_->HasNextMessage(); }
404
405 private:
406 raw_ptr<SyncWebSocket> socket_;
407};
408
Tricia Crichton82d78842019-11-19 21:50:45409} // namespace
410
Tricia Crichton8e82b242019-11-22 15:42:00411TEST(CreateChild, MultiLevel) {
Peter Kasting098eeab2021-09-02 22:54:21412 SyncWebSocketFactory factory = base::BindRepeating(
413 &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
Tricia Crichton8e82b242019-11-22 15:42:00414 // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
415 std::unique_ptr<DevToolsClientImpl> client_uptr =
Vladimir Nechaeve840c4b2022-05-20 08:38:22416 std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
Tricia Crichton8e82b242019-11-22 15:42:00417 DevToolsClientImpl* client_ptr = client_uptr.get();
418 BrowserInfo browser_info;
419 WebViewImpl level1(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43420 std::move(client_uptr), absl::nullopt,
421 PageLoadStrategy::kEager);
Vladimir Nechaevd0786c72022-12-09 12:37:44422 Status status = client_ptr->Connect();
Vladimir Nechaev355dc822022-08-08 12:12:33423 ASSERT_EQ(kOk, status.code()) << status.message();
Tricia Crichton8e82b242019-11-22 15:42:00424 std::string sessionid = "2";
425 std::unique_ptr<WebViewImpl> level2 =
426 std::unique_ptr<WebViewImpl>(level1.CreateChild(sessionid, "1234"));
Vladimir Nechaev355dc822022-08-08 12:12:33427 level2->AttachTo(client_ptr);
Tricia Crichton8e82b242019-11-22 15:42:00428 sessionid = "3";
429 std::unique_ptr<WebViewImpl> level3 =
430 std::unique_ptr<WebViewImpl>(level2->CreateChild(sessionid, "3456"));
Vladimir Nechaev355dc822022-08-08 12:12:33431 level3->AttachTo(client_ptr);
Tricia Crichton8e82b242019-11-22 15:42:00432 sessionid = "4";
433 std::unique_ptr<WebViewImpl> level4 =
434 std::unique_ptr<WebViewImpl>(level3->CreateChild(sessionid, "5678"));
Vladimir Nechaev355dc822022-08-08 12:12:33435 level4->AttachTo(client_ptr);
Tricia Crichton8e82b242019-11-22 15:42:00436}
437
Tricia Crichton82d78842019-11-19 21:50:45438TEST(CreateChild, IsNonBlocking_NoErrors) {
Peter Kasting098eeab2021-09-02 22:54:21439 SyncWebSocketFactory factory = base::BindRepeating(
440 &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
Tricia Crichton82d78842019-11-19 21:50:45441 // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
442 std::unique_ptr<DevToolsClientImpl> client_uptr =
Vladimir Nechaeve840c4b2022-05-20 08:38:22443 std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
Tricia Crichton82d78842019-11-19 21:50:45444 DevToolsClientImpl* client_ptr = client_uptr.get();
445 BrowserInfo browser_info;
446 WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43447 std::move(client_uptr), absl::nullopt,
Tricia Crichton82d78842019-11-19 21:50:45448 PageLoadStrategy::kEager);
Vladimir Nechaevd0786c72022-12-09 12:37:44449 Status status = client_ptr->Connect();
Vladimir Nechaev355dc822022-08-08 12:12:33450 ASSERT_EQ(kOk, status.code()) << status.message();
Tricia Crichton82d78842019-11-19 21:50:45451 ASSERT_FALSE(parent_view.IsNonBlocking());
452
453 std::string sessionid = "2";
454 std::unique_ptr<WebViewImpl> child_view =
455 std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
Vladimir Nechaev355dc822022-08-08 12:12:33456 child_view->AttachTo(client_ptr);
Tricia Crichton82d78842019-11-19 21:50:45457 ASSERT_NO_FATAL_FAILURE(child_view->IsNonBlocking());
458 ASSERT_FALSE(child_view->IsNonBlocking());
459}
460
461TEST(CreateChild, Load_NoErrors) {
Peter Kasting098eeab2021-09-02 22:54:21462 SyncWebSocketFactory factory = base::BindRepeating(
463 &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
Tricia Crichton82d78842019-11-19 21:50:45464 // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
465 std::unique_ptr<DevToolsClientImpl> client_uptr =
Vladimir Nechaeve840c4b2022-05-20 08:38:22466 std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
Tricia Crichton82d78842019-11-19 21:50:45467 DevToolsClientImpl* client_ptr = client_uptr.get();
468 BrowserInfo browser_info;
469 WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43470 std::move(client_uptr), absl::nullopt,
Tricia Crichton82d78842019-11-19 21:50:45471 PageLoadStrategy::kNone);
Vladimir Nechaevd0786c72022-12-09 12:37:44472 Status status = client_ptr->Connect();
Vladimir Nechaev355dc822022-08-08 12:12:33473 ASSERT_EQ(kOk, status.code()) << status.message();
Tricia Crichton82d78842019-11-19 21:50:45474 std::string sessionid = "2";
475 std::unique_ptr<WebViewImpl> child_view =
476 std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
Vladimir Nechaev355dc822022-08-08 12:12:33477 child_view->AttachTo(client_ptr);
Tricia Crichton82d78842019-11-19 21:50:45478
479 ASSERT_NO_FATAL_FAILURE(child_view->Load("chrome://version", nullptr));
480}
481
482TEST(CreateChild, WaitForPendingNavigations_NoErrors) {
Vladimir Nechaev355dc822022-08-08 12:12:33483 std::unique_ptr<MockSyncWebSocket> socket =
484 std::make_unique<MockSyncWebSocket>(SyncWebSocket::StatusCode::kOk);
Peter Kasting098eeab2021-09-02 22:54:21485 SyncWebSocketFactory factory = base::BindRepeating(
Vladimir Nechaev355dc822022-08-08 12:12:33486 [](SyncWebSocket* socket) {
487 return std::unique_ptr<SyncWebSocket>(new SyncWebSocketWrapper(socket));
488 },
489 socket.get());
Tricia Crichton82d78842019-11-19 21:50:45490 // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
491 std::unique_ptr<DevToolsClientImpl> client_uptr =
Vladimir Nechaeve840c4b2022-05-20 08:38:22492 std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
Tricia Crichton82d78842019-11-19 21:50:45493 DevToolsClientImpl* client_ptr = client_uptr.get();
494 BrowserInfo browser_info;
495 WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43496 std::move(client_uptr), absl::nullopt,
Tricia Crichton82d78842019-11-19 21:50:45497 PageLoadStrategy::kNone);
Vladimir Nechaevd0786c72022-12-09 12:37:44498 Status status = client_ptr->Connect();
Vladimir Nechaev355dc822022-08-08 12:12:33499 ASSERT_EQ(kOk, status.code()) << status.message();
Tricia Crichton82d78842019-11-19 21:50:45500 std::string sessionid = "2";
501 std::unique_ptr<WebViewImpl> child_view =
502 std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
Vladimir Nechaev355dc822022-08-08 12:12:33503 child_view->AttachTo(client_ptr);
Tricia Crichton82d78842019-11-19 21:50:45504
505 // child_view gets no socket...
Vladimir Nechaev355dc822022-08-08 12:12:33506 socket->SetNexStatusCode(SyncWebSocket::StatusCode::kTimeout);
Tricia Crichton82d78842019-11-19 21:50:45507 ASSERT_NO_FATAL_FAILURE(child_view->WaitForPendingNavigations(
Peter Kastinge5a38ed2021-10-02 03:06:35508 "1234", Timeout(base::Milliseconds(10)), true));
Tricia Crichton82d78842019-11-19 21:50:45509}
510
511TEST(CreateChild, IsPendingNavigation_NoErrors) {
Peter Kasting098eeab2021-09-02 22:54:21512 SyncWebSocketFactory factory = base::BindRepeating(
513 &CreateMockSyncWebSocket, SyncWebSocket::StatusCode::kOk);
Tricia Crichton82d78842019-11-19 21:50:45514 // CreateChild relies on client_ being a DevToolsClientImpl, so no mocking
515 std::unique_ptr<DevToolsClientImpl> client_uptr =
Vladimir Nechaeve840c4b2022-05-20 08:38:22516 std::make_unique<DevToolsClientImpl>("id", "", "http://url", factory);
Tricia Crichton82d78842019-11-19 21:50:45517 DevToolsClientImpl* client_ptr = client_uptr.get();
518 BrowserInfo browser_info;
519 WebViewImpl parent_view(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43520 std::move(client_uptr), absl::nullopt,
Tricia Crichton82d78842019-11-19 21:50:45521 PageLoadStrategy::kNormal);
Vladimir Nechaevd0786c72022-12-09 12:37:44522 Status status = client_ptr->Connect();
Vladimir Nechaev355dc822022-08-08 12:12:33523 ASSERT_EQ(kOk, status.code()) << status.message();
Tricia Crichton82d78842019-11-19 21:50:45524 std::string sessionid = "2";
525 std::unique_ptr<WebViewImpl> child_view =
526 std::unique_ptr<WebViewImpl>(parent_view.CreateChild(sessionid, "1234"));
Vladimir Nechaev355dc822022-08-08 12:12:33527 child_view->AttachTo(client_ptr);
Tricia Crichton82d78842019-11-19 21:50:45528
Peter Kastinge5a38ed2021-10-02 03:06:35529 Timeout timeout(base::Milliseconds(10));
Tricia Crichton82d78842019-11-19 21:50:45530 bool result;
Shengfa Lin19cd50092020-05-20 00:41:49531 ASSERT_NO_FATAL_FAILURE(child_view->IsPendingNavigation(&timeout, &result));
Tricia Crichton82d78842019-11-19 21:50:45532}
Tricia Crichton118865f322019-12-06 19:49:09533
534TEST(ManageCookies, AddCookie_SameSiteTrue) {
535 std::unique_ptr<FakeDevToolsClient> client_uptr =
536 std::make_unique<FakeDevToolsClient>();
537 FakeDevToolsClient* client_ptr = client_uptr.get();
538 BrowserInfo browser_info;
539 WebViewImpl view(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43540 std::move(client_uptr), absl::nullopt,
541 PageLoadStrategy::kEager);
Tricia Crichton118865f322019-12-06 19:49:09542 std::string samesite = "Strict";
Matt Menkeb24aeee2022-11-04 12:18:06543 base::Value::Dict dict;
544 dict.Set("success", true);
Vladimir Nechaeva94351f2023-03-08 10:31:42545 client_ptr->SetResult(dict);
Tricia Crichton118865f322019-12-06 19:49:09546 Status status = view.AddCookie("utest", "chrome://version", "value", "domain",
547 "path", samesite, true, true, 123456789);
548 ASSERT_EQ(kOk, status.code());
549}
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12550
551TEST(GetBackendNodeId, W3C) {
552 std::unique_ptr<FakeDevToolsClient> client_uptr =
553 std::make_unique<FakeDevToolsClient>();
554 FakeDevToolsClient* client_ptr = client_uptr.get();
555 BrowserInfo browser_info;
556 WebViewImpl view(client_ptr->GetId(), true, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43557 std::move(client_uptr), absl::nullopt,
558 PageLoadStrategy::kEager);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12559 {
560 base::Value::Dict node_ref;
561 node_ref.Set(kElementKey, "one_element_25");
562 node_ref.Set(kElementKeyW3C, "one_element_13");
563 int backend_node_id = -1;
564 EXPECT_TRUE(StatusOk(view.GetBackendNodeIdByElement(
565 "", base::Value(std::move(node_ref)), &backend_node_id)));
566 EXPECT_EQ(13, backend_node_id);
567 }
568 {
569 base::Value::Dict node_ref;
570 node_ref.Set(kShadowRootKey, "one_element_11");
571 int backend_node_id = -1;
572 EXPECT_TRUE(StatusOk(view.GetBackendNodeIdByElement(
573 "", base::Value(std::move(node_ref)), &backend_node_id)));
574 EXPECT_EQ(11, backend_node_id);
575 }
576}
577
578TEST(GetBackendNodeId, NonW3C) {
579 std::unique_ptr<FakeDevToolsClient> client_uptr =
580 std::make_unique<FakeDevToolsClient>();
581 FakeDevToolsClient* client_ptr = client_uptr.get();
582 BrowserInfo browser_info;
583 WebViewImpl view(client_ptr->GetId(), false, nullptr, &browser_info,
Vladimir Nechaev9f135392023-04-20 07:02:43584 std::move(client_uptr), absl::nullopt,
585 PageLoadStrategy::kEager);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12586 {
587 base::Value::Dict node_ref;
588 node_ref.Set(kElementKey, "one_element_25");
589 node_ref.Set(kElementKeyW3C, "one_element_13");
590 int backend_node_id = -1;
591 EXPECT_TRUE(StatusOk(view.GetBackendNodeIdByElement(
592 "", base::Value(std::move(node_ref)), &backend_node_id)));
593 EXPECT_EQ(25, backend_node_id);
594 }
595 {
596 base::Value::Dict node_ref;
597 node_ref.Set(kShadowRootKey, "one_element_11");
598 int backend_node_id = -1;
599 EXPECT_TRUE(StatusOk(view.GetBackendNodeIdByElement(
600 "", base::Value(std::move(node_ref)), &backend_node_id)));
601 EXPECT_EQ(11, backend_node_id);
602 }
603}
604
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12605TEST(CallUserSyncScript, ElementIdAsResultRootFrame) {
606 BrowserInfo browser_info;
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12607 std::unique_ptr<base::Value> result;
608 std::unique_ptr<FakeDevToolsClient> client_uptr =
609 std::make_unique<FakeDevToolsClient>("root");
Vladimir Nechaeva94351f2023-03-08 10:31:42610 client_uptr->SetResult(GenerateResponse(4321));
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12611 WebViewImpl view("root", true, nullptr, &browser_info, std::move(client_uptr),
Vladimir Nechaev9f135392023-04-20 07:02:43612 absl::nullopt, PageLoadStrategy::kEager);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12613 view.GetFrameTracker()->SetContextIdForFrame("root", "irrelevant");
614 view.GetFrameTracker()->SetContextIdForFrame("good", "irrelevant");
615 {
616 EXPECT_TRUE(StatusOk(
617 view.CallUserSyncScript("root", "some_code", base::Value::List(),
618 base::TimeDelta::Max(), &result)));
619 ASSERT_TRUE(result->is_dict());
620 EXPECT_THAT(result->GetDict().FindString(kElementKeyW3C),
621 Pointee(Eq("root_loader_element_4321")));
622 }
623 result.reset();
624 {
625 EXPECT_TRUE(
626 StatusOk(view.CallUserSyncScript("", "some_code", base::Value::List(),
627 base::TimeDelta::Max(), &result)));
628 ASSERT_TRUE(result->is_dict());
629 EXPECT_THAT(result->GetDict().FindString(kElementKeyW3C),
630 Pointee(Eq("root_loader_element_4321")));
631 }
632 result.reset();
633 {
634 EXPECT_TRUE(StatusOk(
635 view.CallUserSyncScript("good", "some_code", base::Value::List(),
636 base::TimeDelta::Max(), &result)));
637 ASSERT_TRUE(result->is_dict());
638 EXPECT_THAT(result->GetDict().FindString(kElementKeyW3C),
639 Pointee(Eq("good_loader_element_4321")));
640 }
641}
642
643TEST(CallUserSyncScript, ElementIdAsResultChildFrame) {
644 BrowserInfo browser_info;
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12645 std::unique_ptr<base::Value> result;
646 std::unique_ptr<FakeDevToolsClient> client_uptr =
647 std::make_unique<FakeDevToolsClient>("good");
Vladimir Nechaeva94351f2023-03-08 10:31:42648 client_uptr->SetResult(GenerateResponse(4321));
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12649 WebViewImpl view("good", true, nullptr, &browser_info, std::move(client_uptr),
Vladimir Nechaev9f135392023-04-20 07:02:43650 absl::nullopt, PageLoadStrategy::kEager);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12651 view.GetFrameTracker()->SetContextIdForFrame("root", "irrelevant");
652 view.GetFrameTracker()->SetContextIdForFrame("good", "irrelevant");
653 {
654 EXPECT_TRUE(StatusOk(
655 view.CallUserSyncScript("root", "some_code", base::Value::List(),
656 base::TimeDelta::Max(), &result)));
657 ASSERT_TRUE(result->is_dict());
658 EXPECT_THAT(result->GetDict().FindString(kElementKeyW3C),
659 Pointee(Eq("root_loader_element_4321")));
660 }
661 result.reset();
662 {
663 EXPECT_TRUE(
664 StatusOk(view.CallUserSyncScript("", "some_code", base::Value::List(),
665 base::TimeDelta::Max(), &result)));
666 ASSERT_TRUE(result->is_dict());
667 EXPECT_THAT(result->GetDict().FindString(kElementKeyW3C),
668 Pointee(Eq("good_loader_element_4321")));
669 }
670 result.reset();
671 {
672 EXPECT_TRUE(StatusOk(
673 view.CallUserSyncScript("good", "some_code", base::Value::List(),
674 base::TimeDelta::Max(), &result)));
675 ASSERT_TRUE(result->is_dict());
676 EXPECT_THAT(result->GetDict().FindString(kElementKeyW3C),
677 Pointee(Eq("good_loader_element_4321")));
678 }
679}
680
681TEST(CallUserSyncScript, ElementIdAsResultChildFrameErrors) {
682 BrowserInfo browser_info;
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12683 std::unique_ptr<base::Value> result;
684 std::unique_ptr<FakeDevToolsClient> client_uptr =
685 std::make_unique<FakeDevToolsClient>("root");
686 FakeDevToolsClient* client_ptr = client_uptr.get();
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12687 WebViewImpl view("root", true, nullptr, &browser_info, std::move(client_uptr),
Vladimir Nechaev9f135392023-04-20 07:02:43688 absl::nullopt, PageLoadStrategy::kEager);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12689 view.GetFrameTracker()->SetContextIdForFrame("root", "irrelevant");
690 view.GetFrameTracker()->SetContextIdForFrame("good", "irrelevant");
691 view.GetFrameTracker()->SetContextIdForFrame("bad", "irrelevant");
692 {
693 // missing frame.id case
694 base::Value::Dict bad_child;
695 bad_child.SetByDottedPath("frame.loaderId", "bad_loader");
696 client_ptr->AddExtraChildFrame(std::move(bad_child));
697 EXPECT_FALSE(view.CallUserSyncScript("bad", "some_code",
698 base::Value::List(),
699 base::TimeDelta::Max(), &result)
700 .IsOk());
701 client_ptr->ClearExtraChildFrames();
702 }
703 result.reset();
704 {
705 // missing loaderId case
706 base::Value::Dict bad_child;
707 bad_child.SetByDottedPath("frame.id", "bad");
708 client_ptr->AddExtraChildFrame(std::move(bad_child));
709 EXPECT_FALSE(view.CallUserSyncScript("bad", "some_code",
710 base::Value::List(),
711 base::TimeDelta::Max(), &result)
712 .IsOk());
713 client_ptr->ClearExtraChildFrames();
714 }
715 result.reset();
716 {
717 // empty frame description
718 base::Value::Dict bad_child;
719 client_ptr->AddExtraChildFrame(std::move(bad_child));
720 EXPECT_FALSE(view.CallUserSyncScript("bad", "some_code",
721 base::Value::List(),
722 base::TimeDelta::Max(), &result)
723 .IsOk());
724 client_ptr->ClearExtraChildFrames();
725 }
726 result.reset();
727 {
728 // frame is not a dictionary
729 base::Value::Dict bad_child;
730 bad_child.Set("frame", "bad");
731 client_ptr->AddExtraChildFrame(std::move(bad_child));
732 EXPECT_FALSE(view.CallUserSyncScript("bad", "some_code",
733 base::Value::List(),
734 base::TimeDelta::Max(), &result)
735 .IsOk());
736 client_ptr->ClearExtraChildFrames();
737 }
738 result.reset();
739 {
740 // frame does not exist
741 EXPECT_FALSE(view.CallUserSyncScript("non_existent_frame", "some_code",
742 base::Value::List(),
743 base::TimeDelta::Max(), &result)
744 .IsOk());
745 }
746 result.reset();
747 {
748 // no execution context information
749 base::Value::Dict bad_child;
750 bad_child.SetByDottedPath("frame.id", "no_execution_context");
751 bad_child.SetByDottedPath("frame.loaderId", "no_execution_context_loader");
752 client_ptr->AddExtraChildFrame(std::move(bad_child));
753 EXPECT_FALSE(view.CallUserSyncScript("no_execution_context", "some_code",
754 base::Value::List(),
755 base::TimeDelta::Max(), &result)
756 .IsOk());
757 client_ptr->ClearExtraChildFrames();
758 }
759 result.reset();
760 {
761 // Test self-check: make sure that one shot frames work correctly
762 base::Value::Dict another_good_child;
763 another_good_child.SetByDottedPath("frame.id", "bad");
764 another_good_child.SetByDottedPath("frame.loaderId", "bad_loader");
765 client_ptr->AddExtraChildFrame(std::move(another_good_child));
766 EXPECT_TRUE(StatusOk(
767 view.CallUserSyncScript("bad", "some_code", base::Value::List(),
768 base::TimeDelta::Max(), &result)));
769 client_ptr->ClearExtraChildFrames();
770 }
771}
772
773class CallUserSyncScriptArgs
774 : public testing::TestWithParam<std::pair<std::string, bool>> {
775 public:
776 void SetUp() override {
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12777 std::unique_ptr<FakeDevToolsClient> client_uptr =
778 std::make_unique<FakeDevToolsClient>("root");
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12779 client_ptr = client_uptr.get();
Vladimir Nechaev9f135392023-04-20 07:02:43780 view = std::make_unique<WebViewImpl>(
781 "root", IsW3C(), nullptr, &browser_info, std::move(client_uptr),
782 absl::nullopt, PageLoadStrategy::kEager);
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12783 view->GetFrameTracker()->SetContextIdForFrame("root", "irrelevant");
784 view->GetFrameTracker()->SetContextIdForFrame("good", "irrelevant");
785 view->GetFrameTracker()->SetContextIdForFrame("bad", "irrelevant");
786 }
787
788 void TearDown() override {
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12789 client_ptr = nullptr;
Tom Sepeza0e0e792023-03-27 19:58:38790 view.reset();
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12791 }
792
793 bool IsW3C() { return GetParam().second; }
794
795 std::string ElementKey() { return GetParam().first; }
796
Tom Sepeza0e0e792023-03-27 19:58:38797 BrowserInfo browser_info;
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12798 std::unique_ptr<WebViewImpl> view;
799 base::raw_ptr<FakeDevToolsClient> client_ptr;
800};
801
802TEST_P(CallUserSyncScriptArgs, Root) {
803 // Expecting success as the frame and loader_id match each other.
804 base::Value::List args;
805 base::Value::Dict ref;
806 ref.Set(ElementKey(), "root_loader_element_99");
807 args.Append(std::move(ref));
808 std::unique_ptr<base::Value> result;
809 EXPECT_TRUE(StatusOk(view->CallUserSyncScript(
810 "root", "some_code", std::move(args), base::TimeDelta::Max(), &result)));
811}
812
813TEST_P(CallUserSyncScriptArgs, GoodChild) {
814 // Expecting success as the frame and loader_id match each other.
815 base::Value::List args;
816 base::Value::Dict ref;
817 ref.Set(ElementKey(), "good_loader_element_99");
818 args.Append(std::move(ref));
819 std::unique_ptr<base::Value> result;
820 EXPECT_TRUE(StatusOk(view->CallUserSyncScript(
821 "good", "some_code", std::move(args), base::TimeDelta::Max(), &result)));
822}
823
Vladimir Nechaeva94351f2023-03-08 10:31:42824TEST_P(CallUserSyncScriptArgs, DeepElement) {
825 std::string element_id = "good_loader_element_99";
826 base::Value::Dict ref;
827 ref.Set(ElementKey(), element_id);
828 base::Value::List list;
829 list.Append(1);
830 list.Append(std::move(ref));
831 list.Append("xyz");
832 base::Value::Dict arg;
833 arg.SetByDottedPath("uno.a", "b");
834 arg.SetByDottedPath("uno.dos", std::move(list));
835 arg.SetByDottedPath("dos.b", 7.7);
836 base::Value::List nodes;
837 base::Value::List args;
838 args.Append(std::move(arg));
839 std::unique_ptr<base::Value> result;
840 client_ptr->SetElementKey(ElementKey());
841 EXPECT_TRUE(
842 StatusOk(view->CallUserSyncScript("good", "return nodes", std::move(args),
843 base::TimeDelta::Max(), &result)));
844
845 ASSERT_TRUE(result->is_list());
846 ASSERT_EQ(result->GetList().size(), size_t(1));
847 base::Value::Dict* received_ref = result->GetList()[0].GetIfDict();
848 ASSERT_NE(received_ref, nullptr);
849 std::string* maybe_backend_node_id = received_ref->FindString(ElementKey());
850 EXPECT_THAT(maybe_backend_node_id, Pointee(Eq(element_id)));
851}
852
Vladimir Nechaev90ebbc5ba2023-02-28 12:55:12853TEST_P(CallUserSyncScriptArgs, FrameAndLoaderMismatch) {
854 base::Value::List args;
855 base::Value::Dict ref;
856 ref.Set(ElementKey(), "root_loader_element_99");
857 args.Append(std::move(ref));
858 std::unique_ptr<base::Value> result;
859 const int expected_error = ElementKey() == kShadowRootKey
860 ? kDetachedShadowRoot
861 : kStaleElementReference;
862 EXPECT_EQ(expected_error,
863 view->CallUserSyncScript("good", "some_code", std::move(args),
864 base::TimeDelta::Max(), &result)
865 .code());
866}
867
868TEST_P(CallUserSyncScriptArgs, NoSuchLoader) {
869 base::Value::List args;
870 base::Value::Dict ref;
871 ref.Set(ElementKey(), "bad_loader_element_99");
872 args.Append(std::move(ref));
873 std::unique_ptr<base::Value> result;
874 const int expected_error = ElementKey() == kShadowRootKey
875 ? kDetachedShadowRoot
876 : kStaleElementReference;
877 EXPECT_EQ(expected_error,
878 view->CallUserSyncScript("root", "some_code", std::move(args),
879 base::TimeDelta::Max(), &result)
880 .code());
881}
882
883TEST_P(CallUserSyncScriptArgs, IncorrectSeparator) {
884 base::Value::List args;
885 base::Value::Dict ref;
886 ref.Set(ElementKey(), "good_loader_eeeeeee_99");
887 args.Append(std::move(ref));
888 std::unique_ptr<base::Value> result;
889 EXPECT_FALSE(view->CallUserSyncScript("good", "some_code", std::move(args),
890 base::TimeDelta::Max(), &result)
891 .IsOk());
892}
893
894TEST_P(CallUserSyncScriptArgs, NoBackendNodeId) {
895 base::Value::List args;
896 base::Value::Dict ref;
897 ref.Set(ElementKey(), "good_loader_element_xx");
898 args.Append(std::move(ref));
899 std::unique_ptr<base::Value> result;
900 EXPECT_FALSE(view->CallUserSyncScript("good", "some_code", std::move(args),
901 base::TimeDelta::Max(), &result)
902 .IsOk());
903}
904
905TEST_P(CallUserSyncScriptArgs, RepeatedSeparator) {
906 // We have a test that checks if the second component (BackendNodeId) is
907 // integer.
908 // Here it is sufficient to check that the call does not fail.
909 // This would mean that only the last _element_ id was used as a separation
910 // point.
911 base::Value::Dict extra_child;
912 extra_child.SetByDottedPath("frame.id", "extra_child_element_some_text");
913 extra_child.SetByDottedPath("frame.loaderId",
914 "extra_child_element_some_text_loader");
915 client_ptr->AddExtraChildFrame(std::move(extra_child));
916 view->GetFrameTracker()->SetContextIdForFrame("extra_child_element_some_text",
917 "irrelevant");
918 base::Value::List args;
919 base::Value::Dict ref;
920 ref.Set(ElementKey(), "extra_child_element_some_text_loader_element_71");
921 args.Append(std::move(ref));
922 std::unique_ptr<base::Value> result;
923 EXPECT_TRUE(StatusOk(view->CallUserSyncScript(
924 "extra_child_element_some_text", "some_code", std::move(args),
925 base::TimeDelta::Max(), &result)));
926}
927
928INSTANTIATE_TEST_SUITE_P(References,
929 CallUserSyncScriptArgs,
930 ::testing::Values(std::make_pair(kElementKeyW3C, true),
931 std::make_pair(kShadowRootKey, true),
932 std::make_pair(kElementKey, false),
933 std::make_pair(kShadowRootKey,
934 false)));