PluginProbe
Extendify / 3.1.1
Extendify v3.1.1
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 / components / toolbar / HeadingLevelButton.test.jsx

HeadingLevelButton.test.jsx in Extendify 3.1.1, at tests/unit/QuickEdit/components/toolbar/HeadingLevelButton.test.jsx

136 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // HeadingLevelButton restores the H1–H6 picker that the floating bar
2 // otherwise loses by hiding `.block-editor-block-switcher`.
3 // Pin: renders only for core/heading, shows the current level, click
4 // dispatches updateBlockAttributes({ level: N }) against the local
5 // BlockEditor registry.
6
7 import { act, fireEvent, render, waitFor } from '@testing-library/react';
8
9 const mockUpdateBlockAttributes = jest.fn();
10
11 let mockSelectedBlock = null;
12
13 jest.mock('@wordpress/data', () => ({
14 useSelect: (fn) =>
15 fn(() => ({
16 getSelectedBlockClientId: () => mockSelectedBlock?.clientId ?? null,
17 getBlock: () => mockSelectedBlock?.block ?? null,
18 })),
19 useDispatch: () => ({
20 updateBlockAttributes: (...args) => mockUpdateBlockAttributes(...args),
21 }),
22 }));
23
24 jest.mock('@wordpress/i18n', () => ({
25 __: (s) => s,
26 sprintf: (format, ...args) => {
27 let i = 0;
28 return format.replace(/%[ds]/g, () => String(args[i++]));
29 },
30 }));
31
32 jest.mock('@wordpress/components', () => ({
33 Button: ({ children, onClick, onMouseDown, label, role }) => (
34 <button
35 type="button"
36 onClick={onClick}
37 onMouseDown={onMouseDown}
38 aria-label={label}
39 role={role}
40 >
41 {children}
42 </button>
43 ),
44 Popover: ({ children }) => <div data-testid="popover">{children}</div>,
45 }));
46
47 beforeEach(() => {
48 jest.clearAllMocks();
49 mockSelectedBlock = null;
50 });
51
52 const importButton = () =>
53 require('@quick-edit/components/toolbar/HeadingLevelButton')
54 .HeadingLevelButton;
55
56 const setHeading = (level) => {
57 mockSelectedBlock = {
58 clientId: 'block-1',
59 block: { name: 'core/heading', attributes: { level } },
60 };
61 };
62
63 describe('HeadingLevelButton — visibility', () => {
64 it('renders nothing when no block is selected', () => {
65 const HeadingLevelButton = importButton();
66 const { container } = render(<HeadingLevelButton />);
67 expect(container.firstChild).toBeNull();
68 });
69
70 it('renders nothing for non-heading blocks', () => {
71 mockSelectedBlock = {
72 clientId: 'p-1',
73 block: { name: 'core/paragraph', attributes: {} },
74 };
75 const HeadingLevelButton = importButton();
76 const { container } = render(<HeadingLevelButton />);
77 expect(container.firstChild).toBeNull();
78 });
79
80 it('renders the current level for a heading block', () => {
81 setHeading(3);
82 const HeadingLevelButton = importButton();
83 const { getByText } = render(<HeadingLevelButton />);
84 expect(getByText('H3')).toBeTruthy();
85 });
86
87 it('defaults to H2 when the heading has no explicit level attribute', () => {
88 mockSelectedBlock = {
89 clientId: 'h-1',
90 block: { name: 'core/heading', attributes: {} },
91 };
92 const HeadingLevelButton = importButton();
93 const { getByText } = render(<HeadingLevelButton />);
94 expect(getByText('H2')).toBeTruthy();
95 });
96 });
97
98 describe('HeadingLevelButton — picker', () => {
99 it('opens the picker on click and dispatches the level change', async () => {
100 setHeading(2);
101 const HeadingLevelButton = importButton();
102 const { getByLabelText, container } = render(<HeadingLevelButton />);
103
104 act(() => {
105 fireEvent.click(getByLabelText('Heading level'));
106 });
107
108 await waitFor(() => {
109 expect(container.querySelector('[data-testid="popover"]')).not.toBeNull();
110 });
111
112 const h4Option = getByLabelText('Heading 4');
113 act(() => {
114 fireEvent.click(h4Option);
115 });
116
117 expect(mockUpdateBlockAttributes).toHaveBeenCalledWith('block-1', {
118 level: 4,
119 });
120 });
121
122 it('renders all six heading levels in the picker', () => {
123 setHeading(1);
124 const HeadingLevelButton = importButton();
125 const { getByLabelText } = render(<HeadingLevelButton />);
126
127 act(() => {
128 fireEvent.click(getByLabelText('Heading level'));
129 });
130
131 for (const n of [1, 2, 3, 4, 5, 6]) {
132 expect(getByLabelText(`Heading ${n}`)).toBeTruthy();
133 }
134 });
135 });
136