Chapter 6 - TestModelCountdown never succeeds

Hi,

I’m trying out the tests in chapter 6 and the testModelCountdown never passes. I’m still getting the ‘operation timed out failure’. I have tried running the final project and I get the same result.

I’m running Xcode 13.3

hey @hammerhead, the tests definitely passed when we did the last book update. Have you by any chance tried with Xcode 13.2.1? I wonder if they did some non-obvious changes in 13.3

Hi @icanzilb thanks for getting back to me, as luck would have it I still have 13.2 installed on my machine and the tests do pass, so something must have changed between 13.2 and 13.3. I’ll have a play around today and see if I can find out what changed. On 13.3 the TimeoutTask is throwing the ‘The operation timed out’ error.

Oh that’s great @hammerhead, I’ll make a note to have a look at this. In case you figure it out I’ll appreciate a ping.

I’ve hacked the code a bit and come up with this:

 func testModelCountdown() async throws {
    
    async let countdown: Void = model.countdown(to: "Tada!")

    let messages = await TestURLProtocol.requests
      .prefix(4)
      .reduce(into: []) { result, request in
        result.append(request)
      }
      .compactMap(\.httpBody)
      .compactMap { data in
        try? JSONDecoder().decode(Message.self, from: data)
          .message
      }
    
    let _ = try await countdown
    
    XCTAssertEqual(
      ["3...", "2...", "1...", "🎉 Tada!"],
      messages
    )
  }

The test passes, but I don’t know if is a good solution though. If the value of the prefix > 4, then we still have the problem with the test hanging, it does correctly fail when the prefix is < 3 though.

1 Like

Thank you for sharing, I have a little time today and I’ll look into this as well

OK … this looks like a bug to me that’s been introduced in Xcode 13.3. If you use the compactMap on the async sequence instead of the one on array, it works as expected. So you need to take the code in the book and move reduce few lines downwards like so:

async let countdown: Void = model.countdown(to: "Tada!")
async let messages = TimeoutTask(seconds: 10) {
  await TestURLProtocol.requests
    .prefix(4)
    .compactMap(\.httpBody)
    .compactMap { data in
      try? JSONDecoder()
        .decode(Message.self, from: data).message
    }
    .reduce(into: []) { result, request in
      result.append(request)
    }
}
.value

let (messagesResult, _) = try await (messages, countdown)