A typical test lifecycle is:

  1. Create two instances of Ditto with the same identity and different directories.
  2. Call startSync() on both instances.
  3. Listen for changes to data using subscribe() and write tests as a response to the observeLocal() function.
  4. Clean up Ditto directories between tests and stop any open synchronization threads using stopSync().

For complete examples and running tests, see the open source samples GitHub repository.

Getting Started

To test Ditto using SwiftUI, we provide you with some basic convenience functions you can use to get started.

For code that you can use in your project, see the example on GitHub.

Create custom directories

Each instance of Ditto should use a different directory. You can create a convenience class to provide a custom directory for every instance of Ditto.

Swift
/// Test helper which wraps a Ditto instance.
public class DittoInstance {
    internal var ditto: Ditto?
    private let instanceDir: URL

    public init(appID: String) {
        // No need for cleanup, as the TestsSetup class is configured as NSPrincipalClass
        // and will delete topLevelDittoDir() before any test job is run

        let instanceDir = topLevelDittoDir()
            .appendingPathComponent(appID)
            .appendingPathComponent(UUID().uuidString)

        self.instanceDir = instanceDir
        self.ditto = Ditto(
            identity: .onlinePlayground(appID: appID, persistenceDirectory: instanceDir),
            persistenceDirectory: instanceDir
        )
    }

    public func stop() {
        self.ditto!.stopSync()
        self.ditto = nil
    }
}

func topLevelDittoDir() -> URL {
    let fileManager = FileManager.default
    return try! fileManager.url(
        for: .documentDirectory,
        in: .userDomainMask,
        appropriateFor: nil,
        create: false
    ).appendingPathComponent("ditto_top_level")
}

Create your test

  1. Initialize two ditto instances with different directories.
  2. Call startSync() on both instances.
Swift
import XCTest
import DittoSwift


final class SwiftUITests: XCTestCase {

    var ditto1: DittoInstance!
    var ditto2: DittoInstance!

    override func setUp() {
        self.ditto1 = DittoInstance(appID: "test-app")
        self.ditto2 = DittoInstance(appID: "test-app")
        try! self.ditto1.ditto?.startSync()
        try! self.ditto2.ditto?.startSync()
    }

    func testExample() throws {
      // your test here
    }
}

Listen for Data Changes

Using observeLocal(), we listen to changes to data. We write tests as a response to the observeLocal() function based on what we expect to happen.

The tests should reside within the callback so that they properly test the state of the database after synchronization is complete.

...
let initialResultExpectation = expectation(description: "Initial event received")
let docID = try! ditto1.ditto!.store.collection("cars").upsert(["make": "toyota", "color": "red"])
let subscription = ditto2.ditto!.store.collection("cars").findAll().subscribe()
let liveQuery = ditto2.ditto!.store.collection("cars").findByID(docID).observeLocal { doc, event in
    if (!event.isInitial) {
        XCTAssertEqual(doc!.value["make"] as! String, "toyota")
        initialResultExpectation.fulfill()
    }
}

wait(for: [initialResultExpectation], timeout: 2)

Clean up

Don’t forget to clean up between tests. This can also be implemented as part of a base test class.

Swift

func testExample() throws {
  let initialResultExpectation = expectation(description: "Initial event received")
  let docID = try! ditto1.ditto!.store.collection("cars").upsert(["make": "toyota", "color": "red"])
  let subscription = ditto2.ditto!.store.collection("cars").findAll().subscribe()
  let liveQuery = ditto2.ditto!.store.collection("cars").findByID(docID).observeLocal { doc, event in
      if (!event.isInitial) {
          XCTAssertEqual(doc!.value["make"] as! String, "toyota")
          initialResultExpectation.fulfill()
      }
  }

  wait(for: [initialResultExpectation], timeout: 2)
  liveQuery.stop()
  ditto1.stop()
  ditto2.stop()
}

Full example

For the full example that you can use in your project, see the open source testing library on GitHub.`