diff --git a/packages/core/api/sync/__tests__/collector.test.js b/packages/core/api/sync/__tests__/collector.test.js deleted file mode 100644 index eac8dfa4e..000000000 --- a/packages/core/api/sync/__tests__/collector.test.js +++ /dev/null @@ -1,94 +0,0 @@ -import StorageInterface from "../../../__mocks__/storage.mock"; -import Collector from "../collector"; -import { enableFetchMocks, disableFetchMocks } from "jest-fetch-mock"; -import { - noteTest, - TEST_NOTE, - TEST_NOTEBOOK, - databaseTest, -} from "../../../__tests__/utils"; -import { login } from "./utils"; - -function getMainCollectionParams(name, testItem) { - return [ - name, - (db, collection) => db[collection].add(testItem), - (db, collection) => - db[collection].add({ - ...testItem, - id: Math.random().toString(), - remote: true, - dateEdited: 1, - }), - ]; -} - -function getTagsCollectionParams(name, testItem) { - return [ - name, - (db, collection) => db[collection].add(testItem + Math.random(), 2), - (db, collection) => - db[collection]._collection.addItem({ - title: testItem + MAX_ITEMS + 1, - noteIds: [2], - deletedIds: [], - id: Math.random().toString(), - remote: true, - dateEdited: 1, - }), - ]; -} - -const MAX_ITEMS = 5; - -const tests = [ - getMainCollectionParams("notes", TEST_NOTE), - getMainCollectionParams("notebooks", TEST_NOTEBOOK), - getMainCollectionParams("content", { ops: [{ insert: "true" }] }), -]; - -describe.each(tests)("%s preparation", (collection, add, addExtra) => { - beforeAll(() => { - enableFetchMocks(); - }); - - beforeEach(() => { - fetch.resetMocks(); - StorageInterface.clear(); - }); - - test(`prepare ${collection} when user has never synced before`, () => { - return databaseTest().then(async (db) => { - await login(db); - await Promise.all( - Array(MAX_ITEMS) - .fill(0) - .map(() => add(db, collection)) - ); - const collector = new Collector(db); - const data = await collector.collect(0); - expect(data[collection].length).toBe(MAX_ITEMS); - expect( - data[collection].every((item) => !!item.iv && !!item.cipher) - ).toBeTruthy(); - }); - }); - - test(`prepare ${collection} when user has synced before`, () => { - return databaseTest().then(async (db) => { - await login(db); - await Promise.all( - Array(MAX_ITEMS) - .fill(0) - .map(() => add(db, collection)) - ); - await addExtra(db, collection); - const collector = new Collector(db); - const data = await collector.collect(10); - expect(data[collection].length).toBe(MAX_ITEMS); - expect( - data[collection].every((item) => !!item.iv && !!item.cipher) - ).toBeTruthy(); - }); - }); -}); diff --git a/packages/core/api/sync/__tests__/merger.test.js b/packages/core/api/sync/__tests__/merger.test.js deleted file mode 100644 index 67c6af5af..000000000 --- a/packages/core/api/sync/__tests__/merger.test.js +++ /dev/null @@ -1,160 +0,0 @@ -import Merger from "../merger"; -import { - StorageInterface, - databaseTest, - noteTest, - TEST_NOTE, - TEST_NOTEBOOK, -} from "../../../__tests__/utils"; -import { enableFetchMocks, disableFetchMocks } from "jest-fetch-mock"; -import { tagsCollectionParams, mainCollectionParams } from "./utils"; -import { login, getEncrypted } from "./utils"; -import { CURRENT_DATABASE_VERSION } from "../../../common"; - -const emptyServerResponse = { - notes: [], - notebooks: [], - content: [], - settings: [], -}; - -const testItem = { id: "someId", dateEdited: 2 }; - -test("server response with all arrays empty should cause early return", async () => { - const merger = new Merger(); - const result = await merger.merge(emptyServerResponse); - expect(result).toBe(false); -}); - -test("null server response should return false", async () => { - const merger = new Merger(); - const result = await merger.merge(); - expect(result).toBe(false); -}); - -const tests = [ - mainCollectionParams("notes", "note", TEST_NOTE), - mainCollectionParams("notebooks", "notebook", TEST_NOTEBOOK), -]; - -describe.each(tests)( - "general %s syncing tests", - (collection, add, edit, get, itemType) => { - beforeAll(() => { - enableFetchMocks(); - }); - - beforeEach(() => { - fetch.resetMocks(); - StorageInterface.clear(); - }); - - test(`merge ${collection} into empty database`, () => - databaseTest().then(async (db) => { - await login(db); - const merger = new Merger(db); - const result = await merger.merge( - { - [collection]: [ - { - id: testItem.id, - v: CURRENT_DATABASE_VERSION, - ...(await getEncrypted({ ...testItem, type: itemType })), - }, - ], - synced: false, - }, - 0 - ); - expect(result).toBe(true); - expect(db[collection].all[0].id).toStrictEqual(testItem.id); - expect(db[collection].all[0].dateEdited).toStrictEqual( - testItem.dateEdited - ); - })); - - test(`merge local and remote ${collection}`, () => - databaseTest().then(async (db) => { - await login(db); - const merger = new Merger(db); - const item = await add(db); - item.title = "Google"; - const result = await merger.merge( - { - [collection]: [ - { - v: CURRENT_DATABASE_VERSION, - id: item.id, - ...(await getEncrypted(item)), - }, - ], - synced: false, - }, - 0 - ); - expect(result).toBe(true); - expect(db[collection].all.length).toBe(1); - expect(db[collection].all[0]).toStrictEqual(item); - })); - - test(`local ${collection} are more updated than remote ones`, () => - databaseTest().then(async (db) => { - await login(db); - const merger = new Merger(db); - const item = await add(db); - await edit(db, item); - item.title = "Google"; - const result = await merger.merge( - { - [collection]: [ - { - id: item.id, - v: CURRENT_DATABASE_VERSION, - ...(await getEncrypted(item)), - }, - ], - synced: false, - }, - 0 - ); - expect(result).toBe(true); - expect(db[collection].all.length).toBe(1); - expect(db[collection].all[0]).toStrictEqual(get(db, item)); - })); - } -); - -test("local content updated after lastSyncedTimestamp should cause merge conflict", () => { - StorageInterface.clear(); - return noteTest().then(async ({ db, id }) => { - await login(db); - - const contentId = db.notes.note(id).data.contentId; - const merger = new Merger(db); - const result = await merger.merge( - { - content: [ - { - id: contentId, - v: CURRENT_DATABASE_VERSION, - ...(await getEncrypted({ - id: contentId, - noteId: id, - type: "tiny", - data: "

my name is

", - dateEdited: 2919, - conflicted: false, - resolved: false, - })), - }, - ], - }, - 200 - ); - const localContent = await db.content.raw(contentId); - expect(localContent.conflicted.id).toBe(contentId); - expect(localContent.conflicted.noteId).toBe(id); - expect(result).toBe(true); - expect(await db.context.read("hasConflicts")).toBe(true); - }); -}); diff --git a/packages/core/api/sync/__tests__/sync.test.js b/packages/core/api/sync/__tests__/sync.test.js deleted file mode 100644 index 911e76f2c..000000000 --- a/packages/core/api/sync/__tests__/sync.test.js +++ /dev/null @@ -1,113 +0,0 @@ -//import User from "../../models/user"; -import { enableFetchMocks, disableFetchMocks } from "jest-fetch-mock"; -import { CURRENT_DATABASE_VERSION } from "../../../common"; -import StorageInterface from "../../../__mocks__/storage.mock"; -//import Sync from "../sync"; -//import Collector from "../prepare"; -import { databaseTest, TEST_NOTE } from "../../../__tests__/utils"; -import { login, getEncrypted } from "./utils"; - -const RESPONSE_PARAMS = { - headers: { "Content-Type": "application/json" }, -}; - -beforeAll(() => { - enableFetchMocks(); -}); - -beforeEach(() => { - fetch.resetMocks(); - StorageInterface.clear(); -}); - -test("syncing when user is not logged in should throw", () => - databaseTest().then((db) => { - expect(db.sync()).rejects.toThrow("You need to login to sync."); - })); - -test("sync without merge conflicts, cause merge conflicts, resolve them and then resync", () => { - return databaseTest().then(async (db) => { - // 1. login - await login(db); - - // 2. create local note - const noteId = await db.notes.add(TEST_NOTE); - - // 3. start sync - fetchMock - .once(JSON.stringify({ notes: [], synced: false }), RESPONSE_PARAMS) - .once( - JSON.stringify({ lastSynced: Date.now() }), - { status: 200 }, - RESPONSE_PARAMS - ); - await db.sync(); - - /////// CAUSE MERGE CONFLICT! /////// - // 4. edit the note's content - await db.notes.add({ - id: noteId, - content: { ...TEST_NOTE.content }, - }); - - // 5. sync again and expect conflicts - const contentId = db.notes.note(noteId).data.contentId; - const content = { - id: contentId, - v: CURRENT_DATABASE_VERSION, - ...(await getEncrypted({ - id: contentId, - type: TEST_NOTE.content.type, - dateEdited: Date.now(), - conflicted: false, - data: "

hello world what are you doing

", - })), - }; - - fetchMock - .once( - JSON.stringify({ notes: [], content: [content], synced: false }), - RESPONSE_PARAMS - ) - .once( - JSON.stringify({ lastSynced: Date.now() }), - { status: 200 }, - RESPONSE_PARAMS - ); - - await expect(db.sync()).rejects.toThrow( - "Merge conflicts detected. Please resolve all conflicts to continue syncing." - ); - - let rawContent = await db.content.raw(contentId); - expect(rawContent.conflicted.id).toBe(contentId); - expect(rawContent.conflicted.data).toBeTruthy(); - - // 6. Resolve conflicts - await db.notes.add({ - id: noteId, - conflicted: false, - content: { - type: TEST_NOTE.content.type, - data: TEST_NOTE.content.data, - resolved: true, - }, - }); - rawContent = await db.content.raw(contentId); - expect(rawContent.conflicted).toBe(false); - //expect(rawDelta.resolved).toBe(true); - - // 7. Resync (no conflicts should appear) - fetchMock - .once( - JSON.stringify({ notes: [], content: [content], synced: false }), - RESPONSE_PARAMS - ) - .once( - JSON.stringify({ lastSynced: Date.now() }), - { status: 200 }, - RESPONSE_PARAMS - ); - await expect(db.sync()).resolves.toBeUndefined(); - }); -}); diff --git a/packages/core/api/sync/__tests__/utils.js b/packages/core/api/sync/__tests__/utils.js deleted file mode 100644 index 9e3dfd8f6..000000000 --- a/packages/core/api/sync/__tests__/utils.js +++ /dev/null @@ -1,73 +0,0 @@ -import "jest-fetch-mock"; -import Storage from "../../../__mocks__/storage.mock"; - -const SUCCESS_LOGIN_RESPONSE = { - access_token: "access_token", - refresh_token: "refresh_token", - scope: "sync", - expires_in: 3600, -}; - -const SUCCESS_USER_RESPONSE = { - id: "0", - email: process.env.EMAIL, - salt: "", - vaultKey: null, -}; - -async function login(db) { - fetchMock - .mockResponseOnce(JSON.stringify(SUCCESS_LOGIN_RESPONSE), { - headers: { "Content-Type": "application/json" }, - }) - .mockResponseOnce(JSON.stringify(SUCCESS_USER_RESPONSE), { - headers: { "Content-Type": "application/json" }, - }); - - await db.user.login( - SUCCESS_USER_RESPONSE.email, - "password", - true, - "password" - ); -} - -function mainCollectionParams(collection, itemKey, item) { - async function addItem(db) { - const id = await db[collection].add(item); - return db[collection][itemKey](id).data; - } - - async function editItem(db, item) { - await db[collection].add({ ...item, title: "dobido" }); - } - - function getItem(db, item) { - return db[collection][itemKey](item.id).data; - } - - return [collection, addItem, editItem, getItem, itemKey]; -} - -function tagsCollectionParams(collection, item, type) { - async function addItem(db) { - const id = await db[collection].add(item, 20); - return db[collection].tag(id); - } - - async function editItem(db) { - await db[collection].add(item, 240); - } - - function getItem(db, item) { - return db[collection].tag(item.id); - } - - return [collection, addItem, editItem, getItem, type]; -} - -function getEncrypted(item) { - return Storage.encrypt("password", JSON.stringify(item)); -} - -export { tagsCollectionParams, mainCollectionParams, login, getEncrypted }; diff --git a/packages/core/api/sync/__tests__/utils.test.js b/packages/core/api/sync/__tests__/utils.test.js deleted file mode 100644 index ec436447e..000000000 --- a/packages/core/api/sync/__tests__/utils.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import { areAllEmpty } from "../utils"; - -test("return true if all array items in object are empty", () => { - const result = areAllEmpty({ a: [], b: [], c: true, f: 214 }); - expect(result).toBe(true); -}); - -test("return false if any array item in object is not empty", () => { - const result = areAllEmpty({ a: [2, 3, 4], b: [], c: true, f: 214 }); - expect(result).toBe(false); -});