blob: f621a0298e87b8d14d861928865029897e4af0b3 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_TEST_INTERACTION_INTERACTIVE_BROWSER_TEST_INTERNAL_H_
#define CHROME_TEST_INTERACTION_INTERACTIVE_BROWSER_TEST_INTERNAL_H_
#include <compare>
#include <memory>
#include <utility>
#include <vector>
#include "base/values.h"
#include "chrome/test/interaction/interaction_test_util_browser.h"
#include "chrome/test/interaction/tracked_element_webcontents.h"
#include "chrome/test/interaction/webcontents_interaction_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/interaction/element_tracker.h"
#include "ui/base/interaction/interaction_sequence.h"
#include "ui/base/interaction/interactive_test_definitions.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/views/interaction/interactive_views_test_internal.h"
class DevToolsAgentCoverageObserver;
class InteractiveBrowserTestApi;
namespace internal {
// Class that provides functionality needed by InteractiveBrowserTestApi but
// which should not be directly visible to tests inheriting from the API class.
class InteractiveBrowserTestPrivate
: public views::test::internal::InteractiveViewsTestPrivate {
public:
explicit InteractiveBrowserTestPrivate(
std::unique_ptr<InteractionTestUtilBrowser> test_util);
~InteractiveBrowserTestPrivate() override;
// views::test::internal::InteractiveViewsTestPrivate:
void DoTestTearDown() override;
// Starts code coverage if the proper configuration is present.
void MaybeStartWebUICodeCoverage();
void AddInstrumentedWebContents(
std::unique_ptr<WebContentsInteractionTestUtil>
instrumented_web_contents);
bool IsInstrumentedWebContents(ui::ElementIdentifier element_id) const;
// Removes WebContents instrumentation; can allow for re-instrumentation using
// the same ID later. Returns whether `to_remove` was found and removed.
bool UninstrumentWebContents(ui::ElementIdentifier to_remove);
static std::string DeepQueryToString(
const WebContentsInteractionTestUtil::DeepQuery& deep_query);
protected:
// views::test::InteractiveViewsTestPrivate:
gfx::NativeWindow GetNativeWindowFromElement(
ui::TrackedElement* el) const override;
gfx::NativeWindow GetNativeWindowFromContext(
ui::ElementContext context) const override;
std::string DebugDescribeContext(ui::ElementContext context) const override;
DebugTreeNode DebugDumpElement(const ui::TrackedElement* el) const override;
private:
friend InteractiveBrowserTestApi;
// Optional WebUI code coverage tool.
std::unique_ptr<DevToolsAgentCoverageObserver> coverage_observer_;
// Stores instrumented WebContents and WebUI.
std::vector<std::unique_ptr<WebContentsInteractionTestUtil>>
instrumented_web_contents_;
};
// This class wraps a `base::Value` in a wrapper that allows copying when
// necessary via the `Clone()` method. This is so that Value objects can be
// used with gtest and gmock matchers, much of the logic of which requires copy
// operations in order to work.
class MatchableValue {
public:
MatchableValue() noexcept;
MatchableValue(const base::Value& value) noexcept; // NOLINT
MatchableValue(base::Value&& value) noexcept; // NOLINT
MatchableValue(const MatchableValue& value) noexcept;
MatchableValue(MatchableValue&&) noexcept;
MatchableValue& operator=(const base::Value& value) noexcept;
MatchableValue& operator=(base::Value&& value) noexcept;
MatchableValue& operator=(const MatchableValue& value) noexcept;
MatchableValue& operator=(MatchableValue&&) noexcept;
~MatchableValue();
template <typename T>
MatchableValue(T value) noexcept // NOLINT
: MatchableValue(base::Value(value)) {}
// These enable implicit comparison between MatchableValue objects and types
// that a base::Value can be constructed from. This is also required for a lot
// of gtest and gmock logic to work properly.
bool operator==(const MatchableValue& other) const;
bool operator<(const MatchableValue& other) const;
bool operator>(const MatchableValue& other) const;
bool operator<=(const MatchableValue& other) const;
bool operator>=(const MatchableValue& other) const;
operator std::string() const; // NOLINT
const base::Value& value() const { return value_; }
private:
base::Value value_;
};
// Matcher that determines whether a particular value is truthy.
//
// Uses an `internal::MatchableValue` because much of the gtest infrastructure
// expects a value that can be copied, and `base::Value` cannot.
class IsTruthyMatcher
: public testing::MatcherInterface<const internal::MatchableValue&> {
public:
IsTruthyMatcher() = default;
IsTruthyMatcher(const IsTruthyMatcher&) = default;
IsTruthyMatcher& operator=(const IsTruthyMatcher&) = default;
~IsTruthyMatcher() override = default;
using is_gtest_matcher = void;
bool MatchAndExplain(const internal::MatchableValue& x,
testing::MatchResultListener* listener) const override;
void DescribeTo(std::ostream* os) const override;
void DescribeNegationTo(std::ostream* os) const override;
};
extern std::ostream& operator<<(std::ostream& out, const MatchableValue& value);
// Helper class that converts am input into a matcher that can match a
// `base::Value`.
//
// The default implementation wraps a literal value or something that unwraps to
// a literal value to be matched.
template <typename M>
struct MakeValueMatcherHelper {
static auto MakeValueMatcher(M m) {
return testing::Matcher<base::Value>(testing::Eq(m));
}
};
// This specialization handles things that can be directly cast/moved into a
// `testing::Matcher`, which is required since "matcher" is very duck-typed.
template <typename M>
requires requires(M&& m) {
testing::Matcher<MatchableValue>(std::forward<M>(m));
}
struct MakeValueMatcherHelper<M> {
static auto MakeValueMatcher(M&& m) {
return testing::Matcher<MatchableValue>(std::forward<M>(m));
}
};
// Wraps `m` in a `testing::Matcher` that will match a `base::Value`.
// Does not work for all possible inputs, but will work for most.
template <typename M>
auto MakeValueMatcher(M&& m) {
return MakeValueMatcherHelper<M>::MakeValueMatcher(
ui::test::internal::UnwrapArgument(std::forward<M>(m)));
}
// Wraps `m` in a `testing::Matcher` that will match a `base::Value`.
// Does not work for all possible inputs, but will work for most.
template <typename M>
auto MakeConstValueMatcher(const M& m) {
return MakeValueMatcherHelper<M>::MakeValueMatcher(
ui::test::internal::UnwrapArgument(m));
}
} // namespace internal
#endif // CHROME_TEST_INTERACTION_INTERACTIVE_BROWSER_TEST_INTERNAL_H_