-
Notifications
You must be signed in to change notification settings - Fork 11
/
periodic-table.test.ts
230 lines (186 loc) · 7.57 KB
/
periodic-table.test.ts
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
import { element_data, PeriodicTable, PropertySelect } from '$lib'
import { category_counts, heatmap_labels } from '$lib/labels'
import { tick } from 'svelte'
import { describe, expect, test, vi } from 'vitest'
import { doc_query } from '.'
const mouseenter = new MouseEvent(`mouseenter`)
const mouseleave = new MouseEvent(`mouseleave`)
describe(`PeriodicTable`, () => {
test.each([
[true, 120],
[false, 118],
[null, 118],
[[], 118],
])(
`renders element tiles with show_lanth_act_tiles=%s`,
async (lanth_act_tiles, expected_tiles) => {
const props = lanth_act_tiles == true ? {} : { lanth_act_tiles }
new PeriodicTable({ target: document.body, props })
const element_tiles = document.querySelectorAll(`.element-tile`)
expect(element_tiles.length).toBe(expected_tiles)
}
)
test(`has no text content when symbols, names and numbers are disabled`, async () => {
const tile_props = {
show_symbol: false,
show_name: false,
show_number: false,
}
new PeriodicTable({ target: document.body, props: { tile_props } })
const ptable = doc_query(`.periodic-table`)
expect(ptable?.textContent?.trim()).toBe(``)
// make sure empty tiles are still rendered
const symbol_tiles = document.querySelectorAll(`.element-tile`)
expect(symbol_tiles.length).toBe(118)
})
test(`hovering element tile toggles CSS class 'active'`, async () => {
new PeriodicTable({ target: document.body })
const element_tile = doc_query(`.element-tile`)
element_tile?.dispatchEvent(mouseenter)
await tick()
expect([...element_tile.classList]).toContain(`active`)
element_tile?.dispatchEvent(mouseleave)
await tick()
expect([...element_tile.classList]).not.toContain(`active`)
})
test(`shows element photo when hovering element tile`, async () => {
new PeriodicTable({ target: document.body })
const rand_idx = Math.floor(Math.random() * element_data.length)
const random_element = element_data[rand_idx]
const element_tile = document.querySelectorAll(`.element-tile`)[rand_idx]
element_tile?.dispatchEvent(mouseenter)
await tick()
const element_photo = doc_query(`img[alt="${random_element.name}"]`)
expect(element_photo?.style.gridArea).toBe(`9/1/span 2/span 2`)
element_tile?.dispatchEvent(mouseleave)
await tick()
expect(document.querySelector(`img`)).toBeNull()
})
test(`hooking PeriodicTable up to PropertySelect and selecting heatmap sets element tile background`, async () => {
const ptable = new PeriodicTable({ target: document.body })
new PropertySelect({ target: document.body })
const li = doc_query(`ul.options > li`)
li.dispatchEvent(new MouseEvent(`mouseup`))
await tick()
const selected = doc_query(`div.multiselect > ul.selected`)
const heatmap_label = `Atomic Mass (u)`
expect(selected.textContent?.trim()).toBe(heatmap_label)
const heatmap_key = heatmap_labels[heatmap_label]
expect(heatmap_key).toBe(`atomic_mass`)
ptable.$set({ heatmap_values: element_data.map((e) => e[heatmap_key]) })
await tick()
const element_tile = doc_query(`div.element-tile`)
// hydrogen with lowest mass should be blue (low end of color scale)
expect(element_tile.style.backgroundColor).toBe(`rgb(68, 1, 84)`)
})
test.each([[0], [0.5], [1], [2]])(
`inner_transition_metal_offset`,
async (inner_transition_metal_offset) => {
new PeriodicTable({
target: document.body,
props: { inner_transition_metal_offset },
})
if (inner_transition_metal_offset) {
const spacer = doc_query(`div.spacer`)
expect(getComputedStyle(spacer).gridRow).toBe(`8`)
} else {
expect(document.querySelector(`div.spacer`)).toBeNull()
}
}
)
test(`clicking element tile emits event`, async () => {
const ptable = new PeriodicTable({ target: document.body })
let expected_active = false
let emitted = false
ptable.$on(`click`, (e) => {
emitted = true
expect(e.detail.element).toBe(element_data[0])
expect(e.detail.active).toBe(expected_active)
expect(e.detail.event).toBeInstanceOf(MouseEvent)
expect(e.detail.event.type).toBe(`click`)
})
const element_tile = doc_query(`.element-tile`)
element_tile?.dispatchEvent(new MouseEvent(`click`))
await tick()
expect(emitted).toBe(true)
expected_active = true
element_tile?.dispatchEvent(mouseenter)
await tick()
element_tile?.dispatchEvent(new MouseEvent(`click`))
})
test.each([[`0`], [`10px`], [`1cqw`]])(`gap prop`, (gap) => {
new PeriodicTable({ target: document.body, props: { gap } })
const ptable = doc_query(`.periodic-table`)
expect(getComputedStyle(ptable).gap).toBe(gap)
})
test.each(Object.entries(category_counts))(
`setting active_category=%s highlights corresponding element tiles`,
(active_category, expected_active) => {
new PeriodicTable({
target: document.body,
props: { active_category: active_category.replaceAll(` `, `-`) },
})
const active_tiles = document.querySelectorAll(`.element-tile.active`)
expect(active_tiles.length).toBe(expected_active)
}
)
test.each([[[...Array(1000).keys()]], [[...Array(119).keys()]]])(
`raises error when receiving more than 118 heatmap values`,
(heatmap_values) => {
console.error = vi.fn()
new PeriodicTable({
target: document.body,
props: { heatmap_values },
})
expect(console.error).toHaveBeenCalledOnce()
expect(console.error).toBeCalledWith(
`heatmap_values is an array of numbers, length should be 118 or less, one for ` +
`each element possibly omitting elements at the end, got ${heatmap_values.length}`
)
}
)
test.each([{ foo: 42 }], [{}])(
`raises error when heatmap_values is object with unknown element symbols`,
(heatmap_values) => {
console.error = vi.fn()
new PeriodicTable({
target: document.body,
props: { heatmap_values },
})
expect(console.error).toHaveBeenCalledOnce()
expect(console.error).toBeCalledWith(
`heatmap_values is an object, keys should be element symbols, got ${Object.keys(
heatmap_values
)}`
)
}
)
test(`element tiles are accessible to keyboard users`, async () => {
new PeriodicTable({ target: document.body })
const element_tiles = document.querySelectorAll(`.element-tile`)
// Simulate keyboard navigation of the element tiles
let activeIndex = 0
element_tiles[activeIndex].dispatchEvent(mouseenter)
await tick()
expect(element_tiles[activeIndex].classList.contains(`active`)).toBe(true)
expect(element_tiles[activeIndex].textContent?.trim()).toBe(`1 H Hydrogen`)
// Press the down arrow key to move to the next row
window.dispatchEvent(new KeyboardEvent(`keydown`, { key: `ArrowDown` }))
await tick()
activeIndex += 2
expect(element_tiles[activeIndex].classList.contains(`active`)).toBe(true)
expect(element_tiles[activeIndex].textContent?.trim()).toBe(`3 Li Lithium`)
// Press the right arrow key to move to the next column
activeIndex += 1
window.dispatchEvent(new KeyboardEvent(`keydown`, { key: `ArrowRight` }))
await tick()
expect(element_tiles[activeIndex].textContent?.trim()).toBe(
`4 Be Beryllium`
)
// Press the left arrow key to move back to the previous column
activeIndex -= 1
window.dispatchEvent(new KeyboardEvent(`keydown`, { key: `ArrowLeft` }))
await tick()
expect(element_tiles[activeIndex].textContent?.trim()).toBe(`3 Li Lithium`)
})
})