@stratawp/testing 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +579 -0
- package/dist/index.d.ts +227 -0
- package/dist/index.js +308 -0
- package/dist/index.js.map +1 -0
- package/dist/playwright.d.ts +98 -0
- package/dist/playwright.js +143 -0
- package/dist/playwright.js.map +1 -0
- package/dist/vitest.d.ts +4 -0
- package/dist/vitest.js +322 -0
- package/dist/vitest.js.map +1 -0
- package/package.json +70 -0
- package/playwright.config.ts +84 -0
- package/vitest.config.ts +43 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { RenderOptions, render } from '@testing-library/react';
|
|
2
|
+
export { RenderOptions } from '@testing-library/react';
|
|
3
|
+
import * as vitest from 'vitest';
|
|
4
|
+
import '@testing-library/user-event';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Block Testing Utilities
|
|
8
|
+
* Helper functions for testing Gutenberg blocks
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Block Configuration Interface
|
|
13
|
+
*/
|
|
14
|
+
interface BlockConfiguration {
|
|
15
|
+
name?: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
category?: string;
|
|
19
|
+
icon?: string | Record<string, any>;
|
|
20
|
+
keywords?: string[];
|
|
21
|
+
attributes?: Record<string, any>;
|
|
22
|
+
supports?: Record<string, any>;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Render a block's edit component for testing
|
|
27
|
+
*/
|
|
28
|
+
declare function renderBlockEdit(EditComponent: React.ComponentType<any>, props?: any, options?: RenderOptions): ReturnType<typeof render>;
|
|
29
|
+
/**
|
|
30
|
+
* Render a block's save component for testing
|
|
31
|
+
*/
|
|
32
|
+
declare function renderBlockSave(SaveComponent: React.ComponentType<any>, props?: any, options?: RenderOptions): ReturnType<typeof render>;
|
|
33
|
+
/**
|
|
34
|
+
* Test if a block is registered correctly
|
|
35
|
+
*/
|
|
36
|
+
declare function testBlockRegistration(blockName: string, expectedConfig: Partial<BlockConfiguration>): any;
|
|
37
|
+
/**
|
|
38
|
+
* Create mock block attributes
|
|
39
|
+
*/
|
|
40
|
+
declare function createMockAttributes(blockType: string, overrides?: Record<string, any>): Record<string, any>;
|
|
41
|
+
/**
|
|
42
|
+
* Test block attribute validation
|
|
43
|
+
*/
|
|
44
|
+
declare function testBlockAttributes(EditComponent: React.ComponentType<any>, attributes: Record<string, any>): {
|
|
45
|
+
setAttributes: any;
|
|
46
|
+
rerender: (newAttributes: Record<string, any>) => void;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Test block save output
|
|
50
|
+
*/
|
|
51
|
+
declare function testBlockSaveOutput(SaveComponent: React.ComponentType<any>, attributes: Record<string, any>): string;
|
|
52
|
+
/**
|
|
53
|
+
* Mock block context
|
|
54
|
+
*/
|
|
55
|
+
declare function createMockBlockContext(overrides?: any): any;
|
|
56
|
+
/**
|
|
57
|
+
* Wait for block to render
|
|
58
|
+
*/
|
|
59
|
+
declare function waitForBlockRender(callback: () => void, options?: {
|
|
60
|
+
timeout?: number;
|
|
61
|
+
}): Promise<void>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* WordPress API Mocks
|
|
65
|
+
* Mock implementations of WordPress JavaScript APIs for testing
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* Mock @wordpress/blocks
|
|
69
|
+
*/
|
|
70
|
+
declare const mockWordPressBlocks: {
|
|
71
|
+
registerBlockType: vitest.Mock<[name: string, settings: any], any>;
|
|
72
|
+
unregisterBlockType: vitest.Mock<any, any>;
|
|
73
|
+
getBlockType: vitest.Mock<[name: string], {
|
|
74
|
+
name: string;
|
|
75
|
+
title: string;
|
|
76
|
+
category: string;
|
|
77
|
+
icon: string;
|
|
78
|
+
attributes: {};
|
|
79
|
+
}>;
|
|
80
|
+
getBlockTypes: vitest.Mock<[], never[]>;
|
|
81
|
+
hasBlockSupport: vitest.Mock<[], boolean>;
|
|
82
|
+
createBlock: vitest.Mock<[name: string, attributes?: any], {
|
|
83
|
+
name: string;
|
|
84
|
+
attributes: any;
|
|
85
|
+
clientId: string;
|
|
86
|
+
}>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Mock @wordpress/data
|
|
90
|
+
*/
|
|
91
|
+
declare const mockWordPressData: {
|
|
92
|
+
useSelect: vitest.Mock<[callback: any], any>;
|
|
93
|
+
useDispatch: vitest.Mock<[_storeName: string], {}>;
|
|
94
|
+
select: vitest.Mock<[_storeName: string], {}>;
|
|
95
|
+
dispatch: vitest.Mock<[_storeName: string], {}>;
|
|
96
|
+
subscribe: vitest.Mock<any, any>;
|
|
97
|
+
registerStore: vitest.Mock<any, any>;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Mock @wordpress/i18n
|
|
101
|
+
*/
|
|
102
|
+
declare const mockWordPressi18n: {
|
|
103
|
+
__: vitest.Mock<[text: string], string>;
|
|
104
|
+
_x: vitest.Mock<[text: string], string>;
|
|
105
|
+
_n: vitest.Mock<[single: string, plural: string, number: number], string>;
|
|
106
|
+
sprintf: vitest.Mock<[format: string, ..._args: any[]], string>;
|
|
107
|
+
setLocaleData: vitest.Mock<any, any>;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Mock @wordpress/components
|
|
111
|
+
*/
|
|
112
|
+
declare const mockWordPressComponents: {
|
|
113
|
+
Button: vitest.Mock<[any], any>;
|
|
114
|
+
TextControl: vitest.Mock<[], null>;
|
|
115
|
+
SelectControl: vitest.Mock<[], null>;
|
|
116
|
+
RangeControl: vitest.Mock<[], null>;
|
|
117
|
+
ToggleControl: vitest.Mock<[], null>;
|
|
118
|
+
Panel: vitest.Mock<[any], any>;
|
|
119
|
+
PanelBody: vitest.Mock<[any], any>;
|
|
120
|
+
PanelRow: vitest.Mock<[any], any>;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Mock @wordpress/block-editor
|
|
124
|
+
*/
|
|
125
|
+
declare const mockWordPressBlockEditor: {
|
|
126
|
+
InspectorControls: vitest.Mock<[any], any>;
|
|
127
|
+
BlockControls: vitest.Mock<[any], any>;
|
|
128
|
+
useBlockProps: vitest.Mock<[props?: any], any>;
|
|
129
|
+
RichText: vitest.Mock<[], null>;
|
|
130
|
+
MediaUpload: vitest.Mock<[], null>;
|
|
131
|
+
MediaUploadCheck: vitest.Mock<[any], any>;
|
|
132
|
+
ColorPalette: vitest.Mock<[], null>;
|
|
133
|
+
URLInput: vitest.Mock<[], null>;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Mock @wordpress/element
|
|
137
|
+
*/
|
|
138
|
+
declare const mockWordPressElement: {
|
|
139
|
+
createElement: vitest.Mock<[type: any, props?: any, ...children: any[]], {
|
|
140
|
+
type: any;
|
|
141
|
+
props: any;
|
|
142
|
+
}>;
|
|
143
|
+
Fragment: vitest.Mock<[any], any>;
|
|
144
|
+
useState: vitest.Mock<[initialState: any], any[]>;
|
|
145
|
+
useEffect: vitest.Mock<[_effect: () => void, _deps?: any[] | undefined], undefined>;
|
|
146
|
+
useRef: vitest.Mock<[initialValue: any], {
|
|
147
|
+
current: any;
|
|
148
|
+
}>;
|
|
149
|
+
useMemo: vitest.Mock<[factory: () => any, _deps?: any[] | undefined], any>;
|
|
150
|
+
useCallback: vitest.Mock<[callback: (...args: any[]) => any, _deps?: any[] | undefined], (...args: any[]) => any>;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Mock @wordpress/api-fetch
|
|
154
|
+
*/
|
|
155
|
+
declare const mockWordPressApiFetch: vitest.Mock<[_options: {
|
|
156
|
+
path: string;
|
|
157
|
+
method?: string;
|
|
158
|
+
data?: any;
|
|
159
|
+
}], Promise<{
|
|
160
|
+
ok: boolean;
|
|
161
|
+
json: () => Promise<{}>;
|
|
162
|
+
}>>;
|
|
163
|
+
/**
|
|
164
|
+
* Setup all WordPress mocks
|
|
165
|
+
*/
|
|
166
|
+
declare function setupWordPressMocks(): void;
|
|
167
|
+
/**
|
|
168
|
+
* Clear all WordPress mocks
|
|
169
|
+
*/
|
|
170
|
+
declare function clearWordPressMocks(): void;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Custom Vitest Matchers
|
|
174
|
+
* WordPress-specific test matchers
|
|
175
|
+
*/
|
|
176
|
+
/**
|
|
177
|
+
* Check if element has WordPress block class
|
|
178
|
+
*/
|
|
179
|
+
declare function toHaveBlockClass(received: HTMLElement, blockName: string): {
|
|
180
|
+
pass: boolean;
|
|
181
|
+
message: () => string;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Check if block is registered
|
|
185
|
+
*/
|
|
186
|
+
declare function toBeRegisteredBlock(received: string): {
|
|
187
|
+
pass: boolean;
|
|
188
|
+
message: () => string;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Check if block has required attributes
|
|
192
|
+
*/
|
|
193
|
+
declare function toHaveBlockAttributes(received: any, expectedAttributes: string[]): {
|
|
194
|
+
pass: boolean;
|
|
195
|
+
message: () => string;
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Check if element is a valid WordPress block
|
|
199
|
+
*/
|
|
200
|
+
declare function toBeValidWordPressBlock(received: HTMLElement): {
|
|
201
|
+
pass: boolean;
|
|
202
|
+
message: () => "Expected element not to be a valid WordPress block" | "Expected element to be a valid WordPress block (must have data-type attribute and wp-block class)";
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Check if string is valid block markup
|
|
206
|
+
*/
|
|
207
|
+
declare function toBeValidBlockMarkup(received: string): {
|
|
208
|
+
pass: boolean;
|
|
209
|
+
message: () => "Expected string not to be valid block markup" | "Expected string to be valid block markup (must include WordPress block comments)";
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Extend Vitest matchers
|
|
213
|
+
*/
|
|
214
|
+
declare function setupCustomMatchers(): void;
|
|
215
|
+
declare global {
|
|
216
|
+
namespace Vi {
|
|
217
|
+
interface Matchers<R = any> {
|
|
218
|
+
toHaveBlockClass(blockName: string): R;
|
|
219
|
+
toBeRegisteredBlock(): R;
|
|
220
|
+
toHaveBlockAttributes(attributes: string[]): R;
|
|
221
|
+
toBeValidWordPressBlock(): R;
|
|
222
|
+
toBeValidBlockMarkup(): R;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export { type BlockConfiguration, clearWordPressMocks, createMockAttributes, createMockBlockContext, mockWordPressApiFetch, mockWordPressBlockEditor, mockWordPressBlocks, mockWordPressComponents, mockWordPressData, mockWordPressElement, mockWordPressi18n, renderBlockEdit, renderBlockSave, setupCustomMatchers, setupWordPressMocks, testBlockAttributes, testBlockRegistration, testBlockSaveOutput, toBeRegisteredBlock, toBeValidBlockMarkup, toBeValidWordPressBlock, toHaveBlockAttributes, toHaveBlockClass, waitForBlockRender };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// src/utils/block-testing.ts
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
import { createElement } from "react";
|
|
4
|
+
function renderBlockEdit(EditComponent, props = {}, options) {
|
|
5
|
+
const defaultProps = {
|
|
6
|
+
attributes: {},
|
|
7
|
+
setAttributes: vi.fn(),
|
|
8
|
+
isSelected: false,
|
|
9
|
+
clientId: "test-block-id",
|
|
10
|
+
...props
|
|
11
|
+
};
|
|
12
|
+
return render(createElement(EditComponent, defaultProps), options);
|
|
13
|
+
}
|
|
14
|
+
function renderBlockSave(SaveComponent, props = {}, options) {
|
|
15
|
+
const defaultProps = {
|
|
16
|
+
attributes: {},
|
|
17
|
+
...props
|
|
18
|
+
};
|
|
19
|
+
return render(createElement(SaveComponent, defaultProps), options);
|
|
20
|
+
}
|
|
21
|
+
function testBlockRegistration(blockName, expectedConfig) {
|
|
22
|
+
const { getBlockType } = wp.blocks;
|
|
23
|
+
const blockType = getBlockType(blockName);
|
|
24
|
+
if (!blockType) {
|
|
25
|
+
throw new Error(`Block ${blockName} is not registered`);
|
|
26
|
+
}
|
|
27
|
+
expect(blockType.name).toBe(blockName);
|
|
28
|
+
if (expectedConfig.title) {
|
|
29
|
+
expect(blockType.title).toBe(expectedConfig.title);
|
|
30
|
+
}
|
|
31
|
+
if (expectedConfig.category) {
|
|
32
|
+
expect(blockType.category).toBe(expectedConfig.category);
|
|
33
|
+
}
|
|
34
|
+
if (expectedConfig.attributes) {
|
|
35
|
+
expect(blockType.attributes).toEqual(expectedConfig.attributes);
|
|
36
|
+
}
|
|
37
|
+
return blockType;
|
|
38
|
+
}
|
|
39
|
+
function createMockAttributes(blockType, overrides = {}) {
|
|
40
|
+
const defaults = {
|
|
41
|
+
"core/paragraph": {
|
|
42
|
+
content: "Test paragraph content",
|
|
43
|
+
align: "left"
|
|
44
|
+
},
|
|
45
|
+
"core/heading": {
|
|
46
|
+
content: "Test heading",
|
|
47
|
+
level: 2
|
|
48
|
+
},
|
|
49
|
+
"core/image": {
|
|
50
|
+
url: "https://example.com/image.jpg",
|
|
51
|
+
alt: "Test image",
|
|
52
|
+
id: 123
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
...defaults[blockType] || {},
|
|
57
|
+
...overrides
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function testBlockAttributes(EditComponent, attributes) {
|
|
61
|
+
const setAttributes = vi.fn();
|
|
62
|
+
const { rerender } = renderBlockEdit(EditComponent, {
|
|
63
|
+
attributes,
|
|
64
|
+
setAttributes
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
setAttributes,
|
|
68
|
+
rerender: (newAttributes) => {
|
|
69
|
+
return rerender(
|
|
70
|
+
createElement(EditComponent, {
|
|
71
|
+
attributes: newAttributes,
|
|
72
|
+
setAttributes
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function testBlockSaveOutput(SaveComponent, attributes) {
|
|
79
|
+
const { container } = renderBlockSave(SaveComponent, { attributes });
|
|
80
|
+
return container.innerHTML;
|
|
81
|
+
}
|
|
82
|
+
function createMockBlockContext(overrides = {}) {
|
|
83
|
+
return {
|
|
84
|
+
clientId: "mock-client-id",
|
|
85
|
+
isSelected: false,
|
|
86
|
+
isMultiSelected: false,
|
|
87
|
+
hasSelectedInnerBlock: false,
|
|
88
|
+
index: 0,
|
|
89
|
+
...overrides
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function waitForBlockRender(callback, options = {}) {
|
|
93
|
+
const timeout = options.timeout || 1e3;
|
|
94
|
+
const startTime = Date.now();
|
|
95
|
+
while (Date.now() - startTime < timeout) {
|
|
96
|
+
try {
|
|
97
|
+
callback();
|
|
98
|
+
return;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
throw new Error("Block failed to render within timeout");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/mocks/wordpress.ts
|
|
107
|
+
import { vi as vi2 } from "vitest";
|
|
108
|
+
var mockWordPressBlocks = {
|
|
109
|
+
registerBlockType: vi2.fn((name, settings) => {
|
|
110
|
+
return { name, ...settings };
|
|
111
|
+
}),
|
|
112
|
+
unregisterBlockType: vi2.fn(),
|
|
113
|
+
getBlockType: vi2.fn((name) => ({
|
|
114
|
+
name,
|
|
115
|
+
title: "Mock Block",
|
|
116
|
+
category: "common",
|
|
117
|
+
icon: "block-default",
|
|
118
|
+
attributes: {}
|
|
119
|
+
})),
|
|
120
|
+
getBlockTypes: vi2.fn(() => []),
|
|
121
|
+
hasBlockSupport: vi2.fn(() => true),
|
|
122
|
+
createBlock: vi2.fn((name, attributes) => ({
|
|
123
|
+
name,
|
|
124
|
+
attributes: attributes || {},
|
|
125
|
+
clientId: "mock-client-id"
|
|
126
|
+
}))
|
|
127
|
+
};
|
|
128
|
+
var mockWordPressData = {
|
|
129
|
+
useSelect: vi2.fn((callback) => callback(() => ({}))),
|
|
130
|
+
useDispatch: vi2.fn((_storeName) => ({})),
|
|
131
|
+
select: vi2.fn((_storeName) => ({})),
|
|
132
|
+
dispatch: vi2.fn((_storeName) => ({})),
|
|
133
|
+
subscribe: vi2.fn(),
|
|
134
|
+
registerStore: vi2.fn()
|
|
135
|
+
};
|
|
136
|
+
var mockWordPressi18n = {
|
|
137
|
+
__: vi2.fn((text) => text),
|
|
138
|
+
_x: vi2.fn((text) => text),
|
|
139
|
+
_n: vi2.fn(
|
|
140
|
+
(single, plural, number) => number === 1 ? single : plural
|
|
141
|
+
),
|
|
142
|
+
sprintf: vi2.fn((format, ..._args) => format),
|
|
143
|
+
setLocaleData: vi2.fn()
|
|
144
|
+
};
|
|
145
|
+
var mockWordPressComponents = {
|
|
146
|
+
Button: vi2.fn(({ children }) => children),
|
|
147
|
+
TextControl: vi2.fn(() => null),
|
|
148
|
+
SelectControl: vi2.fn(() => null),
|
|
149
|
+
RangeControl: vi2.fn(() => null),
|
|
150
|
+
ToggleControl: vi2.fn(() => null),
|
|
151
|
+
Panel: vi2.fn(({ children }) => children),
|
|
152
|
+
PanelBody: vi2.fn(({ children }) => children),
|
|
153
|
+
PanelRow: vi2.fn(({ children }) => children)
|
|
154
|
+
};
|
|
155
|
+
var mockWordPressBlockEditor = {
|
|
156
|
+
InspectorControls: vi2.fn(({ children }) => children),
|
|
157
|
+
BlockControls: vi2.fn(({ children }) => children),
|
|
158
|
+
useBlockProps: vi2.fn((props) => ({
|
|
159
|
+
className: "wp-block",
|
|
160
|
+
...props
|
|
161
|
+
})),
|
|
162
|
+
RichText: vi2.fn(() => null),
|
|
163
|
+
MediaUpload: vi2.fn(() => null),
|
|
164
|
+
MediaUploadCheck: vi2.fn(({ children }) => children),
|
|
165
|
+
ColorPalette: vi2.fn(() => null),
|
|
166
|
+
URLInput: vi2.fn(() => null)
|
|
167
|
+
};
|
|
168
|
+
var mockWordPressElement = {
|
|
169
|
+
createElement: vi2.fn((type, props, ...children) => ({
|
|
170
|
+
type,
|
|
171
|
+
props: { ...props, children }
|
|
172
|
+
})),
|
|
173
|
+
Fragment: vi2.fn(({ children }) => children),
|
|
174
|
+
useState: vi2.fn((initialState) => [initialState, vi2.fn()]),
|
|
175
|
+
useEffect: vi2.fn((_effect, _deps) => void 0),
|
|
176
|
+
useRef: vi2.fn((initialValue) => ({ current: initialValue })),
|
|
177
|
+
useMemo: vi2.fn((factory, _deps) => factory()),
|
|
178
|
+
useCallback: vi2.fn((callback, _deps) => callback)
|
|
179
|
+
};
|
|
180
|
+
var mockWordPressApiFetch = vi2.fn(
|
|
181
|
+
(_options) => Promise.resolve({ ok: true, json: () => Promise.resolve({}) })
|
|
182
|
+
);
|
|
183
|
+
function setupWordPressMocks() {
|
|
184
|
+
vi2.mock("@wordpress/blocks", () => mockWordPressBlocks);
|
|
185
|
+
vi2.mock("@wordpress/data", () => mockWordPressData);
|
|
186
|
+
vi2.mock("@wordpress/i18n", () => mockWordPressi18n);
|
|
187
|
+
vi2.mock("@wordpress/components", () => mockWordPressComponents);
|
|
188
|
+
vi2.mock("@wordpress/block-editor", () => mockWordPressBlockEditor);
|
|
189
|
+
vi2.mock("@wordpress/element", () => mockWordPressElement);
|
|
190
|
+
vi2.mock("@wordpress/api-fetch", () => ({ default: mockWordPressApiFetch }));
|
|
191
|
+
global.wp = {
|
|
192
|
+
blocks: mockWordPressBlocks,
|
|
193
|
+
data: mockWordPressData,
|
|
194
|
+
i18n: mockWordPressi18n,
|
|
195
|
+
components: mockWordPressComponents,
|
|
196
|
+
blockEditor: mockWordPressBlockEditor,
|
|
197
|
+
element: mockWordPressElement,
|
|
198
|
+
apiFetch: mockWordPressApiFetch
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function clearWordPressMocks() {
|
|
202
|
+
Object.values(mockWordPressBlocks).forEach((mock) => {
|
|
203
|
+
if (typeof mock?.mockClear === "function") {
|
|
204
|
+
mock.mockClear();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
Object.values(mockWordPressData).forEach((mock) => {
|
|
208
|
+
if (typeof mock?.mockClear === "function") {
|
|
209
|
+
mock.mockClear();
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/matchers/index.ts
|
|
215
|
+
import { expect as expect2 } from "vitest";
|
|
216
|
+
function toHaveBlockClass(received, blockName) {
|
|
217
|
+
const className = `wp-block-${blockName.replace("/", "-")}`;
|
|
218
|
+
const pass = received.classList.contains(className);
|
|
219
|
+
return {
|
|
220
|
+
pass,
|
|
221
|
+
message: () => pass ? `Expected element not to have block class ${className}` : `Expected element to have block class ${className}`
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function toBeRegisteredBlock(received) {
|
|
225
|
+
const { getBlockType } = global.wp?.blocks || {};
|
|
226
|
+
if (!getBlockType) {
|
|
227
|
+
return {
|
|
228
|
+
pass: false,
|
|
229
|
+
message: () => "WordPress blocks API is not available"
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const blockType = getBlockType(received);
|
|
233
|
+
const pass = blockType !== void 0;
|
|
234
|
+
return {
|
|
235
|
+
pass,
|
|
236
|
+
message: () => pass ? `Expected block ${received} not to be registered` : `Expected block ${received} to be registered`
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function toHaveBlockAttributes(received, expectedAttributes) {
|
|
240
|
+
if (!received || !received.attributes) {
|
|
241
|
+
return {
|
|
242
|
+
pass: false,
|
|
243
|
+
message: () => "Block does not have attributes property"
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const actualAttributes = Object.keys(received.attributes);
|
|
247
|
+
const missingAttributes = expectedAttributes.filter(
|
|
248
|
+
(attr) => !actualAttributes.includes(attr)
|
|
249
|
+
);
|
|
250
|
+
const pass = missingAttributes.length === 0;
|
|
251
|
+
return {
|
|
252
|
+
pass,
|
|
253
|
+
message: () => pass ? `Expected block not to have attributes: ${expectedAttributes.join(", ")}` : `Expected block to have attributes: ${missingAttributes.join(", ")}`
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function toBeValidWordPressBlock(received) {
|
|
257
|
+
const hasDataType = received.hasAttribute("data-type");
|
|
258
|
+
const hasWpBlock = received.classList.contains("wp-block") || Array.from(received.classList).some((c) => c.startsWith("wp-block-"));
|
|
259
|
+
const pass = hasDataType && hasWpBlock;
|
|
260
|
+
return {
|
|
261
|
+
pass,
|
|
262
|
+
message: () => pass ? "Expected element not to be a valid WordPress block" : "Expected element to be a valid WordPress block (must have data-type attribute and wp-block class)"
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function toBeValidBlockMarkup(received) {
|
|
266
|
+
const hasStartComment = received.includes("<!-- wp:");
|
|
267
|
+
const hasEndComment = received.includes("<!-- /wp:") || received.includes("/-->");
|
|
268
|
+
const pass = hasStartComment && hasEndComment;
|
|
269
|
+
return {
|
|
270
|
+
pass,
|
|
271
|
+
message: () => pass ? "Expected string not to be valid block markup" : "Expected string to be valid block markup (must include WordPress block comments)"
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function setupCustomMatchers() {
|
|
275
|
+
expect2.extend({
|
|
276
|
+
toHaveBlockClass,
|
|
277
|
+
toBeRegisteredBlock,
|
|
278
|
+
toHaveBlockAttributes,
|
|
279
|
+
toBeValidWordPressBlock,
|
|
280
|
+
toBeValidBlockMarkup
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
export {
|
|
284
|
+
clearWordPressMocks,
|
|
285
|
+
createMockAttributes,
|
|
286
|
+
createMockBlockContext,
|
|
287
|
+
mockWordPressApiFetch,
|
|
288
|
+
mockWordPressBlockEditor,
|
|
289
|
+
mockWordPressBlocks,
|
|
290
|
+
mockWordPressComponents,
|
|
291
|
+
mockWordPressData,
|
|
292
|
+
mockWordPressElement,
|
|
293
|
+
mockWordPressi18n,
|
|
294
|
+
renderBlockEdit,
|
|
295
|
+
renderBlockSave,
|
|
296
|
+
setupCustomMatchers,
|
|
297
|
+
setupWordPressMocks,
|
|
298
|
+
testBlockAttributes,
|
|
299
|
+
testBlockRegistration,
|
|
300
|
+
testBlockSaveOutput,
|
|
301
|
+
toBeRegisteredBlock,
|
|
302
|
+
toBeValidBlockMarkup,
|
|
303
|
+
toBeValidWordPressBlock,
|
|
304
|
+
toHaveBlockAttributes,
|
|
305
|
+
toHaveBlockClass,
|
|
306
|
+
waitForBlockRender
|
|
307
|
+
};
|
|
308
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/block-testing.ts","../src/mocks/wordpress.ts","../src/matchers/index.ts"],"sourcesContent":["/**\n * Block Testing Utilities\n * Helper functions for testing Gutenberg blocks\n */\n\nimport { render, RenderOptions } from '@testing-library/react'\nimport { createElement } from 'react'\n\n/**\n * Block Configuration Interface\n */\nexport interface BlockConfiguration {\n name?: string\n title?: string\n description?: string\n category?: string\n icon?: string | Record<string, any>\n keywords?: string[]\n attributes?: Record<string, any>\n supports?: Record<string, any>\n [key: string]: any\n}\n\n/**\n * Render a block's edit component for testing\n */\nexport function renderBlockEdit(\n EditComponent: React.ComponentType<any>,\n props: any = {},\n options?: RenderOptions\n): ReturnType<typeof render> {\n const defaultProps = {\n attributes: {},\n setAttributes: vi.fn(),\n isSelected: false,\n clientId: 'test-block-id',\n ...props,\n }\n\n return render(createElement(EditComponent, defaultProps), options)\n}\n\n/**\n * Render a block's save component for testing\n */\nexport function renderBlockSave(\n SaveComponent: React.ComponentType<any>,\n props: any = {},\n options?: RenderOptions\n): ReturnType<typeof render> {\n const defaultProps = {\n attributes: {},\n ...props,\n }\n\n return render(createElement(SaveComponent, defaultProps), options)\n}\n\n/**\n * Test if a block is registered correctly\n */\nexport function testBlockRegistration(\n blockName: string,\n expectedConfig: Partial<BlockConfiguration>\n) {\n const { getBlockType } = wp.blocks\n\n const blockType = getBlockType(blockName)\n\n if (!blockType) {\n throw new Error(`Block ${blockName} is not registered`)\n }\n\n // Check required fields\n expect(blockType.name).toBe(blockName)\n\n if (expectedConfig.title) {\n expect(blockType.title).toBe(expectedConfig.title)\n }\n\n if (expectedConfig.category) {\n expect(blockType.category).toBe(expectedConfig.category)\n }\n\n if (expectedConfig.attributes) {\n expect(blockType.attributes).toEqual(expectedConfig.attributes)\n }\n\n return blockType\n}\n\n/**\n * Create mock block attributes\n */\nexport function createMockAttributes(\n blockType: string,\n overrides: Record<string, any> = {}\n): Record<string, any> {\n const defaults: Record<string, Record<string, any>> = {\n 'core/paragraph': {\n content: 'Test paragraph content',\n align: 'left',\n },\n 'core/heading': {\n content: 'Test heading',\n level: 2,\n },\n 'core/image': {\n url: 'https://example.com/image.jpg',\n alt: 'Test image',\n id: 123,\n },\n }\n\n return {\n ...(defaults[blockType] || {}),\n ...overrides,\n }\n}\n\n/**\n * Test block attribute validation\n */\nexport function testBlockAttributes(\n EditComponent: React.ComponentType<any>,\n attributes: Record<string, any>\n) {\n const setAttributes = vi.fn()\n\n const { rerender } = renderBlockEdit(EditComponent, {\n attributes,\n setAttributes,\n })\n\n return {\n setAttributes,\n rerender: (newAttributes: Record<string, any>) => {\n return rerender(\n createElement(EditComponent, {\n attributes: newAttributes,\n setAttributes,\n })\n )\n },\n }\n}\n\n/**\n * Test block save output\n */\nexport function testBlockSaveOutput(\n SaveComponent: React.ComponentType<any>,\n attributes: Record<string, any>\n) {\n const { container } = renderBlockSave(SaveComponent, { attributes })\n return container.innerHTML\n}\n\n/**\n * Mock block context\n */\nexport function createMockBlockContext(overrides: any = {}) {\n return {\n clientId: 'mock-client-id',\n isSelected: false,\n isMultiSelected: false,\n hasSelectedInnerBlock: false,\n index: 0,\n ...overrides,\n }\n}\n\n/**\n * Wait for block to render\n */\nexport async function waitForBlockRender(\n callback: () => void,\n options: { timeout?: number } = {}\n) {\n const timeout = options.timeout || 1000\n const startTime = Date.now()\n\n while (Date.now() - startTime < timeout) {\n try {\n callback()\n return\n } catch (error) {\n await new Promise((resolve) => setTimeout(resolve, 50))\n }\n }\n\n throw new Error('Block failed to render within timeout')\n}\n","/**\n * WordPress API Mocks\n * Mock implementations of WordPress JavaScript APIs for testing\n */\n\nimport { vi } from 'vitest'\n\n/**\n * Mock @wordpress/blocks\n */\nexport const mockWordPressBlocks = {\n registerBlockType: vi.fn((name: string, settings: any) => {\n return { name, ...settings }\n }),\n unregisterBlockType: vi.fn(),\n getBlockType: vi.fn((name: string) => ({\n name,\n title: 'Mock Block',\n category: 'common',\n icon: 'block-default',\n attributes: {},\n })),\n getBlockTypes: vi.fn(() => []),\n hasBlockSupport: vi.fn(() => true),\n createBlock: vi.fn((name: string, attributes?: any) => ({\n name,\n attributes: attributes || {},\n clientId: 'mock-client-id',\n })),\n}\n\n/**\n * Mock @wordpress/data\n */\nexport const mockWordPressData = {\n useSelect: vi.fn((callback: any) => callback(() => ({}))),\n useDispatch: vi.fn((_storeName: string) => ({})),\n select: vi.fn((_storeName: string) => ({})),\n dispatch: vi.fn((_storeName: string) => ({})),\n subscribe: vi.fn(),\n registerStore: vi.fn(),\n}\n\n/**\n * Mock @wordpress/i18n\n */\nexport const mockWordPressi18n = {\n __: vi.fn((text: string) => text),\n _x: vi.fn((text: string) => text),\n _n: vi.fn((single: string, plural: string, number: number) =>\n number === 1 ? single : plural\n ),\n sprintf: vi.fn((format: string, ..._args: any[]) => format),\n setLocaleData: vi.fn(),\n}\n\n/**\n * Mock @wordpress/components\n */\nexport const mockWordPressComponents = {\n Button: vi.fn(({ children }: any) => children),\n TextControl: vi.fn(() => null),\n SelectControl: vi.fn(() => null),\n RangeControl: vi.fn(() => null),\n ToggleControl: vi.fn(() => null),\n Panel: vi.fn(({ children }: any) => children),\n PanelBody: vi.fn(({ children }: any) => children),\n PanelRow: vi.fn(({ children }: any) => children),\n}\n\n/**\n * Mock @wordpress/block-editor\n */\nexport const mockWordPressBlockEditor = {\n InspectorControls: vi.fn(({ children }: any) => children),\n BlockControls: vi.fn(({ children }: any) => children),\n useBlockProps: vi.fn((props?: any) => ({\n className: 'wp-block',\n ...props,\n })),\n RichText: vi.fn(() => null),\n MediaUpload: vi.fn(() => null),\n MediaUploadCheck: vi.fn(({ children }: any) => children),\n ColorPalette: vi.fn(() => null),\n URLInput: vi.fn(() => null),\n}\n\n/**\n * Mock @wordpress/element\n */\nexport const mockWordPressElement = {\n createElement: vi.fn((type: any, props?: any, ...children: any[]) => ({\n type,\n props: { ...props, children },\n })),\n Fragment: vi.fn(({ children }: any) => children),\n useState: vi.fn((initialState: any) => [initialState, vi.fn()]),\n useEffect: vi.fn((_effect: () => void, _deps?: any[]) => undefined),\n useRef: vi.fn((initialValue: any) => ({ current: initialValue })),\n useMemo: vi.fn((factory: () => any, _deps?: any[]) => factory()),\n useCallback: vi.fn((callback: (...args: any[]) => any, _deps?: any[]) => callback),\n}\n\n/**\n * Mock @wordpress/api-fetch\n */\nexport const mockWordPressApiFetch = vi.fn(\n (_options: { path: string; method?: string; data?: any }) =>\n Promise.resolve({ ok: true, json: () => Promise.resolve({}) })\n)\n\n/**\n * Setup all WordPress mocks\n */\nexport function setupWordPressMocks() {\n vi.mock('@wordpress/blocks', () => mockWordPressBlocks)\n vi.mock('@wordpress/data', () => mockWordPressData)\n vi.mock('@wordpress/i18n', () => mockWordPressi18n)\n vi.mock('@wordpress/components', () => mockWordPressComponents)\n vi.mock('@wordpress/block-editor', () => mockWordPressBlockEditor)\n vi.mock('@wordpress/element', () => mockWordPressElement)\n vi.mock('@wordpress/api-fetch', () => ({ default: mockWordPressApiFetch }))\n\n // Setup global WordPress objects\n ;(global as any).wp = {\n blocks: mockWordPressBlocks,\n data: mockWordPressData,\n i18n: mockWordPressi18n,\n components: mockWordPressComponents,\n blockEditor: mockWordPressBlockEditor,\n element: mockWordPressElement,\n apiFetch: mockWordPressApiFetch,\n }\n}\n\n/**\n * Clear all WordPress mocks\n */\nexport function clearWordPressMocks() {\n Object.values(mockWordPressBlocks).forEach((mock: any) => {\n if (typeof mock?.mockClear === 'function') {\n mock.mockClear()\n }\n })\n\n Object.values(mockWordPressData).forEach((mock: any) => {\n if (typeof mock?.mockClear === 'function') {\n mock.mockClear()\n }\n })\n\n // Clear other mocks...\n}\n","/**\n * Custom Vitest Matchers\n * WordPress-specific test matchers\n */\n\nimport { expect } from 'vitest'\n\n/**\n * Check if element has WordPress block class\n */\nexport function toHaveBlockClass(received: HTMLElement, blockName: string) {\n const className = `wp-block-${blockName.replace('/', '-')}`\n const pass = received.classList.contains(className)\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected element not to have block class ${className}`\n : `Expected element to have block class ${className}`,\n }\n}\n\n/**\n * Check if block is registered\n */\nexport function toBeRegisteredBlock(received: string) {\n const { getBlockType } = (global as any).wp?.blocks || {}\n\n if (!getBlockType) {\n return {\n pass: false,\n message: () => 'WordPress blocks API is not available',\n }\n }\n\n const blockType = getBlockType(received)\n const pass = blockType !== undefined\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected block ${received} not to be registered`\n : `Expected block ${received} to be registered`,\n }\n}\n\n/**\n * Check if block has required attributes\n */\nexport function toHaveBlockAttributes(\n received: any,\n expectedAttributes: string[]\n) {\n if (!received || !received.attributes) {\n return {\n pass: false,\n message: () => 'Block does not have attributes property',\n }\n }\n\n const actualAttributes = Object.keys(received.attributes)\n const missingAttributes = expectedAttributes.filter(\n (attr) => !actualAttributes.includes(attr)\n )\n\n const pass = missingAttributes.length === 0\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected block not to have attributes: ${expectedAttributes.join(', ')}`\n : `Expected block to have attributes: ${missingAttributes.join(', ')}`,\n }\n}\n\n/**\n * Check if element is a valid WordPress block\n */\nexport function toBeValidWordPressBlock(received: HTMLElement) {\n const hasDataType = received.hasAttribute('data-type')\n const hasWpBlock = received.classList.contains('wp-block') ||\n Array.from(received.classList).some(c => c.startsWith('wp-block-'))\n\n const pass = hasDataType && hasWpBlock\n\n return {\n pass,\n message: () =>\n pass\n ? 'Expected element not to be a valid WordPress block'\n : 'Expected element to be a valid WordPress block (must have data-type attribute and wp-block class)',\n }\n}\n\n/**\n * Check if string is valid block markup\n */\nexport function toBeValidBlockMarkup(received: string) {\n // Check for WordPress block comment syntax\n const hasStartComment = received.includes('<!-- wp:')\n const hasEndComment = received.includes('<!-- /wp:') || received.includes('/-->')\n\n const pass = hasStartComment && hasEndComment\n\n return {\n pass,\n message: () =>\n pass\n ? 'Expected string not to be valid block markup'\n : 'Expected string to be valid block markup (must include WordPress block comments)',\n }\n}\n\n/**\n * Extend Vitest matchers\n */\nexport function setupCustomMatchers() {\n expect.extend({\n toHaveBlockClass,\n toBeRegisteredBlock,\n toHaveBlockAttributes,\n toBeValidWordPressBlock,\n toBeValidBlockMarkup,\n })\n}\n\n// Type declarations for TypeScript\ndeclare global {\n namespace Vi {\n interface Matchers<R = any> {\n toHaveBlockClass(blockName: string): R\n toBeRegisteredBlock(): R\n toHaveBlockAttributes(attributes: string[]): R\n toBeValidWordPressBlock(): R\n toBeValidBlockMarkup(): R\n }\n }\n}\n"],"mappings":"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","names":["vi","expect"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Page, Locator } from '@playwright/test';
|
|
2
|
+
export { Browser, BrowserContext, Locator, Page, expect, test } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Playwright E2E Testing Helpers
|
|
6
|
+
* Helper functions for WordPress E2E testing with Playwright
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* WordPress login helper
|
|
11
|
+
*/
|
|
12
|
+
declare function wpLogin(page: Page, username?: string, password?: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* WordPress logout helper
|
|
15
|
+
*/
|
|
16
|
+
declare function wpLogout(page: Page): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Navigate to block editor
|
|
19
|
+
*/
|
|
20
|
+
declare function openBlockEditor(page: Page, postType?: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Insert a block in the editor
|
|
23
|
+
*/
|
|
24
|
+
declare function insertBlock(page: Page, blockName: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Get block by type
|
|
27
|
+
*/
|
|
28
|
+
declare function getBlock(page: Page, blockType: string): Locator;
|
|
29
|
+
/**
|
|
30
|
+
* Get selected block
|
|
31
|
+
*/
|
|
32
|
+
declare function getSelectedBlock(page: Page): Locator;
|
|
33
|
+
/**
|
|
34
|
+
* Type in block
|
|
35
|
+
*/
|
|
36
|
+
declare function typeInBlock(page: Page, blockType: string, text: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Update block attribute via inspector
|
|
39
|
+
*/
|
|
40
|
+
declare function updateBlockAttribute(page: Page, attributeName: string, value: string | number | boolean): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Publish post
|
|
43
|
+
*/
|
|
44
|
+
declare function publishPost(page: Page): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Save draft
|
|
47
|
+
*/
|
|
48
|
+
declare function saveDraft(page: Page): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Preview post
|
|
51
|
+
*/
|
|
52
|
+
declare function previewPost(page: Page): Promise<Page>;
|
|
53
|
+
/**
|
|
54
|
+
* Check if block exists
|
|
55
|
+
*/
|
|
56
|
+
declare function blockExists(page: Page, blockType: string): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Get block count
|
|
59
|
+
*/
|
|
60
|
+
declare function getBlockCount(page: Page, blockType?: string): Promise<number>;
|
|
61
|
+
/**
|
|
62
|
+
* Select block
|
|
63
|
+
*/
|
|
64
|
+
declare function selectBlock(page: Page, blockType: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Delete block
|
|
67
|
+
*/
|
|
68
|
+
declare function deleteBlock(page: Page, blockType: string): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Move block up
|
|
71
|
+
*/
|
|
72
|
+
declare function moveBlockUp(page: Page, blockType: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Move block down
|
|
75
|
+
*/
|
|
76
|
+
declare function moveBlockDown(page: Page, blockType: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Wait for WordPress admin
|
|
79
|
+
*/
|
|
80
|
+
declare function waitForWPAdmin(page: Page): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Navigate to WordPress admin page
|
|
83
|
+
*/
|
|
84
|
+
declare function goToWPAdmin(page: Page, path?: string): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Check if user is logged in
|
|
87
|
+
*/
|
|
88
|
+
declare function isLoggedIn(page: Page): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Take accessible screenshot
|
|
91
|
+
*/
|
|
92
|
+
declare function takeA11yScreenshot(page: Page, name: string): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Check for console errors
|
|
95
|
+
*/
|
|
96
|
+
declare function setupConsoleErrorTracking(page: Page): string[];
|
|
97
|
+
|
|
98
|
+
export { blockExists, deleteBlock, getBlock, getBlockCount, getSelectedBlock, goToWPAdmin, insertBlock, isLoggedIn, moveBlockDown, moveBlockUp, openBlockEditor, previewPost, publishPost, saveDraft, selectBlock, setupConsoleErrorTracking, takeA11yScreenshot, typeInBlock, updateBlockAttribute, waitForWPAdmin, wpLogin, wpLogout };
|