forked from silverstripe/silverstripe-linkfield
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinkField-test.js
More file actions
274 lines (249 loc) · 8.05 KB
/
Copy pathLinkField-test.js
File metadata and controls
274 lines (249 loc) · 8.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/* global jest, test, expect, document */
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { Component as LinkField } from '../LinkField';
let doResolve;
jest.mock('lib/Backend', () => ({
get: () => new Promise((resolve) => {
doResolve = resolve;
})
}));
window.ss.config = {
sections: [
{
name: 'SilverStripe\\LinkField\\Controllers\\LinkFieldController',
form: {
linkForm: {
dataUrl: 'http://example.com/mock-endpoint'
}
}
}
]
};
function makeProps(obj = {}) {
return {
value: 123,
onChange: () => {},
types: {
mylink: {
key: 'mylink',
title: 'My Link',
handlerName: 'FormBuilderModal',
priority: 100,
icon: 'font-icon-link',
allowed: true
}
},
actions: {
toasts: {
success: () => {},
error: () => {}
}
},
isMulti: false,
canCreate: true,
readonly: false,
disabled: false,
inHistoryViewer: false,
ownerID: 123,
ownerClass: 'Page',
ownerRelation: 'MyRelation',
...obj
};
}
test('LinkField returns list of links if they exist', async () => {
const { container } = render(<LinkField {...makeProps({
isMulti: true,
value: [1, 2],
types: {
sitetree: { key: 'sitetree', title: 'Page', icon: 'font-icon-page', allowed: true },
email: { key: 'email', title: 'Email', icon: 'font-icon-email', allowed: true },
},
})}
/>);
await doResolve({ json: () => ({
1: {
title: 'Page title',
typeKey: 'sitetree',
},
2: {
title: 'Email title',
typeKey: 'email',
},
}) });
await screen.findByText('Page title');
expect(container.querySelectorAll('.link-picker__button')).toHaveLength(2);
expect(container.querySelectorAll('.link-picker__button .font-icon-page')[0].parentNode).toHaveTextContent('Page title');
expect(container.querySelectorAll('.link-picker__button .font-icon-email')[0].parentNode).toHaveTextContent('Email title');
});
test('LinkField can handle a string "0" value', async () => {
const { container } = render(<LinkField {...makeProps({
value: '0'
})}
/>);
await screen.findByText('Add new Link');
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
});
test('LinkField can handle a multi-digit string value', async () => {
const { container } = render(<LinkField {...makeProps({
value: '123'
})}
/>);
await doResolve({ json: () => ({
123: {
title: 'Page title',
typeKey: 'sitetree',
},
}) });
await screen.findByText('Page title');
expect(container.querySelectorAll('.link-picker__button')).toHaveLength(1);
});
test('LinkField will render disabled state if disabled is true', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
disabled: true
})}
/>);
await doResolve({ json: () => ({
123: {
title: 'Page title',
typeKey: 'mylink',
}
}) });
await screen.findByText('Page title');
const linkPicker = container.querySelectorAll('#link-picker__link-123');
expect(linkPicker[0].getAttribute('aria-disabled')).toBe('true');
expect(linkPicker[0]).toHaveClass('link-picker__link--disabled');
});
test('LinkField will have aria-disabled true if readonly is true', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
readonly: true
})}
/>);
await doResolve({ json: () => ({
123: {
title: 'Page title',
typeKey: 'mylink',
}
}) });
await screen.findByText('Page title');
const linkPicker = container.querySelectorAll('#link-picker__link-123');
expect(linkPicker[0].getAttribute('aria-disabled')).toBe('true');
});
test('Empty disabled LinkField will display cannot edit message', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
disabled: true,
value: undefined
})}
/>);
await screen.findByText('Cannot create link');
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
expect(container.querySelectorAll('.link-picker')[0]).toHaveTextContent('Cannot create link');
});
test('LinkField will render readonly state if readonly is true', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
readonly: true,
value: null,
})}
/>);
await screen.findByText('Cannot create link');
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
expect(container.querySelectorAll('.link-picker')[0]).toHaveTextContent('Cannot create link');
});
test('LinkField tab order', async () => {
const user = userEvent.setup();
const { container } = render(<LinkField {...makeProps({
isMulti: true,
value: [123, 456],
})}
/>);
await doResolve({ json: () => ({
123: {
title: 'First title',
typeKey: 'mylink',
},
456: {
title: 'Second title',
typeKey: 'mylink',
},
}) });
await screen.findByText('First title');
expect(Array.from(container.querySelectorAll('.link-picker__title-text')).map(el => el.innerHTML))
.toStrictEqual(['First title', 'Second title']);
const linkPicker123 = container.querySelector('#link-picker__link-123');
const button123 = linkPicker123.querySelector('.link-picker__button');
const dragHandle123 = linkPicker123.querySelector('.link-picker__drag-handle');
const linkPicker456 = container.querySelector('#link-picker__link-456');
const button456 = linkPicker456.querySelector('.link-picker__button');
const dragHandle456 = linkPicker456.querySelector('.link-picker__drag-handle');
// Focus starts on document <body>
expect(container.parentNode).toHaveFocus();
await user.tab();
expect(container.querySelector('.link-picker__menu-toggle')).toHaveFocus();
// note need to tab twice because jest will focus on the .dropdown-item, however in a real browser
// this doesn't happen because it will have a display of none at this point
await user.tab();
await user.tab();
expect(button123).toHaveFocus();
await user.tab();
expect(dragHandle123).toHaveFocus();
await user.tab();
expect(button456).toHaveFocus();
await user.tab();
expect(dragHandle456).toHaveFocus();
// Note that we cannot test keyboard sorting with up + down keys in jest because jsdom does not have a layout engine
// e.g. el.getBoundingClientRect() will always return 0,0,0,0
});
test('LinkField will render loading indicator if ownerID is 0', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 0
})}
/>);
expect(container.querySelectorAll('.link-field__loading')).toHaveLength(1);
expect(container.querySelectorAll('.link-picker')).toHaveLength(0);
});
test('LinkField will render loading indicator if ownerID is not 0', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1
})}
/>);
expect(container.querySelectorAll('.link-field__loading')).toHaveLength(1);
expect(container.querySelectorAll('.link-picker')).toHaveLength(0);
});
test('LinkField will render link-picker if ownerID is 0 and isMulti and has finished loading', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 0,
isMulti: true,
})}
/>);
await doResolve({ json: () => ({
123: {
title: 'First title',
typeKey: 'mylink',
},
}) });
await screen.findByText('First title');
expect(container.querySelectorAll('.link-field__loading')).toHaveLength(0);
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
});
test('LinkField will render link-picker if ownerID is not 0 and isMulti and has finished loading', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
isMulti: true,
})}
/>);
await doResolve({ json: () => ({
123: {
title: 'First title',
typeKey: 'mylink',
},
}) });
await screen.findByText('First title');
expect(container.querySelectorAll('.link-field__loading')).toHaveLength(0);
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
});