有没有办法在Swift XCTest UI中的测试之间重置应用程序?

时间:2015-10-13 16:18:19

标签: swift xcode7 xctest xcode-ui-testing

我是否可以在XCTest中调用API调用setUP()或tearDown()以在测试之间重置应用程序?我查看了XCUIApplication的点语法,我看到的只是.launch()

OR有没有办法在Swift中调用shell脚本?然后,我可以调用xcrun中间的测试方法来重置模拟器。

18 个答案:

答案 0 :(得分:66)

您可以添加“运行脚本”阶段来构建测试目标中的阶段,以便在针对它运行单元测试之前卸载应用程序,不幸的是,这不是测试用例之间,但

/usr/bin/xcrun simctl uninstall booted com.mycompany.bundleId

<强>更新

在测试之间,您可以在tearDown阶段通过Springboard删除应用。虽然,这确实需要使用XCTest的私有头。 (标头转储可从Facebook's WebDriverAgent here获得。)

以下是Springboard类中的一些示例代码,用于通过点击并按住从Springboard中删除应用程序:

Swift 4:

import XCTest

class Springboard {

    static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

    /**
     Terminate and delete the app via springboard
     */
    class func deleteMyApp() {
        XCUIApplication().terminate()

         // Force delete the app from the springboard
        let icon = springboard.icons["Citizen"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.press(forDuration: 1.3)

            // Tap the little "X" button at approximately where it is. The X is not exposed directly
            springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3) / springboardFrame.maxX, dy: (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

            springboard.alerts.buttons["Delete"].tap()
        }
    }
 }

Swift 3 - :

import XCTest

class Springboard {

    static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")

    /**
     Terminate and delete the app via springboard
     */
    class func deleteMyApp() {
        XCUIApplication().terminate()

        // Resolve the query for the springboard rather than launching it
        springboard.resolve()

        // Force delete the app from the springboard
        let icon = springboard.icons["MyAppName"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.pressForDuration(1.3)

            // Tap the little "X" button at approximately where it is. The X is not exposed directly
            springboard.coordinateWithNormalizedOffset(CGVectorMake((iconFrame.minX + 3) / springboardFrame.maxX, (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

            springboard.alerts.buttons["Delete"].tap()
        }
    }
 }

然后:

override func tearDown() {
    Springboard.deleteMyApp()
    super.tearDown()
}

私有标头是在Swift桥接头中导入的。您需要导入:

// Private headers from XCTest
#import "XCUIApplication.h"
#import "XCUIElement.h"

注意:从Xcode 10开始,Apple现在公开了XCUIApplication(bundleIdentifier:),并且不再需要私有标头

答案 1 :(得分:35)

此时,Xcode 7&amp; amp;中的公共API 8,模拟器没有出现任何可从setUp()tearDown() XCText子类调用到模拟器的“重置内容和设置”的方法。

还有其他使用公共API的方法:

  1. 应用程序代码。添加一些myResetApplication()应用程序代码以使应用程序处于已知状态。但是,设备(模拟器)状态控制受应用程序沙箱的限制......这在应用程序之外没什么帮助。这种方法可以清除应用程序可控制的持久性。

  2. Shell脚本。从shell脚本运行测试。在每次测试运行之间使用xcrun simctl erase allxcrun simctl uninstall <device> <app identifier>或类似设置重置模拟器(或卸载应用程序)see StackOverflow: "How can I reset the iOS Simulator from the command line?"

  3.     macos> xcrun simctl --help
        # can uninstall a single application
        macos> xcrun simctl uninstall --help  
        # Usage: simctl uninstall <device> <app identifier>
    
    1. Xcode架构操作。将xcrun simctl erase all(或xcrun simctl erase <DEVICE_UUID>)或类似内容添加到“方案测试”部分。选择产品&gt;方案&gt;编辑方案...菜单。展开Scheme Test部分。在“测试”部分下选择“预执行”。单击(+)添加“新建运行脚本操作”。可以直接输入命令xcrun simctl erase all,而无需任何外部脚本。
    2. 调用 1的选项。应用程序代码重置应用程序:

      一个。 应用程序用户界面 [UI测试] 提供重置按钮或其他重置应用程序的UI操作。可以通过XCUIApplication例程XCTestsetUp()tearDown()中的testSomething()来行使UI元素。

      B中。 启动参数 [UI测试] 如Victor Ronin所述,可以从测试setUp()传递参数...

      class AppResetUITests: XCTestCase {
      
        override func setUp() {
          // ...
          let app = XCUIApplication()
          app.launchArguments = ["MY_UI_TEST_MODE"]
          app.launch()
      

      ......由AppDelegate ...

      收到
      class AppDelegate: UIResponder, UIApplicationDelegate {
      
        func application( …didFinishLaunchingWithOptions… ) -> Bool {
          // ...
          let args = NSProcessInfo.processInfo().arguments
          if args.contains("MY_UI_TEST_MODE") {
              myResetApplication()
          }
      

      ℃。 Xcode方案参数 [UI测试,单元测试] 选择产品&gt;方案&gt;编辑方案...菜单。展开“方案运行”部分。 (+)添加一些参数,如MY_UI_TEST_MODE。该参数将在NSProcessInfo.processInfo()

      中提供
      // ... in application
      let args = NSProcessInfo.processInfo().arguments
      if args.contains("MY_UI_TEST_MODE") {
          myResetApplication()
      }
      

      ž。 直接通话 [单元测试] 单元测试包被注入到正在运行的应用程序中,可以直接调用应用程序中的一些myResetApplication()例程。警告:在加载主屏幕后运行默认单元测试。 see Test Load Sequence但是,UI测试包作为被测应用程序外部的进程运行。因此,在单元测试中有效的方法会在UI测试中出现链接错误。

      class AppResetUnitTests: XCTestCase {
      
        override func setUp() {
          // ... Unit Test: runs.  UI Test: link error.
          myResetApplication() // visible code implemented in application
      

答案 2 :(得分:14)

更新了swift 3.1 / xcode 8.3

在测试目标中创建桥接头:

#import <XCTest/XCUIApplication.h>
#import <XCTest/XCUIElement.h>

@interface XCUIApplication (Private)
- (id)initPrivateWithPath:(NSString *)path bundleID:(NSString *)bundleID;
- (void)resolve;
@end

更新了Springboard类

class Springboard {
   static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")!
   static let settings = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.Preferences")!

/**
Terminate and delete the app via springboard
*/

class func deleteMyApp() {
   XCUIApplication().terminate()

// Resolve the query for the springboard rather than launching it

   springboard.resolve()

// Force delete the app from the springboard
   let icon = springboard.icons["{MyAppName}"] /// change to correct app name
   if icon.exists {
     let iconFrame = icon.frame
     let springboardFrame = springboard.frame
     icon.press(forDuration: 1.3)

  // Tap the little "X" button at approximately where it is. The X is not exposed directly

    springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3) / springboardFrame.maxX, dy: (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

     springboard.alerts.buttons["Delete"].tap()

     // Press home once make the icons stop wiggling

     XCUIDevice.shared().press(.home)
     // Press home again to go to the first page of the springboard
     XCUIDevice.shared().press(.home)
     // Wait some time for the animation end
     Thread.sleep(forTimeInterval: 0.5)

      let settingsIcon = springboard.icons["Settings"]
      if settingsIcon.exists {
       settingsIcon.tap()
       settings.tables.staticTexts["General"].tap()
       settings.tables.staticTexts["Reset"].tap()
       settings.tables.staticTexts["Reset Location & Privacy"].tap()
       settings.buttons["Reset Warnings"].tap()
       settings.terminate()
      }
     }
    }
   }

答案 3 :(得分:9)

您可以要求您的应用清理&#34;本身

  • 您使用XCUIApplication.launchArguments设置了一些标志
  • 在AppDelegate中,您可以检查

    如果NSProcessInfo.processInfo()。arguments.contains(&#34; YOUR_FLAG_NAME_HERE&#34;){   //在这里清理一下 }

答案 4 :(得分:9)

我使用了@ ODM answer,但修改了它以适用于Swift 4.注意:一些S / O答案不能区分Swift版本,这些版本有时会有相当的根本差异。我已经在iPhone 7模拟器和iPad Air模拟器上进行了纵向测试,它适用于我的应用程序。

Swift 4

import XCTest
import Foundation

class Springboard {

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let settings = XCUIApplication(bundleIdentifier: "com.apple.Preferences")


/**
 Terminate and delete the app via springboard
 */
func deleteMyApp() {
    XCUIApplication().terminate()

    // Resolve the query for the springboard rather than launching it
    springboard.activate()

    // Rotate back to Portrait, just to ensure repeatability here
    XCUIDevice.shared.orientation = UIDeviceOrientation.portrait
    // Sleep to let the device finish its rotation animation, if it needed rotating
    sleep(2)

    // Force delete the app from the springboard
    // Handle iOS 11 iPad 'duplication' of icons (one nested under "Home screen icons" and the other nested under "Multitasking Dock"
    let icon = springboard.otherElements["Home screen icons"].scrollViews.otherElements.icons["YourAppName"]
    if icon.exists {
        let iconFrame = icon.frame
        let springboardFrame = springboard.frame
        icon.press(forDuration: 2.5)

        // Tap the little "X" button at approximately where it is. The X is not exposed directly
        springboard.coordinate(withNormalizedOffset: CGVector(dx: ((iconFrame.minX + 3) / springboardFrame.maxX), dy:((iconFrame.minY + 3) / springboardFrame.maxY))).tap()
        // Wait some time for the animation end
        Thread.sleep(forTimeInterval: 0.5)

        //springboard.alerts.buttons["Delete"].firstMatch.tap()
        springboard.buttons["Delete"].firstMatch.tap()

        // Press home once make the icons stop wiggling
        XCUIDevice.shared.press(.home)
        // Press home again to go to the first page of the springboard
        XCUIDevice.shared.press(.home)
        // Wait some time for the animation end
        Thread.sleep(forTimeInterval: 0.5)

        // Handle iOS 11 iPad 'duplication' of icons (one nested under "Home screen icons" and the other nested under "Multitasking Dock"
        let settingsIcon = springboard.otherElements["Home screen icons"].scrollViews.otherElements.icons["Settings"]
        if settingsIcon.exists {
            settingsIcon.tap()
            settings.tables.staticTexts["General"].tap()
            settings.tables.staticTexts["Reset"].tap()
            settings.tables.staticTexts["Reset Location & Privacy"].tap()
            // Handle iOS 11 iPad difference in error button text
            if UIDevice.current.userInterfaceIdiom == .pad {
                settings.buttons["Reset"].tap()
            }
            else {
                settings.buttons["Reset Warnings"].tap()
            }
            settings.terminate()
        }
    }
  }
}

答案 5 :(得分:7)

我使用@Chase Holland answer并使用相同的方法更新了Springboard类,以使用“设置”应用重置内容和设置。当您需要重置权限对话框时,这非常有用。

import XCTest

class Springboard {
    static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")
    static let settings = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.Preferences")

    /**
     Terminate and delete the app via springboard
     */
    class func deleteMyApp() {
        XCUIApplication().terminate()

        // Resolve the query for the springboard rather than launching it
        springboard.resolve()

        // Force delete the app from the springboard
        let icon = springboard.icons["MyAppName"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.pressForDuration(1.3)

            // Tap the little "X" button at approximately where it is. The X is not exposed directly
            springboard.coordinateWithNormalizedOffset(CGVectorMake((iconFrame.minX + 3) / springboardFrame.maxX, (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

            springboard.alerts.buttons["Delete"].tap()

            // Press home once make the icons stop wiggling
            XCUIDevice.sharedDevice().pressButton(.Home)
            // Press home again to go to the first page of the springboard
            XCUIDevice.sharedDevice().pressButton(.Home)
            // Wait some time for the animation end
            NSThread.sleepForTimeInterval(0.5)

            let settingsIcon = springboard.icons["Settings"]
            if settingsIcon.exists {
                settingsIcon.tap()
                settings.tables.staticTexts["General"].tap()
                settings.tables.staticTexts["Reset"].tap()
                settings.tables.staticTexts["Reset Location & Privacy"].tap()
                settings.buttons["Reset Warnings"].tap()
                settings.terminate()
            }
        }
    }
}

答案 6 :(得分:6)

从Xcode 11.4开始,如果您只想重置权限,则可以在resetAuthorizationStatus(for:)的实例上使用XCUIApplication,请参见 https://developer.apple.com/documentation/xctest/xcuiapplication/3526066-resetauthorizationstatusforresou

如果需要,也可以使用Xcode 11.4 Release Notes引述的simctl

simctl现在支持修改隐私权限。您可以修改隐私权限以创建已知状态以进行测试。例如,要允许示例应用程序在没有任何提示的情况下访问照片库:
xcrun simctl privacy <device> grant photos com.example.app

要将所有权限重置为默认值,就像以前从未安装过该应用程序一样:
xcrun simctl privacy <device> reset all com.example.app

答案 7 :(得分:3)

对于iOS 11 sims up,我进行了一次轻微的修改,点击“x”图标,我们按照修复@Code Monkey建议点击。修复在10.3和11.2手机模拟中都能很好地工作。为了记录,我正在使用swift 3.我想通过一些代码来复制和粘贴,以便更容易找到修复。 :)

import XCTest

class Springboard {

    static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")

    class func deleteMyApp() {
        XCUIApplication().terminate()

        // Resolve the query for the springboard rather than launching it
        springboard!.resolve()

        // Force delete the app from the springboard
        let icon = springboard!.icons["My Test App"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard!.frame
            icon.press(forDuration: 1.3)

            springboard!.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3 * UIScreen.main.scale) / springboardFrame.maxX, dy: (iconFrame.minY + 3 * UIScreen.main.scale) / springboardFrame.maxY)).tap()

            springboard!.alerts.buttons["Delete"].tap()
        }
    }
}

答案 8 :(得分:3)

iOS 13.1 / Swift 5.1 基于用户界面的删除

static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")!

class func deleteApp() {
    XCUIApplication().terminate()
    XCUIDevice.shared.press(.home)
    XCUIDevice.shared.press(.home)

    let icon = springboard.icons["YourApplication"]
    if !icon.exists { return }

    springboard.swipeLeft()
    springboard.activate()
    Thread.sleep(forTimeInterval: 1.0)

    icon.press(forDuration: 1.3)
    springboard.buttons["Rearrange Apps"].eventuallyExists().tap()

    icon.buttons["DeleteButton"].eventuallyExists().tap()
    springboard.alerts.buttons["Delete"].eventuallyExists().tap()

    XCUIDevice.shared.press(.home)
    XCUIDevice.shared.press(.home)
}

答案 9 :(得分:3)

适用于 iOS14 的工作解决方案

final class Springboard {

    private static var springboardApp = XCUIApplication(bundleIdentifier: "com.apple.springboard")

    class func deleteApp(name: String) {
        XCUIApplication().terminate()

        springboardApp.activate()

        sleep(1)

        let appIcon = springboardApp.icons.matching(identifier: name).firstMatch
        appIcon.press(forDuration: 1.3)

        sleep(1)

        springboardApp.buttons["Remove App"].tap()

        let deleteButton = springboardApp.alerts.buttons["Delete App"].firstMatch
        if deleteButton.waitForExistence(timeout: 5) {
            deleteButton.tap()
            springboardApp.alerts.buttons["Delete"].tap()
        }
    }
}

答案 10 :(得分:3)

iOS 13.2解决方案

for url in url_list:
    try_again = 3
    while try_again != 0:
        response = requests.get(url)
        if response.status_code == 200:
            print('do scraping')
            try_again = 0

        if response.status_code != 200:
            try_again -= 1
            print ('Request failed. Attempts remaining: %s' %try_again)
            if try_again == 0:
                print ('Tried 3 times. Moving to next URL.')

答案 11 :(得分:1)

这似乎对我在iOS 12.1和模拟器上有效

class func deleteApp(appName: String) {
    XCUIApplication().terminate()

    // Force delete the app from the springboard
    let icon = springboard.icons[appName]
    if icon.exists {
        icon.press(forDuration: 2.0)

        icon.buttons["DeleteButton"].tap()
        sleep(2)
        springboard.alerts["Delete “\(appName)”?"].buttons["Delete"].tap()
        sleep(2)

        XCUIDevice.shared.press(.home)
    }
}

答案 12 :(得分:0)

答案有很多变化,我什至不确定我是否应该添加,但以防万一有人需要通用解决方案:

iOS 14.6 和 15 测试版

    class func deleteApp() {
    XCUIApplication().terminate()
    
    // Force delete the app from the springboard
    let icon = springboard.icons["APP_NAME"]
    if icon.exists {
        icon.press(forDuration: 1.3)
        
        springboard.buttons["Remove App"].tap()
        springboard.alerts.buttons["Delete App"].tap()
        springboard.alerts.buttons["Delete"].tap()
        
        // Press home once to make the icons stop wiggling
        XCUIDevice.shared.press(.home)
    }
}

答案 13 :(得分:0)

经过一些实验,我完成了一个更清晰的解决方案,涵盖了不同的 iOS 版本:

import XCTest

private enum Constants {
  static let springboardBundleIdentifier = "com.apple.springboard"
  static let appIconName = "Your App Name"
  static let appIconPressShortDuration: TimeInterval = 2.0
  static let appIconPressLongDuration: TimeInterval = 3.0
  static let deleteAppButton = "Delete App"
  static let removeAppButton = "Remove App"
  static let deleteButton = "Delete"
  static let deleteButtonVectorOffset: CGFloat = 3.0
}

final class SpringboardManager {

  private static let springboard = XCUIApplication(bundleIdentifier: Constants.springboardBundleIdentifier)

  static func deleteApp(_ app: XCUIApplication) {
    if app.exists && app.isHittable {
      XCUIDevice.shared.press(.home)
    }

    app.terminate()

    self.deleteAppIfNeeded(with: Constants.appIconName)
    sleep(1)
  }

  private static func deleteAppIfNeeded(with iconName: String) {
    let appIcon = self.springboard.icons[iconName]

    guard appIcon.exists else {
      return
    }

    appIcon.press(forDuration: Constants.appIconPressShortDuration)

    if let deleteListButton = self.deleteListButton() {
      deleteListButton.tap()
      self.pressDeleteAlertButtons()
    } else {
      appIcon.press(forDuration: Constants.appIconPressLongDuration)
      self.pressDeleteTopLeftButton(for: appIcon)
      self.pressDeleteAlertButtons()
    }
  }

}

private extension SpringboardManager {

  static func pressDeleteAlertButtons() {
    self.pressDeleteAlertButton(self.deleteAppAlertButton())
    self.pressDeleteAlertButton(self.deleteAlertButton())
  }

  static func pressDeleteAlertButton(_ button: XCUIElement?) {
    guard let button = button else {
      return
    }

    button.tap()
  }

  static func pressDeleteTopLeftButton(for appIcon: XCUIElement) {
    let iconFrame = appIcon.frame
    let springboardFrame = self.springboard.frame

    let deleteButtonVector = CGVector(
      dx: (iconFrame.minX + Constants.deleteButtonVectorOffset) / springboardFrame.maxX,
      dy: (iconFrame.minY + Constants.deleteButtonVectorOffset) / springboardFrame.maxY)

    let deleteButtonCoordinate = self.springboard.coordinate(withNormalizedOffset: deleteButtonVector)
    deleteButtonCoordinate.tap()
  }

}

private extension SpringboardManager {

  static func deleteListButton() -> XCUIElement? {
    sleep(1)
    
    let removeListButton = self.springboard.buttons[Constants.removeAppButton]
    let deleteListButton = self.springboard.buttons[Constants.deleteAppButton]

    if removeListButton.exists {
      return removeListButton
    } else if deleteListButton.exists {
      return deleteListButton
    }

    return nil
  }

  static func deleteAppAlertButton() -> XCUIElement? {
    sleep(1)

    let deleteAppButton = self.springboard.alerts.buttons[Constants.deleteAppButton]

    if deleteAppButton.exists {
      return deleteAppButton
    }

    return nil
  }

  static func deleteAlertButton() -> XCUIElement? {
    sleep(1)

    let deleteButton = self.springboard.alerts.buttons[Constants.deleteButton]

    if deleteButton.exists {
      return deleteButton
    }

    return nil
  }

}

答案 14 :(得分:0)

我在测试的setUptearDown中看到了很多卸载应用的答案。

但是,通过在测试目标中添加运行脚本阶段,可以在启动测试之前轻松卸载应用程序。

要这样做:

  1. 选择应用程序的Xcode项目
  2. 选择测试目标
  3. 选择“构建阶段”
  4. 点击“ +”和“新运行脚本阶段”

然后,用以下命令替换占位符# Type a script or drag a script file from your workspace to insert its path.

xcrun simctl boot ${TARGET_DEVICE_IDENTIFIER}
xcrun simctl uninstall ${TARGET_DEVICE_IDENTIFIER} YOUR_APP_BUNDLE

答案 15 :(得分:0)

这适用于所有操作系统版本(iOS11、12和13)

static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

    func deleteApp() {
        XCUIApplication().terminate()
        springboard.activate()

        let icon = springboard.icons[appName]

        if icon.exists {
            icon.firstMatch.press(forDuration: 5)
            icon.buttons["DeleteButton"].tap()

            let deleteConfirmation = springboard.alerts["Delete “\(appName)”?"].buttons["Delete"]
            XCTAssertTrue(deleteConfirmation.waitForExistence(timeout: 5), "Delete confirmation not shown")
            deleteConfirmation.tap()
        }
    }

答案 16 :(得分:0)

以下是上述答案的Objective C版本,用于删除应用并重置警告(已在iOS 11和12上测试):

- (void)uninstallAppNamed:(NSString *)appName {

    [[[XCUIApplication alloc] init] terminate];

    XCUIApplication *springboard = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"];
    [springboard activate];
    XCUIElement *icon = springboard.otherElements[@"Home screen icons"].scrollViews.otherElements.icons[appName];

    if (icon.exists) {
        [icon pressForDuration:2.3];
        [icon.buttons[@"DeleteButton"] tap];
        sleep(2);
        [[springboard.alerts firstMatch].buttons[@"Delete"] tap];
        sleep(2);
        [[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome];
        sleep(2);
    }
}

..

- (void)resetWarnings {

    XCUIApplication *settings = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.Preferences"];
    [settings activate];
    sleep(2);
    [settings.tables.staticTexts[@"General"] tap];
    [settings.tables.staticTexts[@"Reset"] tap];
    [settings.tables.staticTexts[@"Reset Location & Privacy"] tap];

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        [settings.buttons[@"Reset"] tap];
    } else {
        [settings.buttons[@"Reset Warnings"] tap];
    }
    sleep(2);
    [settings terminate];
}

答案 17 :(得分:0)

更新Craig Fishers的Swift 4答案。为iPad横向更新。可能仅适用于左侧横向。

导入XCTest

跳板类{

static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

class func deleteMyApp(name: String) {        
    // Force delete the app from the springboard
    let icon = springboard.icons[name]
    if icon.exists {
        let iconFrame = icon.frame
        let springboardFrame = springboard.frame
        icon.press(forDuration: 2.0)

        var portaitOffset = 0.0 as CGFloat
        if XCUIDevice.shared.orientation != .portrait {
            portaitOffset = iconFrame.size.width - 2 * 3 * UIScreen.main.scale
        }

        let coord = springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + portaitOffset + 3 * UIScreen.main.scale) / springboardFrame.maxX, dy: (iconFrame.minY + 3 * UIScreen.main.scale) / springboardFrame.maxY))
        coord.tap()

        let _ = springboard.alerts.buttons["Delete"].waitForExistence(timeout: 5)
        springboard.alerts.buttons["Delete"].tap()

        XCUIDevice.shared.press(.home)
    }
}

}