Skip to content

Commit

Permalink
Split InteractionHelper into classes without changing the behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
artyom-razinov committed Mar 5, 2019
1 parent 2ae76bf commit a088341
Show file tree
Hide file tree
Showing 26 changed files with 920 additions and 634 deletions.
3 changes: 3 additions & 0 deletions Frameworks/TestsFoundation/Utilities/Date/DateProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public protocol DateProvider {
func currentDate() -> Date
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public final class SystemClockDateProvider: DateProvider {
public init() {
}

public func currentDate() -> Date {
return Date()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import MixboxFoundation
public final class ResolvedInteractionSettings {
public let interactionSettings: InteractionSettings
public let elementSettings: ElementSettings
public let pollingConfiguration: PollingConfiguration
public let pollingConfiguration: PollingConfiguration // TODO: Remove from here!

public var elementName: String {
return elementSettings.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public final class AlmightyElementChecksImpl: AlmightyElementChecks {
return .success
case let .mismatch(_, mismatchDescription):
return .failureWithMessage(
"проверка не прошла: \(mismatchDescription())"
"Проверка неуспешна: \(mismatchDescription())"
)
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,53 @@ public final class InteractionFactoryImpl: InteractionFactory {
minimalPercentageOfVisibleArea: CGFloat)
-> Interaction
{
let interactionFailureResultFactory = actionInteractionFailureResultFactory(
interactionName: settings.interactionName
)

return ActionInteraction(
settings: settings,
specificImplementation: specificImplementation,
interactionRetrier: interactionRetrier(
settings: settings
),
performerOfSpecificImplementationOfInteractionForVisibleElement: performerOfSpecificImplementationOfInteractionForVisibleElement(
elementSettings: settings.elementSettings,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
interactionFailureResultFactory: interactionFailureResultFactory
),
interactionFailureResultFactory: interactionFailureResultFactory,
elementResolverWithScrollingAndRetries: elementResolverWithScrollingAndRetries(
settings: settings
)
)
}

public func checkInteraction(
specificImplementation: InteractionSpecificImplementation,
settings: ResolvedInteractionSettings,
minimalPercentageOfVisibleArea: CGFloat)
-> Interaction
{
let interactionFailureResultFactory = checkInteractionFailureResultFactory(
interactionName: settings.interactionName
)

return VisibleElementCheckInteraction(
settings: settings,
elementFinder: elementFinder,
elementVisibilityChecker: elementVisibilityChecker,
scrollingHintsProvider: scrollingHintsProvider,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
applicationProvider: applicationProvider,
applicationCoordinatesProvider: applicationCoordinatesProvider
specificImplementation: specificImplementation,
interactionRetrier: interactionRetrier(
settings: settings
),
performerOfSpecificImplementationOfInteractionForVisibleElement: performerOfSpecificImplementationOfInteractionForVisibleElement(
elementSettings: settings.elementSettings,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
interactionFailureResultFactory: interactionFailureResultFactory
),
interactionFailureResultFactory: interactionFailureResultFactory,
elementResolverWithScrollingAndRetries: elementResolverWithScrollingAndRetries(
settings: settings
)
)
}

Expand All @@ -48,30 +86,144 @@ public final class InteractionFactoryImpl: InteractionFactory {
{
return InvisibilityCheckInteraction(
settings: settings,
elementFinder: elementFinder,
interactionRetrier: interactionRetrier(
settings: settings
),
interactionFailureResultFactory: checkInteractionFailureResultFactory(
interactionName: settings.interactionName
),
elementResolverWithScrollingAndRetries: elementResolverWithScrollingAndRetries(
settings: settings
),
scroller: scroller(
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
elementSettings: settings.elementSettings
),
elementVisibilityChecker: elementVisibilityChecker,
scrollingHintsProvider: scrollingHintsProvider,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea
)
}

// MARK: - Private

private func performerOfSpecificImplementationOfInteractionForVisibleElement(
elementSettings: ElementSettings,
minimalPercentageOfVisibleArea: CGFloat,
interactionFailureResultFactory: InteractionFailureResultFactory)
-> PerformerOfSpecificImplementationOfInteractionForVisibleElement
{
return PerformerOfSpecificImplementationOfInteractionForVisibleElementImpl(
elementVisibilityChecker: elementVisibilityChecker,
elementSettings: elementSettings,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
interactionFailureResultFactory: interactionFailureResultFactory,
scroller: scroller(
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
elementSettings: elementSettings
)
)
}

private func elementResolverWithScrollingAndRetries(
settings: ResolvedInteractionSettings)
-> ElementResolverWithScrollingAndRetries
{
return ElementResolverWithScrollingAndRetriesImpl(
elementResolver: elementResolver(
elementSettings: settings.elementSettings
),
elementSettings: settings.elementSettings,
applicationProvider: applicationProvider,
applicationCoordinatesProvider: applicationCoordinatesProvider
applicationCoordinatesProvider: applicationCoordinatesProvider,
retrier: retrier(settings: settings)
)
}

public func checkInteraction(
specificImplementation: InteractionSpecificImplementation,
settings: ResolvedInteractionSettings,
minimalPercentageOfVisibleArea: CGFloat)
-> Interaction
private func interactionRetrier(
settings: ResolvedInteractionSettings)
-> InteractionRetrier
{
return VisibleElementCheckInteraction(
specificImplementation: specificImplementation,
settings: settings,
let defaultTimeout: TimeInterval = 15

return InteractionRetrierImpl(
dateProvider: dateProvider(),
timeout: settings.elementSettings.searchTimeout ?? defaultTimeout,
retrier: retrier(
settings: settings
)
)
}

private func retrier(
settings: ResolvedInteractionSettings)
-> Retrier
{
return RetrierImpl(
pollingConfiguration: settings.pollingConfiguration
)
}

private func actionInteractionFailureResultFactory(
interactionName: String)
-> InteractionFailureResultFactory
{
return interactionFailureResultFactory(
messagePrefix: "Действие неуспешно",
interactionName: interactionName
)
}

private func checkInteractionFailureResultFactory(
interactionName: String)
-> InteractionFailureResultFactory
{
return interactionFailureResultFactory(
messagePrefix: "Проверка неуспешна",
interactionName: interactionName
)
}

private func interactionFailureResultFactory(
messagePrefix: String,
interactionName: String)
-> InteractionFailureResultFactory
{
return InteractionFailureResultFactoryImpl(
applicationProvider: applicationProvider,
messagePrefix: messagePrefix,
interactionName: interactionName
)
}

private func elementResolver(
elementSettings: ElementSettings)
-> ElementResolver
{
return ElementResolverImpl(
elementFinder: elementFinder,
elementVisibilityChecker: elementVisibilityChecker,
elementSettings: elementSettings
)
}

private func scroller(
minimalPercentageOfVisibleArea: CGFloat,
elementSettings: ElementSettings)
-> Scroller
{
return ScrollerImpl(
scrollingHintsProvider: scrollingHintsProvider,
elementVisibilityChecker: elementVisibilityChecker,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
elementResolver: elementResolver(
elementSettings: elementSettings
),
applicationProvider: applicationProvider,
applicationCoordinatesProvider: applicationCoordinatesProvider
applicationCoordinatesProvider: applicationCoordinatesProvider,
elementSettings: elementSettings
)
}

private func dateProvider() -> DateProvider {
return SystemClockDateProvider()
}
}
Original file line number Diff line number Diff line change
@@ -1,79 +1,57 @@
import MixboxUiTestsFoundation
import MixboxTestsFoundation

// It is very similar to VisibleElementCheckInteraction. It seems like a copypaste,
// but it is only fields and constructor. But there's still a possibility to reduce amount of code.
// The code is shared in InteractionHelper. However InteractionHelper is bloated and needs to be split.
final class ActionInteraction: Interaction {
let description: InteractionDescription
let elementMatcher: ElementMatcher

private let settings: ResolvedInteractionSettings
private let elementVisibilityChecker: ElementVisibilityChecker
private let scrollingHintsProvider: ScrollingHintsProvider
private let elementFinder: ElementFinder
private let specificImplementation: InteractionSpecificImplementation
private let minimalPercentageOfVisibleArea: CGFloat
private let applicationProvider: ApplicationProvider
private let applicationCoordinatesProvider: ApplicationCoordinatesProvider
private let interactionRetrier: InteractionRetrier
private let performerOfSpecificImplementationOfInteractionForVisibleElement: PerformerOfSpecificImplementationOfInteractionForVisibleElement
private let interactionFailureResultFactory: InteractionFailureResultFactory
private let elementResolverWithScrollingAndRetries: ElementResolverWithScrollingAndRetries

// MARK: - State

private var wasSuccessful = false

init(
specificImplementation: InteractionSpecificImplementation,
settings: ResolvedInteractionSettings,
elementFinder: ElementFinder,
elementVisibilityChecker: ElementVisibilityChecker,
scrollingHintsProvider: ScrollingHintsProvider,
minimalPercentageOfVisibleArea: CGFloat,
applicationProvider: ApplicationProvider,
applicationCoordinatesProvider: ApplicationCoordinatesProvider)
specificImplementation: InteractionSpecificImplementation,
interactionRetrier: InteractionRetrier,
performerOfSpecificImplementationOfInteractionForVisibleElement: PerformerOfSpecificImplementationOfInteractionForVisibleElement,
interactionFailureResultFactory: InteractionFailureResultFactory,
elementResolverWithScrollingAndRetries: ElementResolverWithScrollingAndRetries)
{
self.settings = settings
self.description = InteractionDescription(
type: .action,
settings: settings
)
self.elementMatcher = settings.elementSettings.matcher
self.specificImplementation = specificImplementation
self.elementFinder = elementFinder
self.elementVisibilityChecker = elementVisibilityChecker
self.scrollingHintsProvider = scrollingHintsProvider
self.minimalPercentageOfVisibleArea = minimalPercentageOfVisibleArea
self.applicationProvider = applicationProvider
self.applicationCoordinatesProvider = applicationCoordinatesProvider
self.interactionRetrier = interactionRetrier
self.performerOfSpecificImplementationOfInteractionForVisibleElement = performerOfSpecificImplementationOfInteractionForVisibleElement
self.interactionFailureResultFactory = interactionFailureResultFactory
self.elementResolverWithScrollingAndRetries = elementResolverWithScrollingAndRetries
}

func perform() -> InteractionResult {
if wasSuccessful {
return .failure(
InteractionFailureMaker.interactionFailure(
applicationProvider: applicationProvider,
message: "Attempted to run successful action twice"
)
return interactionFailureResultFactory.failureResult(
resolvedElementQuery: nil,
interactionSpecificFailure: nil,
message: "Attempted to run successful action twice"
)
}

let helper = InteractionHelperImpl(
messagePrefix: "Действие неуспешно",
elementVisibilityChecker: elementVisibilityChecker,
scrollingHintsProvider: scrollingHintsProvider,
elementFinder: elementFinder,
interactionSettings: description.settings,
minimalPercentageOfVisibleArea: minimalPercentageOfVisibleArea,
applicationProvider: applicationProvider,
applicationCoordinatesProvider: applicationCoordinatesProvider
)

return helper.retryInteractionUntilTimeout {
let resolvedElementQuery = helper.resolveElementWithRetries()
return interactionRetrier.retryInteractionUntilTimeout { retriableTimedInteractionState in
let resolvedElementQuery = elementResolverWithScrollingAndRetries.resolveElementWithRetries(
isPossibleToRetryProvider: retriableTimedInteractionState
)

return helper.performInteractionForVisibleElement(
return performerOfSpecificImplementationOfInteractionForVisibleElement.performInteractionForVisibleElement(
resolvedElementQuery: resolvedElementQuery,
interactionSpecificImplementation: specificImplementation,
performingSpecificImplementationCanBeRepeated: true,
performingSpecificImplementationCanBeRepeated: false,
interactionMarkableAsImpossibleToRetry: retriableTimedInteractionState,
closureFailureMessage: "пофейлилось само действие"
)
}
Expand Down

0 comments on commit a088341

Please sign in to comment.