Full document, spreadsheet, slideshow, and diagram tooling
1import { describe, it, expect } from 'vitest';
2
3/**
4 * Tests for Focus/Zen Mode (src/docs/zen-mode.js)
5 *
6 * Zen mode provides distraction-free editing by hiding the toolbar and
7 * topbar, expanding the editor to full width. Since we can't run DOM
8 * in Node, we test the pure logic: state management, CSS class names,
9 * and localStorage persistence.
10 */
11
12import {
13 ZenModeState,
14 ZEN_STORAGE_KEY,
15 ZEN_CLASS,
16 ZEN_TRANSITION_MS,
17} from '../src/docs/zen-mode.js';
18
19describe('ZenModeState — state management', () => {
20 it('starts inactive by default', () => {
21 const state = new ZenModeState();
22 expect(state.isActive).toBe(false);
23 });
24
25 it('can be initialized as active', () => {
26 const state = new ZenModeState(true);
27 expect(state.isActive).toBe(true);
28 });
29
30 it('toggle flips the state', () => {
31 const state = new ZenModeState();
32 state.toggle();
33 expect(state.isActive).toBe(true);
34 state.toggle();
35 expect(state.isActive).toBe(false);
36 });
37
38 it('activate/deactivate are explicit', () => {
39 const state = new ZenModeState();
40 state.activate();
41 expect(state.isActive).toBe(true);
42 state.activate(); // idempotent
43 expect(state.isActive).toBe(true);
44 state.deactivate();
45 expect(state.isActive).toBe(false);
46 state.deactivate(); // idempotent
47 expect(state.isActive).toBe(false);
48 });
49
50 it('tracks toggle count for debugging', () => {
51 const state = new ZenModeState();
52 expect(state.toggleCount).toBe(0);
53 state.toggle();
54 expect(state.toggleCount).toBe(1);
55 state.toggle();
56 expect(state.toggleCount).toBe(2);
57 });
58});
59
60describe('ZEN_STORAGE_KEY — localStorage key', () => {
61 it('is a non-empty string', () => {
62 expect(typeof ZEN_STORAGE_KEY).toBe('string');
63 expect(ZEN_STORAGE_KEY.length).toBeGreaterThan(0);
64 });
65
66 it('is namespaced to atmos', () => {
67 expect(ZEN_STORAGE_KEY).toContain('atmos');
68 });
69});
70
71describe('ZEN_CLASS — CSS class applied to body/app', () => {
72 it('is a non-empty string', () => {
73 expect(typeof ZEN_CLASS).toBe('string');
74 expect(ZEN_CLASS.length).toBeGreaterThan(0);
75 });
76
77 it('contains "zen"', () => {
78 expect(ZEN_CLASS).toContain('zen');
79 });
80});
81
82describe('ZEN_TRANSITION_MS — transition duration', () => {
83 it('is a positive number', () => {
84 expect(typeof ZEN_TRANSITION_MS).toBe('number');
85 expect(ZEN_TRANSITION_MS).toBeGreaterThan(0);
86 });
87
88 it('is reasonable for CSS animation (100-500ms)', () => {
89 expect(ZEN_TRANSITION_MS).toBeGreaterThanOrEqual(100);
90 expect(ZEN_TRANSITION_MS).toBeLessThanOrEqual(500);
91 });
92});
93
94describe('ZenModeState — getClassList returns correct classes', () => {
95 it('returns zen class when active', () => {
96 const state = new ZenModeState();
97 state.activate();
98 expect(state.getClassList()).toContain(ZEN_CLASS);
99 });
100
101 it('returns empty array when inactive', () => {
102 const state = new ZenModeState();
103 expect(state.getClassList()).toEqual([]);
104 });
105});
106
107describe('ZenModeState — serialization for localStorage', () => {
108 it('serialize returns "true" when active', () => {
109 const state = new ZenModeState(true);
110 expect(state.serialize()).toBe('true');
111 });
112
113 it('serialize returns "false" when inactive', () => {
114 const state = new ZenModeState(false);
115 expect(state.serialize()).toBe('false');
116 });
117
118 it('fromStored creates active state from "true"', () => {
119 const state = ZenModeState.fromStored('true');
120 expect(state.isActive).toBe(true);
121 });
122
123 it('fromStored creates inactive state from "false"', () => {
124 const state = ZenModeState.fromStored('false');
125 expect(state.isActive).toBe(false);
126 });
127
128 it('fromStored creates inactive state from null/empty', () => {
129 const state = ZenModeState.fromStored(null);
130 expect(state.isActive).toBe(false);
131 const state2 = ZenModeState.fromStored('');
132 expect(state2.isActive).toBe(false);
133 const state3 = ZenModeState.fromStored(undefined);
134 expect(state3.isActive).toBe(false);
135 });
136});