TeraPublicationNavigationTests.swift (5314B)
1 import Foundation 2 @testable import TeraApp 3 import XCTest 4 5 @MainActor 6 final class TeraPublicationNavigationTests: XCTestCase { 7 func testNewDuringUploadAndAdvanceRetainsWorkerAndCreatesSeparateComposer() async throws { 8 for upload in [false, true] { 9 let fixture = try await NavigationFixture(upload: upload) 10 let store = fixture.store 11 let original = try XCTUnwrap(store.submissions.status) 12 XCTAssertTrue(store.canCreateNewComposer) 13 // Navigation cancels the view waiter and observation, not publication. 14 fixture.waiter.cancel() 15 store.suspend() 16 await store.start() 17 store.newDraft(type: .createAsk) 18 await TeraScopeFixtures.eventually { !store.protection.isWorking } 19 XCTAssertFalse(store.protection.failed) 20 XCTAssertEqual(store.form.commandType, .createAsk) 21 XCTAssertTrue(store.form.content.isEmpty) 22 XCTAssertTrue(store.submissions.isWorking) 23 XCTAssertEqual(store.submissions.request, original.request) 24 XCTAssertEqual(store.submissions.status?.captured, original.captured) 25 XCTAssertEqual(store.submitLabel, "Submit") 26 XCTAssertFalse(store.canSubmit, "One bounded worker; New does not start another effect") 27 store.updateForm(\.content, "separate new editing") 28 await store.save() 29 let editing = try XCTUnwrap(store.savedComposer) 30 XCTAssertNotEqual(editing.id, original.captured.id) 31 XCTAssertEqual(editing.form.content, "separate new editing") 32 await fixture.pause.resume.open() 33 await fixture.waiter.value 34 XCTAssertEqual(store.submissions.status?.request, original.request) 35 XCTAssertEqual(store.submissions.status?.captured, original.captured) 36 XCTAssertEqual(store.form.content, "separate new editing") 37 XCTAssertTrue(store.canSubmit) 38 await store.submit() 39 let next = try XCTUnwrap(store.submissions.status) 40 XCTAssertNotEqual(next.request.commandID, original.request.commandID) 41 XCTAssertNotEqual(next.captured.id, original.captured.id) 42 XCTAssertEqual(next.captured.form.content, "separate new editing") 43 let count = await fixture.backend.submissionBackend.prepareCount 44 XCTAssertEqual(count, 2, "Exactly one original and one explicit new submission") 45 store.stop() 46 _ = try await fixture.client.stop() 47 } 48 } 49 50 func testNewRefusesUnacknowledgedPreparationWithoutDiscardingRequest() async throws { 51 let backend = AddBackend() 52 let client = try await TeraAddStoreTests.startedClient(backend) 53 let store = TeraAddStore(runtimeClient: client) 54 await store.configure(snapshot: backend.snapshot()) 55 await store.start() 56 store.updateForm(\.content, "pending capture") 57 let pause = ResourceTestPause() 58 await backend.submissionBackend.pausePrepare(pause) 59 let waiter = Task { await store.submit() } 60 await pause.entered.wait() 61 let request = store.submissions.request 62 XCTAssertFalse(store.canCreateNewComposer) 63 store.newDraft() 64 XCTAssertEqual(store.form.content, "pending capture") 65 XCTAssertEqual(store.submissions.request, request) 66 await pause.resume.open() 67 await waiter.value 68 store.stop() 69 _ = try await client.stop() 70 } 71 72 func testExplicitStopAfterNewStillTargetsOriginalPublication() async throws { 73 let fixture = try await NavigationFixture(upload: false) 74 let store = fixture.store 75 let request = try XCTUnwrap(store.submissions.request) 76 store.newDraft(type: .createAsk) 77 await TeraScopeFixtures.eventually { !store.protection.isWorking } 78 store.updateForm(\.content, "retain separate editing") 79 await store.submissions.requestStop() 80 XCTAssertEqual(store.submissions.request, request) 81 XCTAssertEqual(store.submissions.status?.delivery.isStopped, true) 82 await fixture.pause.resume.open() 83 await fixture.waiter.value 84 XCTAssertEqual(store.form.content, "retain separate editing") 85 XCTAssertEqual(store.submissions.request, request) 86 let count = await fixture.backend.submissionBackend.prepareCount 87 XCTAssertEqual(count, 1) 88 store.stop() 89 _ = try await fixture.client.stop() 90 } 91 } 92 93 @MainActor 94 private struct NavigationFixture { 95 let backend: AddBackend 96 let client: TeraRuntimeClient 97 let store: TeraAddStore 98 let pause: ResourceTestPause 99 let waiter: Task<Void, Never> 100 101 init(upload: Bool) async throws { 102 let backend = AddBackend() 103 let client = try await TeraAddStoreTests.startedClient(backend) 104 let media = AddMediaHarness(foreground: true) 105 let store = TeraAddStore(runtimeClient: client, media: media) 106 await store.configure(snapshot: backend.snapshot()) 107 await store.start() 108 if upload { 109 store.selectType(.createPhotoUpdate) 110 await TeraScopeFixtures.eventually { !store.protection.isWorking } 111 let photo = await media.captureImage() 112 store.updateForm(\.media, [photo]) 113 } 114 store.updateForm(\.content, "frozen original") 115 let pause = ResourceTestPause() 116 if upload { 117 await backend.submissionBackend.pauseForeground(pause) 118 } else { 119 await backend.submissionBackend.pauseAdvance(pause) 120 } 121 let waiter = Task { await store.submit() } 122 await pause.entered.wait() 123 self.backend = backend 124 self.client = client 125 self.store = store 126 self.pause = pause 127 self.waiter = waiter 128 } 129 }