diff --git a/packages/automerge-repo/src/DocHandle.ts b/packages/automerge-repo/src/DocHandle.ts index 4e6266da6..b5d9c8198 100644 --- a/packages/automerge-repo/src/DocHandle.ts +++ b/packages/automerge-repo/src/DocHandle.ts @@ -72,12 +72,6 @@ export class DocHandle extends EventEmitter> { this.emit("delete", { handle: this }) return { doc: A.init() } }), - onUnload: assign(() => { - return { doc: A.init() } - }), - onUnavailable: () => { - this.emit("unavailable", { handle: this }) - }, }, }).createMachine({ /** @xstate-layout N4IgpgJg5mDOIC5QAoC2BDAxgCwJYDswBKAYgFUAFAEQEEAVAUQG0AGAXUVAAcB7WXAC64e+TiAAeiAOwAOAKwA6ACxSAzKqks1ATjlTdAGhABPRAFolAJksKN2y1KtKAbFLla5AX09G0WPISkVAwAMgyMrBxIILz8QiJikggAjCzOijKqLEqqybJyLizaRqYIFpbJtro5Uo7J2o5S3r4YOATECrgQADZgJADCAEoM9MzsYrGCwqLRSeoyCtra8pa5adquySXmDjY5ac7JljLJeepKzSB+bYGdPX0AYgCSAHJUkRN8UwmziM7HCgqyVcUnqcmScmcMm2ZV2yiyzkOx1OalUFx8V1aAQ63R46AgBCgJGGAEUyAwAMp0D7RSbxGagJKHFgKOSWJTJGRSCosCpKaEmRCqbQKU5yXINeTaer6LwY67YogKXH4wkkKgAeX6AH1hjQqABNGncL70xKIJQ5RY5BHOJag6wwpRyEWImQVeT1aWrVSXBXtJUqgn4Ik0ADqNCedG1L3CYY1gwA0saYqbpuaEG4pKLksKpFDgcsCjDhTnxTKpTLdH6sQGFOgAO7oKYhl5gAQNngAJwA1iRY3R40ndSNDSm6enfpm5BkWAVkvy7bpuTCKq7ndZnfVeSwuTX-HWu2AAI4AVzgQhD6q12rILxoADVIyEaAAhMLjtM-RmIE4LVSQi4nLLDIGzOCWwLKA0cgyLBoFWNy+43B0R5nheaqajqepjuMtJfgyEh-FoixqMCoKqOyhzgYKCDOq6UIeuCSxHOoSGKgop74OgABuzbdOgABGvTXlho5GrhJpxJOP4pLulT6KoMhpJY2hzsWNF0QobqMV6LG+pc+A8BAcBiP6gSfFJ36EQgKksksKxrHamwwmY7gLKB85QjBzoAWxdZdL0FnfARST8ooLC7qoTnWBU4pyC5ViVMKBQaHUDQuM4fm3EGhJBWaU7-CysEAUp3LpEpWw0WYRw2LmqzgqciIsCxWUdI2zaXlAbYdt2PZ5dJ1n5jY2iJY1ikOIcMJHCyUWHC62hRZkUVNPKta3Kh56wJ1-VWUyzhFc64JWJCtQNBBzhQW4cHwbsrVKpxPF8YJgV4ZZIWIKkiKiiNSkqZYWjzCWaQ5hFh0AcCuR3QoR74qUknBRmzholpv3OkpRQNNRpTzaKTWKbIWR5FDxm9AIkA7e9skUYCWayLILBZGoLkUSKbIyIdpxHPoyTeN4QA */ @@ -588,7 +582,6 @@ export interface DocHandleEvents { "heads-changed": (payload: DocHandleEncodedChangePayload) => void change: (payload: DocHandleChangePayload) => void delete: (payload: DocHandleDeletePayload) => void - unavailable: (payload: DocHandleUnavailablePayload) => void "ephemeral-message": (payload: DocHandleEphemeralMessagePayload) => void "ephemeral-message-outbound": ( payload: DocHandleOutboundEphemeralMessagePayload diff --git a/packages/automerge-repo/src/Repo.ts b/packages/automerge-repo/src/Repo.ts index 2cfb713df..a6e6e38f5 100644 --- a/packages/automerge-repo/src/Repo.ts +++ b/packages/automerge-repo/src/Repo.ts @@ -254,18 +254,8 @@ export class Repo extends EventEmitter { handle.on("heads-changed", throttle(saveFn, this.saveDebounceRate)) } - handle.on("unavailable", () => { - this.#log("document unavailable", { documentId: handle.documentId }) - this.emit("unavailable-document", { - documentId: handle.documentId, - }) - }) - // Register the document with the synchronizer. This advertises our interest in the document. - this.synchronizer.addDocument(handle.documentId) - - // Preserve the old event in case anyone was using it. - this.emit("document", { handle }) + void this.synchronizer.addDocument(handle) } #receiveMessage(message: RepoMessage) { @@ -426,22 +416,20 @@ export class Repo extends EventEmitter { * Retrieves a document by id. It gets data from the local system, but also emits a `document` * event to advertise interest in the document. */ - find( + async find( /** The url or documentId of the handle to retrieve */ - id: AnyDocumentId - ): DocHandle { + id: AnyDocumentId, + { skipReady = false }: { skipReady?: boolean } = {} + ): Promise> { const documentId = interpretAsDocumentId(id) // If we have the handle cached, return it if (this.#handleCache[documentId]) { - if (this.#handleCache[documentId].isUnavailable()) { - // this ensures that the event fires after the handle has been returned - setTimeout(() => { - this.#handleCache[documentId].emit("unavailable", { - handle: this.#handleCache[documentId], - }) - }) + if (skipReady) { + return this.#handleCache[documentId] } + await this.#handleCache[documentId].whenReady([READY]) + return this.#handleCache[documentId] } @@ -456,23 +444,29 @@ export class Repo extends EventEmitter { ? this.storageSubsystem.loadDoc(handle.documentId) : Promise.resolve(null) - attemptLoad - .then(async loadedDoc => { - if (loadedDoc) { - // uhhhh, sorry if you're reading this because we were lying to the type system - handle.update(() => loadedDoc as Automerge.Doc) - handle.doneLoading() - } else { - // we want to wait for the network subsystem to be ready before - // we request the document. this prevents entering unavailable during initialization. - await this.networkSubsystem.whenReady() - handle.request() - } - this.#registerHandleWithSubsystems(handle) - }) - .catch(err => { - this.#log("error waiting for network", { err }) - }) + const loadedDoc = await attemptLoad + + if (loadedDoc) { + // uhhhh, sorry if you're reading this because we were lying to the type system + handle.update(() => loadedDoc as Automerge.Doc) + handle.doneLoading() + } else { + // we want to wait for the network subsystem to be ready before + // we request the document. this prevents entering unavailable during initialization. + await this.networkSubsystem.whenReady() + handle.request() + } + this.#registerHandleWithSubsystems(handle) + if (skipReady) { + console.log("Skipping ready for sync messages") + return handle + } + await handle.whenReady([READY, UNAVAILABLE]) + + console.log("handle state", handle.state) + if (handle.state === UNAVAILABLE) { + throw new Error(`Document ${id} is unavailable`) + } return handle } diff --git a/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts b/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts index 97612a347..118cde7e6 100644 --- a/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts +++ b/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts @@ -1,6 +1,6 @@ import debug from "debug" import { DocHandle } from "../DocHandle.js" -import { parseAutomergeUrl, stringifyAutomergeUrl } from "../AutomergeUrl.js" +import { parseAutomergeUrl } from "../AutomergeUrl.js" import { Repo } from "../Repo.js" import { DocMessage } from "../network/messages.js" import { AutomergeUrl, DocumentId, PeerId } from "../types.js" @@ -29,12 +29,12 @@ export class CollectionSynchronizer extends Synchronizer { } /** Returns a synchronizer for the given document, creating one if it doesn't already exist. */ - #fetchDocSynchronizer(documentId: DocumentId) { - if (!this.docSynchronizers[documentId]) { - const handle = this.repo.find(stringifyAutomergeUrl({ documentId })) - this.docSynchronizers[documentId] = this.#initDocSynchronizer(handle) + async #fetchDocSynchronizer(handle: DocHandle) { + if (!this.docSynchronizers[handle.documentId]) { + this.docSynchronizers[handle.documentId] = + this.#initDocSynchronizer(handle) } - return this.docSynchronizers[documentId] + return this.docSynchronizers[handle.documentId] } /** Creates a new docSynchronizer and sets it up to propagate messages */ @@ -109,7 +109,8 @@ export class CollectionSynchronizer extends Synchronizer { this.#docSetUp[documentId] = true - const docSynchronizer = this.#fetchDocSynchronizer(documentId) + const handle = await this.repo.find(documentId, { skipReady: true }) + const docSynchronizer = await this.#fetchDocSynchronizer(handle) docSynchronizer.receiveMessage(message) @@ -123,13 +124,13 @@ export class CollectionSynchronizer extends Synchronizer { /** * Starts synchronizing the given document with all peers that we share it generously with. */ - addDocument(documentId: DocumentId) { + async addDocument(handle: DocHandle) { // HACK: this is a hack to prevent us from adding the same document twice - if (this.#docSetUp[documentId]) { + if (this.#docSetUp[handle.documentId]) { return } - const docSynchronizer = this.#fetchDocSynchronizer(documentId) - void this.#documentGenerousPeers(documentId).then(peers => { + const docSynchronizer = await this.#fetchDocSynchronizer(handle) + void this.#documentGenerousPeers(handle.documentId).then(peers => { docSynchronizer.beginSync(peers) }) } diff --git a/packages/automerge-repo/src/synchronizer/DocSynchronizer.ts b/packages/automerge-repo/src/synchronizer/DocSynchronizer.ts index e4dc6c0f4..05f1db6f3 100644 --- a/packages/automerge-repo/src/synchronizer/DocSynchronizer.ts +++ b/packages/automerge-repo/src/synchronizer/DocSynchronizer.ts @@ -351,7 +351,13 @@ export class DocSynchronizer extends Synchronizer { this.#withSyncState(message.senderId, syncState => { this.#handle.update(doc => { + console.log( + "received sync message in state", + this.#handle.documentId, + this.#handle.state + ) const start = performance.now() + const [newDoc, newSyncState] = A.receiveSyncMessage( doc, syncState, diff --git a/packages/automerge-repo/test/Repo.test.ts b/packages/automerge-repo/test/Repo.test.ts index 94aa3e6b2..592fc4bfe 100644 --- a/packages/automerge-repo/test/Repo.test.ts +++ b/packages/automerge-repo/test/Repo.test.ts @@ -76,31 +76,31 @@ describe("Repo", () => { assert.equal(handle.docSync().foo, "bar") }) - it("can find a document by url", () => { + it("can find a document by url", async () => { const { repo } = setup() const handle = repo.create() handle.change((d: TestDoc) => { d.foo = "bar" }) - const handle2 = repo.find(handle.url) + const handle2 = await repo.find(handle.url) assert.equal(handle, handle2) assert.deepEqual(handle2.docSync(), { foo: "bar" }) }) - it("can find a document by its unprefixed document ID", () => { + it("can find a document by its unprefixed document ID", async () => { const { repo } = setup() const handle = repo.create() handle.change((d: TestDoc) => { d.foo = "bar" }) - const handle2 = repo.find(handle.documentId) + const handle2 = await repo.find(handle.documentId) assert.equal(handle, handle2) assert.deepEqual(handle2.docSync(), { foo: "bar" }) }) - it("can find a document by legacy UUID (for now)", () => { + it("can find a document by legacy UUID (for now)", async () => { disableConsoleWarn() const { repo } = setup() @@ -113,7 +113,7 @@ describe("Repo", () => { const { binaryDocumentId } = parseAutomergeUrl(url) const legacyDocId = Uuid.stringify(binaryDocumentId) as LegacyDocumentId - const handle2 = repo.find(legacyDocId) + const handle2 = await repo.find(legacyDocId) assert.equal(handle, handle2) assert.deepEqual(handle2.docSync(), { foo: "bar" }) @@ -192,48 +192,36 @@ describe("Repo", () => { it("throws an error if we try to find a handle with an invalid AutomergeUrl", async () => { const { repo } = setup() - try { - repo.find("invalid-url" as unknown as AutomergeUrl) - } catch (e: any) { - assert.equal(e.message, "Invalid AutomergeUrl: 'invalid-url'") - } + expect(async () => { + await repo.find("invalid-url" as unknown as AutomergeUrl) + }).rejects.toThrow("Invalid AutomergeUrl: 'invalid-url'") }) it("doesn't find a document that doesn't exist", async () => { const { repo } = setup() - const handle = repo.find(generateAutomergeUrl()) - - await handle.whenReady(["ready", "unavailable"]) - - assert.equal(handle.isReady(), false) - assert.equal(handle.state, "unavailable") - const doc = await handle.doc() - assert.equal(doc, undefined) - }) - - it("emits an unavailable event when you don't have the document locally and are not connected to anyone", async () => { - const { repo } = setup() - const url = generateAutomergeUrl() - const handle = repo.find(url) - assert.equal(handle.isReady(), false) - await eventPromise(handle, "unavailable") + expect(async () => { + await repo.find(generateAutomergeUrl()) + }).rejects.toThrow(/Document (.*) is unavailable/) }) it("doesn't mark a document as unavailable until network adapters are ready", async () => { const { repo, networkAdapter } = setup({ startReady: false }) const url = generateAutomergeUrl() - const handle = repo.find(url) - let wasUnavailable = false - handle.on("unavailable", () => { - wasUnavailable = true - }) + const attemptedFind = repo.find(url) - await pause(50) - assert.equal(wasUnavailable, false) + // First verify it stays pending for 50ms + await expect( + Promise.race([attemptedFind, pause(50)]) + ).resolves.toBeUndefined() + // Trigger the rejection networkAdapter.forceReady() - await eventPromise(handle, "unavailable") + + // Now verify it rejects + await expect(attemptedFind).rejects.toThrow( + /Document (.*) is unavailable/ + ) }) it("can find a created document", async () => { @@ -244,7 +232,7 @@ describe("Repo", () => { }) assert.equal(handle.isReady(), true) - const bobHandle = repo.find(handle.url) + const bobHandle = await repo.find(handle.url) assert.equal(handle, bobHandle) assert.equal(handle.isReady(), true) @@ -263,7 +251,7 @@ describe("Repo", () => { await repo.flush() - const bobHandle = repo2.find(handle.url) + const bobHandle = await repo2.find(handle.url) await bobHandle.whenReady() assert.equal(bobHandle.isReady(), true) }) @@ -284,7 +272,7 @@ describe("Repo", () => { storage: storageAdapter, }) - const bobHandle = repo2.find(handle.url) + const bobHandle = await repo2.find(handle.url) const v = await bobHandle.doc() assert.equal(v?.foo, "bar") @@ -386,7 +374,7 @@ describe("Repo", () => { const repo2 = new Repo({ storage, }) - const handle2 = repo2.find(handle.url) + const handle2 = await repo2.find(handle.url) await handle2.doc() assert.deepEqual(storage.keys(), initialKeys) @@ -414,7 +402,7 @@ describe("Repo", () => { const repo2 = new Repo({ storage, }) - const handle2 = repo2.find(handle.url) + const handle2 = await repo2.find(handle.url) await handle2.doc() assert(storage.keys().length !== 0) @@ -574,9 +562,10 @@ describe("Repo", () => { }) // Could not find the document that is not yet saved because of slow storage. - const reloadedHandle = repo2.find<{ foo: string }>(handle.url) + expect(async () => { + const reloadedHandle = await repo2.find<{ foo: string }>(handle.url) + }).rejects.toThrow(/Document (.*) is unavailable/) expect(pausedStorage.keys()).to.deep.equal([]) - expect(await reloadedHandle.doc()).toEqual(undefined) }) it("should be visible to a new repo after flush()", async () => { @@ -596,10 +585,10 @@ describe("Repo", () => { }) expect( - (await repo.find<{ foo: string }>(handle.documentId).doc()).foo + (await repo.find<{ foo: string }>(handle.documentId)).docSync().foo ).toEqual("first") expect( - (await repo.find<{ foo: string }>(handle2.documentId).doc()).foo + (await repo.find<{ foo: string }>(handle2.documentId)).docSync().foo ).toEqual("second") } }) @@ -621,13 +610,13 @@ describe("Repo", () => { }) expect( - (await repo.find<{ foo: string }>(handle.documentId).doc()).foo + (await repo.find<{ foo: string }>(handle.documentId)).docSync().foo ).toEqual("first") // Really, it's okay if the second one is also flushed but I'm forcing the issue // in the test storage engine above to make sure the behaviour is as documented - expect( - await repo.find<{ foo: string }>(handle2.documentId).doc() - ).toEqual(undefined) + expect(async () => { + ;(await repo.find<{ foo: string }>(handle2.documentId)).docSync() + }).rejects.toThrow(/Document (.*) is unavailable/) } }) @@ -706,7 +695,7 @@ describe("Repo", () => { } await connectedPromise - + console.log("All connected") return { repos } } @@ -718,9 +707,8 @@ describe("Repo", () => { d.foo = "bar" }) - const handleN = repos[numberOfPeers - 1].find(handle0.url) - - await handleN.whenReady() + await pause(500) + const handleN = await repos[numberOfPeers - 1].find(handle0.url) assert.deepStrictEqual(handleN.docSync(), { foo: "bar" }) }) @@ -848,9 +836,11 @@ describe("Repo", () => { it("changes are replicated from aliceRepo to bobRepo", async () => { const { bobRepo, aliceHandle, teardown } = await setup() - const bobHandle = bobRepo.find(aliceHandle.url) - await eventPromise(bobHandle, "change") + console.log("before bob") + const bobHandle = await bobRepo.find(aliceHandle.url) + console.log("found bob") const bobDoc = await bobHandle.doc() + console.log("bobDoc", bobDoc) assert.deepStrictEqual(bobDoc, { foo: "bar" }) teardown() }) @@ -858,8 +848,7 @@ describe("Repo", () => { it("can load a document from aliceRepo on charlieRepo", async () => { const { charlieRepo, aliceHandle, teardown } = await setup() - const handle3 = charlieRepo.find(aliceHandle.url) - await eventPromise(handle3, "change") + const handle3 = await charlieRepo.find(aliceHandle.url) const doc3 = await handle3.doc() assert.deepStrictEqual(doc3, { foo: "bar" }) teardown() @@ -879,7 +868,7 @@ describe("Repo", () => { await bobRepo2.flush() // Now, let's load it on the original bob repo (which shares a "disk") - const bobFoundIt = bobRepo.find(inStorageHandle.url) + const bobFoundIt = await bobRepo.find(inStorageHandle.url) await bobFoundIt.whenReady() // Before checking if it syncs, make sure we have it! @@ -924,7 +913,7 @@ describe("Repo", () => { it("charlieRepo can request a document not initially shared with it", async () => { const { charlieRepo, notForCharlie, teardown } = await setup() - const handle = charlieRepo.find(notForCharlie) + const handle = await charlieRepo.find(notForCharlie) await pause(50) @@ -938,7 +927,7 @@ describe("Repo", () => { it("charlieRepo can request a document across a network of multiple peers", async () => { const { charlieRepo, notForBob, teardown } = await setup() - const handle = charlieRepo.find(notForBob) + const handle = await charlieRepo.find(notForBob) await pause(50) @@ -951,42 +940,10 @@ describe("Repo", () => { it("doesn't find a document which doesn't exist anywhere on the network", async () => { const { charlieRepo, teardown } = await setup() const url = generateAutomergeUrl() - const handle = charlieRepo.find(url) - assert.equal(handle.isReady(), false) - - const doc = await handle.doc() - assert.equal(doc, undefined) - - teardown() - }) - it("emits an unavailable event when it's not found on the network", async () => { - const { aliceRepo, teardown } = await setup() - const url = generateAutomergeUrl() - const handle = aliceRepo.find(url) - assert.equal(handle.isReady(), false) - await eventPromise(handle, "unavailable") - teardown() - }) - - it("emits an unavailable event every time an unavailable doc is requested", async () => { - const { charlieRepo, teardown } = await setup() - const url = generateAutomergeUrl() - const handle = charlieRepo.find(url) - assert.equal(handle.isReady(), false) - - await Promise.all([ - eventPromise(handle, "unavailable"), - eventPromise(charlieRepo, "unavailable-document"), - ]) - - // make sure it emits a second time if the doc is still unavailable - const handle2 = charlieRepo.find(url) - assert.equal(handle2.isReady(), false) - await Promise.all([ - eventPromise(handle, "unavailable"), - eventPromise(charlieRepo, "unavailable-document"), - ]) + await expect(charlieRepo.find(url)).rejects.toThrow( + /Document (.*) is unavailable/ + ) teardown() }) @@ -1001,20 +958,20 @@ describe("Repo", () => { } = await setup({ connectAlice: false }) const url = stringifyAutomergeUrl({ documentId: notForCharlie }) - const handle = charlieRepo.find(url) - assert.equal(handle.isReady(), false) - - await eventPromise(handle, "unavailable") + await expect(charlieRepo.find(url)).rejects.toThrow( + /Document (.*) is unavailable/ + ) connectAliceToBob() await eventPromise(aliceRepo.networkSubsystem, "peer") - const doc = await handle.doc(["ready"]) + const handle = await charlieRepo.find(url) + const doc = await handle.doc() assert.deepStrictEqual(doc, { foo: "baz" }) // an additional find should also return the correct resolved document - const handle2 = charlieRepo.find(url) + const handle2 = await charlieRepo.find(url) const doc2 = await handle2.doc() assert.deepStrictEqual(doc2, { foo: "baz" }) @@ -1051,11 +1008,9 @@ describe("Repo", () => { sharePolicy: async () => true, }) - const handle = a.find(url) - - // We expect this to be unavailable as there is no connected peer and - // the repo has no storage. - await eventPromise(handle, "unavailable") + await expect(a.find(url)).rejects.toThrow( + /Document (.*) is unavailable/ + ) // Now create a repo pointing at the storage containing the document and // connect it to the other end of the MessageChannel @@ -1067,7 +1022,8 @@ describe("Repo", () => { // The empty repo should be notified of the new peer, send it a request // and eventually resolve the handle to "READY" - await handle.whenReady() + const handle = await a.find(url) + expect(handle.state).toBe("ready") }) it("a deleted document from charlieRepo can be refetched", async () => { @@ -1083,8 +1039,7 @@ describe("Repo", () => { }) await changePromise - const handle3 = charlieRepo.find(aliceHandle.url) - await eventPromise(handle3, "change") + const handle3 = await charlieRepo.find(aliceHandle.url) const doc3 = await handle3.doc() assert.deepStrictEqual(doc3, { foo: "baz" }) @@ -1129,10 +1084,10 @@ describe("Repo", () => { const data = { presence: "alice" } - const aliceHandle = aliceRepo.find( + const aliceHandle = await aliceRepo.find( stringifyAutomergeUrl({ documentId: notForCharlie }) ) - const bobHandle = bobRepo.find( + const bobHandle = await bobRepo.find( stringifyAutomergeUrl({ documentId: notForCharlie }) ) @@ -1282,7 +1237,7 @@ describe("Repo", () => { }) }) - const charlieHandle = charlieRepo.find(handle.url) + const charlieHandle = await charlieRepo.find(handle.url) await charlieHandle.whenReady() // make a change on charlie @@ -1335,16 +1290,16 @@ describe("Repo", () => { const aliceDoc = aliceRepo.create() aliceDoc.change((doc: any) => (doc.text = "Hello world")) - const bobDoc = bobRepo.find(aliceDoc.url) - await eventPromise(bobDoc, "unavailable") + expect(async () => { + const bobDoc = await bobRepo.find(aliceDoc.url) + }).rejects.toThrow(/Document (.*) is unavailable/) aliceAdapter.peerCandidate(bob) // Bob isn't yet connected to Alice and can't respond to her sync message await pause(100) bobAdapter.peerCandidate(alice) - await bobDoc.whenReady() - + const bobDoc = await bobRepo.find(aliceDoc.url) assert.equal(bobDoc.isReady(), true) }) @@ -1409,8 +1364,8 @@ describe("Repo", () => { const aliceHandle = aliceRepo.create() - const bobHandle = bobRepo.find(aliceHandle.url) - const charlieHandle = charlieRepo.find(aliceHandle.url) + const bobHandle = await bobRepo.find(aliceHandle.url) + const charlieHandle = await charlieRepo.find(aliceHandle.url) // Alice should not receive her own ephemeral message aliceHandle.on("ephemeral-message", () => { @@ -1448,7 +1403,7 @@ describe("Repo", () => { // pause to let the sync happen await pause(50) - const charlieHandle = charlieRepo.find(handle2.url) + const charlieHandle = await charlieRepo.find(handle2.url) await charlieHandle.doc() assert.deepStrictEqual(charlieHandle.docSync(), { foo: "bar" }) @@ -1467,7 +1422,7 @@ describe("Repo", () => { // pause to let the sync happen await pause(50) - const charlieHandle = charlieRepo.find(handle2.url) + const charlieHandle = await charlieRepo.find(handle2.url) await charlieHandle.doc() assert.deepStrictEqual(charlieHandle.docSync(), { foo: "bar" }) @@ -1516,9 +1471,9 @@ describe("Repo", () => { eventPromise(client.networkSubsystem, "peer"), ]) - const clientDoc = client.find(doc.url) - await pause(100) - assert.strictEqual(clientDoc.docSync(), undefined) + expect(async () => { + const clientDoc = await client.find(doc.url) + }).rejects.toThrow(/Document (.*) is unavailable/) const openDocs = Object.keys(server.metrics().documents).length assert.deepEqual(openDocs, 0) diff --git a/packages/automerge-repo/test/remoteHeads.test.ts b/packages/automerge-repo/test/remoteHeads.test.ts index 23f626118..e02609c37 100644 --- a/packages/automerge-repo/test/remoteHeads.test.ts +++ b/packages/automerge-repo/test/remoteHeads.test.ts @@ -129,11 +129,13 @@ describe("DocHandle.remoteHeads", () => { aliceDoc.change(d => (d.foo = "bar")) // bob waits for the document to arrive - const bobDoc = bob.find(aliceDoc.url) + const bobDoc = await bob.find(aliceDoc.url) await bobDoc.whenReady() // alice's service worker waits for the document to arrive - const aliceServiceWorkerDoc = aliceServiceWorker.find(aliceDoc.documentId) + const aliceServiceWorkerDoc = await aliceServiceWorker.find( + aliceDoc.documentId + ) await aliceServiceWorkerDoc.whenReady() let aliceSeenByBobPromise = new Promise( @@ -169,7 +171,7 @@ describe("DocHandle.remoteHeads", () => { bobDocB.change(d => (d.foo = "B")) // alice opens doc A - const aliceDocA = alice.find(bobDocA.url) + const aliceDocA = await alice.find(bobDocA.url) const remoteHeadsChangedMessages = ( await collectMessages({ @@ -198,8 +200,8 @@ describe("DocHandle.remoteHeads", () => { bobDocB.change(d => (d.foo = "B")) // alice opens the docs - const _aliceDocA = alice.find(bobDocA.url) - const _aliceDocB = alice.find(bobDocB.url) + const _aliceDocA = await alice.find(bobDocA.url) + const _aliceDocB = await alice.find(bobDocB.url) // alice subscribes to bob's service worker alice.subscribeToRemotes([bobServiceWorkerStorageId]) @@ -209,7 +211,7 @@ describe("DocHandle.remoteHeads", () => { // stored remote heads immediately. // open doc and subscribe alice's second tab to bob's service worker - const alice2DocA = alice2.find(bobDocA.url) + const alice2DocA = await alice2.find(bobDocA.url) alice2.subscribeToRemotes([bobServiceWorkerStorageId]) const remoteHeadsChangedMessages = ( @@ -243,7 +245,7 @@ describe("DocHandle.remoteHeads", () => { alice.subscribeToRemotes([bobServiceWorkerStorageId]) // alice opens doc A - const alice1DocA = alice.find(bobDocA.url) + const alice1DocA = await alice.find(bobDocA.url) const remoteHeadsChangedMessages = ( await collectMessages({