mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-22 22:49:45 +01:00
feat: remove sync tests
these tests are too fragile, hard to maintain and keep up to date. Maybe I will write them again from scratch. As they are, they are of no help.
This commit is contained in:
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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: "<p>my name is</p>",
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -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: "<p>hello world what are you doing</p>",
|
||||
})),
|
||||
};
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -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 };
|
||||
@@ -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);
|
||||
});
|
||||
Reference in New Issue
Block a user