| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import XCTest |
| |
| final class NativeUIKitSwiftExperimentUITests: XCTestCase { |
| |
| override func setUp() { |
| continueAfterFailure = false |
| } |
| |
| @MainActor |
| func testColdStartUniversalLink() throws { |
| guard #available(iOS 16.4, *) else { |
| throw XCTSkip("app.open(url) is only available on iOS 16.4+") |
| } |
| |
| let app = XCUIApplication() |
| let url = URL(string: "https://flutter-dashboard.appspot.com/cold")! |
| app.open(url) |
| |
| let button = app.buttons["Get Lifecycle Events"].firstMatch |
| XCTAssertTrue(button.waitForExistence(timeout: 10)) |
| button.tap() |
| |
| // Unmigrated plugins receive applicationDidFinishLaunchingWithOptions twice on cold start: |
| // once during plugin registration with FlutterEngine, and once when FlutterAppDelegate forwards it. |
| let expectedEvents = [ |
| "applicationDidFinishLaunchingWithOptions", |
| "applicationDidFinishLaunchingWithOptions", |
| "url:https://flutter-dashboard.appspot.com/cold", |
| "applicationWillEnterForeground", |
| "applicationDidBecomeActive", |
| ] |
| let eventsPredicate = NSPredicate( |
| format: "label == %@", |
| expectedEvents.joined(separator: "\n") |
| ) |
| let eventsElement = app.staticTexts.element(matching: eventsPredicate) |
| if !eventsElement.waitForExistence(timeout: 5) { |
| let allLabels = app.staticTexts.allElementsBoundByIndex.map(\.label).joined(separator: "\n---\n") |
| XCTFail("Cold start Universal Link fallback lifecycle sequence failed. Actual:\n\(allLabels)") |
| } |
| } |
| |
| @MainActor |
| func testColdStartCustomScheme() throws { |
| guard #available(iOS 16.4, *) else { |
| throw XCTSkip("app.open(url) is only available on iOS 16.4+") |
| } |
| |
| let app = XCUIApplication() |
| let url = URL(string: "testscheme://flutter/cold")! |
| app.open(url) |
| |
| let button = app.buttons["Get Lifecycle Events"].firstMatch |
| XCTAssertTrue(button.waitForExistence(timeout: 10)) |
| button.tap() |
| |
| // Unmigrated plugins receive applicationDidFinishLaunchingWithOptions twice on cold start: |
| // once during plugin registration with FlutterEngine, and once when FlutterAppDelegate forwards it. |
| let expectedEvents = [ |
| "applicationDidFinishLaunchingWithOptions", |
| "applicationDidFinishLaunchingWithOptions", |
| "url:testscheme://flutter/cold", |
| "applicationWillEnterForeground", |
| "applicationDidBecomeActive", |
| ] |
| let eventsPredicate = NSPredicate( |
| format: "label == %@", |
| expectedEvents.joined(separator: "\n") |
| ) |
| let eventsElement = app.staticTexts.element(matching: eventsPredicate) |
| if !eventsElement.waitForExistence(timeout: 5) { |
| let allLabels = app.staticTexts.allElementsBoundByIndex.map(\.label).joined(separator: "\n---\n") |
| XCTFail("Cold start Custom Scheme fallback lifecycle sequence failed. Actual:\n\(allLabels)") |
| } |
| } |
| |
| @MainActor |
| func testWarmStartUniversalLink() throws { |
| guard #available(iOS 16.4, *) else { |
| throw XCTSkip("system.open(url) is only available on iOS 16.4+") |
| } |
| |
| let app = XCUIApplication() |
| app.launch() |
| |
| let button = app.buttons["Get Lifecycle Events"].firstMatch |
| XCTAssertTrue(button.waitForExistence(timeout: 10)) |
| |
| // Background the app before sending deep link to test warm start |
| XCUIDevice.shared.press(.home) |
| |
| let url = URL(string: "https://flutter-dashboard.appspot.com/warm")! |
| XCUIDevice.shared.system.open(url) |
| |
| XCTAssertTrue(button.waitForExistence(timeout: 10)) |
| button.tap() |
| |
| // On warm start, the app was already launched so applicationDidFinishLaunchingWithOptions |
| // is only logged once. The deep link resumes the backgrounded app via scene continuation. |
| let expectedEvents = [ |
| "applicationDidFinishLaunchingWithOptions", |
| "applicationWillEnterForeground", |
| "applicationDidBecomeActive", |
| "applicationWillResignActive", |
| "applicationDidEnterBackground", |
| "applicationWillEnterForeground", |
| "applicationContinueUserActivity", |
| "url:https://flutter-dashboard.appspot.com/warm", |
| "applicationDidBecomeActive", |
| ] |
| let eventsPredicate = NSPredicate( |
| format: "label == %@", |
| expectedEvents.joined(separator: "\n") |
| ) |
| let eventsElement = app.staticTexts.element(matching: eventsPredicate) |
| if !eventsElement.waitForExistence(timeout: 5) { |
| let allLabels = app.staticTexts.allElementsBoundByIndex.map(\.label).joined(separator: "\n---\n") |
| XCTFail("Warm start Universal Link fallback lifecycle sequence failed. Actual:\n\(allLabels)") |
| } |
| } |
| |
| @MainActor |
| func testWarmStartCustomScheme() throws { |
| guard #available(iOS 16.4, *) else { |
| throw XCTSkip("system.open(url) is only available on iOS 16.4+") |
| } |
| |
| let app = XCUIApplication() |
| app.launch() |
| |
| let button = app.buttons["Get Lifecycle Events"].firstMatch |
| XCTAssertTrue(button.waitForExistence(timeout: 10)) |
| |
| // Background the app before sending deep link to test warm start |
| XCUIDevice.shared.press(.home) |
| |
| let url = URL(string: "testscheme://flutter/warm")! |
| XCUIDevice.shared.system.open(url) |
| |
| XCTAssertTrue(button.waitForExistence(timeout: 10)) |
| button.tap() |
| |
| // On warm start, applicationDidFinishLaunchingWithOptions was only logged once during initial launch. |
| // The custom scheme deep link resumes the backgrounded app via openURL. |
| let expectedEvents = [ |
| "applicationDidFinishLaunchingWithOptions", |
| "applicationWillEnterForeground", |
| "applicationDidBecomeActive", |
| "applicationWillResignActive", |
| "applicationDidEnterBackground", |
| "applicationOpenURL", |
| "url:testscheme://flutter/warm", |
| "applicationWillEnterForeground", |
| "applicationDidBecomeActive", |
| ] |
| let eventsPredicate = NSPredicate( |
| format: "label == %@", |
| expectedEvents.joined(separator: "\n") |
| ) |
| let eventsElement = app.staticTexts.element(matching: eventsPredicate) |
| if !eventsElement.waitForExistence(timeout: 5) { |
| let allLabels = app.staticTexts.allElementsBoundByIndex.map(\.label).joined(separator: "\n---\n") |
| XCTFail("Warm start Custom Scheme fallback lifecycle sequence failed. Actual:\n\(allLabels)") |
| } |
| } |
| } |