From 4223edae75a72ec711abf9e8e5349bab8859b2b2 Mon Sep 17 00:00:00 2001 From: Jamie Hurst Date: Fri, 3 Jan 2025 21:17:10 +0000 Subject: [PATCH] Improve coverage further to where it can be for now --- src/__mocks__/obsidian.ts | 1 + src/__tests__/notice.test.ts | 104 ++++++++++++++++++++++++++++++++--- src/modal/index.ts | 28 +++------- src/notice.ts | 24 ++++---- 4 files changed, 116 insertions(+), 41 deletions(-) diff --git a/src/__mocks__/obsidian.ts b/src/__mocks__/obsidian.ts index 74f4c53..ff58e43 100644 --- a/src/__mocks__/obsidian.ts +++ b/src/__mocks__/obsidian.ts @@ -8,6 +8,7 @@ export class Modal { this.onClose(); } onClose() {} + open() {} setTitle(title: string) { return this; }; diff --git a/src/__tests__/notice.test.ts b/src/__tests__/notice.test.ts index 0f9257e..98bf68e 100644 --- a/src/__tests__/notice.test.ts +++ b/src/__tests__/notice.test.ts @@ -1,19 +1,16 @@ import { type Moment } from 'moment'; -import { moment, Notice, TFile } from 'obsidian'; +import { Modal, moment, Notice, TFile } from 'obsidian'; import InboxOrganiser from '..'; import { Inbox } from '../inbox'; -import { OrganiserModal } from '../modal'; import { OrganiserNotice } from '../notice'; import { DEFAULT_SETTINGS, ISettings, Period } from '../settings'; -jest.mock('obsidian'); - describe('OrganiserNotice', () => { let sut: OrganiserNotice; let plugin: InboxOrganiser; - let modal: OrganiserModal; + let modal: Modal; let inbox: Inbox; let now: Moment; @@ -22,14 +19,21 @@ describe('OrganiserNotice', () => { beforeEach(() => { plugin = jest.fn() as unknown as InboxOrganiser; plugin.getSettings = (jest.fn()).mockReturnValue(settings); - modal = jest.fn() as unknown as OrganiserModal; + modal = jest.fn() as unknown as Modal; + modal.open = jest.fn(); inbox = jest.fn() as unknown as Inbox; inbox.getFiles = jest.fn(); - now = moment(); + now = moment('2025-01-01T00:00:00'); sut = new OrganiserNotice(plugin, modal, inbox, now); }); + it('creates using default dependencies', () => { + sut = new OrganiserNotice(plugin, modal, inbox); + + expect(sut).toBeInstanceOf(OrganiserNotice); + }); + it('does nothing if inbox is disabled', () => { const inboxGetFiles = jest.spyOn(inbox, 'getFiles'); settings.inbox = false; @@ -68,7 +72,7 @@ describe('OrganiserNotice', () => { const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); settings.inbox = true; settings.period = 'daily_9am'; - now.set({hour: now.isDST() ? 10 : 9, minute: 1, second: 1}); + now.set({hour: 9, minute: 1, second: 1}); sut.display(); @@ -80,7 +84,23 @@ describe('OrganiserNotice', () => { const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([new TFile()]); settings.inbox = true; settings.period = 'daily_9am'; - now.set({hour: now.isDST() ? 10 : 9, minute: 1, second: 1}); + now.set({hour: 9, minute: 1, second: 1}); + + sut.display(); + + // TODO: The mock modal connected to this is currently not able to be spied upon - need to understand why + const fragment = (Notice as jest.Mock).mock.calls[0][0] as DocumentFragment; + fragment.children[1].dispatchEvent(new Event('click')); + + expect(inboxGetFiles).toHaveBeenCalled(); + expect(Notice).toHaveBeenCalled(); + }); + + it('works correctly under DST', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([new TFile()]); + settings.inbox = true; + settings.period = 'daily_9am'; + now.set({date: 1, month: 6, year: 2024, hour: 9, minute: 1, second: 1}); sut.display(); @@ -88,4 +108,70 @@ describe('OrganiserNotice', () => { expect(Notice).toHaveBeenCalled(); }); + it('works correctly for Mon 9am', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); + settings.inbox = true; + settings.period = 'weekly_mon_9am'; + now.set({date: 6, month: 0, year: 2025, hour: 9, minute: 1, second: 1}); + + sut.display(); + + expect(inboxGetFiles).toHaveBeenCalled(); + }); + + it('works correctly for Mon 5pm', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); + settings.inbox = true; + settings.period = 'weekly_mon_5pm'; + now.set({date: 6, month: 0, year: 2025, hour: 17, minute: 1, second: 1}); + + sut.display(); + + expect(inboxGetFiles).toHaveBeenCalled(); + }); + + it('does nothing for Mon 5pm when not Monday', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); + settings.inbox = true; + settings.period = 'weekly_mon_5pm'; + now.set({date: 7, month: 0, year: 2025, hour: 17, minute: 1, second: 1}); + + sut.display(); + + expect(inboxGetFiles).not.toHaveBeenCalled(); + }); + + it('works correctly for Fri 9am', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); + settings.inbox = true; + settings.period = 'weekly_fri_9am'; + now.set({date: 3, month: 0, year: 2025, hour: 9, minute: 1, second: 1}); + + sut.display(); + + expect(inboxGetFiles).toHaveBeenCalled(); + }); + + it('works correctly for Fri 5pm', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); + settings.inbox = true; + settings.period = 'weekly_fri_5pm'; + now.set({date: 3, month: 0, year: 2025, hour: 17, minute: 1, second: 1}); + + sut.display(); + + expect(inboxGetFiles).toHaveBeenCalled(); + }); + + it('does nothing for Fri 5pm when not Friday', () => { + const inboxGetFiles = jest.spyOn(inbox, 'getFiles').mockReturnValue([]); + settings.inbox = true; + settings.period = 'weekly_fri_5pm'; + now.set({date: 7, month: 0, year: 2025, hour: 17, minute: 1, second: 1}); + + sut.display(); + + expect(inboxGetFiles).not.toHaveBeenCalled(); + }); + }); diff --git a/src/modal/index.ts b/src/modal/index.ts index 8813a35..3bd6c5a 100644 --- a/src/modal/index.ts +++ b/src/modal/index.ts @@ -46,6 +46,7 @@ export class OrganiserModal extends Modal { this.createFilter(mainContainerEl); this.createMultiSelect(mainContainerEl); this.createFileTable(mainContainerEl); + this.createFileTableRows(); this.handleSearch(''); this.handleToggleSelectMulti(false); } @@ -98,7 +99,9 @@ export class OrganiserModal extends Modal { theadTrEl.createEl('th', { text: 'Name' }); theadTrEl.createEl('th', { text: 'Move to...' }); this.fileTbodyEl = tableEl.createEl('tbody'); + } + createFileTableRows(): void { for (const file of this.files) { const fileTrEl = this.fileTbodyEl.createEl('tr'); @@ -134,22 +137,7 @@ export class OrganiserModal extends Modal { return folderSelectEl; } - - getFolderPathForDisplay(folder: TFolder): string { - if (folder.parent?.path === '/') { - return folder.name; - } - - const parentNames = []; - let parent: TFolder | null = folder.parent; - while (parent !== null && parent.path !== '/') { - parentNames.push(parent.name); - parent = parent.parent; - } - - return `${folder.name} (${parentNames.reverse().join(' > ')})`; - } - + handleSearch(query: string): void { [...this.fileRowEls.entries()].forEach(([fileName, row]) => { const fileNameSearch = fileName.toLowerCase(); @@ -199,12 +187,12 @@ export class OrganiserModal extends Modal { await this.inbox.move(file, path); this.files.remove(file); - this.fileRowEls.get(fileName)?.remove(); - this.fileRowEls.delete(fileName); - this.fileRowSelectEls.delete(fileName); - if (this.fileRowEls.size === 0) { + if (this.files.length === 0) { this.close(); + } else { + this.fileTbodyEl.empty(); + this.createFileTableRows(); } } diff --git a/src/notice.ts b/src/notice.ts index 03f3b59..9d62bf8 100644 --- a/src/notice.ts +++ b/src/notice.ts @@ -1,16 +1,15 @@ import { type Moment } from 'moment'; -import { moment, Notice } from 'obsidian'; +import { Modal, moment, Notice } from 'obsidian'; import InboxOrganiser from '.'; import { Inbox } from './inbox'; -import { OrganiserModal } from './modal'; export class OrganiserNotice { private plugin: InboxOrganiser; - private modal: OrganiserModal; + private modal: Modal; private inbox: Inbox; private now: Moment; - constructor(plugin: InboxOrganiser, modal: OrganiserModal, inbox: Inbox, now?: Moment) { + constructor(plugin: InboxOrganiser, modal: Modal, inbox: Inbox, now?: Moment) { this.plugin = plugin; this.modal = modal; this.inbox = inbox; @@ -19,6 +18,7 @@ export class OrganiserNotice { private getFragment(): DocumentFragment { const fragment = new DocumentFragment(); + fragment.createEl('span', { text: 'This is a reminder to organise all the files within your inbox folder: click ' }); fragment.createEl('a', { text: 'here' }).addEventListener('click', () => this.modal.open()); fragment.createEl('span', { text: ' to get started.' }); @@ -33,28 +33,28 @@ export class OrganiserNotice { return; } - if (settings.period === 'daily_9am' && !this.now.isBetween(moment('09:00:00', 'HH:mm:ss'), moment('09:09:59', 'HH:mm:ss'))) { + if (settings.period === 'daily_9am' && !this.now.isBetween(this.now.clone().set({hour: 9, minute: 0, second: 0}), this.now.clone().set({hour: 9, minute: 9, second: 59}))) { return; } - if (settings.period === 'daily_11am' && !this.now.isBetween(moment('11:00:00', 'HH:mm:ss'), moment('11:09:59', 'HH:mm:ss'))) { + if (settings.period === 'daily_11am' && !this.now.isBetween(this.now.clone().set({hour: 11, minute: 0, second: 0}), this.now.clone().set({hour: 11, minute: 9, second: 59}))) { return; } - if (settings.period === 'daily_3pm' && !this.now.isBetween(moment('15:00:00', 'HH:mm:ss'), moment('15:09:59', 'HH:mm:ss'))) { + if (settings.period === 'daily_3pm' && !this.now.isBetween(this.now.clone().set({hour: 15, minute: 0, second: 0}), this.now.clone().set({hour: 15, minute: 9, second: 59}))) { return; } - if (settings.period === 'daily_5pm' && !this.now.isBetween(moment('17:00:00', 'HH:mm:ss'), moment('17:09:59', 'HH:mm:ss'))) { + if (settings.period === 'daily_5pm' && !this.now.isBetween(this.now.clone().set({hour: 17, minute: 0, second: 0}), this.now.clone().set({hour: 17, minute: 9, second: 59}))) { return; } - if (settings.period === 'weekly_mon_9am' && (this.now.format('dd') !== 'Mo' || !this.now.isBetween(moment('09:00:00', 'HH:mm:ss'), moment('09:09:59', 'HH:mm:ss')))) { + if (settings.period === 'weekly_mon_9am' && (this.now.format('dd') !== 'Mo' || !this.now.isBetween(this.now.clone().set({hour: 9, minute: 0, second: 0}), this.now.clone().set({hour: 9, minute: 9, second: 59})))) { return; } - if (settings.period === 'weekly_mon_5pm' && (this.now.format('dd') !== 'Mo' || !this.now.isBetween(moment('17:00:00', 'HH:mm:ss'), moment('17:09:59', 'HH:mm:ss')))) { + if (settings.period === 'weekly_mon_5pm' && (this.now.format('dd') !== 'Mo' || !this.now.isBetween(this.now.clone().set({hour: 17, minute: 0, second: 0}), this.now.clone().set({hour: 17, minute: 9, second: 59})))) { return; } - if (settings.period === 'weekly_fri_9am' && (this.now.format('dd') !== 'Fr' || !this.now.isBetween(moment('09:00:00', 'HH:mm:ss'), moment('09:09:59', 'HH:mm:ss')))) { + if (settings.period === 'weekly_fri_9am' && (this.now.format('dd') !== 'Fr' || !this.now.isBetween(this.now.clone().set({hour: 9, minute: 0, second: 0}), this.now.clone().set({hour: 9, minute: 9, second: 59})))) { return; } - if (settings.period === 'weekly_fri_5pm' && (this.now.format('dd') !== 'Fr' || !this.now.isBetween(moment('17:00:00', 'HH:mm:ss'), moment('17:09:59', 'HH:mm:ss')))) { + if (settings.period === 'weekly_fri_5pm' && (this.now.format('dd') !== 'Fr' || !this.now.isBetween(this.now.clone().set({hour: 17, minute: 0, second: 0}), this.now.clone().set({hour: 17, minute: 9, second: 59})))) { return; }