diff --git a/src/__mocks__/setupObsidianMocks.ts b/src/__mocks__/setupObsidianMocks.ts
index 20b3d24..d2626e6 100644
--- a/src/__mocks__/setupObsidianMocks.ts
+++ b/src/__mocks__/setupObsidianMocks.ts
@@ -17,5 +17,8 @@ vi.mock("obsidian", () => {
Vault: MockVault,
Component: MockComponent,
Notice: MockNotice,
+ setIcon: vi.fn((containerEl: HTMLElement, icon: string) => {
+ containerEl.innerHTML += ``;
+ }),
};
});
diff --git a/src/components/domComponent.test.ts b/src/components/domComponent.test.ts
index e2a3710..526e7da 100644
--- a/src/components/domComponent.test.ts
+++ b/src/components/domComponent.test.ts
@@ -72,7 +72,7 @@ describe("DomComponent", () => {
comp.wrapperEl = wrapper;
container.appendChild(wrapper);
- comp.onunload();
+ comp.unload();
expect(comp.unmounted).toBe(true); // only unload sets unmounted
expect(wrapper.parentElement).toBeNull();
@@ -89,7 +89,7 @@ describe("DomComponent", () => {
child.wrapperEl = wrapper;
container.appendChild(wrapper);
- child.onunload();
+ child.unload();
expect(child.unmounted).toBe(true);
expect(wrapper.parentElement).toBe(container);
diff --git a/src/components/obsidianIcon.test.ts b/src/components/obsidianIcon.test.ts
index 283afbf..c369880 100644
--- a/src/components/obsidianIcon.test.ts
+++ b/src/components/obsidianIcon.test.ts
@@ -7,12 +7,6 @@ import { createMockContainer } from "@/__mocks__/obsidian";
import { createObsidianIcon } from "./obsidianIcon";
-vi.mock("obsidian", () => ({
- setIcon: vi.fn((containerEl: HTMLElement, icon: string) => {
- containerEl.innerHTML += ``;
- }),
-}));
-
describe("createObsidianIcon", () => {
let container: HTMLElement;
diff --git a/src/components/timesheet.test.ts b/src/components/timesheet.test.ts
new file mode 100644
index 0000000..10137f6
--- /dev/null
+++ b/src/components/timesheet.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("Timesheet", () => {});
diff --git a/src/components/timesheetApp.test.ts b/src/components/timesheetApp.test.ts
new file mode 100644
index 0000000..70c0fce
--- /dev/null
+++ b/src/components/timesheetApp.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetApp", () => {});
diff --git a/src/components/timesheetCounters.test.ts b/src/components/timesheetCounters.test.ts
index bb7b38e..2a13900 100644
--- a/src/components/timesheetCounters.test.ts
+++ b/src/components/timesheetCounters.test.ts
@@ -35,7 +35,7 @@ describe("TimesheetCounters", () => {
});
it("should initialize wrapper and timers on load", () => {
- component.onload();
+ component.load();
expect(component.wrapperEl).toBeInstanceOf(HTMLDivElement);
expect(component.wrapperEl?.className).toBe("timekeep-timers");
@@ -47,13 +47,13 @@ describe("TimesheetCounters", () => {
it("should call updateTimers on load", () => {
const spy = vi.spyOn(component, "updateTimers");
- component.onload();
+ component.load();
expect(spy).toHaveBeenCalled();
});
it("should set timer values using getEntryDuration and getTotalDuration", () => {
- component.onload();
+ component.load();
const currentSetValues = vi.spyOn(component.currentTimer, "setValues");
const totalSetValues = vi.spyOn(component.totalTimer, "setValues");
@@ -73,7 +73,7 @@ describe("TimesheetCounters", () => {
const registerSpy = vi.spyOn(component, "registerInterval");
- component.onload();
+ component.load();
expect(component.currentContentInterval).toBeDefined();
expect(registerSpy).toHaveBeenCalledWith(component.currentContentInterval);
@@ -87,14 +87,14 @@ describe("TimesheetCounters", () => {
const clearSpy = vi.spyOn(global, "clearInterval");
isKeepRunning.mockReturnValue(true);
- component.onload();
+ component.load();
expect(clearSpy).toHaveBeenCalledWith(fakeIntervalID);
});
it("should show the current and total duration if theres a running entry", () => {
const start = moment();
- const oneHourLater = moment().add(1, "hour");
+ const oneHourLater = moment(start).add(1, "hour");
vi.useFakeTimers();
vi.setSystemTime(oneHourLater.toDate());
@@ -124,7 +124,7 @@ describe("TimesheetCounters", () => {
it("should show total duration as the sum of all entry durations", () => {
const start = moment();
- const oneHourLater = moment().add(1, "hour");
+ const oneHourLater = moment(start).add(1, "hour");
vi.useFakeTimers();
vi.setSystemTime(oneHourLater.toDate());
diff --git a/src/components/timesheetExportActions.test.ts b/src/components/timesheetExportActions.test.ts
new file mode 100644
index 0000000..fac1c80
--- /dev/null
+++ b/src/components/timesheetExportActions.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetExportActions", () => {});
diff --git a/src/components/timesheetFileEntry.test.ts b/src/components/timesheetFileEntry.test.ts
new file mode 100644
index 0000000..ceb021d
--- /dev/null
+++ b/src/components/timesheetFileEntry.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetFileEntry", () => {});
diff --git a/src/components/timesheetLoadError.test.ts b/src/components/timesheetLoadError.test.ts
index 237a477..16a6c62 100644
--- a/src/components/timesheetLoadError.test.ts
+++ b/src/components/timesheetLoadError.test.ts
@@ -34,7 +34,7 @@ describe("TimesheetLoadError", () => {
expect(container.children.length).toBe(1);
- component.onunload();
+ component.unload();
expect(container.children.length).toBe(0);
});
});
diff --git a/src/components/timesheetNameInput.test.ts b/src/components/timesheetNameInput.test.ts
new file mode 100644
index 0000000..1866b59
--- /dev/null
+++ b/src/components/timesheetNameInput.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetNameInput", () => {});
diff --git a/src/components/timesheetRowContainer.test.ts b/src/components/timesheetRowContainer.test.ts
new file mode 100644
index 0000000..600eb40
--- /dev/null
+++ b/src/components/timesheetRowContainer.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetRowContainer", () => {});
diff --git a/src/components/timesheetRowContent.test.ts b/src/components/timesheetRowContent.test.ts
new file mode 100644
index 0000000..805b896
--- /dev/null
+++ b/src/components/timesheetRowContent.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetRowContent", () => {});
diff --git a/src/components/timesheetRowContent.ts b/src/components/timesheetRowContent.ts
index 6c04280..e123c72 100644
--- a/src/components/timesheetRowContent.ts
+++ b/src/components/timesheetRowContent.ts
@@ -14,7 +14,7 @@ import { formatTimestamp } from "@/utils/time";
import { DomComponent } from "./domComponent";
import { createObsidianIcon } from "./obsidianIcon";
import { TimekeepName } from "./timesheetName";
-import { TimesheetRowDurationComponent } from "./timesheetRowDuration";
+import { TimesheetRowDuration } from "./timesheetRowDuration";
/**
* Component for the contents of a timesheet row
@@ -123,7 +123,7 @@ export class TimesheetRowContent extends DomComponent {
cls: ["timekeep-col", "timekeep-col--duration"],
});
- const duration = new TimesheetRowDurationComponent(durationColEl, entry);
+ const duration = new TimesheetRowDuration(durationColEl, entry);
this.addChild(duration);
diff --git a/src/components/timesheetRowContentEditing.test.ts b/src/components/timesheetRowContentEditing.test.ts
new file mode 100644
index 0000000..b35dafc
--- /dev/null
+++ b/src/components/timesheetRowContentEditing.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetRowContentEditing", () => {});
diff --git a/src/components/timesheetRowDuration.test.ts b/src/components/timesheetRowDuration.test.ts
index 37fd65c..39b307a 100644
--- a/src/components/timesheetRowDuration.test.ts
+++ b/src/components/timesheetRowDuration.test.ts
@@ -7,12 +7,12 @@ import { createMockContainer } from "@/__mocks__/obsidian";
import * as queries from "@/timekeep/queries";
import * as timeUtils from "@/utils/time";
-import { TimesheetRowDurationComponent } from "./timesheetRowDuration";
+import { TimesheetRowDuration } from "./timesheetRowDuration";
-describe("TimesheetRowDurationComponent", () => {
+describe("TimesheetRowDuration", () => {
let container: HTMLElement;
let entry: any;
- let component: TimesheetRowDurationComponent;
+ let component: TimesheetRowDuration;
beforeEach(() => {
container = createMockContainer();
@@ -30,7 +30,7 @@ describe("TimesheetRowDurationComponent", () => {
// Mock setInterval / clearInterval
vi.useFakeTimers();
- component = new TimesheetRowDurationComponent(container, entry);
+ component = new TimesheetRowDuration(container, entry);
});
afterEach(() => {
@@ -38,7 +38,7 @@ describe("TimesheetRowDurationComponent", () => {
});
it("should create a wrapper span with the correct class", () => {
- component.onload();
+ component.load();
expect(component.wrapperEl).toBeInstanceOf(HTMLSpanElement);
expect(component.wrapperEl?.className).toBe("timekeep-time");
@@ -47,13 +47,13 @@ describe("TimesheetRowDurationComponent", () => {
it("should call updateTime on load", () => {
const spy = vi.spyOn(component, "updateTime");
- component.onload();
+ component.load();
expect(spy).toHaveBeenCalled();
});
it("should set textContent based on getEntryDuration and formatDurationLong", () => {
- component.onload();
+ component.load();
expect(queries.getEntryDuration).toHaveBeenCalledWith(entry, expect.any(moment));
expect(timeUtils.formatDurationLong).toHaveBeenCalledWith(42);
@@ -64,7 +64,7 @@ describe("TimesheetRowDurationComponent", () => {
(queries.isEntryRunning as any).mockReturnValue(true);
const registerSpy = vi.spyOn(component, "registerInterval");
- component.onload();
+ component.load();
expect(component.currentContentInterval).toBeDefined();
expect(registerSpy).toHaveBeenCalledWith(component.currentContentInterval);
@@ -76,7 +76,7 @@ describe("TimesheetRowDurationComponent", () => {
const clearSpy = vi.spyOn(global, "clearInterval");
(queries.isEntryRunning as any).mockReturnValue(true);
- component.onload();
+ component.load();
expect(clearSpy).toHaveBeenCalledWith(fakeInterval);
});
@@ -84,7 +84,7 @@ describe("TimesheetRowDurationComponent", () => {
it("should not schedule interval if entry is not running", () => {
(queries.isEntryRunning as any).mockReturnValue(false);
const registerSpy = vi.spyOn(component, "registerInterval");
- component.onload();
+ component.load();
expect(component.currentContentInterval).not.toBeDefined();
expect(registerSpy).not.toHaveBeenCalled();
diff --git a/src/components/timesheetRowDuration.ts b/src/components/timesheetRowDuration.ts
index 1cc0f8c..2bdf3a2 100644
--- a/src/components/timesheetRowDuration.ts
+++ b/src/components/timesheetRowDuration.ts
@@ -10,7 +10,7 @@ import { DomComponent } from "./domComponent";
* Component for rendering the live-updating duration on
* an entry row
*/
-export class TimesheetRowDurationComponent extends DomComponent {
+export class TimesheetRowDuration extends DomComponent {
/** The entry this duration belongs to */
entry: TimeEntry;
diff --git a/src/components/timesheetSaveError.test.ts b/src/components/timesheetSaveError.test.ts
index cda3b46..c10eb70 100644
--- a/src/components/timesheetSaveError.test.ts
+++ b/src/components/timesheetSaveError.test.ts
@@ -34,7 +34,7 @@ describe("TimesheetSaveError", () => {
});
it("renders wrapper, error message, and buttons on load", () => {
- component.onload();
+ component.load();
const wrapper = container.querySelector(".timekeep-container");
expect(wrapper).not.toBeNull();
@@ -54,13 +54,13 @@ describe("TimesheetSaveError", () => {
});
it("calls handleSaveTimekeep on retry button click", () => {
- component.onload();
+ component.load();
component.onRetrySave();
expect(handleSaveTimekeep).toHaveBeenCalledWith(timekeepStore.getState());
});
it("writes JSON to clipboard on copy button click", async () => {
- component.onload();
+ component.load();
await component.onCopy();
@@ -70,8 +70,8 @@ describe("TimesheetSaveError", () => {
});
it("removes wrapper on unload", () => {
- component.onload();
- component.onunload();
+ component.load();
+ component.unload();
const wrapper = container.querySelector(".timekeep-container");
expect(wrapper).toBeNull();
});
diff --git a/src/components/timesheetStart.test.ts b/src/components/timesheetStart.test.ts
new file mode 100644
index 0000000..6883353
--- /dev/null
+++ b/src/components/timesheetStart.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetStart", () => {});
diff --git a/src/components/timesheetStartEditing.test.ts b/src/components/timesheetStartEditing.test.ts
new file mode 100644
index 0000000..2aa84eb
--- /dev/null
+++ b/src/components/timesheetStartEditing.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetStartEditing", () => {});
diff --git a/src/components/timesheetStartRunning.test.ts b/src/components/timesheetStartRunning.test.ts
new file mode 100644
index 0000000..0054a64
--- /dev/null
+++ b/src/components/timesheetStartRunning.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetStartRunning", () => {});
diff --git a/src/components/timesheetStatusBarItem.test.ts b/src/components/timesheetStatusBarItem.test.ts
new file mode 100644
index 0000000..4da5d7f
--- /dev/null
+++ b/src/components/timesheetStatusBarItem.test.ts
@@ -0,0 +1,76 @@
+// @vitest-environment happy-dom
+
+import moment from "moment";
+import { v4 } from "uuid";
+import { describe, beforeEach, it, expect, vi, afterEach } from "vitest";
+
+import { createMockContainer } from "@/__mocks__/obsidian";
+import { TimeEntry } from "@/timekeep/schema";
+
+import { TimesheetStatusBarItem } from "./timesheetStatusBarItem";
+
+describe("TimesheetStatusBarItem", () => {
+ const start = moment();
+ const oneHourLater = start.add(1, "hour");
+
+ const entry: TimeEntry = {
+ id: v4(),
+ name: "Test",
+ startTime: moment(start),
+ endTime: null,
+ subEntries: null,
+ };
+ let containerEl: HTMLElement;
+ let onOpen: VoidFunction;
+ let onStop: VoidFunction;
+
+ beforeEach(() => {
+ onOpen = vi.fn();
+ onStop = vi.fn();
+
+ vi.useFakeTimers();
+ vi.setSystemTime(oneHourLater.toDate());
+
+ containerEl = createMockContainer();
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ });
+
+ it("should initialize with the correct entry and callback functions", () => {
+ const statusBarItem = new TimesheetStatusBarItem(containerEl, entry, onOpen, onStop);
+
+ expect(statusBarItem.entry).toBe(entry);
+ expect(statusBarItem.onOpen).toBe(onOpen);
+ expect(statusBarItem.onStop).toBe(onStop);
+ });
+
+ it("should call onStop when the stop icon is clicked", () => {
+ const statusBarItem = new TimesheetStatusBarItem(containerEl, entry, onOpen, onStop);
+ statusBarItem.load();
+
+ // Simulate click on the stop icon
+ const stopIcon = containerEl.querySelector(".button-icon");
+ const event = new MouseEvent("click", { bubbles: true, cancelable: true });
+ if (stopIcon) {
+ stopIcon.dispatchEvent(event);
+ }
+
+ expect(onStop).toHaveBeenCalledTimes(1);
+ });
+
+ it("should call onOpen when the content area is clicked", () => {
+ const statusBarItem = new TimesheetStatusBarItem(containerEl, entry, onOpen, onStop);
+ statusBarItem.load();
+
+ // Simulate click on the content element
+ const contentEl = containerEl.querySelector(".timekeep-status-item__content");
+ const event = new MouseEvent("click", { bubbles: true, cancelable: true });
+ if (contentEl) {
+ contentEl.dispatchEvent(event);
+ }
+
+ expect(onOpen).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/components/timesheetStatusBarItem.ts b/src/components/timesheetStatusBarItem.ts
index 0e381bf..fed8464 100644
--- a/src/components/timesheetStatusBarItem.ts
+++ b/src/components/timesheetStatusBarItem.ts
@@ -2,7 +2,7 @@ import { TimeEntry } from "@/timekeep/schema";
import { DomComponent } from "./domComponent";
import { createObsidianIcon } from "./obsidianIcon";
-import { TimesheetRowDurationComponent } from "./timesheetRowDuration";
+import { TimesheetRowDuration } from "./timesheetRowDuration";
export class TimesheetStatusBarItem extends DomComponent {
/** The entry this duration belongs to */
@@ -12,7 +12,7 @@ export class TimesheetStatusBarItem extends DomComponent {
currentContentInterval: number | undefined;
/** Component for rendering the real time updating duration */
- duration: TimesheetRowDurationComponent;
+ duration: TimesheetRowDuration;
/** Callback to open the file when the content is clicked */
onOpen: VoidFunction;
@@ -44,7 +44,6 @@ export class TimesheetStatusBarItem extends DomComponent {
"timekeep-status-item__button",
"button-icon",
]);
- this.registerDomEvent(stopIcon, "click", this.onStop);
stopIcon.title = "Stop Entry";
const contentEl = wrapperEl.createDiv({
@@ -57,8 +56,9 @@ export class TimesheetStatusBarItem extends DomComponent {
text: entry.name + ":",
});
- this.addChild(new TimesheetRowDurationComponent(contentEl, entry));
+ this.addChild(new TimesheetRowDuration(contentEl, entry));
+ this.registerDomEvent(stopIcon, "click", this.onStop);
this.registerDomEvent(contentEl, "click", this.onOpen);
}
}
diff --git a/src/components/timesheetTable.test.ts b/src/components/timesheetTable.test.ts
new file mode 100644
index 0000000..5139acf
--- /dev/null
+++ b/src/components/timesheetTable.test.ts
@@ -0,0 +1,5 @@
+// @vitest-environment happy-dom
+
+import { describe } from "vitest";
+
+describe("TimesheetTable", () => {});
diff --git a/src/components/timesheetTimer.test.ts b/src/components/timesheetTimer.test.ts
index 32eac46..72a3f4e 100644
--- a/src/components/timesheetTimer.test.ts
+++ b/src/components/timesheetTimer.test.ts
@@ -16,7 +16,7 @@ describe("TimesheetTimer", () => {
});
it("should create timer elements on load", () => {
- timer.onload();
+ timer.load();
const timerEl = container.children[0] as HTMLElement;
expect(timerEl).toBeDefined();
@@ -36,16 +36,16 @@ describe("TimesheetTimer", () => {
});
it("should remove timer element on unload", () => {
- timer.onload();
+ timer.load();
const timerEl = container.children[0] as HTMLElement;
expect(timerEl).toBeDefined();
- timer.onunload();
+ timer.unload();
expect(timerEl.parentElement).toBeNull();
});
it("should hide or show the timer element", () => {
- timer.onload();
+ timer.load();
const timerEl = container.children[0] as HTMLElement;
timer.setHidden(true);
@@ -56,7 +56,7 @@ describe("TimesheetTimer", () => {
});
it("should set primary and secondary values correctly", () => {
- timer.onload();
+ timer.load();
const timerEl = container.children[0] as HTMLElement;
const primary = timerEl.children[0] as HTMLDivElement;
const secondary = timerEl.children[1] as HTMLDivElement;
@@ -73,7 +73,7 @@ describe("TimesheetTimer", () => {
});
it("secondary value should be hidden if it is empty", () => {
- timer.onload();
+ timer.load();
const timerEl = container.children[0] as HTMLElement;
const secondary = timerEl.children[1] as HTMLDivElement;