Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help using async/await and ViewInspector in a single test #186

Open
ethankay opened this issue Jul 28, 2022 · 2 comments
Open

Help using async/await and ViewInspector in a single test #186

ethankay opened this issue Jul 28, 2022 · 2 comments
Labels
feature request New feature or request help wanted Extra attention is needed

Comments

@ethankay
Copy link

TLDR: Is it possible to have an async XCTest method which also uses ViewInspector (e.g. func test...() async { let exp = view.inspect.inspection }?

More details:
I'm attempting to write tests that call async/await methods which eventually will influence a specific View I'm trying to test. Following the ViewInspector examples, I've been using the Inspection setup, which works great normally. However, whenever I mark a test as async it does not work as can be seen in the contrived examples below. Obviously in these examples I don't call any methods in the test body that actually use await, but I didn't include that as the expectations fails regardless of that fact; I can't even attach async to a test method with a ViewInspector expectation and have it work. Of note, I don't run into this problem if I use a simple XCTExpectation directly. Those can handle both async/await and expectations in a single test method.

Example:

final class Inspection<V> {
  let notice = PassthroughSubject<UInt, Never>()
  var callbacks = [UInt: (V) -> Void]()

  func visit(_ view: V, _ line: UInt) {
    if let callback = callbacks.removeValue(forKey: line) {
      callback(view)
    }
  }
}

extension Inspection: InspectionEmissary {}

class TestModel: ObservableObject {
  @Published var examples: [String] = []

  func addExamples() async throws {
    try await Task.sleep(nanoseconds: 1)
    let count = self.examples.count
    self.examples = self.examples + ["test\(count + 1)", "test\(count + 2)"]
  }
}

struct TestView: View {
  @StateObject private var testModel = TestModel()

  let inspection = Inspection<Self>()

  var body: some View {
    VStack {
      Button("button") {
        Task {
          try await testModel.addExamples()
        }
      }.id(1)
      ForEach(testModel.examples, id: \.self) {
        Text($0).tag("text")
      }
    }
    .onReceive(inspection.notice) {
      self.inspection.visit(self, $0)
    }
  }
}

extension TestView: Inspectable {}

class TestViewTest: XCTestCase {
  func test_NoAsyncNoMain() {  // Succeeds
    testImplementation()
  }

  @MainActor
  func test_NoAsyncMain() {  // Succeeds
    testImplementation()
  }

  func test_AsyncMoMain() async {  // Fails "Exceeded timeout of 4 seconds, with unfulfilled expectations"
    testImplementation()
  }

  @MainActor
  func test_AsyncMain() async {  // Fails "Exceeded timeout of 4 seconds, with unfulfilled expectations"
    testImplementation()
  }

  private func testImplementation() {
    let testView = TestView()
    let expectation1 = testView.inspection.inspect(after: 1) { view in
      XCTAssertEqual(view.findAll(where: { try $0.tag() as? String == "text" }).count, 0)
      try view.find(viewWithId: 1).button().tap()
    }
    let expectation2 = testView.inspection.inspect(after: 2) { view in
      XCTAssertEqual(view.findAll(where: { try $0.tag() as? String == "text" }).count, 2)
    }
    ViewHosting.host(view: testView)
    wait(for: [expectation1, expectation2], timeout: 4.0, enforceOrder: true)
  }
}
@nalexn nalexn added feature request New feature or request help wanted Extra attention is needed labels Sep 10, 2022
@nalexn
Copy link
Owner

nalexn commented Jan 20, 2024

While there is no well-thought and finalized approach supported by the library, you can consider going the route suggested by @sisoje in this repo

@nalexn
Copy link
Owner

nalexn commented Feb 25, 2024

For anyone interested, I suggest joining a proposed solution discussion in #291 PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants