1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00

All: Fixes #13531: When creating a conflict, ensure the latest note contents are used to create the conflict (#13552)

This commit is contained in:
mrjo118
2025-11-03 19:21:05 +00:00
committed by GitHub
parent 2c4f0d4d8c
commit 4a17da3df5
4 changed files with 74 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
import BaseItem from '../../models/BaseItem';
import Note from '../../models/Note';
import { setupDatabaseAndSynchronizer, switchClient } from '../../testing/test-utils';
import handleConflictAction from './utils/handleConflictAction';
import { SyncAction } from './utils/types';
describe('handleConflictAction', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
});
test('note conflict is created', async () => {
const local = await Note.save({ title: 'Test', body: 'body' });
// Pass the local note with unsaved changes to verify that the note is reloaded before creating the conflict
const changedLocal = { ...local, title: 'TestChanged' };
const remoteContent = { ...local, title: 'TestRemote' };
const initialSyncItem = await BaseItem.syncItem(1, local.id);
await handleConflictAction(
SyncAction.NoteConflict,
Note,
true,
remoteContent,
changedLocal,
1,
false,
(action) => (action),
);
const createdSyncItem = await BaseItem.syncItem(1, local.id);
const updatedLocal = await Note.load(local.id);
const notes = await Note.all();
const conflictNote = await Note.loadByTitle('Test');
expect(initialSyncItem).toBeUndefined();
expect(createdSyncItem).toBeDefined();
expect(updatedLocal.title).toBe('TestRemote');
expect(notes.length).toBe(2);
expect(conflictNote.id).not.toBe(local.id);
});
test('note conflict is not created when remote and local contents match', async () => {
const local = await Note.save({ title: 'Test', body: 'body' });
// Pass the local note with unsaved changes to verify that the note is reloaded before checking if eligible to create a conflict
const changedLocal = { ...local, title: 'TestChanged' };
const remoteContent = local;
const initialSyncItem = await BaseItem.syncItem(1, local.id);
await handleConflictAction(
SyncAction.NoteConflict,
Note,
true,
remoteContent,
changedLocal,
1,
false,
(action) => (action),
);
const createdSyncItem = await BaseItem.syncItem(1, local.id);
const notes = await Note.all();
expect(initialSyncItem).toBeUndefined();
expect(createdSyncItem).toBeDefined();
expect(notes.length).toBe(1);
});
});

View File

@@ -38,6 +38,9 @@ export default async (action: SyncAction, ItemClass: typeof BaseItem, remoteExis
});
}
} else if (action === SyncAction.NoteConflict) {
// Reload the note, to ensure the latest version is used to create the conflict
local = await Note.load(local.id);
// ------------------------------------------------------------------------------
// First find out if the conflict matters. For example, if the conflict is on the title or body
// we want to preserve all the changes. If it's on todo_completed it doesn't really matter