@astryxdesign/lab 0.7.6-canary.f73623d → 0.7.6-canary.f77aaf2
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/dist/CommentPin/CommentPin.js +1 -1
- package/dist/Comments/CommentComposer.d.ts.map +1 -1
- package/dist/Comments/CommentComposer.js +12 -4
- package/dist/MobilePowerSearch/MobilePowerSearch.d.ts +3 -6
- package/dist/MobilePowerSearch/MobilePowerSearch.d.ts.map +1 -1
- package/dist/MobilePowerSearch/MobilePowerSearch.js +12 -76
- package/dist/MobileTokenizer/MobileTokenizer.d.ts +10 -7
- package/dist/MobileTokenizer/MobileTokenizer.d.ts.map +1 -1
- package/dist/MobileTokenizer/MobileTokenizer.js +191 -114
- package/dist/internal/MobileSheetConfirmation.d.ts +12 -0
- package/dist/internal/MobileSheetConfirmation.d.ts.map +1 -0
- package/dist/internal/MobileSheetConfirmation.js +88 -0
- package/dist/internal/useDismissSearchOnTouchDrag.d.ts +21 -0
- package/dist/internal/useDismissSearchOnTouchDrag.d.ts.map +1 -0
- package/dist/internal/useDismissSearchOnTouchDrag.js +43 -0
- package/package.json +4 -4
- package/src/CommentPin/CommentPin.tsx +1 -1
- package/src/Comments/CommentComposer.test.tsx +56 -0
- package/src/Comments/CommentComposer.tsx +18 -13
- package/src/MobilePowerSearch/MobilePowerSearch.doc.mjs +1 -1
- package/src/MobilePowerSearch/MobilePowerSearch.test.tsx +7 -2
- package/src/MobilePowerSearch/MobilePowerSearch.tsx +16 -83
- package/src/MobileTokenizer/MobileTokenizer.doc.mjs +3 -3
- package/src/MobileTokenizer/MobileTokenizer.test.tsx +287 -31
- package/src/MobileTokenizer/MobileTokenizer.tsx +242 -137
- package/src/Schedule/__tests__/ScheduleTimeDirection.a11y.chromium.spec.ts +4 -0
- package/src/TransferList/TransferList.doc.mjs +1 -1
- package/src/internal/MobileSheetConfirmation.test.tsx +68 -0
- package/src/internal/MobileSheetConfirmation.tsx +97 -0
- package/src/internal/useDismissSearchOnTouchDrag.test.tsx +94 -0
- package/src/internal/useDismissSearchOnTouchDrag.ts +57 -0
- package/src/CommentPin/CommentPin.spec.md +0 -319
- package/src/Schedule/Schedule.spec.md +0 -590
|
@@ -129,6 +129,200 @@ beforeEach(() => {
|
|
|
129
129
|
afterEach(() => vi.unstubAllGlobals());
|
|
130
130
|
|
|
131
131
|
describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
132
|
+
it('keeps the bordered large search and footer actions visible while searching, and dismisses the keyboard without clearing the query when results move', async () => {
|
|
133
|
+
render(<Harness />);
|
|
134
|
+
fireEvent.click(screen.getByRole('button', {name: /Tags/}));
|
|
135
|
+
const search = await screen.findByLabelText('Search Tags');
|
|
136
|
+
const list = await screen.findByTestId('mobile-tokenizer-list');
|
|
137
|
+
await screen.findByRole('checkbox', {name: 'Energizer'});
|
|
138
|
+
|
|
139
|
+
expect(search.closest('.astryx-text-input')).toBeInTheDocument();
|
|
140
|
+
act(() => search.focus());
|
|
141
|
+
fireEvent.change(search, {target: {value: 'En'}});
|
|
142
|
+
await screen.findByRole('checkbox', {name: 'Eng'});
|
|
143
|
+
expect(screen.getByRole('button', {name: 'Clear all'})).toBeVisible();
|
|
144
|
+
expect(screen.getByRole('button', {name: 'Save'})).toBeVisible();
|
|
145
|
+
|
|
146
|
+
fireEvent.scroll(list);
|
|
147
|
+
expect(search).toHaveFocus();
|
|
148
|
+
expect(search).toHaveValue('En');
|
|
149
|
+
|
|
150
|
+
// Filtering a scrolled list can produce its own scroll event as the
|
|
151
|
+
// browser clamps scrollTop; typing must continue to own focus.
|
|
152
|
+
fireEvent.change(search, {target: {value: 'Eng'}});
|
|
153
|
+
fireEvent.scroll(list);
|
|
154
|
+
expect(search).toHaveFocus();
|
|
155
|
+
fireEvent.change(search, {target: {value: 'Engi'}});
|
|
156
|
+
expect(search).toHaveValue('Engi');
|
|
157
|
+
expect(search).toHaveFocus();
|
|
158
|
+
|
|
159
|
+
fireEvent.touchStart(list, {
|
|
160
|
+
touches: [{identifier: 1, target: list, clientY: 120}],
|
|
161
|
+
});
|
|
162
|
+
fireEvent.touchMove(list, {
|
|
163
|
+
touches: [{identifier: 1, target: list, clientY: 115}],
|
|
164
|
+
});
|
|
165
|
+
expect(search).toHaveFocus();
|
|
166
|
+
fireEvent.touchMove(list, {
|
|
167
|
+
touches: [{identifier: 1, target: list, clientY: 100}],
|
|
168
|
+
});
|
|
169
|
+
expect(search).not.toHaveFocus();
|
|
170
|
+
expect(search).toHaveValue('Engi');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('guards dirty Escape, scrim, and swipe dismissal; keeps the draft after confirmation scrim or Keep editing; and discards only on request', async () => {
|
|
174
|
+
const spy = vi.fn();
|
|
175
|
+
render(<Harness spy={spy} />);
|
|
176
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
177
|
+
fireEvent.click(trigger);
|
|
178
|
+
const sheet = await screen.findByRole('dialog', {name: 'Tags'});
|
|
179
|
+
const energizer = await screen.findByRole('checkbox', {name: 'Energizer'});
|
|
180
|
+
fireEvent.click(energizer);
|
|
181
|
+
expect(energizer).toBeChecked();
|
|
182
|
+
expect(spy).not.toHaveBeenCalled();
|
|
183
|
+
|
|
184
|
+
fireEvent.keyDown(sheet, {key: 'Escape'});
|
|
185
|
+
let discard = await screen.findByRole('alertdialog', {
|
|
186
|
+
name: 'Discard changes?',
|
|
187
|
+
});
|
|
188
|
+
fireEvent.click(discard);
|
|
189
|
+
await waitFor(() =>
|
|
190
|
+
expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument(),
|
|
191
|
+
);
|
|
192
|
+
expect(energizer).toBeChecked();
|
|
193
|
+
expect(screen.getByLabelText('Search Tags')).toHaveFocus();
|
|
194
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
195
|
+
|
|
196
|
+
fireEvent.click(sheet);
|
|
197
|
+
discard = await screen.findByRole('alertdialog', {
|
|
198
|
+
name: 'Discard changes?',
|
|
199
|
+
});
|
|
200
|
+
fireEvent.click(
|
|
201
|
+
within(discard).getByRole('button', {name: 'Keep editing'}),
|
|
202
|
+
);
|
|
203
|
+
await waitFor(() =>
|
|
204
|
+
expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument(),
|
|
205
|
+
);
|
|
206
|
+
expect(energizer).toBeChecked();
|
|
207
|
+
expect(screen.getByLabelText('Search Tags')).toHaveFocus();
|
|
208
|
+
|
|
209
|
+
const handle = sheet.querySelector<HTMLElement>(
|
|
210
|
+
'.astryx-bottom-sheet > div[aria-hidden="true"]',
|
|
211
|
+
)!;
|
|
212
|
+
fireEvent.pointerDown(handle, {
|
|
213
|
+
pointerId: 1,
|
|
214
|
+
clientY: 0,
|
|
215
|
+
button: 0,
|
|
216
|
+
isPrimary: true,
|
|
217
|
+
pointerType: 'touch',
|
|
218
|
+
});
|
|
219
|
+
fireEvent.pointerMove(handle, {
|
|
220
|
+
pointerId: 1,
|
|
221
|
+
clientY: 40,
|
|
222
|
+
pointerType: 'touch',
|
|
223
|
+
});
|
|
224
|
+
fireEvent.pointerMove(handle, {
|
|
225
|
+
pointerId: 1,
|
|
226
|
+
clientY: 120,
|
|
227
|
+
pointerType: 'touch',
|
|
228
|
+
});
|
|
229
|
+
fireEvent.pointerUp(handle, {
|
|
230
|
+
pointerId: 1,
|
|
231
|
+
clientY: 120,
|
|
232
|
+
pointerType: 'touch',
|
|
233
|
+
});
|
|
234
|
+
discard = await screen.findByRole('alertdialog', {
|
|
235
|
+
name: 'Discard changes?',
|
|
236
|
+
});
|
|
237
|
+
const actions = within(discard).getAllByRole('button');
|
|
238
|
+
expect(actions.map(action => action.textContent)).toEqual([
|
|
239
|
+
'Discard changes',
|
|
240
|
+
'Keep editing',
|
|
241
|
+
]);
|
|
242
|
+
expect(actions[0]).toHaveAttribute('data-variant', 'destructive');
|
|
243
|
+
expect(actions[1]).toHaveAttribute('data-variant', 'secondary');
|
|
244
|
+
fireEvent.click(actions[0]);
|
|
245
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
246
|
+
expect(spy).not.toHaveBeenCalled();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('forced disabled closure also closes a dirty-discard confirmation', async () => {
|
|
250
|
+
const spy = vi.fn();
|
|
251
|
+
const props = {
|
|
252
|
+
label: 'Tags',
|
|
253
|
+
searchSource: source,
|
|
254
|
+
value: [ITEMS[0]],
|
|
255
|
+
debounceMs: 0,
|
|
256
|
+
onChange: spy,
|
|
257
|
+
};
|
|
258
|
+
const {rerender} = render(<MobileTokenizer {...props} />);
|
|
259
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
260
|
+
fireEvent.click(trigger);
|
|
261
|
+
const sheet = await screen.findByRole('dialog', {name: 'Tags'});
|
|
262
|
+
fireEvent.click(await screen.findByRole('checkbox', {name: 'Energizer'}));
|
|
263
|
+
fireEvent.keyDown(sheet, {key: 'Escape'});
|
|
264
|
+
expect(
|
|
265
|
+
await screen.findByRole('alertdialog', {name: 'Discard changes?'}),
|
|
266
|
+
).toBeInTheDocument();
|
|
267
|
+
|
|
268
|
+
rerender(<MobileTokenizer {...props} isDisabled />);
|
|
269
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
270
|
+
await waitFor(() =>
|
|
271
|
+
expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument(),
|
|
272
|
+
);
|
|
273
|
+
expect(spy).not.toHaveBeenCalled();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('blocks Save if maxEntries drops below the current draft until the draft returns within the limit', async () => {
|
|
277
|
+
const spy = vi.fn();
|
|
278
|
+
const props = {
|
|
279
|
+
label: 'Tags',
|
|
280
|
+
searchSource: source,
|
|
281
|
+
value: [] as SearchableItem[],
|
|
282
|
+
debounceMs: 0,
|
|
283
|
+
onChange: spy,
|
|
284
|
+
};
|
|
285
|
+
const {rerender} = render(<MobileTokenizer {...props} maxEntries={2} />);
|
|
286
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
287
|
+
fireEvent.click(trigger);
|
|
288
|
+
const design = await screen.findByRole('checkbox', {name: 'Design'});
|
|
289
|
+
const eng = await screen.findByRole('checkbox', {name: 'Eng'});
|
|
290
|
+
fireEvent.click(design);
|
|
291
|
+
fireEvent.click(eng);
|
|
292
|
+
|
|
293
|
+
rerender(<MobileTokenizer {...props} maxEntries={1} />);
|
|
294
|
+
const save = screen.getByRole('button', {name: 'Save'});
|
|
295
|
+
expect(save).toHaveAttribute('aria-disabled', 'true');
|
|
296
|
+
expect(save).toHaveAccessibleDescription('Select up to 1 item');
|
|
297
|
+
fireEvent.click(save);
|
|
298
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
299
|
+
expect(spy).not.toHaveBeenCalled();
|
|
300
|
+
|
|
301
|
+
fireEvent.click(eng);
|
|
302
|
+
expect(save).not.toHaveAttribute('aria-disabled');
|
|
303
|
+
fireEvent.click(save);
|
|
304
|
+
expect(spy).toHaveBeenCalledWith(
|
|
305
|
+
[ITEMS[0]],
|
|
306
|
+
expect.objectContaining({item: ITEMS[0], type: 'add'}),
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('closes directly when edits return the draft to its opening selection', async () => {
|
|
311
|
+
const spy = vi.fn();
|
|
312
|
+
render(<Harness spy={spy} />);
|
|
313
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
314
|
+
fireEvent.click(trigger);
|
|
315
|
+
const sheet = await screen.findByRole('dialog', {name: 'Tags'});
|
|
316
|
+
const energizer = await screen.findByRole('checkbox', {name: 'Energizer'});
|
|
317
|
+
fireEvent.click(energizer);
|
|
318
|
+
fireEvent.click(energizer);
|
|
319
|
+
|
|
320
|
+
fireEvent.keyDown(sheet, {key: 'Escape'});
|
|
321
|
+
expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument();
|
|
322
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
323
|
+
expect(spy).not.toHaveBeenCalled();
|
|
324
|
+
});
|
|
325
|
+
|
|
132
326
|
it('keeps rows stable while open and applies selected-first order on reopen', async () => {
|
|
133
327
|
const spy = vi.fn();
|
|
134
328
|
render(<Harness spy={spy} />);
|
|
@@ -160,10 +354,7 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
160
354
|
expect(design.lastElementChild).toHaveAttribute('data-size', 'md');
|
|
161
355
|
|
|
162
356
|
fireEvent.click(screen.getByRole('checkbox', {name: 'Energizer'}));
|
|
163
|
-
expect(spy).
|
|
164
|
-
[ITEMS[0], ITEMS[1], ITEMS[3]],
|
|
165
|
-
expect.objectContaining({type: 'add'}),
|
|
166
|
-
);
|
|
357
|
+
expect(spy).not.toHaveBeenCalled();
|
|
167
358
|
await waitFor(() =>
|
|
168
359
|
expect(screen.getByRole('checkbox', {name: 'Energizer'})).toBeChecked(),
|
|
169
360
|
);
|
|
@@ -175,10 +366,7 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
175
366
|
]);
|
|
176
367
|
|
|
177
368
|
fireEvent.click(screen.getByRole('checkbox', {name: 'Eng'}));
|
|
178
|
-
expect(spy).
|
|
179
|
-
[ITEMS[0], ITEMS[3]],
|
|
180
|
-
expect.objectContaining({type: 'remove'}),
|
|
181
|
-
);
|
|
369
|
+
expect(spy).not.toHaveBeenCalled();
|
|
182
370
|
expect(checkboxLabels()).toEqual([
|
|
183
371
|
'Design',
|
|
184
372
|
'Eng',
|
|
@@ -186,7 +374,11 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
186
374
|
'Energizer',
|
|
187
375
|
]);
|
|
188
376
|
|
|
189
|
-
fireEvent.click(screen.getByRole('button', {name: '
|
|
377
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
378
|
+
expect(spy).toHaveBeenCalledWith(
|
|
379
|
+
[ITEMS[0], ITEMS[3]],
|
|
380
|
+
expect.objectContaining({item: ITEMS[1], type: 'remove'}),
|
|
381
|
+
);
|
|
190
382
|
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
191
383
|
|
|
192
384
|
await act(async () => {
|
|
@@ -200,6 +392,38 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
200
392
|
]);
|
|
201
393
|
});
|
|
202
394
|
|
|
395
|
+
it('reports the net changed item when draft actions cancel each other', async () => {
|
|
396
|
+
const spy = vi.fn();
|
|
397
|
+
render(<Harness spy={spy} />);
|
|
398
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
399
|
+
fireEvent.click(trigger);
|
|
400
|
+
await screen.findByRole('checkbox', {name: 'Energizer'});
|
|
401
|
+
|
|
402
|
+
fireEvent.click(screen.getByRole('checkbox', {name: 'Energizer'}));
|
|
403
|
+
fireEvent.click(screen.getByRole('checkbox', {name: 'Design'}));
|
|
404
|
+
fireEvent.click(screen.getByRole('checkbox', {name: 'Energizer'}));
|
|
405
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
406
|
+
|
|
407
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
408
|
+
expect(spy).toHaveBeenCalledWith([ITEMS[1]], {
|
|
409
|
+
item: ITEMS[0],
|
|
410
|
+
type: 'remove',
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it('does not commit a selection toggled back to its opening value', async () => {
|
|
415
|
+
const spy = vi.fn();
|
|
416
|
+
render(<Harness spy={spy} />);
|
|
417
|
+
fireEvent.click(screen.getByRole('button', {name: /Tags/}));
|
|
418
|
+
await screen.findByRole('checkbox', {name: 'Design'});
|
|
419
|
+
|
|
420
|
+
fireEvent.click(screen.getByRole('checkbox', {name: 'Design'}));
|
|
421
|
+
fireEvent.click(screen.getByRole('checkbox', {name: 'Design'}));
|
|
422
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
423
|
+
|
|
424
|
+
expect(spy).not.toHaveBeenCalled();
|
|
425
|
+
});
|
|
426
|
+
|
|
203
427
|
it('creates a custom entry with a trailing Add action', async () => {
|
|
204
428
|
const spy = vi.fn();
|
|
205
429
|
render(<CreateHarness spy={spy} />);
|
|
@@ -212,12 +436,8 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
212
436
|
screen.queryByRole('checkbox', {name: 'Create "Custom"'}),
|
|
213
437
|
).not.toBeInTheDocument();
|
|
214
438
|
const create = await screen.findByRole('button', {name: 'Add Custom'});
|
|
215
|
-
expect(
|
|
216
|
-
|
|
217
|
-
).not.toBeInTheDocument();
|
|
218
|
-
expect(
|
|
219
|
-
screen.queryByRole('button', {name: 'Done'}),
|
|
220
|
-
).not.toBeInTheDocument();
|
|
439
|
+
expect(screen.getByRole('button', {name: 'Clear all'})).toBeInTheDocument();
|
|
440
|
+
expect(screen.getByRole('button', {name: 'Save'})).toBeInTheDocument();
|
|
221
441
|
expect(create).toHaveAttribute('data-size', 'lg');
|
|
222
442
|
expect(screen.getByTestId('mobile-tokenizer-create-row')).toHaveTextContent(
|
|
223
443
|
'Create "Custom"',
|
|
@@ -225,14 +445,18 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
225
445
|
await act(async () => {
|
|
226
446
|
fireEvent.click(create);
|
|
227
447
|
});
|
|
448
|
+
expect(spy).not.toHaveBeenCalled();
|
|
449
|
+
expect(trigger).not.toHaveTextContent('Custom');
|
|
450
|
+
expect(search).toHaveValue('');
|
|
451
|
+
const custom = await screen.findByRole('checkbox', {name: 'Custom'});
|
|
452
|
+
expect(custom).toBeChecked();
|
|
453
|
+
|
|
454
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
228
455
|
expect(spy).toHaveBeenCalledWith(
|
|
229
456
|
[{id: 'Custom', label: 'Custom'}],
|
|
230
457
|
expect.objectContaining({type: 'create'}),
|
|
231
458
|
);
|
|
232
459
|
await waitFor(() => expect(trigger).toHaveTextContent('Custom'));
|
|
233
|
-
expect(search).toHaveValue('');
|
|
234
|
-
const custom = await screen.findByRole('checkbox', {name: 'Custom'});
|
|
235
|
-
expect(custom).toBeChecked();
|
|
236
460
|
});
|
|
237
461
|
|
|
238
462
|
it('renders long lists in 50-item batches and resets the window for search', async () => {
|
|
@@ -325,30 +549,49 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
325
549
|
);
|
|
326
550
|
});
|
|
327
551
|
|
|
328
|
-
it('keeps large equal-width Clear all and
|
|
552
|
+
it('keeps large equal-width Clear all and Save footer actions while guarding the bulk clear', async () => {
|
|
329
553
|
const spy = vi.fn();
|
|
330
554
|
render(<Harness spy={spy} />);
|
|
331
555
|
fireEvent.click(screen.getByRole('button', {name: /Tags/}));
|
|
332
556
|
const list = await screen.findByTestId('mobile-tokenizer-list');
|
|
333
557
|
|
|
334
558
|
const clearAll = screen.getByRole('button', {name: 'Clear all'});
|
|
335
|
-
const
|
|
559
|
+
const save = screen.getByRole('button', {name: 'Save'});
|
|
336
560
|
expect(clearAll).toHaveAttribute('data-size', 'lg');
|
|
337
561
|
expect(clearAll).toHaveAttribute('data-variant', 'secondary');
|
|
338
|
-
expect(
|
|
562
|
+
expect(save).toHaveAttribute('data-size', 'lg');
|
|
339
563
|
expect(list.compareDocumentPosition(clearAll)).toBe(
|
|
340
564
|
Node.DOCUMENT_POSITION_FOLLOWING,
|
|
341
565
|
);
|
|
342
|
-
expect(list.compareDocumentPosition(
|
|
566
|
+
expect(list.compareDocumentPosition(save)).toBe(
|
|
343
567
|
Node.DOCUMENT_POSITION_FOLLOWING,
|
|
344
568
|
);
|
|
345
569
|
fireEvent.click(clearAll);
|
|
346
570
|
const confirmation = screen.getByRole('alertdialog');
|
|
571
|
+
expect(confirmation).toHaveClass('astryx-alert-dialog');
|
|
347
572
|
expect(confirmation).toHaveTextContent('Clear all selected items?');
|
|
573
|
+
const confirmationActions = within(confirmation).getAllByRole('button');
|
|
574
|
+
expect(confirmationActions.map(action => action.textContent)).toEqual([
|
|
575
|
+
'Clear selection',
|
|
576
|
+
'Cancel',
|
|
577
|
+
]);
|
|
578
|
+
expect(confirmationActions[0]).toHaveAttribute(
|
|
579
|
+
'data-variant',
|
|
580
|
+
'destructive',
|
|
581
|
+
);
|
|
582
|
+
expect(confirmationActions[1]).toHaveAttribute('data-variant', 'secondary');
|
|
348
583
|
expect(spy).not.toHaveBeenCalled();
|
|
349
584
|
fireEvent.click(
|
|
350
585
|
within(confirmation).getByRole('button', {name: 'Clear selection'}),
|
|
351
586
|
);
|
|
587
|
+
expect(spy).not.toHaveBeenCalled();
|
|
588
|
+
await waitFor(() =>
|
|
589
|
+
expect(screen.getByRole('button', {name: 'Clear all'})).toHaveAttribute(
|
|
590
|
+
'aria-disabled',
|
|
591
|
+
'true',
|
|
592
|
+
),
|
|
593
|
+
);
|
|
594
|
+
fireEvent.click(save);
|
|
352
595
|
expect(spy).toHaveBeenLastCalledWith(
|
|
353
596
|
[],
|
|
354
597
|
expect.objectContaining({type: 'remove'}),
|
|
@@ -441,6 +684,17 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
441
684
|
for (const name of indicatorClasses) {
|
|
442
685
|
expect(indicator).toHaveClass(name);
|
|
443
686
|
}
|
|
687
|
+
|
|
688
|
+
fireEvent.click(screen.getByRole('checkbox', {name: 'Design'}));
|
|
689
|
+
expect(row).not.toHaveAttribute('aria-disabled');
|
|
690
|
+
fireEvent.click(row);
|
|
691
|
+
expect(row).toBeChecked();
|
|
692
|
+
expect(spy).not.toHaveBeenCalled();
|
|
693
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
694
|
+
expect(spy).toHaveBeenCalledWith(
|
|
695
|
+
[ITEMS[3]],
|
|
696
|
+
expect.objectContaining({item: ITEMS[3], type: 'add'}),
|
|
697
|
+
);
|
|
444
698
|
});
|
|
445
699
|
|
|
446
700
|
it('paints the placeholder of a disabled empty trigger GrayText in forced colors (AST-085 FR6)', () => {
|
|
@@ -569,7 +823,7 @@ describe('MobileTokenizer Core-sheet parity', () => {
|
|
|
569
823
|
expect(screen.queryByLabelText('Search Tags')).toBeNull();
|
|
570
824
|
const sheet = await openSheet();
|
|
571
825
|
expect(sheet).toHaveAttribute('open');
|
|
572
|
-
fireEvent.click(screen.getByRole('button', {name: '
|
|
826
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
573
827
|
// Closed but retained for its exit; the trigger's focus (BottomSheet's
|
|
574
828
|
// hand-back after the exit) releases it.
|
|
575
829
|
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
@@ -798,7 +1052,7 @@ describe('MobileTokenizer Core-sheet parity', () => {
|
|
|
798
1052
|
expect(onBlur).not.toHaveBeenCalled();
|
|
799
1053
|
// Closing hands focus back to the trigger: that is not focus entering
|
|
800
1054
|
// from outside, so the caller's onFocus stays quiet for it.
|
|
801
|
-
fireEvent.click(screen.getByRole('button', {name: '
|
|
1055
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
802
1056
|
act(() => trigger.focus());
|
|
803
1057
|
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull());
|
|
804
1058
|
expect(sheet).not.toBeInTheDocument();
|
|
@@ -832,9 +1086,9 @@ describe('MobileTokenizer Core-sheet parity', () => {
|
|
|
832
1086
|
await screen.findByRole('checkbox', {name: 'Design'});
|
|
833
1087
|
expect(trigger).not.toHaveFocus();
|
|
834
1088
|
expect(events).toEqual([]);
|
|
835
|
-
//
|
|
1089
|
+
// Save: BottomSheet hands focus to the trigger. The trigger never had
|
|
836
1090
|
// focus, so this is the entry.
|
|
837
|
-
fireEvent.click(screen.getByRole('button', {name: '
|
|
1091
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
838
1092
|
act(() => trigger.focus());
|
|
839
1093
|
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull());
|
|
840
1094
|
expect(events).toEqual(['focus']);
|
|
@@ -846,7 +1100,7 @@ describe('MobileTokenizer Core-sheet parity', () => {
|
|
|
846
1100
|
act(() => trigger.focus());
|
|
847
1101
|
fireEvent.click(trigger);
|
|
848
1102
|
await screen.findByRole('dialog');
|
|
849
|
-
fireEvent.click(screen.getByRole('button', {name: '
|
|
1103
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
850
1104
|
act(() => trigger.focus());
|
|
851
1105
|
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull());
|
|
852
1106
|
act(() => screen.getByRole('button', {name: 'Elsewhere'}).focus());
|
|
@@ -1034,10 +1288,7 @@ describe('MobileTokenizer Core-sheet parity', () => {
|
|
|
1034
1288
|
fireEvent.click(
|
|
1035
1289
|
within(confirmation).getByRole('button', {name: 'Clear selection'}),
|
|
1036
1290
|
);
|
|
1037
|
-
expect(spy).
|
|
1038
|
-
[],
|
|
1039
|
-
expect.objectContaining({type: 'remove'}),
|
|
1040
|
-
);
|
|
1291
|
+
expect(spy).not.toHaveBeenCalled();
|
|
1041
1292
|
await waitFor(() => expect(screen.queryByRole('alertdialog')).toBeNull());
|
|
1042
1293
|
expect(screen.getByLabelText('Search Tags')).toHaveFocus();
|
|
1043
1294
|
await waitFor(() => expect(liveText(sheet)).toBe('All items removed'));
|
|
@@ -1048,6 +1299,11 @@ describe('MobileTokenizer Core-sheet parity', () => {
|
|
|
1048
1299
|
expect(spent).toHaveAccessibleDescription('Nothing selected');
|
|
1049
1300
|
fireEvent.click(spent);
|
|
1050
1301
|
expect(screen.queryByRole('alertdialog')).toBeNull();
|
|
1302
|
+
fireEvent.click(screen.getByRole('button', {name: 'Save'}));
|
|
1303
|
+
expect(spy).toHaveBeenCalledWith(
|
|
1304
|
+
[],
|
|
1305
|
+
expect.objectContaining({type: 'remove'}),
|
|
1306
|
+
);
|
|
1051
1307
|
});
|
|
1052
1308
|
|
|
1053
1309
|
it('announces each toggle and the result count from inside the dialog (AR6, AST-086 FR14)', async () => {
|