blob: 384c5b261caa74304d6a9a0c654fca233dc538f2 [file] [log] [blame]
// Copyright 2021 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 "ui/base/interaction/interaction_sequence.h"
#include "base/callback_forward.h"
#include "base/debug/stack_trace.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/interaction/element_test_util.h"
#include "ui/base/interaction/element_tracker.h"
#include "ui/base/interaction/expect_call_in_scope.h"
namespace ui {
namespace {
const char kElementName1[] = "Element1";
const char kElementName2[] = "Element2";
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTestIdentifier1);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTestIdentifier2);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTestIdentifier3);
DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kCustomEventType1);
DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kCustomEventType2);
const ElementContext kTestContext1(1);
const ElementContext kTestContext2(2);
} // namespace
TEST(InteractionSequenceTest, ConstructAndDestructContext) {
auto sequence =
InteractionSequence::Builder()
.SetContext(kTestContext1)
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(kTestIdentifier1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence.reset();
}
TEST(InteractionSequenceTest, ConstructAndDestructWithWithInitialElement) {
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.AddStep(InteractionSequence::WithInitialElement(&element))
.Build();
sequence.reset();
}
TEST(InteractionSequenceTest, StartAndDestruct) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence.reset());
}
TEST(InteractionSequenceTest, StartFailsIfWithInitialElementNotVisible) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element(kTestIdentifier1, kTestContext1);
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
StartFailsIfWithInitialElementNotVisibleIdentifierOnly) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element(kTestIdentifier1, kTestContext1);
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.SetMustRemainVisible(true)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest, AbortIfWithInitialElementHiddenBeforeStart) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElementPtr element =
std::make_unique<test::TestElement>(kTestIdentifier1, kTestContext1);
element->Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(element.get()))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element->identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
element.reset();
EXPECT_CALL_IN_SCOPE(
aborted,
Run(nullptr, ElementIdentifier(), InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::
kElementHiddenBeforeSequenceStart),
sequence->Start());
}
TEST(InteractionSequenceTest,
AbortIfWithInitialElementHiddenBeforeStartIdentifierOnly) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElementPtr element =
std::make_unique<test::TestElement>(kTestIdentifier1, kTestContext1);
element->Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element->context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element->identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.SetMustRemainVisible(true)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element->identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
element.reset();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest, HideWithInitialElementAborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element.Hide());
}
TEST(InteractionSequenceTest,
HideWithInitialElementDoesNotAbortIfMustRemainVisibleIsFalse) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.SetMustRemainVisible(false)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetMustBeVisibleAtStart(false)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
element.Hide();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence.reset());
}
TEST(InteractionSequenceTest, TransitionOnActivated) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL(step, Run(sequence.get(), &element)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
element.Activate();
}
TEST(InteractionSeuenceTest, TransitionOnCustomEventSameId) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element), completed, Run,
element.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSeuenceTest, TransitionOnCustomEventDifferentId) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
// Non-matching ID should not trigger the step, even if the event type
// matches.
element.SendCustomEvent(kCustomEventType1);
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element2), completed, Run,
element2.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSeuenceTest, TransitionOnCustomEventAnyElement) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2);
test::TestElement element(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step2.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step, Run(sequence.get(), &element),
element.SendCustomEvent(kCustomEventType1));
EXPECT_CALLS_IN_SCOPE_2(step2, Run(sequence.get(), &element2), completed, Run,
element2.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSeuenceTest, TransitionOnCustomEventMultipleEvents) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2);
test::TestElement element(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType2)
.SetStartCallback(step2.Get())
.Build())
.Build();
sequence->Start();
// This is the wrong event type so won't cause a transition.
element.SendCustomEvent(kCustomEventType2);
EXPECT_CALL_IN_SCOPE(step, Run(sequence.get(), &element),
element.SendCustomEvent(kCustomEventType1));
// This is the wrong event type so won't cause a transition.
element2.SendCustomEvent(kCustomEventType1);
EXPECT_CALLS_IN_SCOPE_2(step2, Run(sequence.get(), &element2), completed, Run,
element2.SendCustomEvent(kCustomEventType2));
}
TEST(InteractionSeuenceTest, TransitionOnCustomEventFailsIfMustBeVisible) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetMustBeVisibleAtStart(true)
.SetStartCallback(step.Get())
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(
aborted,
Run(nullptr, element2.identifier(),
InteractionSequence::StepType::kCustomEvent,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep),
sequence->Start());
}
TEST(InteractionSequenceTest, TransitionOnElementShown) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL(step, Run(sequence.get(), &element2)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
element2.Show();
}
TEST(InteractionSequenceTest, TransitionFailsOnElementShownIfMustBeVisible) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step.Get())
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL(
aborted,
Run(nullptr, element2.identifier(), InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep))
.Times(1);
sequence->Start();
}
TEST(InteractionSequenceTest, TransitionOnSameElementHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustRemainVisible(false)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
element2.Show();
EXPECT_CALL(step, Run(sequence.get(), nullptr)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
element2.Hide();
}
TEST(InteractionSequenceTest, TransitionOnOtherElementHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL(step, Run(sequence.get(), nullptr)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
element2.Hide();
}
TEST(InteractionSequenceTest, TransitionOnOtherElementAlreadyHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetStartCallback(step.Get())
.Build())
.Build();
EXPECT_CALL(step, Run(sequence.get(), testing::_)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
sequence->Start();
}
TEST(InteractionSequenceTest, FailOnOtherElementAlreadyHiddenIfMustBeVisible) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetMustBeVisibleAtStart(true)
.SetStartCallback(step.Get())
.Build())
.Build();
EXPECT_CALL(
aborted,
Run(nullptr, element2.identifier(),
InteractionSequence::StepType::kHidden,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep))
.Times(1);
sequence->Start();
}
TEST(InteractionSequenceTest, FailIfFirstElementBecomesHiddenBeforeActivation) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element1.Hide());
}
TEST(InteractionSequenceTest,
FailIfSecondElementBecomesHiddenBeforeActivation) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element2.Hide());
}
TEST(InteractionSequenceTest,
FailIfFirstElementBecomesHiddenBeforeCustomEvent) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element1.Hide());
}
TEST(InteractionSequenceTest, NoInitialElementTransitionsOnActivation) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetMustBeVisibleAtStart(false)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL(step, Run(sequence.get(), &element)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
element.Activate();
}
TEST(InteractionSequenceTest, NoInitialElementTransitionsOnCustomEvent) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element.context())
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element), completed, Run,
element.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSequenceTest, NoInitialElementTransitionsOnShown) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element(kTestIdentifier1, kTestContext1);
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL(step, Run(sequence.get(), &element)).Times(1);
EXPECT_CALL(completed, Run).Times(1);
element.Show();
}
TEST(InteractionSequenceTest, StepEndCallbackCalled) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step_end);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step_start.Get())
.SetEndCallback(step_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step_start, Run(sequence.get(), &element), step_end,
Run(&element), completed, Run, element.Activate());
}
TEST(InteractionSequenceTest, StepEndCallbackCalledForInitialStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2);
test::TestElement element(kTestIdentifier1, kTestContext1);
element.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element, step_start.Get(), step_end.Get()))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2.Get())
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(step_start, Run, sequence->Start());
EXPECT_CALLS_IN_SCOPE_3(step_end, Run(&element), step2,
Run(sequence.get(), &element), completed, Run,
element.Activate());
}
TEST(InteractionSequenceTest, MultipleStepsComplete) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALLS_IN_SCOPE_2(step1_end, Run, step2_start, Run,
element2.Activate());
EXPECT_CALLS_IN_SCOPE_2(step2_end, Run, completed, Run, element3.Show());
}
TEST(InteractionSequenceTest, MultipleStepsWithImmediateTransition) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
element3.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
// Since element3 is already visible, we skip straight to the end.
{
testing::InSequence in_sequence;
EXPECT_CALL(step1_end, Run).Times(1);
EXPECT_CALL(step2_start, Run).Times(1);
EXPECT_CALL(step2_end, Run).Times(1);
EXPECT_CALL(completed, Run).Times(1);
}
element2.Activate();
}
TEST(InteractionSequenceTest, CancelMidSequenceWhenViewHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
// Specify that this element must remain visible:
.SetMustRemainVisible(true)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALLS_IN_SCOPE_2(step1_end, Run, step2_start, Run,
element2.Activate());
EXPECT_CALLS_IN_SCOPE_2(
step2_end, Run, aborted,
Run(testing::_, element2.identifier(),
InteractionSequence::StepType::kActivated,
InteractionSequence::AbortedReason::kElementHiddenDuringStep),
element2.Hide());
}
TEST(InteractionSequenceTest, DontCancelIfViewDoesNotNeedToRemainVisible) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
// Specify that this element need not remain visible:
.SetMustRemainVisible(false)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALLS_IN_SCOPE_2(step1_end, Run, step2_start, Run,
element2.Activate());
element2.Hide();
EXPECT_CALLS_IN_SCOPE_2(step2_end, Run, completed, Run, element3.Show());
}
TEST(InteractionSequenceTest,
MultipleSequencesInDifferentContextsOneCompletes) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted2);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed2);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier1, kTestContext2);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step.Get())
.Build())
.Build();
auto sequence2 =
InteractionSequence::Builder()
.SetAbortedCallback(aborted2.Get())
.SetCompletedCallback(completed2.Get())
.AddStep(InteractionSequence::WithInitialElement(&element2))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2.Get())
.Build())
.Build();
sequence->Start();
sequence2->Start();
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element1), completed, Run,
element1.Activate());
EXPECT_CALL_IN_SCOPE(aborted2, Run, element2.Hide());
}
TEST(InteractionSequenceTest,
MultipleSequencesInDifferentContextsBothComplete) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted2);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed2);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier1, kTestContext2);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step.Get())
.Build())
.Build();
auto sequence2 =
InteractionSequence::Builder()
.SetAbortedCallback(aborted2.Get())
.SetCompletedCallback(completed2.Get())
.AddStep(InteractionSequence::WithInitialElement(&element2))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2.Get())
.Build())
.Build();
sequence->Start();
sequence2->Start();
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element1), completed, Run,
element1.Activate());
EXPECT_CALLS_IN_SCOPE_2(step2, Run(sequence2.get(), &element2), completed2,
Run, element2.Activate());
}
// These tests verify that events sent during callbacks (as might be used by an
// interactive UI test powered by an InteractionSequence) do not break the
// sequence.
TEST(InteractionSequenceTest, ShowDuringCallback) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Show();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element1.Activate());
}
TEST(InteractionSequenceTest, HideDuringCallback) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element1.Activate());
}
TEST(InteractionSequenceTest, ActivateDuringCallbackDifferentView) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Activate();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element1.Activate());
}
TEST(InteractionSequenceTest, ActivateDuringCallbackSameView) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Activate();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element2.Show());
}
TEST(InteractionSequenceTest, CustomEventDuringCallbackDifferentView) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.SendCustomEvent(kCustomEventType1);
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element1.Activate());
}
TEST(InteractionSequenceTest, CustomEventDuringCallbackSameView) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.SendCustomEvent(kCustomEventType1);
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element2.Show());
}
TEST(InteractionSequenceTest, HideAfterActivateDoesntAbort) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
element3.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Activate();
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Show());
}
TEST(InteractionSequenceTest, HideAfterCustomEventDoesntAbort) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
element3.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.SendCustomEvent(kCustomEventType1);
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Show());
}
TEST(InteractionSequenceTest, HideUnnamedElementAfterCustomEventDoesntAbort) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
element3.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.SendCustomEvent(kCustomEventType1);
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Show());
}
TEST(InteractionSequenceTest, HideDuringStepStartedCallbackAborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element2.Show());
}
TEST(InteractionSequenceTest, HideDuringStepEndedCallbackAborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](TrackedElement*) { element2.Hide(); };
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, InteractionSequence::StepStartCallback(),
base::BindLambdaForTesting(std::move(callback))))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
HideDuringStepStartedCallbackBeforeCustomEventAborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(
base::BindLambdaForTesting(std::move(callback)))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element2.Show());
}
TEST(InteractionSequenceTest,
HideDuringStepEndedCallbackBeforeCustomEventAborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](TrackedElement*) { element2.Hide(); };
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, InteractionSequence::StepStartCallback(),
base::BindLambdaForTesting(std::move(callback))))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest, ElementHiddenDuringFinalStepStart) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](InteractionSequence*, TrackedElement*) {
element2.Hide();
};
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustRemainVisible(false)
.SetStartCallback(base::BindLambdaForTesting(callback))
.SetEndCallback(step_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_2(step_end, Run(nullptr), completed, Run,
element2.Show());
}
TEST(InteractionSequenceTest, ElementHiddenDuringFinalStepEnd) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](TrackedElement*) { element2.Hide(); };
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustRemainVisible(false)
.SetEndCallback(base::BindLambdaForTesting(callback))
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Show());
}
TEST(InteractionSequenceTest, ElementHiddenDuringStepEndDuringAbort) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto callback = [&](TrackedElement*) { element2.Hide(); };
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetEndCallback(base::BindLambdaForTesting(callback))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
element2.Show();
// First parameter will be null because during the delete the step end
// callback will hide the element, which happens before the abort callback is
// called.
EXPECT_CALL_IN_SCOPE(
aborted,
Run(nullptr, element2.identifier(), InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::kSequenceDestroyed),
sequence.reset());
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringInitialStepStartCallback) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](InteractionSequence*, TrackedElement*) {
sequence.reset();
};
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, base::BindLambdaForTesting(callback), step1_end.Get()))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALLS_IN_SCOPE_2(step1_end, Run, aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringInitialStepEndCallback) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](TrackedElement*) { sequence.reset(); };
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, InteractionSequence::StepStartCallback(),
base::BindLambdaForTesting(callback)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element1.Activate());
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringInitialStepAbort) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](TrackedElement*, ElementIdentifier,
InteractionSequence::StepType,
InteractionSequence::AbortedReason) { sequence.reset(); };
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(base::BindLambdaForTesting(callback))
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, step1_start.Get(), step1_end.Get()))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(step1_start, Run, sequence->Start());
EXPECT_CALL_IN_SCOPE(step1_end, Run, element1.Hide());
EXPECT_FALSE(sequence);
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringMidSequenceStepStart) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](InteractionSequence*, TrackedElement*) {
sequence.reset();
};
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(base::BindLambdaForTesting(callback))
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_2(step1_end, Run, aborted, Run, element2.Show());
EXPECT_FALSE(sequence);
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringMidSequenceStepEnd) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](TrackedElement*) { sequence.reset(); };
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(base::BindLambdaForTesting(callback))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALL_IN_SCOPE(aborted, Run, element2.Activate());
EXPECT_FALSE(sequence);
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringMidSequenceAbort) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](TrackedElement*, ElementIdentifier,
InteractionSequence::StepType,
InteractionSequence::AbortedReason) { sequence.reset(); };
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(base::BindLambdaForTesting(callback))
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALL_IN_SCOPE(step1_end, Run, element2.Hide());
EXPECT_FALSE(sequence);
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringFinalStepEnd) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&](TrackedElement*) { sequence.reset(); };
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(base::BindLambdaForTesting(callback))
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, completed, Run,
element2.Activate());
EXPECT_FALSE(sequence);
}
TEST(InteractionSequenceTest, SequenceDestroyedDuringCompleted) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
auto callback = [&]() { sequence.reset(); };
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(base::BindLambdaForTesting(callback))
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetStartCallback(step2_start.Get())
.SetEndCallback(step2_end.Get())
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_start, Run, element2.Show());
EXPECT_CALLS_IN_SCOPE_3(step1_end, Run, step2_start, Run, step2_end, Run,
element2.Activate());
EXPECT_FALSE(sequence);
}
// Bait-and-switch tests - verify that when an element must start visible and
// there are multiple such elements, it's okay if any of them receive the
// following event.
TEST(InteractionSequenceTest, BaitAndSwitchActivation) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
sequence->Start();
element3.Show();
element2.Hide();
EXPECT_CALL_IN_SCOPE(completed, Run, element3.Activate());
}
TEST(InteractionSequenceTest, BaitAndSwitchActivationFails) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, {
// By hiding before showing the other element, there are no visible
// elements.
element2.Hide();
element3.Show();
element3.Activate();
});
}
TEST(InteractionSequenceTest, BaitAndSwitchActivationDuringStepTransition) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step_start =
base::BindLambdaForTesting([&](InteractionSequence*, TrackedElement*) {
element3.Show();
element2.Hide();
element3.Activate();
});
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, std::move(step_start)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
BaitAndSwitchActivationDuringStepTransitionEventuallyConsistent) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step_start =
base::BindLambdaForTesting([&](InteractionSequence*, TrackedElement*) {
// By hiding before showing the other element, there are no visible
// elements. However, because the system becomes consistent before the
// end of the callback and the event is triggered, we are allowed to
// proceed. This is technically incorrect behavior but adds a bit of
// forgiveness into the system if visibility of elements is updated in
// arbitrary order.
element2.Hide();
element3.Show();
element3.Activate();
});
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, std::move(step_start)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest, BaitAndSwitchCustomEvent) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
sequence->Start();
element3.Show();
element2.Hide();
EXPECT_CALL_IN_SCOPE(completed, Run,
element3.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSequenceTest, BaitAndSwitchCustomEventFails) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
sequence->Start();
// By hiding before showing the other element, there are no visible elements.
EXPECT_CALL_IN_SCOPE(aborted, Run, {
element2.Hide();
element3.Show();
element3.SendCustomEvent(kCustomEventType1);
});
}
TEST(InteractionSequenceTest, BaitAndSwitchCustomEventDuringStepTransition) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step_start =
base::BindLambdaForTesting([&](InteractionSequence*, TrackedElement*) {
element3.Show();
element2.Hide();
element3.SendCustomEvent(kCustomEventType1);
});
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, std::move(step_start)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
BaitAndSwitchCustomEventDuringStepTransitionEventuallyConsistent) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step_start =
base::BindLambdaForTesting([&](InteractionSequence*, TrackedElement*) {
// By hiding before showing the other element, there are no visible
// elements. However, because the system becomes consistent before the
// end of the callback and the event is triggered, we are allowed to
// proceed. This is technically incorrect behavior but adds a bit of
// forgiveness into the system if visibility of elements is updated in
// arbitrary order.
element2.Hide();
element3.Show();
element3.SendCustomEvent(kCustomEventType1);
});
std::unique_ptr<InteractionSequence> sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(
&element1, std::move(step_start)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
// Test step default values:
TEST(InteractionSequenceTest, MustBeVisibleAtStart_DefaultsToTrueForActivated) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
auto sequence =
InteractionSequence::Builder()
.SetContext(element1.context())
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(
step1_end, Run, step2_end, Run, aborted,
Run(nullptr, element3.identifier(),
InteractionSequence::StepType::kActivated,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep),
element1.Show());
}
TEST(InteractionSequenceTest,
MustBeVisibleAtStart_DefaultsToTrueForCustomEventIfElementIdSet) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
auto sequence =
InteractionSequence::Builder()
.SetContext(element1.context())
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->Start();
EXPECT_CALLS_IN_SCOPE_3(
step1_end, Run, step2_end, Run, aborted,
Run(nullptr, element3.identifier(),
InteractionSequence::StepType::kCustomEvent,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep),
element1.Show());
}
TEST(InteractionSequenceTest,
MustBeVisibleAtStart_DefaultsToFalseForCustomEventWithUnnamedElement) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step1_end);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepEndCallback, step2_end);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
auto sequence =
InteractionSequence::Builder()
.SetContext(element1.context())
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetEndCallback(step1_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetEndCallback(step2_end.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(step1_end, Run, element1.Show());
element3.Show();
EXPECT_CALLS_IN_SCOPE_2(step2_end, Run, completed, Run,
element3.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSequenceTest,
MustRemainVisible_DefaultsBasedOnCurrentAndNextStep_Activation) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetContext(element1.context())
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
// Shown followed by hidden defaults to must_remain_visible = false.
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.Build())
// Activated step defaults to false.
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetMustBeVisibleAtStart(false)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
// Shown followed by activated defaults to true.
// (We will fail the sequence on this step.)
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
// Trigger step 2.
element1.Hide();
element2.Show();
// Trigger step 3.
element2.Activate();
// Trigger step 4.
element3.Show();
// Fail step four.
EXPECT_CALL_IN_SCOPE(
aborted,
Run(&element3, element3.identifier(),
InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::kElementHiddenDuringStep),
element3.Hide());
}
TEST(InteractionSequenceTest,
MustRemainVisible_DefaultsBasedOnCurrentAndNextStep_CustomEvents) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
test::TestElement element3(kTestIdentifier3, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetContext(element1.context())
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
// Shown followed by hidden defaults to must_remain_visible = false.
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.Build())
// Activated step defaults to false.
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetMustBeVisibleAtStart(false)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
// Shown followed by activated defaults to true.
// (We will fail the sequence on this step.)
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element3.identifier())
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType2)
.Build())
.Build();
sequence->Start();
// Trigger step 2.
element1.Hide();
element2.Show();
// Trigger step 3.
element2.SendCustomEvent(kCustomEventType1);
// Trigger step 4.
element3.Show();
// Fail step four.
EXPECT_CALL_IN_SCOPE(
aborted,
Run(&element3, element3.identifier(),
InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::kElementHiddenDuringStep),
element3.Hide());
}
// SetTransitionOnlyOnEvent tests:
TEST(InteractionSequenceTest,
SetTransitionOnlyOnEvent_TransitionsOnDifferentElementShown) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step_start);
// Two elements have the same identifier, but only the first is visible.
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetTransitionOnlyOnEvent(true)
.SetStartCallback(step_start.Get())
.Build())
.Build();
sequence->Start();
// Fail step four.
EXPECT_CALLS_IN_SCOPE_2(step_start, Run, completed, Run, element2.Show());
}
TEST(InteractionSequenceTest,
SetTransitionOnlyOnEvent_TransitionsOnSameElementShown) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetContext(element1.context())
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.SetMustRemainVisible(false)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetTransitionOnlyOnEvent(true)
.SetStartCallback(step_start.Get())
.Build())
.Build();
sequence->Start();
element1.Hide();
// Fail step four.
EXPECT_CALLS_IN_SCOPE_2(step_start, Run, completed, Run, element1.Show());
}
TEST(InteractionSequenceTest,
SetTransitionOnlyOnEvent_TransitionsOnElementHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kHidden)
.SetTransitionOnlyOnEvent(true)
.SetStartCallback(step_start.Get())
.Build())
.Build();
sequence->Start();
element2.Show();
// Fail step four.
EXPECT_CALLS_IN_SCOPE_2(step_start, Run, completed, Run, element2.Hide());
}
// Named element tests:
TEST(InteractionSequenceTest,
NameElement_ElementShown_NamedBeforeSequenceStarts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementShown_NamedDuringStepCallback_SameIdentifier) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier1, kTestContext1);
auto step1_start = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
EXPECT_EQ(&element1, element);
sequence->NameElement(&element2, kElementName1);
});
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element2), completed, Run,
sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementShown_NamedDuringStepCallback_DifferentIdentifiers) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
auto step1_start = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
EXPECT_EQ(&element1, element);
sequence->NameElement(&element2, kElementName1);
});
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step.Get())
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
EXPECT_CALLS_IN_SCOPE_2(step, Run(sequence.get(), &element2), completed, Run,
sequence->Start());
}
TEST(InteractionSequenceTest, NameElement_ElementShown_FirstElementNamed) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest, NameElement_ElementShown_MultipleNamedElements) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step1_start);
UNCALLED_MOCK_CALLBACK(InteractionSequence::StepStartCallback, step2_start);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier1, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step1_start.Get())
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName2)
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(step2_start.Get())
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
sequence->NameElement(&element2, kElementName2);
EXPECT_CALLS_IN_SCOPE_3(step1_start, Run(sequence.get(), &element1),
step2_start, Run(sequence.get(), &element2),
completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementShown_DisappearsBeforeSequenceStart) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
element1.Hide();
EXPECT_CALL_IN_SCOPE(
aborted,
Run(nullptr, element1.identifier(), InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep),
sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementShown_DisappearsBeforeStepAbortsTheSequence) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
sequence->Start();
element2.Hide();
EXPECT_CALL_IN_SCOPE(
aborted,
Run(nullptr, element2.identifier(), InteractionSequence::StepType::kShown,
InteractionSequence::AbortedReason::kElementNotVisibleAtStartOfStep),
element1.Activate());
}
TEST(InteractionSequenceTest,
NameElement_ElementShown_RespectsMustRemainVisibleFalse) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.SetMustRemainVisible(false)
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
sequence->Start();
element2.Hide();
EXPECT_CALL_IN_SCOPE(completed, Run, element1.Activate());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NamedBeforeSequenceStarts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element1.Activate());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NamedBeforeSequenceStarts_AbortsIfHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element1.Hide());
}
TEST(InteractionSequenceTest, NameElement_ElementActivated_NamedDuringStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Activate());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NamedDuringStep_AbortsIfHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element2.Hide());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NamedAndActivatedDuringStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.Activate();
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NamedAndHiddenDuringStep_Aborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.Hide();
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NamedActivatedAndHiddenDuringStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.Activate();
element2.Hide();
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_CustomEvent_NamedBeforeSequenceStarts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run,
element1.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSequenceTest,
NameElement_CustomEvent_NamedBeforeSequenceStarts_AbortsIfHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(element1.context())
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->NameElement(&element1, kElementName1);
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element1.Hide());
}
TEST(InteractionSequenceTest, NameElement_CustomEvent_NamedDuringStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run,
element2.SendCustomEvent(kCustomEventType1));
}
TEST(InteractionSequenceTest,
NameElement_CustomEvent_NamedDuringStep_AbortsIfHidden) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(aborted, Run, element2.Hide());
}
TEST(InteractionSequenceTest,
NameElement_CustomEvent_NamedAndActivatedDuringStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.SendCustomEvent(kCustomEventType1);
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_CustomEvent_NamedAndHiddenDuringStep_Aborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.Hide();
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_CustomEvent_NamedActivatedAndHiddenDuringStep) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.SendCustomEvent(kCustomEventType1);
element2.Hide();
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kCustomEvent,
kCustomEventType1)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementHidden_NamedBeforeSequenceAndHiddenBeforeSequence) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kHidden)
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
element2.Hide();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementHidden_NamedBeforeSequenceAndHiddenDuringSequence) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kHidden)
.Build())
.Build();
sequence->NameElement(&element2, kElementName1);
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Hide());
}
TEST(InteractionSequenceTest,
NameElement_ElementHidden_NamedDuringCallbackAndHiddenDuringSequence) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kHidden)
.Build())
.Build();
sequence->Start();
EXPECT_CALL_IN_SCOPE(completed, Run, element2.Hide());
}
TEST(InteractionSequenceTest,
NameElement_ElementHidden_NamedAndHiddenDuringCallback) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto step = base::BindLambdaForTesting(
[&](InteractionSequence* sequence, TrackedElement* element) {
sequence->NameElement(&element2, kElementName1);
element2.Hide();
});
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1,
std::move(step)))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kHidden)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest, NameElement_ElementHidden_NoElementExplicitly) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kHidden)
.Build())
.Build();
sequence->NameElement(nullptr, kElementName1);
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementShown_NoElementExplicitly_Aborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
sequence->NameElement(nullptr, kElementName1);
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_ElementActivated_NoElementExplicitly_Aborts) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
auto sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence->NameElement(nullptr, kElementName1);
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->Start());
}
TEST(InteractionSequenceTest,
NameElement_TwoSequencesWithSameElementWithDifferentNames) {
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted1);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed1);
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted2);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed2);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
element2.Show();
auto sequence1 =
InteractionSequence::Builder()
.SetAbortedCallback(aborted1.Get())
.SetCompletedCallback(completed1.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName1)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
auto sequence2 =
InteractionSequence::Builder()
.SetAbortedCallback(aborted2.Get())
.SetCompletedCallback(completed2.Get())
.AddStep(InteractionSequence::WithInitialElement(&element1))
.AddStep(InteractionSequence::StepBuilder()
.SetElementName(kElementName2)
.SetType(InteractionSequence::StepType::kActivated)
.Build())
.Build();
sequence1->NameElement(&element2, kElementName1);
sequence2->NameElement(&element2, kElementName2);
sequence1->Start();
sequence2->Start();
EXPECT_CALL(completed1, Run).Times(1);
EXPECT_CALL(completed2, Run).Times(1);
element2.Activate();
}
// RunSynchronouslyForTesting() tests:
TEST(InteractionSequenceTest,
RunSynchronouslyForTesting_SequenceAbortsDuringStart) {
base::test::TaskEnvironment task_environment;
auto task_runner = base::ThreadPool::CreateSequencedTaskRunner({});
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
std::unique_ptr<InteractionSequence> sequence;
sequence = InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(kTestContext1)
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->RunSynchronouslyForTesting());
}
TEST(InteractionSequenceTest,
RunSynchronouslyForTesting_SequenceCompletesDuringStart) {
base::test::TaskEnvironment task_environment;
auto task_runner = base::ThreadPool::CreateSequencedTaskRunner({});
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
sequence = InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(kTestContext1)
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustBeVisibleAtStart(true)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->RunSynchronouslyForTesting());
}
TEST(InteractionSequenceTest,
RunSynchronouslyForTesting_SequenceAbortsDuringStep) {
base::test::SingleThreadTaskEnvironment task_environment;
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(kTestContext1)
.AddStep(
InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetMustRemainVisible(true)
.SetStartCallback(base::BindLambdaForTesting(
[&](InteractionSequence*, TrackedElement*) {
task_environment.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindLambdaForTesting(
[&]() { element1.Hide(); }));
}))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(aborted, Run, sequence->RunSynchronouslyForTesting());
}
TEST(InteractionSequenceTest,
RunSynchronouslyForTesting_SequenceCompletesDuringStep) {
base::test::SingleThreadTaskEnvironment task_environment;
UNCALLED_MOCK_CALLBACK(InteractionSequence::AbortedCallback, aborted);
UNCALLED_MOCK_CALLBACK(InteractionSequence::CompletedCallback, completed);
test::TestElement element1(kTestIdentifier1, kTestContext1);
test::TestElement element2(kTestIdentifier2, kTestContext1);
element1.Show();
std::unique_ptr<InteractionSequence> sequence;
sequence =
InteractionSequence::Builder()
.SetAbortedCallback(aborted.Get())
.SetCompletedCallback(completed.Get())
.SetContext(kTestContext1)
.AddStep(
InteractionSequence::StepBuilder()
.SetElementID(element1.identifier())
.SetType(InteractionSequence::StepType::kShown)
.SetStartCallback(base::BindLambdaForTesting(
[&](InteractionSequence*, TrackedElement*) {
task_environment.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindLambdaForTesting(
[&]() { element2.Show(); }));
}))
.Build())
.AddStep(InteractionSequence::StepBuilder()
.SetElementID(element2.identifier())
.SetType(InteractionSequence::StepType::kShown)
.Build())
.Build();
EXPECT_CALL_IN_SCOPE(completed, Run, sequence->RunSynchronouslyForTesting());
}
} // namespace ui