blob: 021d47d640ad7e6d2f2afad069e0b7e08e85bac1 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill_assistant/browser/script_precondition.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/web/element.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
namespace {
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Key;
using ::testing::Property;
using ::testing::UnorderedElementsAre;
using ::testing::WithArgs;
class ElementPreconditionTest : public testing::Test {
public:
void SetUp() override {
ON_CALL(mock_web_controller_, FindElement(Selector({"exists"}), _, _))
.WillByDefault(WithArgs<2>([](auto&& callback) {
std::move(callback).Run(OkClientStatus(),
std::make_unique<ElementFinder::Result>());
}));
ON_CALL(mock_web_controller_, FindElement(Selector({"exists_too"}), _, _))
.WillByDefault(WithArgs<2>([](auto&& callback) {
std::move(callback).Run(OkClientStatus(),
std::make_unique<ElementFinder::Result>());
}));
ON_CALL(mock_web_controller_,
FindElement(Selector({"does_not_exist"}), _, _))
.WillByDefault(RunOnceCallback<2>(
ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
ON_CALL(mock_web_controller_,
FindElement(Selector({"does_not_exist_either"}), _, _))
.WillByDefault(RunOnceCallback<2>(
ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
}
protected:
// Runs a precondition given |exists_| and |value_match_|.
void Check(
base::OnceCallback<void(
const ClientStatus&,
const std::vector<std::string>&,
const base::flat_map<std::string, DomObjectFrameStack>&)> callback) {
ElementPrecondition precondition(condition_);
BatchElementChecker batch_checks;
precondition.Check(&batch_checks, std::move(callback));
batch_checks.Run(&mock_web_controller_);
}
MockWebController mock_web_controller_;
base::MockCallback<base::OnceCallback<void(
const ClientStatus&,
const std::vector<std::string>&,
const base::flat_map<std::string, DomObjectFrameStack>&)>>
mock_callback_;
ElementConditionProto condition_;
};
TEST_F(ElementPreconditionTest, Empty) {
EXPECT_TRUE(ElementPrecondition(condition_).empty());
}
TEST_F(ElementPreconditionTest, NonEmpty) {
*condition_.mutable_match() = ToSelectorProto("exists");
EXPECT_FALSE(ElementPrecondition(condition_).empty());
}
TEST_F(ElementPreconditionTest, NoConditions) {
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, EmptySelector) {
condition_.mutable_match();
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, ElementExists) {
*condition_.mutable_match() = ToSelectorProto("exists");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, ElementDoes_Not_Exist) {
*condition_.mutable_match() = ToSelectorProto("does_not_exist");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AnyOf_Empty) {
condition_.mutable_any_of();
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AnyOf_NoneMatch) {
*condition_.mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
*condition_.mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist_either");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AnyOf_SomeMatch) {
*condition_.mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AnyOf_AllMatch) {
*condition_.mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists_too");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AllOf_Empty) {
condition_.mutable_all_of();
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AllOf_NoneMatch) {
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist_either");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AllOf_SomeMatch) {
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, AllOf_AllMatch) {
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists_too");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, NoneOf_Empty) {
condition_.mutable_none_of();
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, NoneOf_NoneMatch) {
*condition_.mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
*condition_.mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist_either");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, NoneOf_SomeMatch) {
*condition_.mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, NoneOf_AllMatch) {
*condition_.mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists_too");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
_, _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, Payload_ConditionMet) {
auto* exists = condition_.mutable_any_of()->add_conditions();
*exists->mutable_match() = ToSelectorProto("exists");
exists->set_payload("exists");
auto* exists_too = condition_.mutable_any_of()->add_conditions();
*exists_too->mutable_match() = ToSelectorProto("exists_too");
exists_too->set_payload("exists_too");
condition_.set_payload("any_of");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
ElementsAre("exists", "exists_too", "any_of"), _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, Payload_ConditionNotMet) {
auto* exists = condition_.mutable_none_of()->add_conditions();
*exists->mutable_match() = ToSelectorProto("exists");
exists->set_payload("exists");
auto* exists_too = condition_.mutable_none_of()->add_conditions();
*exists_too->mutable_match() = ToSelectorProto("exists_too");
exists_too->set_payload("exists_too");
condition_.set_payload("none_of");
EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
ELEMENT_RESOLUTION_FAILED),
ElementsAre("exists", "exists_too"), _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, Complex) {
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists");
*condition_.mutable_all_of()->add_conditions()->mutable_match() =
ToSelectorProto("exists_too");
auto* none_of = condition_.mutable_all_of()->add_conditions();
none_of->set_payload("none_of");
auto* does_not_exist_in_none_of =
none_of->mutable_none_of()->add_conditions();
*does_not_exist_in_none_of->mutable_match() =
ToSelectorProto("does_not_exist");
does_not_exist_in_none_of->set_payload("does_not_exist in none_of");
*none_of->mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist_either");
auto* any_of = condition_.mutable_all_of()->add_conditions();
any_of->set_payload("any_of");
auto* exists_in_any_of = any_of->mutable_any_of()->add_conditions();
*exists_in_any_of->mutable_match() = ToSelectorProto("exists");
exists_in_any_of->set_payload("exists in any_of");
*any_of->mutable_any_of()->add_conditions()->mutable_match() =
ToSelectorProto("does_not_exist");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
ElementsAre("none_of", "exists in any_of", "any_of"), _));
Check(mock_callback_.Get());
}
TEST_F(ElementPreconditionTest, ReturnsFoundElements) {
auto* exists = condition_.mutable_all_of()->add_conditions();
*exists->mutable_match() = ToSelectorProto("exists");
exists->set_payload("exists");
exists->mutable_client_id()->set_identifier("exists");
auto* exists_too = condition_.mutable_all_of()->add_conditions();
*exists_too->mutable_match() = ToSelectorProto("exists_too");
exists_too->set_payload("exists_too");
exists_too->mutable_client_id()->set_identifier("exists_too");
EXPECT_CALL(mock_callback_,
Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
ElementsAre("exists", "exists_too"),
UnorderedElementsAre(Key("exists"), Key("exists_too"))));
Check(mock_callback_.Get());
}
} // namespace
} // namespace autofill_assistant