Skip to content

Commit 7eb8a02

Browse files
committed
Harden burst animation lifecycle.
Use full SVGator teardown by calling player.destruct() on unmount, add focused unit coverage for burst render and teardown behavior, and remove the unused submitBurst.svg design-source artifact. Keep lint suppressions scoped to generated SVG constraints and the UMD wrapper import context. Resolves #15097 AI-assisted-by: gpt-5
1 parent 5998b44 commit 7eb8a02

3 files changed

Lines changed: 257 additions & 47 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { mount } from '@vue/test-utils';
2+
import SubmitBurstAnimation from '../animations/SubmitBurstAnimation.vue';
3+
4+
describe('SubmitBurstAnimation', () => {
5+
let getElementByIdSpy;
6+
7+
afterEach(() => {
8+
if (getElementByIdSpy) {
9+
getElementByIdSpy.mockRestore();
10+
getElementByIdSpy = null;
11+
}
12+
});
13+
14+
it('renders the burst SVG', () => {
15+
const mockPlayer = {
16+
ready: jest.fn(callback => callback({ play: jest.fn() })),
17+
destruct: jest.fn(),
18+
};
19+
getElementByIdSpy = jest.spyOn(document, 'getElementById').mockReturnValue({
20+
svgatorPlayer: mockPlayer,
21+
});
22+
23+
const wrapper = mount(SubmitBurstAnimation);
24+
25+
expect(wrapper.find('svg').exists()).toBe(true);
26+
27+
wrapper.destroy();
28+
});
29+
30+
it('calls player.destruct on unmount when available', () => {
31+
const destruct = jest.fn();
32+
const mockPlayer = {
33+
ready: jest.fn(callback => callback({ play: jest.fn() })),
34+
destruct,
35+
};
36+
getElementByIdSpy = jest.spyOn(document, 'getElementById').mockReturnValue({
37+
svgatorPlayer: mockPlayer,
38+
});
39+
40+
const wrapper = mount(SubmitBurstAnimation);
41+
42+
wrapper.destroy();
43+
44+
expect(destruct).toHaveBeenCalled();
45+
});
46+
});

kolibri/plugins/user_auth/frontend/views/SignInPage/PictureSignIn/animations/SubmitBurstAnimation.vue

