@fmidev/smartmet-alert-client 4.4.19 → 4.7.0-beta.0
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/.eslintignore +2 -14
- package/.github/workflows/test.yaml +26 -0
- package/.nvmrc +1 -0
- package/AGENTS.md +26 -0
- package/index.html +1 -1
- package/package.json +80 -22
- package/src/AlertClientVue.vue +160 -0
- package/src/App.vue +154 -296
- package/src/assets/img/ui/arrow-down.svg +4 -11
- package/src/assets/img/ui/arrow-up.svg +4 -11
- package/src/assets/img/ui/clear.svg +7 -21
- package/src/assets/img/ui/close.svg +4 -15
- package/src/assets/img/ui/toggle-selected.svg +5 -6
- package/src/assets/img/ui/toggle-unselected.svg +5 -6
- package/src/assets/img/warning/cold-weather.svg +3 -6
- package/src/assets/img/warning/flood-level-3.svg +4 -7
- package/src/assets/img/warning/forest-fire-weather.svg +2 -6
- package/src/assets/img/warning/grass-fire-weather.svg +2 -6
- package/src/assets/img/warning/hot-weather.svg +3 -6
- package/src/assets/img/warning/pedestrian-safety.svg +3 -7
- package/src/assets/img/warning/rain.svg +2 -7
- package/src/assets/img/warning/sea-icing.svg +2 -6
- package/src/assets/img/warning/sea-thunder-storm.svg +2 -5
- package/src/assets/img/warning/sea-water-height-high-water.svg +3 -8
- package/src/assets/img/warning/sea-water-height-shallow-water.svg +3 -7
- package/src/assets/img/warning/sea-wave-height.svg +4 -7
- package/src/assets/img/warning/sea-wind-legend.svg +2 -5
- package/src/assets/img/warning/sea-wind.svg +2 -5
- package/src/assets/img/warning/several.svg +2 -5
- package/src/assets/img/warning/thunder-storm.svg +2 -5
- package/src/assets/img/warning/traffic-weather.svg +2 -6
- package/src/assets/img/warning/uv-note.svg +2 -6
- package/src/assets/img/warning/wind.svg +2 -5
- package/src/components/AlertClient.vue +330 -251
- package/src/components/CollapsiblePanel.vue +281 -0
- package/src/components/DayLarge.vue +146 -110
- package/src/components/DaySmall.vue +97 -81
- package/src/components/Days.vue +229 -159
- package/src/components/DescriptionWarning.vue +63 -38
- package/src/components/GrayScaleToggle.vue +58 -54
- package/src/components/Legend.vue +102 -325
- package/src/components/MapLarge.vue +574 -351
- package/src/components/MapSmall.vue +137 -122
- package/src/components/PopupRow.vue +24 -12
- package/src/components/Region.vue +168 -118
- package/src/components/RegionWarning.vue +40 -33
- package/src/components/Regions.vue +189 -105
- package/src/components/Warning.vue +70 -45
- package/src/components/Warnings.vue +136 -72
- package/src/composables/useAlertClient.ts +360 -0
- package/src/composables/useConfig.ts +573 -0
- package/src/composables/useFields.ts +66 -0
- package/src/composables/useI18n.ts +62 -0
- package/src/composables/useKeyCodes.ts +16 -0
- package/src/composables/useMapPaths.ts +477 -0
- package/src/composables/useUtils.ts +683 -0
- package/src/composables/useWarningsProcessor.ts +1007 -0
- package/src/data/geometries.json +993 -0
- package/src/{main.js → main.ts} +1 -0
- package/src/mixins/geojsonsvg.d.ts +57 -0
- package/src/mixins/geojsonsvg.js +5 -3
- package/src/plugins/index.ts +5 -0
- package/src/scss/_utilities.scss +193 -0
- package/src/scss/constants.scss +2 -1
- package/src/scss/warningImages.scss +8 -3
- package/src/types/index.ts +509 -0
- package/src/vite-env.d.ts +23 -0
- package/src/vue.ts +41 -0
- package/svgo.config.js +45 -0
- package/tests/README.md +430 -0
- package/tests/fixtures/mockWarningData.ts +152 -0
- package/tests/integration/warning-flow.spec.ts +445 -0
- package/tests/setup.ts +41 -0
- package/tests/unit/components/AlertClient.spec.ts +701 -0
- package/tests/unit/components/DayLarge.spec.ts +348 -0
- package/tests/unit/components/DaySmall.spec.ts +352 -0
- package/tests/unit/components/Days.spec.ts +548 -0
- package/tests/unit/components/DescriptionWarning.spec.ts +385 -0
- package/tests/unit/components/GrayScaleToggle.spec.ts +318 -0
- package/tests/unit/components/Legend.spec.ts +295 -0
- package/tests/unit/components/MapLarge.spec.ts +448 -0
- package/tests/unit/components/MapSmall.spec.ts +367 -0
- package/tests/unit/components/PopupRow.spec.ts +270 -0
- package/tests/unit/components/Region.spec.ts +373 -0
- package/tests/unit/components/RegionWarning.snapshot.spec.ts +361 -0
- package/tests/unit/components/RegionWarning.spec.ts +381 -0
- package/tests/unit/components/Regions.spec.ts +503 -0
- package/tests/unit/components/Warning.snapshot.spec.ts +483 -0
- package/tests/unit/components/Warning.spec.ts +489 -0
- package/tests/unit/components/Warnings.spec.ts +343 -0
- package/tests/unit/components/__snapshots__/RegionWarning.snapshot.spec.ts.snap +41 -0
- package/tests/unit/components/__snapshots__/Warning.snapshot.spec.ts.snap +433 -0
- package/tests/unit/composables/useConfig.spec.ts +279 -0
- package/tests/unit/composables/useI18n.spec.ts +116 -0
- package/tests/unit/composables/useKeyCodes.spec.ts +27 -0
- package/tests/unit/composables/useUtils.spec.ts +213 -0
- package/tsconfig.json +43 -0
- package/tsconfig.node.json +11 -0
- package/vite.config.js +96 -26
- package/vitest.config.js +40 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.dark.html +0 -20
- package/dist/index.en.html +0 -15
- package/dist/index.fi.html +0 -15
- package/dist/index.html +0 -15
- package/dist/index.js +0 -281
- package/dist/index.mjs +0 -281
- package/dist/index.mjs.map +0 -1
- package/dist/index.relative.html +0 -19
- package/dist/index.start.html +0 -20
- package/dist/index.sv.html +0 -15
- package/playwright.config.ts +0 -18
- package/public/index.relative.html +0 -19
- package/public/index.start.html +0 -20
- package/src/mixins/config.js +0 -1378
- package/src/mixins/fields.js +0 -26
- package/src/mixins/i18n.js +0 -25
- package/src/mixins/keycodes.js +0 -10
- package/src/mixins/panzoom.js +0 -900
- package/src/mixins/utils.js +0 -900
- package/src/plugins/index.js +0 -3
- package/test/snapshot.test.ts +0 -126
- package/vitest.config.ts +0 -6
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest'
|
|
2
|
+
import { mount, VueWrapper } from '@vue/test-utils'
|
|
3
|
+
import MapSmall from '@/components/MapSmall.vue'
|
|
4
|
+
import type { DayRegions, WarningsMap, Theme } from '@/types'
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
type ComponentInstance = any
|
|
8
|
+
|
|
9
|
+
const mockRegions: DayRegions = {
|
|
10
|
+
land: [],
|
|
11
|
+
sea: [],
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('MapSmall.vue', () => {
|
|
15
|
+
let wrapper: VueWrapper | null = null
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
if (wrapper) {
|
|
19
|
+
wrapper.unmount()
|
|
20
|
+
wrapper = null
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('Component mounting', () => {
|
|
25
|
+
it('should mount with default props', () => {
|
|
26
|
+
wrapper = mount(MapSmall, {
|
|
27
|
+
props: {},
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
expect(wrapper.exists()).toBe(true)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should mount with all props', () => {
|
|
34
|
+
wrapper = mount(MapSmall, {
|
|
35
|
+
props: {
|
|
36
|
+
index: 0,
|
|
37
|
+
input: mockRegions,
|
|
38
|
+
visibleWarnings: [],
|
|
39
|
+
warnings: null,
|
|
40
|
+
geometryId: 2021,
|
|
41
|
+
loading: true,
|
|
42
|
+
theme: 'light-theme' as Theme,
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
expect(wrapper.exists()).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('Computed properties', () => {
|
|
51
|
+
it('should compute size as Small', () => {
|
|
52
|
+
wrapper = mount(MapSmall, {
|
|
53
|
+
props: {},
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
expect((wrapper.vm as ComponentInstance).size).toBe('Small')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should have strokeWidth property', () => {
|
|
60
|
+
wrapper = mount(MapSmall, {
|
|
61
|
+
props: {},
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
expect((wrapper.vm as ComponentInstance).strokeWidth).toBe(0.6)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should have pathsNeeded property', () => {
|
|
68
|
+
wrapper = mount(MapSmall, {
|
|
69
|
+
props: {},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
expect(typeof (wrapper.vm as ComponentInstance).pathsNeeded).toBe(
|
|
73
|
+
'boolean'
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('Props handling', () => {
|
|
79
|
+
it('should accept index prop', () => {
|
|
80
|
+
wrapper = mount(MapSmall, {
|
|
81
|
+
props: {
|
|
82
|
+
index: 2,
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
expect((wrapper.vm as ComponentInstance).index).toBe(2)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should accept loading prop', () => {
|
|
90
|
+
wrapper = mount(MapSmall, {
|
|
91
|
+
props: {
|
|
92
|
+
loading: false,
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
expect((wrapper.vm as ComponentInstance).loading).toBe(false)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should accept warnings prop', () => {
|
|
100
|
+
const mockWarnings: WarningsMap = {}
|
|
101
|
+
|
|
102
|
+
wrapper = mount(MapSmall, {
|
|
103
|
+
props: {
|
|
104
|
+
warnings: mockWarnings,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
expect(wrapper.exists()).toBe(true)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('should accept visibleWarnings prop', () => {
|
|
112
|
+
wrapper = mount(MapSmall, {
|
|
113
|
+
props: {
|
|
114
|
+
visibleWarnings: ['wind', 'rain'],
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
expect(wrapper.exists()).toBe(true)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should accept geometryId prop', () => {
|
|
122
|
+
wrapper = mount(MapSmall, {
|
|
123
|
+
props: {
|
|
124
|
+
geometryId: 2021,
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
expect((wrapper.vm as ComponentInstance).geometryId).toBe(2021)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should use default index of 0', () => {
|
|
132
|
+
wrapper = mount(MapSmall, {
|
|
133
|
+
props: {},
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
expect((wrapper.vm as ComponentInstance).index).toBe(0)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('should use default geometryId of 2021', () => {
|
|
140
|
+
wrapper = mount(MapSmall, {
|
|
141
|
+
props: {},
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
expect((wrapper.vm as ComponentInstance).geometryId).toBe(2021)
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
describe('Theme support', () => {
|
|
149
|
+
it('should accept theme prop', () => {
|
|
150
|
+
wrapper = mount(MapSmall, {
|
|
151
|
+
props: {
|
|
152
|
+
theme: 'dark-theme' as Theme,
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
expect((wrapper.vm as ComponentInstance).theme).toBe('dark-theme')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should default to light-theme', () => {
|
|
160
|
+
wrapper = mount(MapSmall, {
|
|
161
|
+
props: {},
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
expect((wrapper.vm as ComponentInstance).theme).toBe('light-theme')
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('should support all theme variants', () => {
|
|
168
|
+
const themes: Theme[] = [
|
|
169
|
+
'light-theme',
|
|
170
|
+
'dark-theme',
|
|
171
|
+
'light-gray-theme',
|
|
172
|
+
'dark-gray-theme',
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
themes.forEach((theme) => {
|
|
176
|
+
wrapper = mount(MapSmall, {
|
|
177
|
+
props: {
|
|
178
|
+
theme,
|
|
179
|
+
},
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
expect((wrapper.vm as ComponentInstance).theme).toBe(theme)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
describe('SVG structure', () => {
|
|
188
|
+
it('should render map-small container', () => {
|
|
189
|
+
wrapper = mount(MapSmall, {
|
|
190
|
+
props: {},
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
expect(wrapper.find('.map-small').exists()).toBe(true)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should render SVG element', () => {
|
|
197
|
+
wrapper = mount(MapSmall, {
|
|
198
|
+
props: {},
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
expect(wrapper.find('svg.finland-small').exists()).toBe(true)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('should have correct SVG dimensions', () => {
|
|
205
|
+
wrapper = mount(MapSmall, {
|
|
206
|
+
props: {},
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
const svg = wrapper.find('svg.finland-small')
|
|
210
|
+
expect(svg.attributes('width')).toBe('75')
|
|
211
|
+
expect(svg.attributes('height')).toBe('120')
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('should have correct viewBox', () => {
|
|
215
|
+
wrapper = mount(MapSmall, {
|
|
216
|
+
props: {},
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
expect(wrapper.find('svg.finland-small').attributes('viewBox')).toBe(
|
|
220
|
+
'0 0 75 120'
|
|
221
|
+
)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('should render SVG group with correct id', () => {
|
|
225
|
+
wrapper = mount(MapSmall, {
|
|
226
|
+
props: {
|
|
227
|
+
index: 2,
|
|
228
|
+
},
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Group is conditionally rendered based on pathsNeeded
|
|
232
|
+
expect(wrapper.exists()).toBe(true)
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
describe('Map paths', () => {
|
|
237
|
+
it('should have access to strokeColor', () => {
|
|
238
|
+
wrapper = mount(MapSmall, {
|
|
239
|
+
props: {},
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
expect((wrapper.vm as ComponentInstance).strokeColor).toBeDefined()
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
it('should have access to bluePaths', () => {
|
|
246
|
+
wrapper = mount(MapSmall, {
|
|
247
|
+
props: {},
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).bluePaths)).toBe(
|
|
251
|
+
true
|
|
252
|
+
)
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
it('should have access to greenPaths', () => {
|
|
256
|
+
wrapper = mount(MapSmall, {
|
|
257
|
+
props: {},
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).greenPaths)).toBe(
|
|
261
|
+
true
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('should have access to yellowPaths', () => {
|
|
266
|
+
wrapper = mount(MapSmall, {
|
|
267
|
+
props: {},
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).yellowPaths)).toBe(
|
|
271
|
+
true
|
|
272
|
+
)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('should have access to orangePaths', () => {
|
|
276
|
+
wrapper = mount(MapSmall, {
|
|
277
|
+
props: {},
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).orangePaths)).toBe(
|
|
281
|
+
true
|
|
282
|
+
)
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('should have access to redPaths', () => {
|
|
286
|
+
wrapper = mount(MapSmall, {
|
|
287
|
+
props: {},
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).redPaths)).toBe(
|
|
291
|
+
true
|
|
292
|
+
)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
it('should have access to overlayPaths', () => {
|
|
296
|
+
wrapper = mount(MapSmall, {
|
|
297
|
+
props: {},
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
expect(
|
|
301
|
+
Array.isArray((wrapper.vm as ComponentInstance).overlayPaths)
|
|
302
|
+
).toBe(true)
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('should have access to landBorders', () => {
|
|
306
|
+
wrapper = mount(MapSmall, {
|
|
307
|
+
props: {},
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).landBorders)).toBe(
|
|
311
|
+
true
|
|
312
|
+
)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('should have access to seaBorders', () => {
|
|
316
|
+
wrapper = mount(MapSmall, {
|
|
317
|
+
props: {},
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
expect(Array.isArray((wrapper.vm as ComponentInstance).seaBorders)).toBe(
|
|
321
|
+
true
|
|
322
|
+
)
|
|
323
|
+
})
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
describe('Coverage data', () => {
|
|
327
|
+
it('should have access to yellowCoverages', () => {
|
|
328
|
+
wrapper = mount(MapSmall, {
|
|
329
|
+
props: {},
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
expect(
|
|
333
|
+
Array.isArray((wrapper.vm as ComponentInstance).yellowCoverages)
|
|
334
|
+
).toBe(true)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('should have access to orangeCoverages', () => {
|
|
338
|
+
wrapper = mount(MapSmall, {
|
|
339
|
+
props: {},
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
expect(
|
|
343
|
+
Array.isArray((wrapper.vm as ComponentInstance).orangeCoverages)
|
|
344
|
+
).toBe(true)
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
it('should have access to redCoverages', () => {
|
|
348
|
+
wrapper = mount(MapSmall, {
|
|
349
|
+
props: {},
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
expect(
|
|
353
|
+
Array.isArray((wrapper.vm as ComponentInstance).redCoverages)
|
|
354
|
+
).toBe(true)
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('should have access to overlayCoverages', () => {
|
|
358
|
+
wrapper = mount(MapSmall, {
|
|
359
|
+
props: {},
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
expect(
|
|
363
|
+
Array.isArray((wrapper.vm as ComponentInstance).overlayCoverages)
|
|
364
|
+
).toBe(true)
|
|
365
|
+
})
|
|
366
|
+
})
|
|
367
|
+
})
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'vitest'
|
|
2
|
+
import { mount, VueWrapper } from '@vue/test-utils'
|
|
3
|
+
import PopupRow from '@/components/PopupRow.vue'
|
|
4
|
+
import type { PopupRowInput } from '@/types'
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
type ComponentInstance = any
|
|
8
|
+
|
|
9
|
+
const mockWarning: PopupRowInput = {
|
|
10
|
+
type: 'wind',
|
|
11
|
+
severity: 3,
|
|
12
|
+
direction: 270,
|
|
13
|
+
text: '15',
|
|
14
|
+
interval: '14:00 – 18:00',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('PopupRow.vue', () => {
|
|
18
|
+
let wrapper: VueWrapper | null = null
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
if (wrapper) {
|
|
22
|
+
wrapper.unmount()
|
|
23
|
+
wrapper = null
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('Component mounting', () => {
|
|
28
|
+
it('should mount with required props', () => {
|
|
29
|
+
wrapper = mount(PopupRow, {
|
|
30
|
+
props: {
|
|
31
|
+
input: mockWarning,
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
expect(wrapper.exists()).toBe(true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should use default empty object for input prop', () => {
|
|
39
|
+
wrapper = mount(PopupRow, {
|
|
40
|
+
props: {
|
|
41
|
+
input: {
|
|
42
|
+
type: 'rain',
|
|
43
|
+
severity: 2,
|
|
44
|
+
interval: '',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
expect(wrapper.exists()).toBe(true)
|
|
50
|
+
expect((wrapper.vm as ComponentInstance).input).toBeDefined()
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('Fields mixin integration', () => {
|
|
55
|
+
it('should compute typeClass from warning type', () => {
|
|
56
|
+
wrapper = mount(PopupRow, {
|
|
57
|
+
props: {
|
|
58
|
+
input: mockWarning,
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
expect((wrapper.vm as ComponentInstance).typeClass).toBe('wind')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should compute typeClass for thunderStorm', () => {
|
|
66
|
+
wrapper = mount(PopupRow, {
|
|
67
|
+
props: {
|
|
68
|
+
input: {
|
|
69
|
+
type: 'thunderStorm',
|
|
70
|
+
severity: 4,
|
|
71
|
+
interval: '',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
expect((wrapper.vm as ComponentInstance).typeClass).toBe('thunder-storm')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('should compute rotation from direction', () => {
|
|
80
|
+
wrapper = mount(PopupRow, {
|
|
81
|
+
props: {
|
|
82
|
+
input: mockWarning,
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
expect((wrapper.vm as ComponentInstance).rotation).toBe(270)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should compute invertedRotation', () => {
|
|
90
|
+
wrapper = mount(PopupRow, {
|
|
91
|
+
props: {
|
|
92
|
+
input: mockWarning,
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
expect((wrapper.vm as ComponentInstance).invertedRotation).toBe(90)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should compute severity', () => {
|
|
100
|
+
wrapper = mount(PopupRow, {
|
|
101
|
+
props: {
|
|
102
|
+
input: mockWarning,
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
expect((wrapper.vm as ComponentInstance).severity).toBe(3)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should return 0 for invalid severity', () => {
|
|
110
|
+
wrapper = mount(PopupRow, {
|
|
111
|
+
props: {
|
|
112
|
+
input: {
|
|
113
|
+
type: 'wind',
|
|
114
|
+
severity: 1,
|
|
115
|
+
interval: '',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect((wrapper.vm as ComponentInstance).severity).toBe(0)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('Content rendering', () => {
|
|
125
|
+
it('should render interval text', () => {
|
|
126
|
+
wrapper = mount(PopupRow, {
|
|
127
|
+
props: {
|
|
128
|
+
input: mockWarning,
|
|
129
|
+
},
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
expect(wrapper.text()).toContain('14:00 – 18:00')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should render warning text in symbol', () => {
|
|
136
|
+
wrapper = mount(PopupRow, {
|
|
137
|
+
props: {
|
|
138
|
+
input: mockWarning,
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
expect(wrapper.find('.symbol-text').text()).toBe('15')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('should render empty text when not provided', () => {
|
|
146
|
+
const warningNoText: PopupRowInput = {
|
|
147
|
+
type: 'rain',
|
|
148
|
+
severity: 2,
|
|
149
|
+
interval: '10:00 – 12:00',
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
wrapper = mount(PopupRow, {
|
|
153
|
+
props: {
|
|
154
|
+
input: warningNoText,
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
expect(wrapper.find('.symbol-text').text()).toBe('')
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('CSS classes', () => {
|
|
163
|
+
it('should apply severity level class to symbol', () => {
|
|
164
|
+
wrapper = mount(PopupRow, {
|
|
165
|
+
props: {
|
|
166
|
+
input: mockWarning,
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const symbol = wrapper.find('.popup-table-symbol-cell')
|
|
171
|
+
expect(symbol.classes()).toContain('level-3')
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('should apply type class to symbol', () => {
|
|
175
|
+
wrapper = mount(PopupRow, {
|
|
176
|
+
props: {
|
|
177
|
+
input: mockWarning,
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
const symbol = wrapper.find('.popup-table-symbol-cell')
|
|
182
|
+
expect(symbol.classes()).toContain('wind')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('should apply rotation class', () => {
|
|
186
|
+
wrapper = mount(PopupRow, {
|
|
187
|
+
props: {
|
|
188
|
+
input: mockWarning,
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
const symbol = wrapper.find('.popup-table-symbol-cell')
|
|
193
|
+
expect(symbol.classes()).toContain('transform-rotate-270')
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should apply inverted rotation to text', () => {
|
|
197
|
+
wrapper = mount(PopupRow, {
|
|
198
|
+
props: {
|
|
199
|
+
input: mockWarning,
|
|
200
|
+
},
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
const text = wrapper.find('.symbol-text')
|
|
204
|
+
expect(text.classes()).toContain('transform-rotate-90')
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('should apply text level class to interval cell', () => {
|
|
208
|
+
wrapper = mount(PopupRow, {
|
|
209
|
+
props: {
|
|
210
|
+
input: mockWarning,
|
|
211
|
+
},
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
const textCell = wrapper.find('.popup-table-text-cell')
|
|
215
|
+
expect(textCell.classes()).toContain('text-level-3')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('should hide level-0 warnings', () => {
|
|
219
|
+
const warningLevel0: PopupRowInput = {
|
|
220
|
+
type: 'wind',
|
|
221
|
+
severity: 0,
|
|
222
|
+
interval: '',
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
wrapper = mount(PopupRow, {
|
|
226
|
+
props: {
|
|
227
|
+
input: warningLevel0,
|
|
228
|
+
},
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Level-0 warning images should have display: none via CSS
|
|
232
|
+
const symbol = wrapper.find('.popup-table-symbol-cell')
|
|
233
|
+
expect(symbol.classes()).toContain('level-0')
|
|
234
|
+
})
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
describe('Table structure', () => {
|
|
238
|
+
it('should render as table row', () => {
|
|
239
|
+
wrapper = mount(PopupRow, {
|
|
240
|
+
props: {
|
|
241
|
+
input: mockWarning,
|
|
242
|
+
},
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
expect(wrapper.find('.popup-table-row').exists()).toBe(true)
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('should have two table cells', () => {
|
|
249
|
+
wrapper = mount(PopupRow, {
|
|
250
|
+
props: {
|
|
251
|
+
input: mockWarning,
|
|
252
|
+
},
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
const cells = wrapper.findAll('.popup-table-cell')
|
|
256
|
+
expect(cells).toHaveLength(2)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('should have symbol cell and text cell', () => {
|
|
260
|
+
wrapper = mount(PopupRow, {
|
|
261
|
+
props: {
|
|
262
|
+
input: mockWarning,
|
|
263
|
+
},
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
expect(wrapper.find('.popup-table-symbol-cell').exists()).toBe(true)
|
|
267
|
+
expect(wrapper.find('.popup-table-text-cell').exists()).toBe(true)
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
})
|