mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
211 lines
5.6 KiB
TypeScript
211 lines
5.6 KiB
TypeScript
import { ModelType } from '../../BaseModel';
|
|
import { UserData } from '../../services/database/types';
|
|
import { msleep, setupDatabaseAndSynchronizer, switchClient } from '../../testing/test-utils';
|
|
import Folder from '../Folder';
|
|
import Note from '../Note';
|
|
import Resource from '../Resource';
|
|
import Tag from '../Tag';
|
|
import { LoadOptions } from './types';
|
|
import { deleteItemUserData, deleteNoteUserData, getItemUserData, getNoteUserData, mergeUserData, setItemUserData, setNoteUserData } from './userData';
|
|
|
|
const loadOptions: LoadOptions = { fields: ['id', 'parent_id', 'user_data', 'updated_time'] };
|
|
|
|
describe('utils/userData', () => {
|
|
|
|
beforeEach(async () => {
|
|
await setupDatabaseAndSynchronizer(1);
|
|
await switchClient(1);
|
|
});
|
|
|
|
it('should set and get user data on a note', async () => {
|
|
const folder = await Folder.save({});
|
|
let note = await Note.save({ parent_id: folder.id });
|
|
note = await Note.load(note.id, loadOptions);
|
|
await msleep(5);
|
|
await setNoteUserData(note, 'org.joplin', 'my-key', 'something');
|
|
|
|
const noteReloaded = await Note.load(note.id);
|
|
expect(await getNoteUserData(noteReloaded, 'org.joplin', 'my-key')).toBe('something');
|
|
|
|
// Check that the updated_time has been updated (for sync purposes), but
|
|
// not the user_updated_time.
|
|
expect(noteReloaded.updated_time).toBeGreaterThan(note.updated_time);
|
|
expect(noteReloaded.user_updated_time).toBe(note.updated_time);
|
|
|
|
// Check for non-existing props
|
|
expect(await getNoteUserData(noteReloaded, 'org.doesntexist', 'my-key')).toBe(undefined);
|
|
expect(await getNoteUserData(noteReloaded, 'org.joplin', 'doesntexist')).toBe(undefined);
|
|
});
|
|
|
|
it('should set and get user data on any item', async () => {
|
|
const folder = await Folder.save({});
|
|
const tag = await Tag.save({});
|
|
const resource = await Resource.save({ mime: 'plain/text' });
|
|
|
|
await setItemUserData(ModelType.Folder, folder.id, 'foldertest', 'folderkey', 123);
|
|
expect(await getItemUserData(ModelType.Folder, folder.id, 'foldertest', 'folderkey')).toBe(123);
|
|
await deleteItemUserData(ModelType.Folder, folder.id, 'foldertest', 'folderkey');
|
|
expect(await getItemUserData(ModelType.Folder, folder.id, 'foldertest', 'folderkey')).toBe(undefined);
|
|
|
|
await setItemUserData(ModelType.Tag, tag.id, 'tagtest', 'tagkey', 123);
|
|
expect(await getItemUserData(ModelType.Tag, tag.id, 'tagtest', 'tagkey')).toBe(123);
|
|
await deleteItemUserData(ModelType.Tag, tag.id, 'tagtest', 'tagkey');
|
|
expect(await getItemUserData(ModelType.Tag, tag.id, 'tagtest', 'tagkey')).toBe(undefined);
|
|
|
|
await setItemUserData(ModelType.Resource, resource.id, 'resourcetest', 'resourcekey', 123);
|
|
expect(await getItemUserData(ModelType.Resource, resource.id, 'resourcetest', 'resourcekey')).toBe(123);
|
|
await deleteItemUserData(ModelType.Resource, resource.id, 'resourcetest', 'resourcekey');
|
|
expect(await getItemUserData(ModelType.Resource, resource.id, 'resourcetest', 'resourcekey')).toBe(undefined);
|
|
});
|
|
|
|
it('should delete user data', async () => {
|
|
const folder = await Folder.save({});
|
|
let note = await Note.save({ parent_id: folder.id });
|
|
note = await Note.load(note.id, loadOptions);
|
|
await setNoteUserData(note, 'org.joplin', 'my-key', 'something');
|
|
|
|
let noteReloaded = await Note.load(note.id);
|
|
expect(await getNoteUserData(noteReloaded, 'org.joplin', 'my-key')).toBe('something');
|
|
|
|
noteReloaded = await deleteNoteUserData(noteReloaded, 'org.joplin', 'my-key');
|
|
expect(await getNoteUserData(noteReloaded, 'org.joplin', 'my-key')).toBe(undefined);
|
|
|
|
// Check that it works if we set it again
|
|
await setNoteUserData(note, 'org.joplin', 'my-key', 'something else');
|
|
noteReloaded = await Note.load(noteReloaded.id, loadOptions);
|
|
expect(await getNoteUserData(noteReloaded, 'org.joplin', 'my-key')).toBe('something else');
|
|
});
|
|
|
|
it('should merge user data', async () => {
|
|
const testCases: [UserData, UserData, UserData][] = [
|
|
[
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 123,
|
|
t: 0,
|
|
},
|
|
'k3': {
|
|
v: 789,
|
|
t: 5,
|
|
},
|
|
'k4': {
|
|
v: 789,
|
|
t: 5,
|
|
},
|
|
},
|
|
'com.example': {},
|
|
},
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 456,
|
|
t: 1,
|
|
},
|
|
'k2': {
|
|
v: 'abc',
|
|
t: 5,
|
|
},
|
|
'k4': {
|
|
v: 111,
|
|
t: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 456,
|
|
t: 1,
|
|
},
|
|
'k2': {
|
|
v: 'abc',
|
|
t: 5,
|
|
},
|
|
'k3': {
|
|
v: 789,
|
|
t: 5,
|
|
},
|
|
'k4': {
|
|
v: 789,
|
|
t: 5,
|
|
},
|
|
},
|
|
'com.example': {},
|
|
},
|
|
],
|
|
|
|
[
|
|
// Client 2 delete a prop
|
|
// Later, client 1 update that prop
|
|
// Then data is merged
|
|
// => In that case, the data is restored using client 1 data
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 123,
|
|
t: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 0,
|
|
t: 0,
|
|
d: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 123,
|
|
t: 10,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
|
|
[
|
|
// Client 1 update a prop
|
|
// Later, client 2 delete a prop
|
|
// Then data is merged
|
|
// => In that case, the data is deleted and the update from client 1 is lost
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 123,
|
|
t: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 0,
|
|
t: 10,
|
|
d: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
'org.joplin': {
|
|
'k1': {
|
|
v: 0,
|
|
t: 10,
|
|
d: 1,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
];
|
|
|
|
for (const [target, source, expected] of testCases) {
|
|
const actual = mergeUserData(target, source);
|
|
expect(actual).toEqual(expected);
|
|
}
|
|
});
|
|
|
|
});
|