Skip to content

Commit 9efc6a1

Browse files
committed
frontend: fix linting
1 parent a39415c commit 9efc6a1

File tree

1 file changed

+61
-52
lines changed

1 file changed

+61
-52
lines changed

frontend/src/pages/__tests__/Devices.test.tsx

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
import { render, screen, waitFor, cleanup } from '@testing-library/preact';
22
import { afterEach, beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
33
import { DeviceList } from '../Devices';
4-
import { createRef } from 'preact';
4+
import { createRef, type RefObject } from 'preact';
55
import { fetchClient, get_decrypted_secret } from '../../utils';
66
import { Base64 } from 'js-base64';
77
import sodium from 'libsodium-wrappers';
88
import { showAlert } from '../../components/Alert';
99

1010
describe('Devices.tsx - DeviceList', () => {
11+
// Helper to safely access the component instance without using non-null assertions
12+
const getRef = (ref: RefObject<DeviceList>): DeviceList => {
13+
const current = ref.current;
14+
if (!current) {
15+
throw new Error('DeviceList ref not set');
16+
}
17+
return current;
18+
};
19+
1120
beforeEach(() => {
1221
vi.clearAllMocks();
1322
});
@@ -138,36 +147,36 @@ describe('Devices.tsx - DeviceList', () => {
138147
{ id: 'a', uid: 2, name: 'Bravo', status: 'Connected', note: '', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
139148
{ id: 'b', uid: 1, name: 'Alpha', status: 'Connected', note: '', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
140149
];
141-
ref.current!.setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
142-
await waitFor(() => expect(ref.current!.state.devices.length).toBe(2));
150+
getRef(ref).setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
151+
await waitFor(() => expect(getRef(ref).state.devices.length).toBe(2));
143152

144153
// First click -> sort by name asc
145-
ref.current!.setSort('name');
146-
await waitFor(() => expect(ref.current!.state.sortColumn).toBe('name'));
147-
expect(ref.current!.state.sortSequence).toBe('asc');
148-
expect(ref.current!.state.devices.map(d => d.name)).toEqual(['Alpha', 'Bravo']);
154+
getRef(ref).setSort('name');
155+
await waitFor(() => expect(getRef(ref).state.sortColumn).toBe('name'));
156+
expect(getRef(ref).state.sortSequence).toBe('asc');
157+
expect(getRef(ref).state.devices.map(d => d.name)).toEqual(['Alpha', 'Bravo']);
149158

150159
// Second click -> name desc
151-
ref.current!.setSort('name');
152-
await waitFor(() => expect(ref.current!.state.sortSequence).toBe('desc'));
153-
expect(ref.current!.state.devices.map(d => d.name)).toEqual(['Bravo', 'Alpha']);
160+
getRef(ref).setSort('name');
161+
await waitFor(() => expect(getRef(ref).state.sortSequence).toBe('desc'));
162+
expect(getRef(ref).state.devices.map(d => d.name)).toEqual(['Bravo', 'Alpha']);
154163

155164
// Third click -> none (defaults to name asc)
156-
ref.current!.setSort('name');
157-
await waitFor(() => expect(ref.current!.state.sortColumn).toBe('none'));
158-
expect(ref.current!.state.devices.map(d => d.name)).toEqual(['Alpha', 'Bravo']);
165+
getRef(ref).setSort('name');
166+
await waitFor(() => expect(getRef(ref).state.sortColumn).toBe('none'));
167+
expect(getRef(ref).state.devices.map(d => d.name)).toEqual(['Alpha', 'Bravo']);
159168
});
160169

161170
it('setMobileSort toggles between selected and none', async () => {
162171
const ref = createRef<DeviceList>();
163172
render(<DeviceList ref={ref} />);
164-
ref.current!.setState({ devices: [], sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
173+
getRef(ref).setState({ devices: [], sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
165174

166-
ref.current!.setMobileSort('uid');
167-
await waitFor(() => expect(ref.current!.state.sortColumn).toBe('uid'));
175+
getRef(ref).setMobileSort('uid');
176+
await waitFor(() => expect(getRef(ref).state.sortColumn).toBe('uid'));
168177

169-
ref.current!.setMobileSort('uid');
170-
await waitFor(() => expect(ref.current!.state.sortColumn).toBe('none'));
178+
getRef(ref).setMobileSort('uid');
179+
await waitFor(() => expect(getRef(ref).state.sortColumn).toBe('none'));
171180
});
172181

173182
it('handleDelete and handleDeleteConfirm remove device on success', async () => {
@@ -179,15 +188,15 @@ describe('Devices.tsx - DeviceList', () => {
179188
{ id: 'x', uid: 10, name: 'X', status: 'Connected', note: '', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
180189
{ id: 'y', uid: 11, name: 'Y', status: 'Connected', note: '', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
181190
];
182-
ref.current!.setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
191+
getRef(ref).setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
183192

184-
ref.current!.handleDelete(devices[0]);
185-
await waitFor(() => expect(ref.current!.state.showDeleteModal).toBe(true));
193+
getRef(ref).handleDelete(devices[0]);
194+
await waitFor(() => expect(getRef(ref).state.showDeleteModal).toBe(true));
186195

187196
(fetchClient.DELETE as unknown as Mock).mockResolvedValue({ response: { status: 200 } });
188-
await ref.current!.handleDeleteConfirm();
189-
await waitFor(() => expect(ref.current!.state.showDeleteModal).toBe(false));
190-
expect(ref.current!.state.devices.map(d => d.id)).toEqual(['y']);
197+
await getRef(ref).handleDeleteConfirm();
198+
await waitFor(() => expect(getRef(ref).state.showDeleteModal).toBe(false));
199+
expect(getRef(ref).state.devices.map(d => d.id)).toEqual(['y']);
191200
});
192201

193202
it('handleEditNote flows: submit updates note and cancel resets', async () => {
@@ -198,26 +207,26 @@ describe('Devices.tsx - DeviceList', () => {
198207
const devices = [
199208
{ id: 'z', uid: 5, name: 'Z', status: 'Connected', note: 'old', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
200209
];
201-
ref.current!.setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
202-
await waitFor(() => expect(ref.current!.state.devices.length).toBe(1));
210+
getRef(ref).setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
211+
await waitFor(() => expect(getRef(ref).state.devices.length).toBe(1));
203212

204-
ref.current!.handleEditNote(devices[0], 0);
205-
await waitFor(() => expect(ref.current!.state.showEditNoteModal).toBe(true));
213+
getRef(ref).handleEditNote(devices[0], 0);
214+
await waitFor(() => expect(getRef(ref).state.showEditNoteModal).toBe(true));
206215

207216
(sodium.crypto_box_seal as unknown as Mock).mockReturnValue(new Uint8Array([9, 9]));
208217
(fetchClient.POST as unknown as Mock).mockResolvedValue({ error: undefined });
209218
const evt = { preventDefault: vi.fn() } as unknown as Event;
210-
ref.current!.setState({ editNote: 'new', editChargerIdx: 0 });
211-
await ref.current!.handleEditNoteSubmit(evt);
212-
await waitFor(() => expect(ref.current!.state.devices[0].note).toBe('new'));
213-
expect(ref.current!.state.showEditNoteModal).toBe(false);
214-
215-
ref.current!.handleEditNote(devices[0], 0);
216-
await waitFor(() => expect(ref.current!.state.showEditNoteModal).toBe(true));
217-
ref.current!.handleEditNoteCancel();
218-
await waitFor(() => expect(ref.current!.state.showEditNoteModal).toBe(false));
219-
expect(ref.current!.state.editNote).toBe('');
220-
expect(ref.current!.state.editChargerIdx).toBe(-1);
219+
getRef(ref).setState({ editNote: 'new', editChargerIdx: 0 });
220+
await getRef(ref).handleEditNoteSubmit(evt);
221+
await waitFor(() => expect(getRef(ref).state.devices[0].note).toBe('new'));
222+
expect(getRef(ref).state.showEditNoteModal).toBe(false);
223+
224+
getRef(ref).handleEditNote(devices[0], 0);
225+
await waitFor(() => expect(getRef(ref).state.showEditNoteModal).toBe(true));
226+
getRef(ref).handleEditNoteCancel();
227+
await waitFor(() => expect(getRef(ref).state.showEditNoteModal).toBe(false));
228+
expect(getRef(ref).state.editNote).toBe('');
229+
expect(getRef(ref).state.editChargerIdx).toBe(-1);
221230
});
222231

223232
it('handleEditNoteSubmit shows alert on error', async () => {
@@ -228,13 +237,13 @@ describe('Devices.tsx - DeviceList', () => {
228237
const devices = [
229238
{ id: 'n1', uid: 1, name: 'Name', status: 'Connected', note: 'old', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
230239
];
231-
ref.current!.setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: true, editNote: 'upd', editChargerIdx: 0 });
232-
await waitFor(() => expect(ref.current!.state.devices.length).toBe(1));
233-
await waitFor(() => expect(ref.current!.state.showEditNoteModal).toBe(true));
240+
getRef(ref).setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: true, editNote: 'upd', editChargerIdx: 0 });
241+
await waitFor(() => expect(getRef(ref).state.devices.length).toBe(1));
242+
await waitFor(() => expect(getRef(ref).state.showEditNoteModal).toBe(true));
234243
(sodium.crypto_box_seal as unknown as Mock).mockReturnValue(new Uint8Array([1]));
235244
(fetchClient.POST as unknown as Mock).mockResolvedValue({ error: 'err' });
236245
const evt = { preventDefault: vi.fn() } as unknown as Event;
237-
await ref.current!.handleEditNoteSubmit(evt);
246+
await getRef(ref).handleEditNoteSubmit(evt);
238247
await waitFor(() => expect((showAlert as unknown as Mock)).toHaveBeenCalled());
239248
});
240249

@@ -246,12 +255,12 @@ describe('Devices.tsx - DeviceList', () => {
246255
const devices = [
247256
{ id: 'u', uid: 7, name: 'U', status: 'Connected', note: '', port: 0, valid: true, last_state_change: null, firmware_version: '1' },
248257
];
249-
ref.current!.setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
250-
await waitFor(() => expect(ref.current!.state.devices.length).toBe(1));
258+
getRef(ref).setState({ devices, sortColumn: 'none', sortSequence: 'asc', showDeleteModal: false, showEditNoteModal: false, editNote: '', editChargerIdx: 0 });
259+
await waitFor(() => expect(getRef(ref).state.devices.length).toBe(1));
251260

252261
(fetchClient.GET as unknown as Mock).mockImplementation(() => { throw new Error('Network fail'); });
253-
await ref.current!.updateChargers();
254-
expect(ref.current!.state.devices[0].status).toBe('Disconnected');
262+
await getRef(ref).updateChargers();
263+
expect(getRef(ref).state.devices[0].status).toBe('Disconnected');
255264
});
256265

257266
it('updateChargers marks device invalid when decryption fails', async () => {
@@ -264,17 +273,17 @@ describe('Devices.tsx - DeviceList', () => {
264273
error: undefined,
265274
response: { status: 200 },
266275
});
267-
await ref.current!.updateChargers();
268-
expect(ref.current!.state.devices[0].valid).toBe(false);
269-
expect(ref.current!.state.devices[0].name).toBe('');
270-
expect(typeof ref.current!.state.devices[0].note).toBe('string');
276+
await getRef(ref).updateChargers();
277+
expect(getRef(ref).state.devices[0].valid).toBe(false);
278+
expect(getRef(ref).state.devices[0].name).toBe('');
279+
expect(typeof getRef(ref).state.devices[0].note).toBe('string');
271280
});
272281

273282
it('componentWillUnmount clears the interval', () => {
274283
const ref = createRef<DeviceList>();
275284
render(<DeviceList ref={ref} />);
276285
const spy = vi.spyOn(global, 'clearInterval');
277-
ref.current!.componentWillUnmount();
286+
getRef(ref).componentWillUnmount();
278287
expect(spy).toHaveBeenCalled();
279288
});
280289
});

0 commit comments

Comments
 (0)