Skip to content

Commit

Permalink
sync: Ignores events from unrelated databases
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed Apr 14, 2021
1 parent 10272b4 commit b05a39f
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 22 deletions.
10 changes: 8 additions & 2 deletions src/extensions/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ export function sync(db: Database<any>) {
'message',
(event: MessageEvent<DatabaseMessageEventData<any>>) => {
const { operationType, payload } = event.data
console.warn('[sync]', operationType, payload)
const [sourceId, ...args] = payload

// Ignore messages originating from unrelated databases.
// Useful in case of multiple databases on the same page.
if (db.id !== sourceId) {
return
}

// Remove database event listener for the signaled operation
// to prevent an infinite loop when applying this operation.
Expand All @@ -49,7 +55,7 @@ export function sync(db: Database<any>) {
// Apply the database operation signaled from another client
// to the current database instance.
// @ts-ignore
db[operationType](...payload)
db[operationType](...args)

// Re-attach database event listeners.
restoreListeners()
Expand Down
15 changes: 15 additions & 0 deletions test/extensions/sync.multiple.runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { factory, primaryKey } from '@mswjs/data'

window.db = factory({
user: {
id: primaryKey(String),
firstName: String,
},
})

window.secondDb = factory({
user: {
id: primaryKey(String),
firstName: String,
},
})
119 changes: 99 additions & 20 deletions test/extensions/sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import * as path from 'path'
import { createBrowser, CreateBrowserApi, pageWith } from 'page-with'
import { FactoryAPI } from '../../src/glossary'

interface User {
id: string
firstName: string
}

declare namespace window {
export const db: FactoryAPI<any>
export const db: FactoryAPI<{ user: User }>
export const secondDb: FactoryAPI<{ user: User }>
}

let browser: CreateBrowserApi
Expand Down Expand Up @@ -41,10 +47,7 @@ test('synchornizes entity create across multiple clients', async () => {
})
})

const users = await secondPage.evaluate(() => {
return window.db.user.getAll()
})
expect(users).toEqual([
expect(await secondPage.evaluate(() => window.db.user.getAll())).toEqual([
{
__type: 'user',
__primaryKey: 'id',
Expand Down Expand Up @@ -90,15 +93,12 @@ test('synchornizes entity update across multiple clients', async () => {
firstName: 'Kate',
},
]
const users = await secondPage.evaluate(() => {
return window.db.user.getAll()
})
expect(users).toEqual(expectedUsers)

const extraneousUsers = await runtime.page.evaluate(() => {
return window.db.user.getAll()
})
expect(extraneousUsers).toEqual(expectedUsers)
expect(await secondPage.evaluate(() => window.db.user.getAll())).toEqual(
expectedUsers,
)
expect(await runtime.page.evaluate(() => window.db.user.getAll())).toEqual(
expectedUsers,
)
})

test('synchronizes entity delete across multiple clients', async () => {
Expand Down Expand Up @@ -126,13 +126,92 @@ test('synchronizes entity delete across multiple clients', async () => {
})
})

const users = await secondPage.evaluate(() => {
return window.db.user.getAll()
expect(await secondPage.evaluate(() => window.db.user.getAll())).toEqual([])
expect(await runtime.page.evaluate(() => window.db.user.getAll())).toEqual([])
})

test('handles events from multiple database instances separately', async () => {
const runtime = await pageWith({
example: path.resolve(__dirname, 'sync.multiple.runtime.js'),
})
const secondPage = await runtime.context.newPage()
await secondPage.goto(runtime.origin)
await runtime.page.bringToFront()

const john = {
__type: 'user',
__primaryKey: 'id',
id: 'abc-123',
firstName: 'John',
}

const kate = {
__type: 'user',
__primaryKey: 'id',
id: 'def-456',
firstName: 'Kate',
}

// Create a new user in the first database.
await runtime.page.evaluate(() => {
window.db.user.create({ id: 'abc-123', firstName: 'John' })
})
expect(await runtime.page.evaluate(() => window.db.user.getAll())).toEqual([
john,
])
expect(await secondPage.evaluate(() => window.db.user.getAll())).toEqual([
john,
])

// No entities are created in the second, unrelated database.
expect(
await secondPage.evaluate(() => {
return window.secondDb.user.getAll()
}),
).toEqual([])

await secondPage.evaluate(() => {
window.secondDb.user.create({ id: 'def-456', firstName: 'Kate' })
})

// A new entity created in a different database is synchronized in another client.
expect(
await runtime.page.evaluate(() => window.secondDb.user.getAll()),
).toEqual([kate])

// An unrelated database does not contain a newly created entity.
expect(await runtime.page.evaluate(() => window.db.user.getAll())).toEqual([
john,
])
})

test('handles events from multiple databases on different hostnames', async () => {
const firstRuntime = await pageWith({
example: path.resolve(__dirname, 'sync.runtime.js'),
})
const secondRuntime = await pageWith({
example: path.resolve(__dirname, 'sync.multiple.runtime.js'),
})
expect(users).toEqual([])
expect(firstRuntime.origin).not.toEqual(secondRuntime.origin)

const extraneousUsers = await runtime.page.evaluate(() => {
return window.db.user.getAll()
await firstRuntime.page.evaluate(() => {
window.db.user.create({ id: 'abc-123', firstName: 'John' })
})
expect(extraneousUsers).toEqual([])
expect(
await secondRuntime.page.evaluate(() => window.db.user.getAll()),
).toEqual([])

await secondRuntime.page.evaluate(() => {
window.db.user.create({ id: 'def-456', firstName: 'Kate' })
})
expect(
await firstRuntime.page.evaluate(() => window.db.user.getAll()),
).toEqual([
{
__type: 'user',
__primaryKey: 'id',
id: 'abc-123',
firstName: 'John',
},
])
})

0 comments on commit b05a39f

Please sign in to comment.