import XCTest @testable import CallsKit /// The guard rails around starting a meeting. The request itself is Go's /// (callscore.StartMeeting, gated server-side), so what is worth holding /// here is the state the button is allowed to be in at all. /// /// Every model here has an in-memory store: none of these tests signs /// in, and none should be able to touch the Keychain of whoever runs it. final class StartMeetingTests: XCTestCase { @MainActor func testStartingIsRefusedOnlyOnceTheServerHasSaidSo() { let model = CallsModel(store: MemorySessionStore()) // canStart goes down only when the server answered that this session // is not a member's. Refusing here means the app does not spend a // round trip learning it again. model.signedIn = true model.room = "abc123" model.canStart = false model.startMeeting() XCTAssertFalse(model.starting) XCTAssertFalse(model.error.isEmpty) XCTAssertEqual(model.room, "abc123", "a refused start must not disturb the meeting in hand") } @MainActor func testStartingIsRefusedDuringACallRatherThanReplacingIt() { let model = CallsModel(store: MemorySessionStore()) model.signedIn = true model.canStart = true model.joining = true model.error = "" model.startMeeting() XCTAssertFalse(model.starting) // Silent, unlike the case above: this is a button that should not have // been reachable, not a person being told something they can act on. XCTAssertTrue(model.error.isEmpty) } @MainActor func testLeavingAndCancellingBothPutTheStartingFlagDown() { // `starting` gates the button. Left up by a leave or a cancel it would // be a button nobody can press again for the rest of the session. let model = CallsModel(store: MemorySessionStore()) model.starting = true model.cancelSignIn() XCTAssertFalse(model.starting) model.starting = true model.leave() XCTAssertFalse(model.starting) } @MainActor func testALinkToAnotherInstanceIsOfferedAndDisturbsNothingUntilSignIn() { let model = CallsModel(store: MemorySessionStore()) model.origin = "https://calls.oficina.works" model.signedIn = true model.canStart = true model.room = "abc123" model.openMeetingURL( URL(string: "oficina-calls://join?url=https%3A%2F%2Fcalls.example.com%2Fj%2Finvitation")!) XCTAssertEqual(model.pendingLink, "https://calls.example.com/j/invitation") XCTAssertFalse(model.pendingOnServer) XCTAssertFalse(model.authenticating, "offered, not started") // The session in hand is untouched until a new sign-in replaces it, // and "Not now" goes straight back to it. XCTAssertTrue(model.signedIn) XCTAssertTrue(model.canStart) XCTAssertEqual(model.room, "abc123") model.dismissPendingLink() XCTAssertEqual(model.pendingLink, "") XCTAssertTrue(model.signedIn) } @MainActor func testHostIsTheInstanceWithoutItsScheme() { let model = CallsModel(store: MemorySessionStore()) model.origin = "https://calls.oficina.works" XCTAssertEqual(model.host, "calls.oficina.works") model.origin = "http://127.0.0.1:8080" XCTAssertEqual(model.host, "127.0.0.1") } }