633 lines
21 KiB
JavaScript
633 lines
21 KiB
JavaScript
import '../../dist/javascripts/compiled.js';
|
|
import '../../node_modules/chai/chai.js';
|
|
import './vendor/chai-as-promised-built.js';
|
|
import '../../vendor/assets/javascripts/lodash/lodash.custom.js';
|
|
import Factory from './lib/factory.js';
|
|
|
|
chai.use(chaiAsPromised);
|
|
var expect = chai.expect;
|
|
|
|
const getNoteParams = () => {
|
|
var params = {
|
|
uuid: SFJS.crypto.generateUUIDSync(),
|
|
content_type: "Note",
|
|
content: {
|
|
title: "hello",
|
|
text: "world"
|
|
}
|
|
};
|
|
return params;
|
|
}
|
|
|
|
const createRelatedNoteTagPair = () => {
|
|
let noteParams = getNoteParams();
|
|
let tagParams = {
|
|
uuid: SFJS.crypto.generateUUIDSync(),
|
|
content_type: "Tag",
|
|
content: {
|
|
title: "thoughts",
|
|
}
|
|
};
|
|
tagParams.content.references = [
|
|
{
|
|
uuid: noteParams.uuid,
|
|
content_type: noteParams.content_type
|
|
}
|
|
]
|
|
|
|
noteParams.content.references = []
|
|
|
|
return [noteParams, tagParams];
|
|
}
|
|
describe("notes and tags", () => {
|
|
|
|
it('uses proper class for note', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
let noteParams = getNoteParams();
|
|
modelManager.mapResponseItemsToLocalModels([noteParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
expect(note).to.be.an.instanceOf(SNNote);
|
|
});
|
|
|
|
it('properly constructs syncing params', () => {
|
|
let note = new SNNote();
|
|
let title = "Foo", text = "Bar";
|
|
note.title = title;
|
|
note.text = text;
|
|
|
|
let content = note.createContentJSONFromProperties();
|
|
expect(content.title).to.equal(title);
|
|
expect(content.text).to.equal(text);
|
|
|
|
let tag = new SNTag();
|
|
tag.title = title;
|
|
|
|
expect(tag.createContentJSONFromProperties().title).to.equal(title);
|
|
|
|
expect(tag.structureParams().title).to.equal(tag.getContentCopy().title);
|
|
})
|
|
|
|
it('properly handles legacy relationships', () => {
|
|
// legacy relationships are when a note has a reference to a tag
|
|
let modelManager = Factory.createModelManager();
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
tagParams.content.references = null;
|
|
noteParams.content.references = [
|
|
{
|
|
uuid: tagParams.uuid,
|
|
content_type: tagParams.content_type
|
|
}
|
|
];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(note.tags.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
})
|
|
|
|
it('creates two-way relationship between note and tag', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
expect(noteParams.content.references.length).to.equal(0);
|
|
expect(tagParams.content.references.length).to.equal(1);
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
// expect to be false
|
|
expect(note.dirty).to.not.be.ok;
|
|
expect(tag.dirty).to.not.be.ok;
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(tag.content.references.length).to.equal(1);
|
|
|
|
expect(note.hasRelationshipWithItem(tag)).to.equal(false);
|
|
expect(tag.hasRelationshipWithItem(note)).to.equal(true);
|
|
|
|
expect(note.tags.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
|
|
modelManager.setItemToBeDeleted(note);
|
|
expect(note.tags.length).to.equal(0);
|
|
expect(tag.notes.length).to.equal(0);
|
|
|
|
// expect to be true
|
|
expect(note.dirty).to.be.ok;
|
|
expect(tag.dirty).to.be.ok;
|
|
});
|
|
|
|
it('handles remote deletion of relationship', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(tag.content.references.length).to.equal(1);
|
|
|
|
tagParams.content.references = [];
|
|
modelManager.mapResponseItemsToLocalModels([tagParams]);
|
|
|
|
expect(tag.content.references.length).to.equal(0);
|
|
expect(note.tags.length).to.equal(0);
|
|
expect(tag.notes.length).to.equal(0);
|
|
|
|
// expect to be false
|
|
expect(note.dirty).to.not.be.ok;
|
|
expect(tag.dirty).to.not.be.ok;
|
|
});
|
|
|
|
it('resets cached note tags string when tag is deleted from remote source', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(note.tagsString().length).to.not.equal(0);
|
|
|
|
tagParams.deleted = true;
|
|
modelManager.mapResponseItemsToLocalModels([tagParams]);
|
|
|
|
// should be null
|
|
expect(note.savedTagsString).to.not.be.ok;
|
|
|
|
expect(note.tags.length).to.equal(0);
|
|
expect(tag.notes.length).to.equal(0);
|
|
});
|
|
|
|
it('resets cached note tags string when tag reference is removed from remote source', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(note.tagsString().length).to.not.equal(0);
|
|
|
|
tagParams.content.references = [];
|
|
modelManager.mapResponseItemsToLocalModels([tagParams]);
|
|
|
|
// should be null
|
|
expect(note.savedTagsString).to.not.be.ok;
|
|
|
|
expect(note.tags.length).to.equal(0);
|
|
expect(tag.notes.length).to.equal(0);
|
|
});
|
|
|
|
it('resets cached note tags string when tag is renamed', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(note.tagsString()).to.equal(`#${tagParams.content.title}`);
|
|
|
|
var title = Math.random();
|
|
|
|
// Saving involves modifying local state first, then syncing with omitting content.
|
|
tag.title = title;
|
|
tagParams.content.title = title;
|
|
// simulate a save, which omits `content`
|
|
modelManager.mapResponseItemsToLocalModelsOmittingFields([tagParams], ['content']);
|
|
|
|
// should be null
|
|
expect(note.savedTagsString).to.not.be.ok;
|
|
expect(note.tagsString()).to.equal(`#${title}`);
|
|
});
|
|
|
|
it('handles removing relationship between note and tag', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(tag.content.references.length).to.equal(1);
|
|
|
|
tag.removeItemAsRelationship(note);
|
|
modelManager.mapResponseItemsToLocalModels([tag]);
|
|
|
|
expect(note.tags.length).to.equal(0);
|
|
expect(tag.notes.length).to.equal(0);
|
|
});
|
|
|
|
it('properly handles tag duplication', async () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
// Usually content_type will be provided by a server response
|
|
var duplicateParams = _.merge({content_type: "Tag"}, tag);
|
|
duplicateParams.uuid = null;
|
|
|
|
expect(duplicateParams.content_type).to.equal("Tag");
|
|
var duplicateTag = await modelManager.createConflictedItem(duplicateParams);
|
|
modelManager.addConflictedItem(duplicateTag, tag);
|
|
|
|
expect(tag.uuid).to.not.equal(duplicateTag.uuid);
|
|
|
|
expect(tag.content.references.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
|
|
expect(duplicateTag.content.references.length).to.equal(1);
|
|
expect(duplicateTag.notes.length).to.equal(1);
|
|
|
|
expect(note.tags.length).to.equal(2);
|
|
|
|
var noteTag1 = note.tags[0];
|
|
var noteTag2 = note.tags[1];
|
|
expect(noteTag1.uuid).to.not.equal(noteTag2.uuid);
|
|
|
|
// expect to be false
|
|
expect(note.dirty).to.not.be.ok;
|
|
expect(tag.dirty).to.not.be.ok;
|
|
});
|
|
|
|
it('duplicating a note should maintain its tag references', async () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
// Usually content_type will be provided by a server response
|
|
var duplicateParams = _.merge({content_type: "Note"}, note);
|
|
duplicateParams.uuid = null;
|
|
|
|
var duplicateNote = await modelManager.createConflictedItem(duplicateParams);
|
|
modelManager.addConflictedItem(duplicateNote, note);
|
|
|
|
expect(note.uuid).to.not.equal(duplicateNote.uuid);
|
|
|
|
expect(duplicateNote.tags.length).to.equal(note.tags.length);
|
|
});
|
|
|
|
it('deleting a note should update tag references', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(tag.content.references.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(note.tags.length).to.equal(1);
|
|
|
|
modelManager.setItemToBeDeleted(tag);
|
|
modelManager.mapResponseItemsToLocalModels([tag]);
|
|
expect(tag.content.references.length).to.equal(0);
|
|
expect(tag.notes.length).to.equal(0);
|
|
});
|
|
|
|
it('importing existing data should keep relationships valid', () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(tag.content.references.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(note.tags.length).to.equal(1);
|
|
|
|
modelManager.importItems([noteParams, tagParams]);
|
|
|
|
expect(modelManager.allItems.length).to.equal(2);
|
|
|
|
expect(tag.content.references.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(note.referencingObjects.length).to.equal(1);
|
|
expect(note.tags.length).to.equal(1);
|
|
});
|
|
|
|
it('importing data with differing content should create duplicates', async () => {
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
noteParams.content.title = Math.random();
|
|
tagParams.content.title = Math.random();
|
|
await modelManager.importItems([noteParams, tagParams]);
|
|
|
|
expect(modelManager.allItems.length).to.equal(4);
|
|
|
|
var newNote = modelManager.allItemsMatchingTypes(["Note"])[1];
|
|
var newTag = modelManager.allItemsMatchingTypes(["Tag"])[1];
|
|
|
|
expect(newNote.uuid).to.not.equal(note.uuid);
|
|
expect(newTag.uuid).to.not.equal(tag.uuid);
|
|
|
|
expect(tag.content.references.length).to.equal(2);
|
|
expect(tag.notes.length).to.equal(2);
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(note.referencingObjects.length).to.equal(2);
|
|
expect(note.tags.length).to.equal(2);
|
|
|
|
expect(newTag.content.references.length).to.equal(1);
|
|
expect(newTag.notes.length).to.equal(1);
|
|
|
|
expect(newNote.content.references.length).to.equal(0);
|
|
expect(newNote.referencingObjects.length).to.equal(1);
|
|
expect(newNote.tags.length).to.equal(1);
|
|
});
|
|
|
|
it('deleting a tag from a note with bi-directional relationship', () => {
|
|
// Tags now reference notes, but it used to be that tags referenced notes and notes referenced tags.
|
|
// After the change, there was an issue where removing an old tag relationship from a note would only
|
|
// remove one way, and thus keep it intact on the visual level.
|
|
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
noteParams.content.references = [{
|
|
content_type: tagParams.content_type,
|
|
uuid: tagParams.uuid
|
|
}]
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(tag.notes.length).to.equal(1);
|
|
expect(note.tags.length).to.equal(1);
|
|
|
|
tag.removeItemAsRelationship(note);
|
|
|
|
expect(tag.notes.length).to.equal(0);
|
|
expect(note.tags.length).to.equal(0);
|
|
|
|
expect(note.content.references.length).to.equal(0);
|
|
expect(tag.content.references.length).to.equal(0);
|
|
});
|
|
|
|
it('deleting a tag should not dirty notes', () => {
|
|
// Tags now reference notes, but it used to be that tags referenced notes and notes referenced tags.
|
|
// After the change, there was an issue where removing an old tag relationship from a note would only
|
|
// remove one way, and thus keep it intact on the visual level.
|
|
|
|
let modelManager = Factory.createModelManager();
|
|
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
modelManager.setItemToBeDeleted(tag);
|
|
|
|
expect(tag.dirty).to.equal(true);
|
|
expect(note.dirty).to.not.be.ok;
|
|
})
|
|
});
|
|
|
|
describe("syncing", () => {
|
|
var totalItemCount = 0;
|
|
|
|
beforeEach((done) => {
|
|
var email = Factory.globalStandardFile().crypto.generateUUIDSync();
|
|
var password = Factory.globalStandardFile().crypto.generateUUIDSync();
|
|
Factory.globalStorageManager().clearAllData().then(() => {
|
|
Factory.newRegisteredUser(email, password).then((user) => {
|
|
done();
|
|
})
|
|
})
|
|
})
|
|
|
|
let modelManager = Factory.createModelManager();
|
|
let authManager = Factory.globalAuthManager();
|
|
let syncManager = new SFSyncManager(modelManager, Factory.globalStorageManager(), Factory.globalHttpManager());
|
|
|
|
syncManager.setKeyRequestHandler(async () => {
|
|
return {
|
|
keys: await authManager.keys(),
|
|
auth_params: await authManager.getAuthParams(),
|
|
offline: false
|
|
};
|
|
})
|
|
|
|
const wait = (secs) => {
|
|
return new Promise((resolve, reject) => {
|
|
setTimeout(function () {
|
|
resolve();
|
|
}, secs * 1000);
|
|
})
|
|
}
|
|
|
|
it.only('syncing a note should collapse its properties into the content object after sync', async () => {
|
|
let note = new SNNote();
|
|
note.title = "Foo";
|
|
note.setDirty(true);
|
|
modelManager.addItem(note);
|
|
|
|
expect(note.content.title).to.not.be.ok;
|
|
|
|
await syncManager.sync();
|
|
|
|
expect(note.content.title).to.equal("Foo");
|
|
});
|
|
|
|
it('syncing a note many times does not cause duplication', async () => {
|
|
modelManager.handleSignout();
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
for(var i = 0; i < 9; i++) {
|
|
note.setDirty(true);
|
|
tag.setDirty(true);
|
|
await syncManager.sync();
|
|
syncManager.clearSyncToken();
|
|
expect(tag.content.references.length).to.equal(1);
|
|
expect(note.tags.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
expect(modelManager.allItems.length).to.equal(2);
|
|
console.log("Waiting 1.1s...");
|
|
await wait(1.1);
|
|
|
|
}
|
|
}).timeout(20000);
|
|
|
|
it("handles signing in and merging data", async () => {
|
|
|
|
let syncManager = new SFSyncManager(modelManager, Factory.globalStorageManager(), Factory.globalHttpManager());
|
|
|
|
// be offline
|
|
syncManager.setKeyRequestHandler(async () => {
|
|
return {
|
|
offline: true
|
|
};
|
|
})
|
|
|
|
modelManager.handleSignout();
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let originalNote = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let originalTag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
originalNote.setDirty(true);
|
|
originalTag.setDirty(true);
|
|
|
|
await syncManager.sync();
|
|
|
|
expect(originalTag.content.references.length).to.equal(1);
|
|
expect(originalTag.notes.length).to.equal(1);
|
|
expect(originalNote.tags.length).to.equal(1);
|
|
|
|
// go online
|
|
syncManager.setKeyRequestHandler(async () => {
|
|
return {
|
|
keys: await authManager.keys(),
|
|
auth_params: await authManager.getAuthParams(),
|
|
offline: false
|
|
};
|
|
})
|
|
|
|
// when signing in, all local items are cleared from storage (but kept in memory; to clear desktop logs),
|
|
// then resaved with alternated uuids.
|
|
await Factory.globalStorageManager().clearAllModels();
|
|
await syncManager.markAllItemsDirtyAndSaveOffline(true)
|
|
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
expect(modelManager.allItems.length).to.equal(2);
|
|
|
|
expect(note.uuid).to.not.equal(originalNote.uuid);
|
|
expect(tag.uuid).to.not.equal(originalTag.uuid);
|
|
|
|
expect(tag.content.references.length).to.equal(1);
|
|
expect(note.content.references.length).to.equal(0);
|
|
|
|
expect(note.referencingObjects.length).to.equal(1);
|
|
expect(tag.notes.length).to.equal(1);
|
|
expect(note.tags.length).to.equal(1);
|
|
})
|
|
|
|
it('duplicating a tag should maintian its relationships', async () => {
|
|
modelManager.handleSignout();
|
|
let pair = createRelatedNoteTagPair();
|
|
let noteParams = pair[0];
|
|
let tagParams = pair[1];
|
|
|
|
modelManager.mapResponseItemsToLocalModels([noteParams, tagParams]);
|
|
let note = modelManager.allItemsMatchingTypes(["Note"])[0];
|
|
let tag = modelManager.allItemsMatchingTypes(["Tag"])[0];
|
|
|
|
note.setDirty(true);
|
|
tag.setDirty(true);
|
|
|
|
await syncManager.sync();
|
|
await syncManager.clearSyncToken();
|
|
|
|
expect(modelManager.allItems.length).to.equal(2);
|
|
|
|
tag.title = `${Math.random()}`
|
|
tag.setDirty(true);
|
|
|
|
expect(note.referencingObjects.length).to.equal(1);
|
|
|
|
// wait about 1s, which is the value the dev server will ignore conflicting changes
|
|
return expect(new Promise((resolve, reject) => {
|
|
setTimeout(function () {
|
|
resolve();
|
|
}, 1100);
|
|
})).to.be.fulfilled.then(async () => {
|
|
return expect(syncManager.sync()).to.be.fulfilled.then(async (response) => {
|
|
// tag should now be conflicted and a copy created
|
|
let models = modelManager.allItems;
|
|
expect(modelManager.allItems.length).to.equal(3);
|
|
var tags = modelManager.allItemsMatchingTypes(["Tag"]);
|
|
var tag1 = tags[0];
|
|
var tag2 = tags[1];
|
|
|
|
expect(tag1.uuid).to.not.equal(tag2.uuid);
|
|
|
|
expect(tag1.uuid).to.equal(tag.uuid);
|
|
expect(tag2.content.conflict_of).to.equal(tag1.uuid);
|
|
expect(tag1.notes.length).to.equal(tag2.notes.length);
|
|
expect(tag1.referencingObjects.length).to.equal(0);
|
|
expect(tag2.referencingObjects.length).to.equal(0);
|
|
|
|
// Two tags now link to this note
|
|
expect(note.referencingObjects.length).to.equal(2);
|
|
expect(note.referencingObjects[0]).to.not.equal(note.referencingObjects[1]);
|
|
})
|
|
})
|
|
}).timeout(10000);
|
|
})
|