Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class JetpackScreenshotGeneration: XCTestCase {
func testGenerateScreenshots() throws {

// Get My Site screenshot
let mySite = MySiteScreen()
let mySite = try MySiteScreen()
.showSiteSwitcher()
.switchToSite(withTitle: "yourjetpack.blog")
.thenTakeScreenshot(1, named: "MySite")
Expand Down Expand Up @@ -77,7 +77,7 @@ class JetpackScreenshotGeneration: XCTestCase {
}

// Get Stats screenshot
let statsScreen = mySite.gotoStatsScreen()
let statsScreen = try mySite.goToStatsScreen()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There'll be a bunch more of this changes because of the goto to goTo rename. Sorry for the noise.

statsScreen
.dismissCustomizeInsightsNotice()
.switchTo(mode: .months)
Expand Down
23 changes: 23 additions & 0 deletions WordPress/UITestsFoundation/Globals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,27 @@ extension ScreenObject {
public func pop() {
navBackButton.tap()
}

public func openMagicLink() {
XCTContext.runActivity(named: "Open magic link in Safari") { activity in
let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
safari.launch()

// Select the URL bar when Safari opens
let urlBar = safari.textFields["URL"]
if !urlBar.waitForExistence(timeout: 5) {
safari.buttons["URL"].tap()
}

// Follow the magic link
var magicLinkComponents = URLComponents(url: WireMock.URL(), resolvingAgainstBaseURL: false)!
magicLinkComponents.path = "/magic-link"
magicLinkComponents.queryItems = [URLQueryItem(name: "scheme", value: "wpdebug")]

urlBar.typeText("\(magicLinkComponents.url!.absoluteString)\n")

// Accept the prompt to open the deep link
safari.scrollViews.element(boundBy: 0).buttons.element(boundBy: 1).tap()
}
}
Comment on lines +17 to +38
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated from the BaseScreen version. Once we'll have no more BaseScreen in the UI tests, it will become the only one in the codebase. It's also something we might want to move to the authentication framework.

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public class LoginEpilogueScreen: BaseScreen {
super.init(element: continueButton)
}

public func continueWithSelectedSite() -> MySiteScreen {
public func continueWithSelectedSite() throws -> MySiteScreen {
continueButton.tap()
return MySiteScreen()
return try MySiteScreen()
}

// Used by "Self-Hosted after WordPress.com login" test. When a site is added from the Sites List, the Sites List modal (MySitesScreen)
Expand Down
26 changes: 14 additions & 12 deletions WordPress/UITestsFoundation/Screens/Login/WelcomeScreen.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import ScreenObject
import XCTest

// TODO: remove when unifiedAuth is permanent.

private struct ElementStringIDs {
static let loginButton = "Prologue Log In Button"
static let signupButton = "Prologue Signup Button"
}
public class WelcomeScreen: ScreenObject {

private let logInButtonGetter: (XCUIApplication) -> XCUIElement = {
$0.buttons["Prologue Log In Button"]
}

public class WelcomeScreen: BaseScreen {
let logInButton: XCUIElement
let signupButton: XCUIElement
private let signupButtonGetter: (XCUIApplication) -> XCUIElement = {
$0.buttons["Prologue Signup Button"]
}

public init() {
logInButton = XCUIApplication().buttons[ElementStringIDs.loginButton]
signupButton = XCUIApplication().buttons[ElementStringIDs.signupButton]
var signupButton: XCUIElement { signupButtonGetter(app) }
var logInButton: XCUIElement { logInButtonGetter(app) }

super.init(element: logInButton)
public init(app: XCUIApplication = XCUIApplication()) throws {
try super.init(expectedElementGetters: [logInButtonGetter, signupButtonGetter], app: app)
}

public func selectSignup() throws -> WelcomeScreenSignupComponent {
Expand All @@ -31,6 +33,6 @@ public class WelcomeScreen: BaseScreen {
}

static func isLoaded() -> Bool {
return XCUIApplication().buttons[ElementStringIDs.loginButton].exists
(try? WelcomeScreen().isLoaded) ?? false
}
Comment on lines 35 to 37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is the same in previous PRs, but for some reason it caught my eye only now.

To be honest, I spent some time not understanding the reason for having an isLoaded() method for some of the screens, when there's an isLoaded variable in the ScreenObject. After a bit of processing, I realized that this is a shorter way to calculate that property in the runtime, without the need to handle potential error every time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.

To be fair, the static approach made sense only in the BaseScreen context, where a calling init on a screen not displayed would fail the test. With ScreenObject, it's less useful. I'd like to remove as many of these as possible.

For example, the following doesn't make much sense anymore:

private func confirmPublish() throws {
if FancyAlertComponent.isLoaded() {
try FancyAlertComponent().acceptAlert()
} else {
publishNowButton.tap()
}
}

We could replace it with something like:

guard let alert = FancyAlertComponent() else {
    publishNowButton.tap() 
    return
}

alert.acceptAlert()

On the other hand, this does. Since we don't access any of those screen directly, it's handy to call a method on the type:

while EditorPostSettings.isLoaded() || CategoriesComponent.isLoaded() || TagsComponent.isLoaded() || MediaPickerAlbumListScreen.isLoaded() || MediaPickerAlbumScreen.isLoaded() {
navBackButton.tap()
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining it, Gio!

}
8 changes: 4 additions & 4 deletions WordPress/UITestsFoundation/Screens/MeTabScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class MeTabScreen: ScreenObject {
return logOutButton.exists
}

public func logout() -> WelcomeScreen {
public func logout() throws -> WelcomeScreen {
app.cells["logOutFromWPcomButton"].tap()

// Some localizations have very long "log out" text, which causes the UIAlertView
Expand All @@ -40,7 +40,7 @@ public class MeTabScreen: ScreenObject {
logOutAlert.buttons.element(boundBy: 1).tap()
}

return WelcomeScreen()
return try WelcomeScreen()
}

public func logoutToPrologue() throws -> PrologueScreen {
Expand All @@ -64,9 +64,9 @@ public class MeTabScreen: ScreenObject {
return try PrologueScreen()
}

public func dismiss() -> MySiteScreen {
public func dismiss() throws -> MySiteScreen {
app.buttons["Done"].tap()

return MySiteScreen()
return try MySiteScreen()
}
}
12 changes: 6 additions & 6 deletions WordPress/UITestsFoundation/Screens/MySiteScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public class MySiteScreen: BaseScreen {
return blogTable.exists && blogTable.isHittable
}

public init() {
public init() throws {
let app = XCUIApplication()
tabBar = TabNavComponent()
tabBar = try TabNavComponent()
removeSiteButton = app.cells[ElementStringIDs.removeSiteButton]
removeSiteSheet = app.sheets.buttons.element(boundBy: 0)
removeSiteAlert = app.alerts.buttons.element(boundBy: 1)
Expand Down Expand Up @@ -105,14 +105,14 @@ public class MySiteScreen: BaseScreen {
return MediaScreen()
}

public func gotoStatsScreen() -> StatsScreen {
public func goToStatsScreen() throws -> StatsScreen {
statsButton.tap()
return StatsScreen()
return try StatsScreen()
}

public func gotoSettingsScreen() -> SiteSettingsScreen {
public func goToSettingsScreen() throws -> SiteSettingsScreen {
siteSettingsButton.tap()
return SiteSettingsScreen()
return try SiteSettingsScreen()
}

func gotoCreateSheet() throws -> ActionSheetComponent {
Expand Down
8 changes: 4 additions & 4 deletions WordPress/UITestsFoundation/Screens/MySitesScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ public class MySitesScreen: BaseScreen {
return LoginSiteAddressScreen()
}

public func closeModal() -> MySiteScreen {
public func closeModal() throws -> MySiteScreen {
cancelButton.tap()
return MySiteScreen()
return try MySiteScreen()
}

@discardableResult
public func switchToSite(withTitle title: String) -> MySiteScreen {
public func switchToSite(withTitle title: String) throws -> MySiteScreen {
XCUIApplication().cells[title].tap()
return MySiteScreen()
return try MySiteScreen()
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import ScreenObject
import XCTest

private struct ElementStringIDs {
static let mailButton = "Open Mail Button"
}

public class SignupCheckMagicLinkScreen: BaseScreen {
let mailButton: XCUIElement

init() {
let app = XCUIApplication()
mailButton = app.buttons[ElementStringIDs.mailButton]
public class SignupCheckMagicLinkScreen: ScreenObject {

super.init(element: mailButton)
init(app: XCUIApplication = XCUIApplication()) throws {
try super.init(
// swiftlint:disable:next opening_brace
expectedElementGetters: [{ $0.buttons["Open Mail Button"] }],
app: app
)
}

public func openMagicSignupLink() -> SignupEpilogueScreen {
Expand Down
29 changes: 15 additions & 14 deletions WordPress/UITestsFoundation/Screens/Signup/SignupEmailScreen.swift
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import ScreenObject
import XCTest

// TODO: remove when unifiedAuth is permanent.

private struct ElementStringIDs {
static let emailTextField = "Signup Email Address"
static let nextButton = "Signup Email Next Button"
}
public class SignupEmailScreen: ScreenObject {

private let emailTextFieldGetter: (XCUIApplication) -> XCUIElement = {
$0.textFields["Signup Email Address"]
}

public class SignupEmailScreen: BaseScreen {
let emailTextField: XCUIElement
let nextButton: XCUIElement
private let nextButtonGetter: (XCUIApplication) -> XCUIElement = {
$0.buttons["Signup Email Next Button"]
}

init() {
let app = XCUIApplication()
emailTextField = app.textFields[ElementStringIDs.emailTextField]
nextButton = app.buttons[ElementStringIDs.nextButton]
var emailTextField: XCUIElement { emailTextFieldGetter(app) }
var nextButton: XCUIElement { nextButtonGetter(app) }

super.init(element: emailTextField)
init(app: XCUIApplication = XCUIApplication()) throws {
try super.init(expectedElementGetters: [emailTextFieldGetter, nextButtonGetter], app: app)
}

public func proceedWith(email: String) -> SignupCheckMagicLinkScreen {
public func proceedWith(email: String) throws -> SignupCheckMagicLinkScreen {
emailTextField.tap()
emailTextField.typeText(email)
nextButton.tap()

return SignupCheckMagicLinkScreen()
return try SignupCheckMagicLinkScreen()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public class SignupEpilogueScreen: BaseScreen {
return self
}

public func continueWithSignup() -> MySiteScreen {
public func continueWithSignup() throws -> MySiteScreen {
continueButton.tap()

return MySiteScreen()
return try MySiteScreen()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public class WelcomeScreenSignupComponent: ScreenObject {
try super.init(expectedElementGetters: [emailSignupButtonGetter], app: app)
}

public func selectEmailSignup() -> SignupEmailScreen {
public func selectEmailSignup() throws -> SignupEmailScreen {
emailSignupButton.tap()

return SignupEmailScreen()
return try SignupEmailScreen()
}
}
24 changes: 11 additions & 13 deletions WordPress/UITestsFoundation/Screens/SiteSettingsScreen.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import ScreenObject
import XCTest

public class SiteSettingsScreen: BaseScreen {
public class SiteSettingsScreen: ScreenObject {

public enum Toggle {
case on
case off
}

let settingsTable: XCUIElement
let blockEditorToggle: XCUIElement
let tabBar: TabNavComponent

public init() {
settingsTable = XCUIApplication().tables["siteSettingsTable"]
blockEditorToggle = settingsTable.switches["useBlockEditorSwitch"]
tabBar = TabNavComponent()
private let blockEditorToggleGetter: (XCUIApplication) -> XCUIElement = {
$0.tables["siteSettingsTable"].switches["useBlockEditorSwitch"]
}
var blockEditorToggle: XCUIElement { blockEditorToggleGetter(app) }

super.init(element: settingsTable)
public init(app: XCUIApplication = XCUIApplication()) throws {
try super.init(expectedElementGetters: [blockEditorToggleGetter], app: app)
}

@discardableResult
Expand All @@ -34,18 +32,18 @@ public class SiteSettingsScreen: BaseScreen {
return self
}

public func goBackToMySite() -> MySiteScreen {
public func goBackToMySite() throws -> MySiteScreen {
if XCUIDevice.isPhone {
navBackButton.tap()
}
return MySiteScreen()
return try MySiteScreen()
}

private func isBlockEditorEnabled() -> Bool {
return blockEditorToggle.value as! String == "1"
}

public static func isLoaded() -> Bool {
return XCUIApplication().navigationBars["Settings"].exists
(try? SiteSettingsScreen().isLoaded) ?? false
}
}
27 changes: 12 additions & 15 deletions WordPress/UITestsFoundation/Screens/StatsScreen.swift
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import ScreenObject
import XCTest

private struct ElementStringIDs {
static let draftsButton = "drafts"
}

public class StatsScreen: BaseScreen {
public class StatsScreen: ScreenObject {

public enum Mode: String {
case months = "months"
case years = "years"
}

struct ElementStringIDs {
static let dismissCustomizeInsightsButton = "dismiss-customize-insights-cell"
case months
case years
}

public init() {
super.init(element: XCUIApplication().otherElements.firstMatch)
public init(app: XCUIApplication = XCUIApplication()) throws {
try super.init(
// swiftlint:disable:next opening_brace
expectedElementGetters: [{ $0.otherElements.firstMatch }],
app: app
)
}

@discardableResult
public func dismissCustomizeInsightsNotice() -> StatsScreen {
let button = XCUIApplication().buttons[ElementStringIDs.dismissCustomizeInsightsButton]
let button = app.buttons["dismiss-customize-insights-cell"]

if button.exists {
button.tap()
Expand All @@ -32,7 +29,7 @@ public class StatsScreen: BaseScreen {

@discardableResult
public func switchTo(mode: Mode) -> StatsScreen {
XCUIApplication().buttons[mode.rawValue].tap()
app.buttons[mode.rawValue].tap()
return self
}
}
Loading