Skip to content

Commit

Permalink
test: add tests for basic functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
bandantonio committed May 5, 2024
1 parent 65a4984 commit eda8f3b
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 27 deletions.
16 changes: 8 additions & 8 deletions test/db.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { seedDatabase } from '../src/db/seed';
import { defaultBooks, defaultAnnotations } from '../src/db/seedData';

afterEach(async () => {
let dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);

const sqlite = new Database(dbPath);
const db = drizzle(sqlite);
Expand All @@ -22,7 +22,7 @@ afterEach(async () => {
describe('Empty database', () => {
test('Should throw an error when books library is empty', async () => {
try {
let dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);

await dbRequest(dbPath, `SELECT * FROM ${BOOKS_LIBRARY_NAME}`);
} catch (error) {
Expand All @@ -34,7 +34,7 @@ describe('Empty database', () => {
try {
await seedDatabase(bookLibrary, defaultBooks);

let dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);

await annotationsRequest(dbPath, `SELECT * FROM ${HIGHLIGHTS_LIBRARY_NAME}`);
} catch (error) {
Expand All @@ -47,7 +47,7 @@ describe('Database operations', () => {
test('Should return a list of books when books library is not empty', async () => {
await seedDatabase(bookLibrary, defaultBooks);

let dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const books = await dbRequest(dbPath, `SELECT * FROM ${BOOKS_LIBRARY_NAME}`);

expect(books).toEqual(defaultBooks);
Expand All @@ -56,7 +56,7 @@ describe('Database operations', () => {
test('Should return a list of highlights when highlights library is not empty', async () => {
await seedDatabase(annotations, defaultAnnotations);

let dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const highlights = await annotationsRequest(dbPath, `SELECT * FROM ${HIGHLIGHTS_LIBRARY_NAME} WHERE ZANNOTATIONDELETED = 0`);

expect(highlights.length).toEqual(4);
Expand All @@ -68,8 +68,8 @@ describe('Database operations', () => {
describe('Database load testing', () => {
test('Should return 1000 books and in less than 500ms', async () => {

let oneThousandBooks = [];
let threeThousandsAnnotations = [];
const oneThousandBooks = [];
const threeThousandsAnnotations = [];

// create 1000 books and 3 annotations for each book
for (let i = 0; i < 1000; i++) {
Expand Down Expand Up @@ -98,7 +98,7 @@ describe('Database load testing', () => {
}
}

let dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
await seedDatabase(bookLibrary, oneThousandBooks);
await seedDatabase(annotations, threeThousandsAnnotations);

Expand Down
2 changes: 1 addition & 1 deletion test/mocks/rawTemplates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const rawCustomTemplate = `Title:: 📕 {{{bookTitle}}}
export const rawCustomTemplateMock = `Title:: 📕 {{{bookTitle}}}
Author:: {{{bookAuthor}}}
Genre:: {{#if bookGenre}}{{{bookGenre}}}{{else}}N/A{{/if}}
Language:: {{#if bookLanguage}}{{bookLanguage}}{{else}}N/A{{/if}}
Expand Down
Binary file modified test/mocks/testDatabase.sqlite
Binary file not shown.
30 changes: 30 additions & 0 deletions test/pluginDocs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import fs from 'fs/promises';
import path from 'path';
import { describe, expect, test } from 'vitest';

describe('Plugin documentation', () => {
test('Check that README.md exists', () => {
expect(path.join(process.cwd(), 'README.md')).toBeDefined();
});

test('Check that Template variables contains complete list of variables', async () => {
const readme = await fs.readFile(path.join(process.cwd(), 'README.md'), 'utf-8');

expect(readme).toContain('{{{bookTitle}}}');
expect(readme).toContain('{{bookId}}');
expect(readme).toContain('{{{bookAuthor}}}');
expect(readme).toContain('{{{bookGenre}}}');
expect(readme).toContain('{{bookLanguage}}');
expect(readme).toContain('{{bookLastOpenedDate}}');
expect(readme).toContain('{{bookCoverUrl}}');
expect(readme).toContain('{{annotations}}');
expect(readme).toContain('{{annotations.length}}');
expect(readme).toContain('{{{chapter}}}');
expect(readme).toContain('{{{contextualText}}}');
expect(readme).toContain('{{{highlight}}}');
expect(readme).toContain('{{{note}}}');
expect(readme).toContain('{{highlightStyle}}');
expect(readme).toContain('{{highlightCreationDate}}');
expect(readme).toContain('{{highlightModificationDate}}');
});
});
26 changes: 11 additions & 15 deletions test/pluginInfo.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os from 'os';
import path from 'path';
import { beforeEach } from 'vitest';
import { describe, expect, test } from 'vitest';
import { beforeEach, describe, expect, test } from 'vitest';

declare module 'vitest' {
export interface TestContext {
Expand All @@ -25,47 +24,44 @@ import {
BOOKS_LIBRARY_COLUMNS,
HIGHLIGHTS_LIBRARY_COLUMNS
} from '../src/db/constants';
import * as packageJson from '../package.json';

describe('Plugin information', () => {
beforeEach(async (context) => {
context.manifest = require('../manifest.json');
});

test(`Check that versions in package.json and manifest.json match`, ({ manifest }) => {
const packageJson = require('../package.json');

test(`Check that versions in package.json and manifest.json match`, ({ manifest }) => {
expect(packageJson.version).toEqual(manifest.version);
});
test(`check minimum Obsidian version`, ({ manifest }) => {

test(`check minimum Obsidian version`, ({ manifest }) => {
expect(manifest.minAppVersion).toEqual('0.15.0');
});

test(`Check plugin id, name and description`, ({ manifest }) => {
expect(manifest.id).toEqual('apple-books-import-highlights');
expect(manifest.name).toEqual('Apple Books - Import Highlights');
expect(manifest.description).toEqual('Import your Apple Books highlights and notes to Obsidian.');
});

test(`Check author information`, ({ manifest }) => {
const packageJson = require('../package.json');

expect(packageJson.author).toEqual(manifest.author);
expect(manifest.authorUrl).toEqual('https://github.com/bandantonio');
});
});

describe('Plugin constants', () => {
test('Check database paths', () => {
test('Check database paths', () => {
expect(BOOKS_DB_PATH).toEqual(path.join(os.homedir(), 'Library/Containers/com.apple.iBooksX/Data/Documents/BKLibrary/BKLibrary-1-091020131601.sqlite'));
expect(HIGHLIGHTS_DB_PATH).toEqual(path.join(os.homedir(), 'Library/Containers/com.apple.iBooksX/Data/Documents/AEAnnotation/AEAnnotation_v10312011_1727_local.sqlite'));
});

test('Check database table names', () => {
expect(BOOKS_LIBRARY_NAME).toEqual('ZBKLIBRARYASSET');
expect(HIGHLIGHTS_LIBRARY_NAME).toEqual('ZAEANNOTATION');
});

test('Check database columns', () => {
expect(BOOKS_LIBRARY_COLUMNS).toEqual([
'ZASSETID',
Expand All @@ -76,7 +72,7 @@ describe('Plugin constants', () => {
'ZLASTOPENDATE',
'ZCOVERURL'
]);

expect(HIGHLIGHTS_LIBRARY_COLUMNS).toEqual([
'ZANNOTATIONASSETID',
'ZFUTUREPROOFING5',
Expand Down
6 changes: 3 additions & 3 deletions test/renderHighlightsTemplate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Handlebars from 'handlebars';
import { describe, expect, test } from 'vitest';
import { renderHighlightsTemplate } from '../src/methods/renderHighlightsTemplate';
import { aggregatedHighlights } from './mocks/aggregatedDetailsData';
import { rawCustomTemplate } from './mocks/rawTemplates';
import { rawCustomTemplateMock } from './mocks/rawTemplates';
import { defaultTemplateMock, renderedCustomTemplateMock } from './mocks/renderedTemplate';
import defaultTemplate from '../src/template';

Expand All @@ -14,14 +14,14 @@ describe('renderHighlightsTemplate', () => {
});

test('Should render a custom template with the provided data', async () => {
const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0], rawCustomTemplate);
const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0], rawCustomTemplateMock);

expect(renderedTemplate).toEqual(renderedCustomTemplateMock);
});
});

describe('Custom Handlebars helpers', () => {
let helpers = Handlebars.helpers;
const helpers = Handlebars.helpers;

describe('eq', () => {
test('Should properly compare two values', async () => {
Expand Down
112 changes: 112 additions & 0 deletions test/saveHighlightsToVault.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
import SaveHighlights from '../src/methods/saveHighlightsToVault';
import { AppleBooksHighlightsImportPluginSettings } from '../src/settings';
import { aggregatedHighlights } from './mocks/aggregatedDetailsData';
import { defaultTemplateMock } from './mocks/renderedTemplate';

const mockVault = {
getAbstractFileByPath: vi.fn(),
// eslint-disable-next-line
createFolder: vi.fn().mockImplementation(async (folderName: string) => {
return;
}),
// eslint-disable-next-line
create: vi.fn().mockImplementation(async (filePath: string, data: string) => {
return;
}),
// eslint-disable-next-line
delete: vi.fn().mockImplementation(async (folderPath: string, force: boolean) => {
return;
}),
adapter: {
list: vi.fn(),
// eslint-disable-next-line
copy: vi.fn().mockImplementation(async (source: string, destination: string) => {
return;
}),
}
};

beforeEach(() => {
Date.now = vi.fn().mockImplementation(() => 1704060001);
});

afterEach(() => {
vi.resetAllMocks();
});

const settings = new AppleBooksHighlightsImportPluginSettings();

describe('Save highlights to vault', () => {
test('Should save highlights to vault', async () => {
// eslint-disable-next-line
const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings);
const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights');

await saveHighlights.saveHighlightsToVault(aggregatedHighlights);

expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1);
expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights');

expect(mockVault.delete).toHaveBeenCalledTimes(1);
expect(mockVault.delete).toHaveBeenCalledWith('ibooks-highlights', true);

expect(mockVault.createFolder).toHaveBeenCalledTimes(1);
expect(mockVault.createFolder).toHaveBeenCalledWith('ibooks-highlights');

expect(mockVault.create).toHaveBeenCalledTimes(1);
expect(mockVault.create).toHaveBeenCalledWith(
`ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md`,
defaultTemplateMock
);
});

test('Should skip saving highlights to vault highlights are not found', async () => {
// eslint-disable-next-line
const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, highlightsFolder: '' });
const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('');

await saveHighlights.saveHighlightsToVault(aggregatedHighlights);

expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1);
expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('');

expect(mockVault.delete).toHaveBeenCalledTimes(0);

expect(mockVault.createFolder).toHaveBeenCalledTimes(1);
expect(mockVault.createFolder).toHaveBeenCalledWith('');
});

test('Should backup highlights if backup option is enabled', async () => {
// eslint-disable-next-line
const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, backup: true });

vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights');
// eslint-disable-next-line
const spyList = vi.spyOn(mockVault.adapter, 'list').mockImplementation(async (folderPath: string) => {
return {
files: [
'ibooks-highlights/Hello-world.md',
'ibooks-highlights/Goodbye-world.md',
],
};
});

await saveHighlights.saveHighlightsToVault(aggregatedHighlights);

expect(spyList).toHaveBeenCalledTimes(1);
expect(spyList).toReturnWith({
files: [
'ibooks-highlights/Hello-world.md',
'ibooks-highlights/Goodbye-world.md',
],
});

expect(mockVault.createFolder).toHaveBeenCalledTimes(2);
expect(mockVault.createFolder).toHaveBeenNthCalledWith(1, `ibooks-highlights-bk-1704060001`);
expect(mockVault.createFolder).toHaveBeenNthCalledWith(2, 'ibooks-highlights');

expect(mockVault.adapter.copy).toHaveBeenNthCalledWith(1, 'ibooks-highlights/Hello-world.md', 'ibooks-highlights-bk-1704060001/Hello-world.md');
expect(mockVault.adapter.copy).toHaveBeenNthCalledWith(2, 'ibooks-highlights/Goodbye-world.md', 'ibooks-highlights-bk-1704060001/Goodbye-world.md');
});
});
22 changes: 22 additions & 0 deletions test/settings.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, expect, test } from 'vitest';
import { AppleBooksHighlightsImportPluginSettings } from '../src/settings';
import defaultTemplate from '../src/template';
const settings = new AppleBooksHighlightsImportPluginSettings();

describe('Plugin default settings', () => {
test("Highlights folder", () => {
expect(settings.highlightsFolder).toEqual('ibooks-highlights');
});

test("Import highlights on start", () => {
expect(settings.importOnStart).toBeFalsy();
});

test("Backup highlights", () => {
expect(settings.backup).toBeFalsy();
});

test('Template', () => {
expect(settings.template).toEqual(defaultTemplate);
});
})

0 comments on commit eda8f3b

Please sign in to comment.