Skip to content

Commit 1ed3ab5

Browse files
authored
feat(loaders): update Dots to use pure CSS animation (#2033)
1 parent 968211e commit 1ed3ab5

File tree

5 files changed

+39
-412
lines changed

5 files changed

+39
-412
lines changed

packages/loaders/src/elements/Dots.spec.tsx

Lines changed: 8 additions & 361 deletions
Original file line numberDiff line numberDiff line change
@@ -7,375 +7,22 @@
77

88
import React from 'react';
99
import { render, act } from 'garden-test-utils';
10-
import mockDate from 'mockdate';
1110
import { PALETTE } from '@zendeskgarden/react-theming';
1211
import { Dots } from './Dots';
1312

14-
jest.useFakeTimers({ legacyFakeTimers: true });
15-
16-
const DEFAULT_DATE = new Date(2019, 1, 5, 1, 1, 1);
17-
1813
describe('Dots', () => {
19-
beforeEach(() => {
20-
jest.mocked(clearTimeout).mockClear();
21-
(global as any).cancelAnimationFrame = jest.fn();
22-
(global as any).requestAnimationFrame = jest.fn();
23-
(global as any).document.elementFromPoint = jest.fn();
24-
mockDate.set(DEFAULT_DATE);
25-
});
14+
it('renders loader, starting as hidden by default', () => {
15+
const { queryByTestId } = render(<Dots data-test-id="dots" />);
2616

27-
afterEach(() => {
28-
mockDate.reset();
17+
expect(queryByTestId('dots')).toBeInTheDocument();
18+
expect(queryByTestId('dots')).not.toBeVisible();
2919
});
3020

31-
describe('Loading delay', () => {
32-
it('hides loader for initial delay', () => {
33-
const { queryByTestId } = render(<Dots data-test-id="dots" />);
34-
35-
expect(queryByTestId('dots')).toBeNull();
36-
});
37-
38-
it('shows loader after initial delay', () => {
39-
const { queryByTestId } = render(<Dots data-test-id="dots" />);
40-
41-
act(() => {
42-
jest.runOnlyPendingTimers();
43-
});
44-
45-
expect(queryByTestId('dots')).not.toBeNull();
46-
});
47-
});
48-
49-
describe('Animation', () => {
50-
it('relies on svg transition attribute if css svg animation is not supported', () => {
51-
const { container } = render(<Dots data-test-id="dots" />);
52-
53-
act(() => {
54-
jest.runOnlyPendingTimers();
55-
});
56-
57-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
58-
.c0 {
59-
animation: kVOdef 1250ms linear infinite;
60-
}
61-
62-
.c1 {
63-
animation: idDvaf 1250ms linear infinite;
64-
}
65-
66-
.c2 {
67-
animation: bDxIcz 1250ms linear infinite;
68-
}
69-
70-
<g
71-
fill="currentColor"
72-
>
73-
<circle
74-
class="c0"
75-
cx="9"
76-
cy="36"
77-
r="9"
78-
transform=""
79-
/>
80-
<circle
81-
class="c1"
82-
cx="40"
83-
cy="36"
84-
r="9"
85-
transform=""
86-
/>
87-
<circle
88-
class="c2"
89-
cx="71"
90-
cy="36"
91-
r="9"
92-
transform=""
93-
/>
94-
</g>
95-
`);
96-
});
97-
98-
it('updates animation after request animation frame', () => {
99-
const { container } = render(<Dots data-test-id="dots" />);
100-
101-
act(() => {
102-
jest.runOnlyPendingTimers();
103-
});
104-
105-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
106-
.c0 {
107-
animation: kVOdef 1250ms linear infinite;
108-
}
109-
110-
.c1 {
111-
animation: idDvaf 1250ms linear infinite;
112-
}
113-
114-
.c2 {
115-
animation: bDxIcz 1250ms linear infinite;
116-
}
117-
118-
<g
119-
fill="currentColor"
120-
>
121-
<circle
122-
class="c0"
123-
cx="9"
124-
cy="36"
125-
r="9"
126-
transform=""
127-
/>
128-
<circle
129-
class="c1"
130-
cx="40"
131-
cy="36"
132-
r="9"
133-
transform=""
134-
/>
135-
<circle
136-
class="c2"
137-
cx="71"
138-
cy="36"
139-
r="9"
140-
transform=""
141-
/>
142-
</g>
143-
`);
144-
145-
act(() => {
146-
// move time forward 1 second
147-
mockDate.set(DEFAULT_DATE.setSeconds(2));
148-
jest.mocked(requestAnimationFrame).mock.calls[0][0](0);
149-
});
150-
151-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
152-
.c0 {
153-
animation: kVOdef 1250ms linear infinite;
154-
}
155-
156-
.c1 {
157-
animation: idDvaf 1250ms linear infinite;
158-
}
21+
it('renders loader but does not hide if no delay', () => {
22+
const { queryByTestId } = render(<Dots data-test-id="dots" delayMS={0} />);
15923

160-
.c2 {
161-
animation: bDxIcz 1250ms linear infinite;
162-
}
163-
164-
<g
165-
fill="currentColor"
166-
>
167-
<circle
168-
class="c0"
169-
cx="9"
170-
cy="36"
171-
r="9"
172-
transform=""
173-
/>
174-
<circle
175-
class="c1"
176-
cx="40"
177-
cy="36"
178-
r="9"
179-
transform=""
180-
/>
181-
<circle
182-
class="c2"
183-
cx="71"
184-
cy="36"
185-
r="9"
186-
transform=""
187-
/>
188-
</g>
189-
`);
190-
});
191-
192-
it('updates animation after request animation frame with slower duration', () => {
193-
const { container } = render(<Dots duration={1125} />);
194-
195-
act(() => {
196-
jest.runOnlyPendingTimers();
197-
});
198-
199-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
200-
.c0 {
201-
animation: kVOdef 1125ms linear infinite;
202-
}
203-
204-
.c1 {
205-
animation: idDvaf 1125ms linear infinite;
206-
}
207-
208-
.c2 {
209-
animation: bDxIcz 1125ms linear infinite;
210-
}
211-
212-
<g
213-
fill="currentColor"
214-
>
215-
<circle
216-
class="c0"
217-
cx="9"
218-
cy="36"
219-
r="9"
220-
transform=""
221-
/>
222-
<circle
223-
class="c1"
224-
cx="40"
225-
cy="36"
226-
r="9"
227-
transform=""
228-
/>
229-
<circle
230-
class="c2"
231-
cx="71"
232-
cy="36"
233-
r="9"
234-
transform=""
235-
/>
236-
</g>
237-
`);
238-
239-
act(() => {
240-
// move time forward 1 second
241-
mockDate.set(DEFAULT_DATE.setSeconds(2));
242-
jest.mocked(requestAnimationFrame).mock.calls[0][0](0);
243-
});
244-
245-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
246-
.c0 {
247-
animation: kVOdef 1125ms linear infinite;
248-
}
249-
250-
.c1 {
251-
animation: idDvaf 1125ms linear infinite;
252-
}
253-
254-
.c2 {
255-
animation: bDxIcz 1125ms linear infinite;
256-
}
257-
258-
<g
259-
fill="currentColor"
260-
>
261-
<circle
262-
class="c0"
263-
cx="9"
264-
cy="36"
265-
r="9"
266-
transform=""
267-
/>
268-
<circle
269-
class="c1"
270-
cx="40"
271-
cy="36"
272-
r="9"
273-
transform=""
274-
/>
275-
<circle
276-
class="c2"
277-
cx="71"
278-
cy="36"
279-
r="9"
280-
transform=""
281-
/>
282-
</g>
283-
`);
284-
});
285-
286-
it('updates animation after request animation frame with increased duration', () => {
287-
const { container } = render(<Dots duration={1375} />);
288-
289-
act(() => {
290-
jest.runOnlyPendingTimers();
291-
});
292-
293-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
294-
.c0 {
295-
animation: kVOdef 1375ms linear infinite;
296-
}
297-
298-
.c1 {
299-
animation: idDvaf 1375ms linear infinite;
300-
}
301-
302-
.c2 {
303-
animation: bDxIcz 1375ms linear infinite;
304-
}
305-
306-
<g
307-
fill="currentColor"
308-
>
309-
<circle
310-
class="c0"
311-
cx="9"
312-
cy="36"
313-
r="9"
314-
transform=""
315-
/>
316-
<circle
317-
class="c1"
318-
cx="40"
319-
cy="36"
320-
r="9"
321-
transform=""
322-
/>
323-
<circle
324-
class="c2"
325-
cx="71"
326-
cy="36"
327-
r="9"
328-
transform=""
329-
/>
330-
</g>
331-
`);
332-
333-
act(() => {
334-
// move time forward 1 second
335-
mockDate.set(DEFAULT_DATE.setSeconds(2));
336-
jest.mocked(requestAnimationFrame).mock.calls[0][0](0);
337-
});
338-
339-
expect(container.querySelector('g')).toMatchInlineSnapshot(`
340-
.c0 {
341-
animation: kVOdef 1375ms linear infinite;
342-
}
343-
344-
.c1 {
345-
animation: idDvaf 1375ms linear infinite;
346-
}
347-
348-
.c2 {
349-
animation: bDxIcz 1375ms linear infinite;
350-
}
351-
352-
<g
353-
fill="currentColor"
354-
>
355-
<circle
356-
class="c0"
357-
cx="9"
358-
cy="36"
359-
r="9"
360-
transform=""
361-
/>
362-
<circle
363-
class="c1"
364-
cx="40"
365-
cy="36"
366-
r="9"
367-
transform=""
368-
/>
369-
<circle
370-
class="c2"
371-
cx="71"
372-
cy="36"
373-
r="9"
374-
transform=""
375-
/>
376-
</g>
377-
`);
378-
});
24+
expect(queryByTestId('dots')).toBeInTheDocument();
25+
expect(queryByTestId('dots')).toBeVisible();
37926
});
38027

38128
it('applies correct accessibility values', () => {

0 commit comments

Comments
 (0)