field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

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 }