PluginProbe
Extendify / 3.1.0
Extendify v3.1.0
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / tests / unit / QuickEdit / state / edit-mode.test.js

edit-mode.test.js in Extendify 3.1.0, at tests/unit/QuickEdit/state/edit-mode.test.js

127 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Mock zustand's persist middleware so it runs synchronously and we don't
2 // have to coordinate hydration timing per test.
3 jest.mock('zustand/middleware', () => ({
4 devtools: (fn) => fn,
5 persist: (config) => config,
6 }));
7
8 jest.mock('@quick-edit/lib/insights', () => ({
9 track: jest.fn(),
10 }));
11
12 const HTML_CLASS = 'extendify-quick-edit-on';
13
14 const loadStore = async () => {
15 const mod = await import('@quick-edit/state/edit-mode');
16 return mod.useEditModeStore;
17 };
18
19 beforeEach(() => {
20 jest.resetModules();
21 jest.clearAllMocks();
22 document.documentElement.className = '';
23 window.extQuickEditData = undefined;
24 });
25
26 describe('useEditModeStore — initial state', () => {
27 it('defaults on=false and clears the HTML class when no extQuickEditData', async () => {
28 const useEditModeStore = await loadStore();
29 expect(useEditModeStore.getState().on).toBe(false);
30 expect(document.documentElement.classList.contains(HTML_CLASS)).toBe(false);
31 });
32
33 it('honors extQuickEditData.defaultOn=true and applies the HTML class at import time', async () => {
34 window.extQuickEditData = { defaultOn: true };
35 const useEditModeStore = await loadStore();
36 expect(useEditModeStore.getState().on).toBe(true);
37 expect(document.documentElement.classList.contains(HTML_CLASS)).toBe(true);
38 });
39
40 it('coerces extQuickEditData.defaultOn to a boolean (truthy non-bool → true)', async () => {
41 window.extQuickEditData = { defaultOn: 'yes' };
42 const useEditModeStore = await loadStore();
43 expect(useEditModeStore.getState().on).toBe(true);
44 });
45 });
46
47 describe('useEditModeStore — actions', () => {
48 it('setOn updates the flag', async () => {
49 const useEditModeStore = await loadStore();
50 useEditModeStore.getState().setOn(true);
51 expect(useEditModeStore.getState().on).toBe(true);
52 useEditModeStore.getState().setOn(false);
53 expect(useEditModeStore.getState().on).toBe(false);
54 });
55
56 it('setOn coerces non-bool args to booleans', async () => {
57 const useEditModeStore = await loadStore();
58 useEditModeStore.getState().setOn('yes');
59 expect(useEditModeStore.getState().on).toBe(true);
60 });
61
62 it('setOn is a no-op when the value is unchanged (does not refire subscribers)', async () => {
63 const useEditModeStore = await loadStore();
64 const insights = require('@quick-edit/lib/insights');
65 insights.track.mockClear();
66 useEditModeStore.getState().setOn(false); // already false
67 expect(insights.track).not.toHaveBeenCalled();
68 });
69
70 it('toggle flips on', async () => {
71 const useEditModeStore = await loadStore();
72 useEditModeStore.getState().toggle();
73 expect(useEditModeStore.getState().on).toBe(true);
74 useEditModeStore.getState().toggle();
75 expect(useEditModeStore.getState().on).toBe(false);
76 });
77 });
78
79 describe('useEditModeStore — HTML class + insights side effects', () => {
80 it('adds the HTML class and tracks edit_mode_on when turning on', async () => {
81 const useEditModeStore = await loadStore();
82 const insights = require('@quick-edit/lib/insights');
83 insights.track.mockClear();
84 useEditModeStore.getState().setOn(true);
85 expect(document.documentElement.classList.contains(HTML_CLASS)).toBe(true);
86 expect(insights.track).toHaveBeenCalledWith('edit_mode_on');
87 });
88
89 it('removes the HTML class and tracks edit_mode_off when turning off', async () => {
90 window.extQuickEditData = { defaultOn: true };
91 const useEditModeStore = await loadStore();
92 const insights = require('@quick-edit/lib/insights');
93 insights.track.mockClear();
94 useEditModeStore.getState().setOn(false);
95 expect(document.documentElement.classList.contains(HTML_CLASS)).toBe(false);
96 expect(insights.track).toHaveBeenCalledWith('edit_mode_off');
97 });
98 });
99
100 describe('useEditModeStore — no Agent workflow bridge', () => {
101 it('loads without importing useWorkflowStore (no bridge required)', () => {
102 const src = require('node:fs').readFileSync(
103 require('node:path').resolve(
104 __dirname,
105 '../../../../src/QuickEdit/state/edit-mode.js',
106 ),
107 'utf8',
108 );
109 expect(src).not.toMatch(/@agent\/state\/workflows/);
110 expect(src).not.toMatch(/useWorkflowStore/);
111 });
112 });
113
114 describe('useEditModeStore — no Esc handling', () => {
115 it('does not attach a document-level Esc listener (handled by global-escape)', () => {
116 const src = require('node:fs').readFileSync(
117 require('node:path').resolve(
118 __dirname,
119 '../../../../src/QuickEdit/state/edit-mode.js',
120 ),
121 'utf8',
122 );
123 expect(src).not.toMatch(/Escape/);
124 expect(src).not.toMatch(/keydown/);
125 });
126 });
127