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 / playwright / QuickEdit / text-alignment / text-alignment.spec.ts

text-alignment.spec.ts in Extendify 3.1.1, at tests/playwright/QuickEdit/text-alignment/text-alignment.spec.ts

189 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Text-alignment dropdown on the QE
2 // floating bar. Gutenberg ships alignment in a BlockControls group the
3 // QE bar hides; the QE-side dropdown restores it for blocks whose render
4 // path applies `has-text-align-*` from `style.typography.textAlign` via
5 // useBlockProps (`core/heading`, `core/paragraph`).
6 //
7 // An earlier design had three inline buttons whose wider tooltips overlapped
8 // neighbouring toolbar buttons. Collapsing to a single trigger
9 // + popover and trying `Tooltip placement="top"` didn't escape the overlap —
10 // the placement-top tooltip still overlapped in real-WP testing because
11 // "Align text" is wider than the 36px icon-only trigger. So the trigger
12 // tooltip is dropped entirely — the popover's visible option
13 // labels carry the affordance once opened. The pin below asserts no
14 // `.components-tooltip` ever appears on hover of the trigger so the
15 // regression can't return.
16
17 import { expect, test } from '../../fixtures';
18
19 const PARAGRAPH = 'A plain paragraph that can take a text alignment.';
20 const HEADING = 'A heading that can take a text alignment.';
21
22 const editModeToggle = (page) => page.locator('#ext-tb-quick-edit');
23
24 const hoverBar = (page) => page.locator('.extendify-quick-edit-bar');
25
26 const paragraph = (page) =>
27 page.locator('p.wp-block-paragraph', { hasText: PARAGRAPH });
28
29 const heading = (page) =>
30 page.locator('h2.wp-block-heading', { hasText: HEADING });
31
32 const image = (page) => page.locator('figure.wp-block-image').first();
33
34 const buttonBlock = (page) =>
35 page.locator('div.wp-block-button', { hasText: 'Browse Collection' });
36
37 const colorsGroup = (page) =>
38 floatingBar(page).locator('[data-test="quick-edit-colors-group"]');
39
40 const editorRichText = (page) =>
41 page
42 .locator('.extendify-quick-edit-canvas .block-editor-rich-text__editable')
43 .first();
44
45 const floatingBar = (page) =>
46 page.locator('[data-test="quick-edit-floating-bar"]');
47
48 const alignTrigger = (page) =>
49 floatingBar(page).locator('.extendify-quick-edit-text-align-button');
50
51 const alignPopover = (page) =>
52 page.locator('.extendify-quick-edit-text-align-popover');
53
54 const alignOption = (page, name: RegExp) =>
55 alignPopover(page).getByRole('option', { name });
56
57 const headingLevelButton = (page) =>
58 floatingBar(page).locator('.extendify-quick-edit-heading-level-button');
59
60 const enableEditMode = async (page) => {
61 await page.addInitScript(() => {
62 window.localStorage.setItem(
63 'extendify-quick-edit-mode',
64 JSON.stringify({ state: { on: true }, version: 0 }),
65 );
66 });
67 };
68
69 const openInlineEditor = async (page, target) => {
70 await target.hover();
71 await hoverBar(page)
72 .getByRole('button', { name: /Quick Edit/ })
73 .click();
74 await expect(editorRichText(page)).toBeVisible();
75 };
76
77 test.beforeEach(async ({ requestUtils }) => {
78 await requestUtils.login();
79 });
80
81 test('paragraph: opening the dropdown and picking center applies has-text-align-center and persists on save', async ({
82 page,
83 }) => {
84 await enableEditMode(page);
85 await page.goto('/');
86 await expect(editModeToggle(page)).toBeVisible({ timeout: 15_000 });
87
88 await openInlineEditor(page, paragraph(page));
89 await expect(alignTrigger(page)).toBeVisible();
90
91 await alignTrigger(page).click();
92 await expect(alignPopover(page)).toBeVisible();
93 await alignOption(page, /^Align text center$/).click();
94 await expect(alignPopover(page)).toBeHidden();
95 await expect(editorRichText(page)).toHaveClass(/has-text-align-center/);
96
97 const saved = page.waitForResponse(
98 (r) => r.url().includes('/quick-edit/save') && r.status() === 200,
99 );
100 await page.locator('[data-test="quick-edit-save"]').click();
101 await saved;
102
103 await expect(editorRichText(page)).toBeHidden();
104 await expect(paragraph(page)).toHaveClass(/has-text-align-center/);
105 });
106
107 test('heading: picking left then right swaps the alignment in place', async ({
108 page,
109 }) => {
110 await enableEditMode(page);
111 await page.goto('/');
112 await expect(editModeToggle(page)).toBeVisible({ timeout: 15_000 });
113
114 await openInlineEditor(page, heading(page));
115
116 await alignTrigger(page).click();
117 await alignOption(page, /^Align text left$/).click();
118 await expect(editorRichText(page)).toHaveClass(/has-text-align-left/);
119
120 await alignTrigger(page).click();
121 await alignOption(page, /^Align text right$/).click();
122 await expect(editorRichText(page)).toHaveClass(/has-text-align-right/);
123 await expect(editorRichText(page)).not.toHaveClass(/has-text-align-left/);
124 });
125
126 test('image: alignment trigger is not rendered (block has no textAlign attribute)', async ({
127 page,
128 }) => {
129 await enableEditMode(page);
130 await page.goto('/');
131 await expect(editModeToggle(page)).toBeVisible({ timeout: 15_000 });
132
133 await image(page).hover();
134 await hoverBar(page)
135 .getByRole('button', { name: /Quick Edit/ })
136 .click();
137
138 await expect(alignTrigger(page)).toHaveCount(0);
139 });
140
141 test('button block: alignment trigger + colors group are NOT rendered', async ({
142 page,
143 }) => {
144 await enableEditMode(page);
145 await page.goto('/');
146 await expect(editModeToggle(page)).toBeVisible({ timeout: 15_000 });
147
148 await openInlineEditor(page, buttonBlock(page));
149
150 // Buttons are controlled by global styles, not inline alignment /
151 // text-color / highlight — the QE bar drops those groups for
152 // `core/button`.
153 await expect(alignTrigger(page)).toHaveCount(0);
154 await expect(colorsGroup(page)).toHaveCount(0);
155
156 // BlockToolbar's B / I / link are still lifted in, so editing the
157 // button's text works.
158 await expect(
159 floatingBar(page).getByRole('button', { name: /^Bold$/ }),
160 ).toBeVisible();
161 });
162
163 test('hovering the alignment trigger does not surface a tooltip while the QE bar is mounted', async ({
164 page,
165 }) => {
166 await enableEditMode(page);
167 await page.goto('/');
168 await expect(editModeToggle(page)).toBeVisible({ timeout: 15_000 });
169
170 await openInlineEditor(page, heading(page));
171
172 // QE bar tooltips are hidden globally (revisit later).
173 // The other half of the contract — that tooltips return when the bar
174 // unmounts — is the scope guarantee of `body:has(.extendify-quick-edit-
175 // floating-bar)` in quick-edit.css.
176 await headingLevelButton(page).hover();
177 await page.waitForTimeout(400);
178 await alignTrigger(page).hover();
179 await page.waitForTimeout(800);
180
181 const visible = await page.evaluate(
182 () =>
183 Array.from(document.querySelectorAll('[id^="portal/tooltip"]')).filter(
184 (el) => getComputedStyle(el).display !== 'none',
185 ).length,
186 );
187 expect(visible).toBe(0);
188 });
189