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 / lib / link-suggestions.test.js

link-suggestions.test.js in Extendify 3.1.1, at tests/unit/QuickEdit/lib/link-suggestions.test.js

102 lines 3.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Thin wrapper over /wp/v2/search; LinkControl in the inline editor calls
2 // this via the settings prop. Tests pin the param shape, defaults, and the
3 // result reshape to {id,url,title,type,kind}.
4
5 jest.mock('@wordpress/api-fetch', () => ({
6 __esModule: true,
7 default: jest.fn(),
8 }));
9
10 let apiFetch;
11 let fetchLinkSuggestions;
12
13 beforeEach(async () => {
14 jest.resetModules();
15 jest.clearAllMocks();
16 apiFetch = require('@wordpress/api-fetch').default;
17 apiFetch.mockReset();
18 apiFetch.mockResolvedValue([]);
19 fetchLinkSuggestions = (await import('@quick-edit/lib/link-suggestions'))
20 .fetchLinkSuggestions;
21 });
22
23 const decodePath = () => {
24 const path = apiFetch.mock.calls[0][0].path;
25 const [base, qs] = path.split('?');
26 return { base, params: new URLSearchParams(qs) };
27 };
28
29 describe('fetchLinkSuggestions — request shape', () => {
30 it('hits /wp/v2/search with search + per_page (default 10)', async () => {
31 await fetchLinkSuggestions('hello');
32 const { base, params } = decodePath();
33 expect(base).toBe('/wp/v2/search');
34 expect(params.get('search')).toBe('hello');
35 expect(params.get('per_page')).toBe('10');
36 expect(params.has('type')).toBe(false);
37 expect(params.has('subtype')).toBe(false);
38 });
39
40 it('passes opts.perPage / type / subtype when supplied', async () => {
41 await fetchLinkSuggestions('hi', {
42 perPage: 5,
43 type: 'post',
44 subtype: 'page',
45 });
46 const { params } = decodePath();
47 expect(params.get('per_page')).toBe('5');
48 expect(params.get('type')).toBe('post');
49 expect(params.get('subtype')).toBe('page');
50 });
51
52 it('coerces null/empty search to ""', async () => {
53 await fetchLinkSuggestions(null);
54 expect(decodePath().params.get('search')).toBe('');
55 await fetchLinkSuggestions(undefined);
56 expect(decodePath().params.get('search')).toBe('');
57 });
58
59 it('encodes special characters in search', async () => {
60 await fetchLinkSuggestions('a & b?');
61 expect(decodePath().params.get('search')).toBe('a & b?');
62 });
63 });
64
65 describe('fetchLinkSuggestions — result reshape', () => {
66 it('maps each row to {id, url, title, type, kind} with subtype winning over type for type', async () => {
67 apiFetch.mockResolvedValue([
68 { id: 1, url: '/a', title: 'A', type: 'post', subtype: 'page' },
69 { id: 2, url: '/b', title: 'B', type: 'post' },
70 ]);
71
72 const out = await fetchLinkSuggestions('x');
73 expect(out).toEqual([
74 { id: 1, url: '/a', title: 'A', type: 'page', kind: 'post' },
75 { id: 2, url: '/b', title: 'B', type: 'post', kind: 'post' },
76 ]);
77 });
78
79 it('falls back to row.url when title is missing or empty', async () => {
80 apiFetch.mockResolvedValue([
81 { id: 1, url: '/a', title: '', type: 'post' },
82 { id: 2, url: '/b', type: 'post' },
83 ]);
84 const out = await fetchLinkSuggestions('x');
85 expect(out.map((r) => r.title)).toEqual(['/a', '/b']);
86 });
87
88 it('returns [] when apiFetch resolves null/undefined', async () => {
89 apiFetch.mockResolvedValue(null);
90 await expect(fetchLinkSuggestions('x')).resolves.toEqual([]);
91 apiFetch.mockResolvedValue(undefined);
92 await expect(fetchLinkSuggestions('x')).resolves.toEqual([]);
93 });
94 });
95
96 describe('fetchLinkSuggestions — error propagation', () => {
97 it('propagates the apiFetch rejection unchanged', async () => {
98 apiFetch.mockRejectedValue(new Error('boom'));
99 await expect(fetchLinkSuggestions('x')).rejects.toThrow('boom');
100 });
101 });
102