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 / lib / click-rule.test.js

click-rule.test.js in Extendify 3.1.0, at tests/unit/QuickEdit/lib/click-rule.test.js

154 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Pins the capture-phase click rule:
2 // anchor → navigate, pill/toolbar → pass through, form control → focus,
3 // tagged block → select (with innermost-tagged), outside → clear.
4 //
5 // The decision function is pure — given a target node, returns the
6 // branch the listener should take. The listener wiring (preventDefault,
7 // stopPropagation, hover-bar render/clear) lives in hover-bar.js and is
8 // exercised by the Playwright spec.
9
10 import { decideClickAction } from '@quick-edit/lib/click-rule';
11
12 beforeEach(() => {
13 document.body.innerHTML = '';
14 });
15
16 const make = (tag, attrs = {}, classes = []) => {
17 const el = document.createElement(tag);
18 for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, v);
19 for (const cls of classes) el.classList.add(cls);
20 return el;
21 };
22
23 describe('decideClickAction — null safety', () => {
24 it('returns ignore for null', () => {
25 expect(decideClickAction(null)).toEqual({ action: 'ignore' });
26 });
27
28 it('returns ignore for a text node target', () => {
29 const text = document.createTextNode('x');
30 expect(decideClickAction(text)).toEqual({ action: 'ignore' });
31 });
32 });
33
34 describe('decideClickAction — navigate beats everything', () => {
35 it('returns navigate for an <a href> target', () => {
36 const a = make('a', { href: '/about' });
37 document.body.appendChild(a);
38 expect(decideClickAction(a)).toEqual({ action: 'navigate' });
39 });
40
41 it('returns navigate for a descendant of <a href>', () => {
42 const a = make('a', { href: '/about' });
43 const span = make('span');
44 a.appendChild(span);
45 document.body.appendChild(a);
46 expect(decideClickAction(span)).toEqual({ action: 'navigate' });
47 });
48
49 it('returns navigate for an anchor inside a tagged block (anchor wins)', () => {
50 const block = make('section', { 'data-extendify-agent-block-id': '7' });
51 const a = make('a', { href: '/contact' });
52 block.appendChild(a);
53 document.body.appendChild(block);
54 expect(decideClickAction(a)).toEqual({ action: 'navigate' });
55 });
56
57 it('does not return navigate for an <a> without href', () => {
58 const a = make('a');
59 document.body.appendChild(a);
60 expect(decideClickAction(a)).toEqual({ action: 'clear' });
61 });
62 });
63
64 describe('decideClickAction — pill / toolbar pass-through', () => {
65 it('returns pill for a button with data-extendify-quick-edit-pill', () => {
66 const btn = make('button', { 'data-extendify-quick-edit-pill': '' });
67 document.body.appendChild(btn);
68 expect(decideClickAction(btn)).toEqual({ action: 'pill' });
69 });
70
71 it('returns pill for a span inside a data-extendify-quick-edit-bar wrapper', () => {
72 const bar = make('div', { 'data-extendify-quick-edit-bar': '' });
73 const inner = make('span');
74 bar.appendChild(inner);
75 document.body.appendChild(bar);
76 expect(decideClickAction(inner)).toEqual({ action: 'pill' });
77 });
78
79 it('returns pill (not select) when a pill sits inside a tagged block', () => {
80 const block = make('div', { 'data-extendify-agent-block-id': '4' });
81 const pill = make('button', { 'data-extendify-quick-edit-pill': '' });
82 block.appendChild(pill);
83 document.body.appendChild(block);
84 expect(decideClickAction(pill)).toEqual({ action: 'pill' });
85 });
86 });
87
88 describe('decideClickAction — form controls focus', () => {
89 it.each([
90 'input',
91 'textarea',
92 'select',
93 'button',
94 ])('returns focus-control for a bare <%s>', (tag) => {
95 const el = make(tag);
96 document.body.appendChild(el);
97 expect(decideClickAction(el)).toEqual({ action: 'focus-control' });
98 });
99
100 it('returns focus-control for a form control inside a tagged block', () => {
101 const block = make('div', { 'data-extendify-agent-block-id': '3' });
102 const input = make('input', { type: 'search' });
103 block.appendChild(input);
104 document.body.appendChild(block);
105 expect(decideClickAction(input)).toEqual({ action: 'focus-control' });
106 });
107 });
108
109 describe('decideClickAction — tagged-block select', () => {
110 it('returns select for a click directly on a tagged block', () => {
111 const block = make('div', { 'data-extendify-agent-block-id': '11' });
112 document.body.appendChild(block);
113 expect(decideClickAction(block)).toEqual({ action: 'select', el: block });
114 });
115
116 it('returns select with the innermost tagged ancestor', () => {
117 const outer = make('section', { 'data-extendify-agent-block-id': '1' });
118 const inner = make('div', { 'data-extendify-part-block-id': '2' });
119 const leaf = make('p');
120 inner.appendChild(leaf);
121 outer.appendChild(inner);
122 document.body.appendChild(outer);
123 expect(decideClickAction(leaf)).toEqual({ action: 'select', el: inner });
124 });
125
126 it('returns select for the WPForm-field-tagged ancestor', () => {
127 const block = make('div', {
128 'data-extendify-quick-edit-wpform-field-id': '7',
129 });
130 const label = make('label');
131 block.appendChild(label);
132 document.body.appendChild(block);
133 expect(decideClickAction(label)).toEqual({ action: 'select', el: block });
134 });
135
136 it('returns select for the product-tagged ancestor', () => {
137 const block = make('div', {
138 'data-extendify-quick-edit-product-id': '99',
139 });
140 const inner = make('span');
141 block.appendChild(inner);
142 document.body.appendChild(block);
143 expect(decideClickAction(inner)).toEqual({ action: 'select', el: block });
144 });
145 });
146
147 describe('decideClickAction — clear', () => {
148 it('returns clear for a click outside every tagged block', () => {
149 const body = make('p', {}, ['random']);
150 document.body.appendChild(body);
151 expect(decideClickAction(body)).toEqual({ action: 'clear' });
152 });
153 });
154