From f5509f8384e6b42e4d86f028f4341177ae216e99 Mon Sep 17 00:00:00 2001 From: David Fahlander Date: Mon, 25 Aug 2025 21:18:01 +0200 Subject: [PATCH 1/2] Repro of #1922 --- .../test/unit/tests-github-issues.ts | 112 ++++++++++++++---- 1 file changed, 92 insertions(+), 20 deletions(-) diff --git a/addons/dexie-cloud/test/unit/tests-github-issues.ts b/addons/dexie-cloud/test/unit/tests-github-issues.ts index 3ac5fc78b..a80f496d7 100644 --- a/addons/dexie-cloud/test/unit/tests-github-issues.ts +++ b/addons/dexie-cloud/test/unit/tests-github-issues.ts @@ -11,10 +11,63 @@ import { } from 'qunit'; import { promisedTest } from '../promisedTest'; import Dexie from 'dexie'; -import dexieCloud, { DexieCloudOptions, DexieCloudTable, getTiedRealmId } from '../../src/dexie-cloud-client'; +import dexieCloud, { DexieCloudTable } from '../../src/dexie-cloud-client'; module('github-issues'); +const DEXIE_CLOUD_PROPS = ['owner', 'realmId', '$ts'] as const; + +/** Dexie issue #1922 (https://github.com/dexie/Dexie.js/issues/1922) + * + */ +promisedTest('https://github.com/dexie/Dexie.js/issues/1922', async () => { + const db = new Dexie('issue1922', { addons: [dexieCloud] }) as Dexie & { + items1922: DexieCloudTable< + { id: string; bookId: string; tags: string[] }, + 'id' + >; + }; + db.version(1).stores({ items1922: '@id, bookid, *tags' }); + db.cloud.configure({ + databaseUrl: 'https://zv8n7bwcs.dexie.cloud', + requireAuth: { email: 'foo@demo.local', grant_type: 'demo' }, + disableEagerSync: true, // Let us manually sync them + }); + await db.open(); + ok(true, 'DB opened and synced successfully'); + await db.items1922.clear(); + ok(true, 'Items cleared successfully'); + let primKeys = await db.items1922.bulkAdd( + [ + { bookId: 'book1', tags: ['tag1', 'tag2'] }, + { bookId: 'book2', tags: ['tag2', 'tag3'] }, + ], + { allKeys: true } + ); + await db.cloud.sync(); + ok(true, 'Items added and synced successfully'); + await db.items1922.where('tags').equals('tag1').modify({ bookId: 'book3' }); + let itemsBeforeSync = await db.items1922.toArray(); + deepEqual( + itemsBeforeSync.map(strip(...DEXIE_CLOUD_PROPS)), + [ + { id: primKeys[0], bookId: 'book3', tags: ['tag1', 'tag2'] }, + { id: primKeys[1], bookId: 'book2', tags: ['tag2', 'tag3'] }, + ], + 'Items before sync' + ); + await db.cloud.sync(); + let itemsAfterSync = await db.items1922.toArray(); + deepEqual( + itemsAfterSync.map(strip(...DEXIE_CLOUD_PROPS)), + [ + { id: primKeys[0], bookId: 'book3', tags: ['tag1', 'tag2'] }, + { id: primKeys[1], bookId: 'book2', tags: ['tag2', 'tag3'] }, + ], + 'Items after sync' + ); +}); + /** Dexie issue #2185 * * Here are the steps to reproduce the issue: @@ -41,36 +94,45 @@ promisedTest('https://github.com/dexie/Dexie.js/issues/2185', async () => { db.version(1).stores({ items2185: '@id, name' }); db.cloud.configure({ databaseUrl: DBURL, - requireAuth: { email: DEMOUSER1, grant_type: 'demo' } + requireAuth: { email: DEMOUSER1, grant_type: 'demo' }, }); await db.open(); ok(true, 'DB opened and synced successfully'); // Clear any existing data - await db.transaction('rw', db.items2185, db.members, db.realms, tx => { + await db.transaction('rw', db.items2185, db.members, db.realms, (tx) => { tx.items2185.clear(); tx.members.where({ realmId: REALM_ID }).delete(); tx.realms.delete(REALM_ID); }); ok(true, 'Existing data cleared successfully'); - await db.cloud.sync({purpose: 'push', wait: true }); - ok(true, 'Cloud sync completed successfully. Now ready to execute the test steps'); - + await db.cloud.sync({ purpose: 'push', wait: true }); + ok( + true, + 'Cloud sync completed successfully. Now ready to execute the test steps' + ); + // 1. Add `item1` const item1Id = await db.items2185.add({ name: 'Item 1' }); // 2. Add `item2` const item2Id = await db.items2185.add({ name: 'Item 2' }); // 3. Share `item2` with another user await db.transaction('rw', db.items2185, db.members, db.realms, async () => { - const realmId = await db.realms.add({ name: 'Test Realm', realmId: REALM_ID }); - db.members.bulkAdd([{ - realmId, - email: DEMOUSER1, - permissions: { manage: '*' } - },{ - realmId, - email: DEMOUSER2, - permissions: { manage: '*' } - }]); + const realmId = await db.realms.add({ + name: 'Test Realm', + realmId: REALM_ID, + }); + db.members.bulkAdd([ + { + realmId, + email: DEMOUSER1, + permissions: { manage: '*' }, + }, + { + realmId, + email: DEMOUSER2, + permissions: { manage: '*' }, + }, + ]); db.items2185.update(item2Id, { realmId }); }); @@ -99,23 +161,34 @@ promisedTest('https://github.com/dexie/Dexie.js/issues/2185', async () => { items = await db.items2185.toArray(); equal(items.length, 2, 'Two items imported successfully'); // 8. The subsequent sync must not remove them again. - await db.cloud.sync({purpose: 'push', wait: true }); + await db.cloud.sync({ purpose: 'push', wait: true }); const itemsAfterSync = await db.items2185.toArray(); equal(itemsAfterSync.length, 2, 'Items NOT removed after sync'); // Clean up - await db.transaction('rw', db.items2185, db.members, db.realms, tx => { + await db.transaction('rw', db.items2185, db.members, db.realms, (tx) => { tx.items2185.clear(); tx.members.where({ realmId: REALM_ID }).delete(); tx.realms.delete(REALM_ID); }); - await db.cloud.sync({purpose: 'push', wait: true }); + await db.cloud.sync({ purpose: 'push', wait: true }); ok(true, 'Test completed successfully'); db.close(); await Dexie.delete(DBNAME); console.log('Database deleted successfully'); }); +/*function strip(...props: (keyof T)[]): (obj: T) => Omit { + return (obj: T) => { + const newObj: any = {}; + for (const key in obj) { + if (!props.includes(key as keyof T)) { + newObj[key] = obj[key]; + } + } + return newObj; + }; +}*/ function strip(...props: string[]) { return (obj: any) => { @@ -128,4 +201,3 @@ function strip(...props: string[]) { return newObj; }; } - From 4d4dd7150f36f2f1249a9f5ce32799276dc259e0 Mon Sep 17 00:00:00 2001 From: David Fahlander Date: Sat, 1 Nov 2025 16:23:56 +0100 Subject: [PATCH 2/2] Cleanup and sync to restore state after the repro of 1922 --- .../test/unit/tests-github-issues.ts | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/addons/dexie-cloud/test/unit/tests-github-issues.ts b/addons/dexie-cloud/test/unit/tests-github-issues.ts index a80f496d7..fd2e39d4d 100644 --- a/addons/dexie-cloud/test/unit/tests-github-issues.ts +++ b/addons/dexie-cloud/test/unit/tests-github-issues.ts @@ -33,39 +33,44 @@ promisedTest('https://github.com/dexie/Dexie.js/issues/1922', async () => { requireAuth: { email: 'foo@demo.local', grant_type: 'demo' }, disableEagerSync: true, // Let us manually sync them }); - await db.open(); - ok(true, 'DB opened and synced successfully'); - await db.items1922.clear(); - ok(true, 'Items cleared successfully'); - let primKeys = await db.items1922.bulkAdd( - [ - { bookId: 'book1', tags: ['tag1', 'tag2'] }, - { bookId: 'book2', tags: ['tag2', 'tag3'] }, - ], - { allKeys: true } - ); - await db.cloud.sync(); - ok(true, 'Items added and synced successfully'); - await db.items1922.where('tags').equals('tag1').modify({ bookId: 'book3' }); - let itemsBeforeSync = await db.items1922.toArray(); - deepEqual( - itemsBeforeSync.map(strip(...DEXIE_CLOUD_PROPS)), - [ - { id: primKeys[0], bookId: 'book3', tags: ['tag1', 'tag2'] }, - { id: primKeys[1], bookId: 'book2', tags: ['tag2', 'tag3'] }, - ], - 'Items before sync' - ); - await db.cloud.sync(); - let itemsAfterSync = await db.items1922.toArray(); - deepEqual( - itemsAfterSync.map(strip(...DEXIE_CLOUD_PROPS)), - [ - { id: primKeys[0], bookId: 'book3', tags: ['tag1', 'tag2'] }, - { id: primKeys[1], bookId: 'book2', tags: ['tag2', 'tag3'] }, - ], - 'Items after sync' - ); + try { + await db.open(); + ok(true, 'DB opened and synced successfully'); + await db.items1922.clear(); + ok(true, 'Items cleared successfully'); + let primKeys = await db.items1922.bulkAdd( + [ + { bookId: 'book1', tags: ['tag1', 'tag2'] }, + { bookId: 'book2', tags: ['tag2', 'tag3'] }, + ], + { allKeys: true } + ); + await db.cloud.sync(); + ok(true, 'Items added and synced successfully'); + await db.items1922.where('tags').equals('tag1').modify({ bookId: 'book3' }); + let itemsBeforeSync = await db.items1922.toArray(); + deepEqual( + itemsBeforeSync.map(strip(...DEXIE_CLOUD_PROPS)), + [ + { id: primKeys[0], bookId: 'book3', tags: ['tag1', 'tag2'] }, + { id: primKeys[1], bookId: 'book2', tags: ['tag2', 'tag3'] }, + ], + 'Items before sync' + ); + await db.cloud.sync(); + let itemsAfterSync = await db.items1922.toArray(); + deepEqual( + itemsAfterSync.map(strip(...DEXIE_CLOUD_PROPS)), + [ + { id: primKeys[0], bookId: 'book3', tags: ['tag1', 'tag2'] }, + { id: primKeys[1], bookId: 'book2', tags: ['tag2', 'tag3'] }, + ], + 'Items after sync' + ); + } finally { + await db.items1922.clear(); + await db.cloud.sync(); + } }); /** Dexie issue #2185