Lines changed: 211 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
<!-- eslint-disable -->
1+
<!-- eslint-disable max-len, vue/max-len -->
22
<template>
3+
34
<!-- prettier-ignore -->
45
<svg
56
id="e9E2fA0WrSF1"
@@ -11,11 +12,28 @@
1112
aria-hidden="true"
1213
style="background-color:transparent"
1314
>
14-
<g id="e9E2fA0WrSF2" transform="translate(31 31)">
15-
<g id="e9E2fA0WrSF3" transform="matrix(0 0 0 0 4.5 4.5)">
16-
<g id="e9E2fA0WrSF4" opacity="0" clip-path="url(#e9E2fA0WrSF5)">
15+
<g
16+
id="e9E2fA0WrSF2"
17+
transform="translate(31 31)"
18+
>
19+
<g
20+
id="e9E2fA0WrSF3"
21+
transform="matrix(0 0 0 0 4.5 4.5)"
22+
>
23+
<g
24+
id="e9E2fA0WrSF4"
25+
opacity="0"
26+
clip-path="url(#e9E2fA0WrSF5)"
27+
>
1728
<clipPath id="e9E2fA0WrSF5">
18-
<rect width="9" height="9" rx="0" ry="0" fill="none" stroke-width="0" />
29+
<rect
30+
width="9"
31+
height="9"
32+
rx="0"
33+
ry="0"
34+
fill="none"
35+
stroke-width="0"
36+
/>
1937
</clipPath>
2038
<g>
2139
<path
@@ -27,11 +45,28 @@
2745
</g>
2846
</g>
2947
</g>
30-
<g id="e9E2fA0WrSF9" transform="translate(31 31)">
31-
<g id="e9E2fA0WrSF10" transform="matrix(0 0 0 0 4.5 31.297)">
32-
<g id="e9E2fA0WrSF11" opacity="0" clip-path="url(#e9E2fA0WrSF12)">
48+
<g
49+
id="e9E2fA0WrSF9"
50+
transform="translate(31 31)"
51+
>
52+
<g
53+
id="e9E2fA0WrSF10"
54+
transform="matrix(0 0 0 0 4.5 31.297)"
55+
>
56+
<g
57+
id="e9E2fA0WrSF11"
58+
opacity="0"
59+
clip-path="url(#e9E2fA0WrSF12)"
60+
>
3361
<clipPath id="e9E2fA0WrSF12">
34-
<rect width="9" height="9" rx="0" ry="0" fill="none" stroke-width="0" />
62+
<rect
63+
width="9"
64+
height="9"
65+
rx="0"
66+
ry="0"
67+
fill="none"
68+
stroke-width="0"
69+
/>
3570
</clipPath>
3671
<g>
3772
<path
@@ -43,11 +78,28 @@
4378
</g>
4479
</g>
4580
</g>
46-
<g id="e9E2fA0WrSF16" transform="translate(31 31)">
47-
<g id="e9E2fA0WrSF17" transform="matrix(0 0 0 0 31.5 4.5)">
48-
<g id="e9E2fA0WrSF18" opacity="0" clip-path="url(#e9E2fA0WrSF19)">
81+
<g
82+
id="e9E2fA0WrSF16"
83+
transform="translate(31 31)"
84+
>
85+
<g
86+
id="e9E2fA0WrSF17"
87+
transform="matrix(0 0 0 0 31.5 4.5)"
88+
>
89+
<g
90+
id="e9E2fA0WrSF18"
91+
opacity="0"
92+
clip-path="url(#e9E2fA0WrSF19)"
93+
>
4994
<clipPath id="e9E2fA0WrSF19">
50-
<rect width="9" height="9" rx="0" ry="0" fill="none" stroke-width="0" />
95+
<rect
96+
width="9"
97+
height="9"
98+
rx="0"
99+
ry="0"
100+
fill="none"
101+
stroke-width="0"
102+
/>
51103
</clipPath>
52104
<g>
53105
<path
@@ -59,11 +111,28 @@
59111
</g>
60112
</g>
61113
</g>
62-
<g id="e9E2fA0WrSF23" transform="translate(31 31)">
63-
<g id="e9E2fA0WrSF24" transform="matrix(0 0 0 0 31.5 31.297)">
64-
<g id="e9E2fA0WrSF25" opacity="0" clip-path="url(#e9E2fA0WrSF26)">
114+
<g
115+
id="e9E2fA0WrSF23"
116+
transform="translate(31 31)"
117+
>
118+
<g
119+
id="e9E2fA0WrSF24"
120+
transform="matrix(0 0 0 0 31.5 31.297)"
121+
>
122+
<g
123+
id="e9E2fA0WrSF25"
124+
opacity="0"
125+
clip-path="url(#e9E2fA0WrSF26)"
126+
>
65127
<clipPath id="e9E2fA0WrSF26">
66-
<rect width="9" height="9" rx="0" ry="0" fill="none" stroke-width="0" />
128+
<rect
129+
width="9"
130+
height="9"
131+
rx="0"
132+
ry="0"
133+
fill="none"
134+
stroke-width="0"
135+
/>
67136
</clipPath>
68137
<g>
69138
<path
@@ -75,50 +144,142 @@
75144
</g>
76145
</g>
77146
</g>
78-
<g id="e9E2fA0WrSF30" transform="translate(24 25)">
79-
<g id="e9E2fA0WrSF31" transform="matrix(0 0 0 0 32 3)">
80-
<g id="e9E2fA0WrSF32" opacity="0" clip-path="url(#e9E2fA0WrSF33)">
147+
<g
148+
id="e9E2fA0WrSF30"
149+
transform="translate(24 25)"
150+
>
151+
<g
152+
id="e9E2fA0WrSF31"
153+
transform="matrix(0 0 0 0 32 3)"
154+
>
155+
<g
156+
id="e9E2fA0WrSF32"
157+
opacity="0"
158+
clip-path="url(#e9E2fA0WrSF33)"
159+
>
81160
<clipPath id="e9E2fA0WrSF33">
82-
<rect width="6" height="6" rx="0" ry="0" fill="none" stroke-width="0" />
161+
<rect
162+
width="6"
163+
height="6"
164+
rx="0"
165+
ry="0"
166+
fill="none"
167+
stroke-width="0"
168+
/>
83169
</clipPath>
84170
<g>
85-
<ellipse rx="3" ry="3" transform="translate(3 3)" fill="#ff7600" stroke-width="0" />
171+
<ellipse
172+
rx="3"
173+
ry="3"
174+
transform="translate(3 3)"
175+
fill="#ff7600"
176+
stroke-width="0"
177+
/>
86178
</g>
87179
</g>
88180
</g>
89181
</g>
90-
<g id="e9E2fA0WrSF37" transform="translate(24 25)">
91-
<g id="e9E2fA0WrSF38" transform="matrix(0 0 0 0 3 14)">
92-
<g id="e9E2fA0WrSF39" opacity="0" clip-path="url(#e9E2fA0WrSF40)">
182+
<g
183+
id="e9E2fA0WrSF37"
184+
transform="translate(24 25)"
185+
>
186+
<g
187+
id="e9E2fA0WrSF38"
188+
transform="matrix(0 0 0 0 3 14)"
189+
>
190+
<g
191+
id="e9E2fA0WrSF39"
192+
opacity="0"
193+
clip-path="url(#e9E2fA0WrSF40)"
194+
>
93195
<clipPath id="e9E2fA0WrSF40">
94-
<rect width="6" height="6" rx="0" ry="0" fill="none" stroke-width="0" />
196+
<rect
197+
width="6"
198+
height="6"
199+
rx="0"
200+
ry="0"
201+
fill="none"
202+
stroke-width="0"
203+
/>
95204
</clipPath>
96205
<g>
97-
<ellipse rx="3" ry="3" transform="translate(3 3)" fill="#00c73c" stroke-width="0" />
206+
<ellipse
207+
rx="3"
208+
ry="3"
209+
transform="translate(3 3)"
210+
fill="#00c73c"
211+
stroke-width="0"
212+
/>
98213
</g>
99214
</g>
100215
</g>
101216
</g>
102-
<g id="e9E2fA0WrSF44" transform="translate(24 25)">
103-
<g id="e9E2fA0WrSF45" transform="matrix(0 0 0 0 14 45)">
104-
<g id="e9E2fA0WrSF46" opacity="0" clip-path="url(#e9E2fA0WrSF47)">
217+
<g
218+
id="e9E2fA0WrSF44"
219+
transform="translate(24 25)"
220+
>
221+
<g
222+
id="e9E2fA0WrSF45"
223+
transform="matrix(0 0 0 0 14 45)"
224+
>
225+
<g
226+
id="e9E2fA0WrSF46"
227+
opacity="0"
228+
clip-path="url(#e9E2fA0WrSF47)"
229+
>
105230
<clipPath id="e9E2fA0WrSF47">
106-
<rect width="6" height="6" rx="0" ry="0" fill="none" stroke-width="0" />
231+
<rect
232+
width="6"
233+
height="6"
234+
rx="0"
235+
ry="0"
236+
fill="none"
237+
stroke-width="0"
238+
/>
107239
</clipPath>
108240
<g>
109-
<ellipse rx="3" ry="3" transform="translate(3 3)" fill="#f76474" stroke-width="0" />
241+
<ellipse
242+
rx="3"
243+
ry="3"
244+
transform="translate(3 3)"
245+
fill="#f76474"
246+
stroke-width="0"
247+
/>
110248
</g>
111249
</g>
112250
</g>
113251
</g>
114-
<g id="e9E2fA0WrSF51" transform="translate(24 25)">
115-
<g id="e9E2fA0WrSF52" transform="matrix(0 0 0 0 47 37)">
116-
<g id="e9E2fA0WrSF53" opacity="0" clip-path="url(#e9E2fA0WrSF54)">
252+
<g
253+
id="e9E2fA0WrSF51"
254+
transform="translate(24 25)"
255+
>
256+
<g
257+
id="e9E2fA0WrSF52"
258+
transform="matrix(0 0 0 0 47 37)"
259+
>
260+
<g
261+
id="e9E2fA0WrSF53"
262+
opacity="0"
263+
clip-path="url(#e9E2fA0WrSF54)"
264+
>
117265
<clipPath id="e9E2fA0WrSF54">
118-
<rect width="6" height="6" rx="0" ry="0" fill="none" stroke-width="0" />
266+
<rect
267+
width="6"
268+
height="6"
269+
rx="0"
270+
ry="0"
271+
fill="none"
272+
stroke-width="0"
273+
/>
119274
</clipPath>
120275
<g>
121-
<ellipse rx="3" ry="3" transform="translate(3 3)" fill="#66c1f7" stroke-width="0" />
276+
<ellipse
277+
rx="3"
278+
ry="3"
279+
transform="translate(3 3)"
280+
fill="#66c1f7"
281+
stroke-width="0"
282+
/>
122283
</g>
123284
</g>
124285
</g>
@@ -157,16 +318,25 @@
157318
</g>
158319
</g>
159320
<clipPath id="e9E2fA0WrSF64">
160-
<rect width="18" height="18" rx="0" ry="0" fill="none" stroke-width="0" />
321+
<rect
322+
width="18"
323+
height="18"
324+
rx="0"
325+
ry="0"
326+
fill="none"
327+
stroke-width="0"
328+
/>
161329
</clipPath>
162330
</g>
163331
</svg>
332+
164333
</template>
165334

166335

167336
<script>
168337
169-
// eslint-disable-next-line import-x/no-import-module-exports -- SVGator UMD wrapper
338+
// SVGator UMD wrapper includes module.exports
339+
// eslint-disable-next-line import-x/no-import-module-exports
170340
import { onMounted, onBeforeUnmount } from 'vue';
171341
172342
export default {
@@ -193,8 +363,8 @@
193363
});
194364
195365
onBeforeUnmount(() => {
196-
if (player && typeof player.stop === 'function') {
197-
player.stop();
366+
if (player && typeof player.destruct === 'function') {
367+
player.destruct();
198368
}
199369
player = null;
200370
});

kolibri/plugins/user_auth/frontend/views/SignInPage/PictureSignIn/animations/submitBurst.svg

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)