Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 97 additions & 20 deletions addons/dexie-cloud/test/unit/tests-github-issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,68 @@ 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
});
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
*
* Here are the steps to reproduce the issue:
Expand All @@ -41,36 +99,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);
});
Comment on lines +107 to 111
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix transaction table access

Dexie.Transaction doesn’t expose tables as direct properties, so tx.items2185/tx.members/tx.realms are undefined. The first call to tx.items2185.clear() throws, breaking both the initial cleanup and the final cleanup for this test. Use the already-bound table instances from db (or tx.table('items2185')) instead.

-  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.transaction('rw', db.items2185, db.members, db.realms, () => {
+    db.items2185.clear();
+    db.members.where({ realmId: REALM_ID }).delete();
+    db.realms.delete(REALM_ID);
   });
@@
-  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.transaction('rw', db.items2185, db.members, db.realms, () => {
+    db.items2185.clear();
+    db.members.where({ realmId: REALM_ID }).delete();
+    db.realms.delete(REALM_ID);
   });

Also applies to: 169-173

🤖 Prompt for AI Agents
In addons/dexie-cloud/test/unit/tests-github-issues.ts around lines 102-106 (and
similarly at 169-173), the transaction callback incorrectly accesses tables via
tx.items2185/tx.members/tx.realms which are undefined; use the already-bound db
table instances or tx.table('tableName') instead. Update the transaction to call
operations on db.items2185, db.members.where(...).delete(), and
db.realms.delete(REALM_ID) (or replace each tx.X with tx.table('X')) so the
transaction uses valid Table objects and no longer throws on the first access.

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 });
});

Expand Down Expand Up @@ -99,23 +166,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<T>(...props: (keyof T)[]): (obj: T) => Omit<T, keyof T> {
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) => {
Expand All @@ -128,4 +206,3 @@ function strip(...props: string[]) {
return newObj;
};
}