1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-11-27 08:21:03 +02:00
joplin/CliClient/tests/reducer.js

376 lines
12 KiB
JavaScript

/* eslint-disable no-unused-vars */
require('app-module-path').addPath(__dirname);
const { setupDatabaseAndSynchronizer, switchClient, asyncTest } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const { reducer, defaultState, stateUtils } = require('lib/reducer.js');
async function createNTestFolders(n) {
let folders = [];
for (let i = 0; i < n; i++) {
let folder = await Folder.save({ title: 'folder' });
folders.push(folder);
}
return folders;
}
async function createNTestNotes(n, folder) {
let notes = [];
for (let i = 0; i < n; i++) {
let note = await Note.save({ title: 'note', parent_id: folder.id, is_conflict: 0 });
notes.push(note);
}
return notes;
}
async function createNTestTags(n) {
let tags = [];
for (let i = 0; i < n; i++) {
let tag = await Tag.save({ title: 'tag' });
tags.push(tag);
}
return tags;
}
function initTestState(folders, selectedFolderIndex, notes, selectedIndexes, tags=null, selectedTagIndex=null) {
let state = defaultState;
if (selectedFolderIndex != null) {
state = reducer(state, { type: 'FOLDER_SELECT', id: folders[selectedFolderIndex].id });
}
if (folders != null) {
state = reducer(state, { type: 'FOLDER_UPDATE_ALL', items: folders });
}
if (notes != null) {
state = reducer(state, { type: 'NOTE_UPDATE_ALL', notes: notes, noteSource: 'test' });
}
if (selectedIndexes != null) {
let selectedIds = [];
for (let i = 0; i < selectedIndexes.length; i++) {
selectedIds.push(notes[selectedIndexes[i]].id);
}
state = reducer(state, { type: 'NOTE_SELECT', ids: selectedIds });
}
if (tags != null) {
state = reducer(state, { type: 'TAG_UPDATE_ALL', items: tags });
}
if (selectedTagIndex != null) {
state = reducer(state, { type: 'TAG_SELECT', id: tags[selectedTagIndex].id });
}
return state;
}
function createExpectedState(items, keepIndexes, selectedIndexes) {
let expected = { items: [], selectedIds: [] };
for (let i = 0; i < selectedIndexes.length; i++) {
expected.selectedIds.push(items[selectedIndexes[i]].id);
}
for (let i = 0; i < keepIndexes.length; i++) {
expected.items.push(items[keepIndexes[i]]);
}
return expected;
}
function getIds(items, indexes=null) {
let ids = [];
for (let i = 0; i < items.length; i++) {
if (indexes == null || i in indexes) {
ids.push(items[i].id);
}
}
return ids;
}
let insideBeforeEach = false;
describe('Reducer', function() {
beforeEach(async (done) => {
insideBeforeEach = true;
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
insideBeforeEach = false;
});
// tests for NOTE_DELETE
it('should delete selected note', asyncTest(async () => {
// create 1 folder
let folders = await createNTestFolders(1);
// create 5 notes
let notes = await createNTestNotes(5, folders[0]);
// select the 1st folder and the 3rd note
let state = initTestState(folders, 0, notes, [2]);
// test action
// delete the third note
state = reducer(state, { type: 'NOTE_DELETE', id: notes[2].id });
// expect that the third note is missing, and the 4th note is now selected
let expected = createExpectedState(notes, [0,1,3,4], [3]);
// check the ids of all the remaining notes
expect(getIds(state.notes)).toEqual(getIds(expected.items));
// check the ids of the selected notes
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete selected note at top', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [1]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[0].id });
let expected = createExpectedState(notes, [1,2,3,4], [1]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete last remaining note', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(1, folders[0]);
let state = initTestState(folders, 0, notes, [0]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[0].id });
let expected = createExpectedState(notes, [], []);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete selected note at bottom', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [4]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[4].id });
let expected = createExpectedState(notes, [0,1,2,3], [3]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete note when a note below is selected', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [3]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[1].id });
let expected = createExpectedState(notes, [0,2,3,4], [3]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete note when a note above is selected', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [1]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[3].id });
let expected = createExpectedState(notes, [0,1,2,4], [1]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete selected notes', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [1,2]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[1].id });
state = reducer(state, { type: 'NOTE_DELETE', id: notes[2].id });
let expected = createExpectedState(notes, [0,3,4], [3]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete note when a notes below it are selected', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [3,4]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[1].id });
let expected = createExpectedState(notes, [0,2,3,4], [3,4]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete note when a notes above it are selected', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [1,2]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[3].id });
let expected = createExpectedState(notes, [0,1,2,4], [1,2]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete notes at end', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [3,4]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[3].id });
state = reducer(state, { type: 'NOTE_DELETE', id: notes[4].id });
let expected = createExpectedState(notes, [0,1,2], [2]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
it('should delete notes when non-contiguous selection', asyncTest(async () => {
let folders = await createNTestFolders(1);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 0, notes, [0,2,4]);
// test action
state = reducer(state, { type: 'NOTE_DELETE', id: notes[0].id });
state = reducer(state, { type: 'NOTE_DELETE', id: notes[2].id });
state = reducer(state, { type: 'NOTE_DELETE', id: notes[4].id });
let expected = createExpectedState(notes, [1,3], [1]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
// tests for FOLDER_DELETE
it('should delete selected notebook', asyncTest(async () => {
let folders = await createNTestFolders(5);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 2, notes, [2]);
// test action
state = reducer(state, { type: 'FOLDER_DELETE', id: folders[2].id });
let expected = createExpectedState(folders, [0,1,3,4], [3]);
expect(getIds(state.folders)).toEqual(getIds(expected.items));
expect(state.selectedFolderId).toEqual(expected.selectedIds[0]);
}));
it('should delete notebook when a book above is selected', asyncTest(async () => {
let folders = await createNTestFolders(5);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 1, notes, [2]);
// test action
state = reducer(state, { type: 'FOLDER_DELETE', id: folders[2].id });
let expected = createExpectedState(folders, [0,1,3,4], [1]);
expect(getIds(state.folders)).toEqual(getIds(expected.items));
expect(state.selectedFolderId).toEqual(expected.selectedIds[0]);
}));
it('should delete notebook when a book below is selected', asyncTest(async () => {
let folders = await createNTestFolders(5);
let notes = await createNTestNotes(5, folders[0]);
let state = initTestState(folders, 4, notes, [2]);
// test action
state = reducer(state, { type: 'FOLDER_DELETE', id: folders[2].id });
let expected = createExpectedState(folders, [0,1,3,4], [4]);
expect(getIds(state.folders)).toEqual(getIds(expected.items));
expect(state.selectedFolderId).toEqual(expected.selectedIds[0]);
}));
// tests for TAG_DELETE
it('should delete selected tag', asyncTest(async () => {
let tags = await createNTestTags(5);
let state = initTestState(null, null, null, null, tags, [2]);
// test action
state = reducer(state, { type: 'TAG_DELETE', id: tags[2].id });
let expected = createExpectedState(tags, [0,1,3,4], [3]);
expect(getIds(state.tags)).toEqual(getIds(expected.items));
expect(state.selectedTagId).toEqual(expected.selectedIds[0]);
}));
it('should delete tag when a tag above is selected', asyncTest(async () => {
let tags = await createNTestTags(5);
let state = initTestState(null, null, null, null, tags, [2]);
// test action
state = reducer(state, { type: 'TAG_DELETE', id: tags[4].id });
let expected = createExpectedState(tags, [0,1,2,3], [2]);
expect(getIds(state.tags)).toEqual(getIds(expected.items));
expect(state.selectedTagId).toEqual(expected.selectedIds[0]);
}));
it('should delete tag when a tag below is selected', asyncTest(async () => {
let tags = await createNTestTags(5);
let state = initTestState(null, null, null, null, tags, [2]);
// test action
state = reducer(state, { type: 'TAG_DELETE', id: tags[0].id });
let expected = createExpectedState(tags, [1,2,3,4], [2]);
expect(getIds(state.tags)).toEqual(getIds(expected.items));
expect(state.selectedTagId).toEqual(expected.selectedIds[0]);
}));
it('should select all notes', asyncTest(async () => {
let folders = await createNTestFolders(2);
let notes = [];
for (let i = 0; i < folders.length; i++) {
notes.push(...await createNTestNotes(3, folders[i]));
}
let state = initTestState(folders, 0, notes.slice(0,3), [0]);
let expected = createExpectedState(notes, [0,1,2], [0]);
expect(state.notes.length).toEqual(expected.items.length);
expect(getIds(state.notes.slice(0,4))).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
// test action
state = reducer(state, { type: 'NOTE_SELECT_ALL' });
expected = createExpectedState(notes.slice(0,3), [0,1,2], [0,1,2]);
expect(getIds(state.notes)).toEqual(getIds(expected.items));
expect(state.selectedNoteIds).toEqual(expected.selectedIds);
}));
});