fix(13-02): eliminate all ESLint violations — pnpm lint exits 0
- eslint.config.js: disable React Compiler rules (v7 flat.recommended enables
them; codebase does not use the Compiler); add e2e/ to disableTypeChecked
block; promote exhaustive-deps to error
- API broker: remove redundant as-casts (outboxWorker, poller, reminderScheduler,
expand, sync, vevent, spike); add targeted ical.js no-unsafe-assignment/argument
disables with justifying comments inside try blocks
- API routes/sse.ts: fix no-misused-promises on async writeSSE callback with
void+IIFE+catch pattern
- API routes/lists.ts: let → const for updateValues
- API tests: remove unused imports (beforeEach, eq, vi); rename unused vars
with _ prefix; remove unused lastActiveId assignment
- PWA components: void navigate() and void queryClient.invalidateQueries() on
all fire-and-forget call sites; fix CalendarShell explicit-type-casts;
Couldn't → HTML entity
- PWA test files: as unknown as Response for partial mock objects; string | null
type annotation on mockLastSyncedUid; remove async from test callbacks without
await; act(() => {}) not await act(async () => {}) for sync ops
- sw.ts: restructure Notification.data?.url access as let+if so disable
comments land on the exact violation lines; void self.skipWaiting()
This commit is contained in:
@@ -11,8 +11,8 @@
|
||||
* Uses React Query's QueryClient directly (no mocked server).
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { renderHook, act } from '@testing-library/react'
|
||||
import { describe, it, expect, beforeEach } from 'vitest'
|
||||
import { act } from '@testing-library/react'
|
||||
import { QueryClient } from '@tanstack/react-query'
|
||||
import type { ListItem, ListItemsResponse } from '../api/listsClient.js'
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
expect(updated?.items[0].checked).toBe(false)
|
||||
})
|
||||
|
||||
it('rolls back the checked state if the server PATCH returns an error', async () => {
|
||||
it('rolls back the checked state if the server PATCH returns an error', () => {
|
||||
const item = makeItem({ checked: false })
|
||||
queryClient.setQueryData<ListItemsResponse>(['list', LIST_ID], makeItemsResponse([item]))
|
||||
|
||||
@@ -88,7 +88,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
const previous = queryClient.getQueryData<ListItemsResponse>(['list', LIST_ID])
|
||||
|
||||
// Step 2: apply optimistic update
|
||||
await act(async () => {
|
||||
act(() => {
|
||||
queryClient.setQueryData<ListItemsResponse>(['list', LIST_ID], (old) => ({
|
||||
items: (old?.items ?? []).map((i) =>
|
||||
i.id === item.id ? { ...i, checked: true } : i,
|
||||
@@ -101,7 +101,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
expect(after?.items[0].checked).toBe(true)
|
||||
|
||||
// Step 3: simulate onError rollback
|
||||
await act(async () => {
|
||||
act(() => {
|
||||
if (previous) {
|
||||
queryClient.setQueryData(['list', LIST_ID], previous)
|
||||
}
|
||||
@@ -112,7 +112,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
expect(rolledBack?.items[0].checked).toBe(false)
|
||||
})
|
||||
|
||||
it('adding an item shows it in the list immediately (optimistic insert)', async () => {
|
||||
it('adding an item shows it in the list immediately (optimistic insert)', () => {
|
||||
queryClient.setQueryData<ListItemsResponse>(['list', LIST_ID], makeItemsResponse([]))
|
||||
|
||||
const optimisticItem: ListItem = {
|
||||
@@ -123,7 +123,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
rank: 'a0',
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
act(() => {
|
||||
queryClient.setQueryData<ListItemsResponse>(['list', LIST_ID], (old) => ({
|
||||
items: [...(old?.items ?? []), optimisticItem],
|
||||
}))
|
||||
@@ -136,7 +136,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
expect(data?.items[0].id).toBeLessThan(0)
|
||||
})
|
||||
|
||||
it('removes the optimistically-added item if the server POST returns an error', async () => {
|
||||
it('removes the optimistically-added item if the server POST returns an error', () => {
|
||||
const existingItem = makeItem({ id: 1 })
|
||||
queryClient.setQueryData<ListItemsResponse>(
|
||||
['list', LIST_ID],
|
||||
@@ -155,7 +155,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
rank: 'a1',
|
||||
}
|
||||
|
||||
await act(async () => {
|
||||
act(() => {
|
||||
queryClient.setQueryData<ListItemsResponse>(['list', LIST_ID], (old) => ({
|
||||
items: [...(old?.items ?? []), optimisticItem],
|
||||
}))
|
||||
@@ -166,7 +166,7 @@ describe('ListDetail — D-07 optimistic update + rollback', () => {
|
||||
).toHaveLength(2)
|
||||
|
||||
// Simulate rollback on error
|
||||
await act(async () => {
|
||||
act(() => {
|
||||
if (previous) queryClient.setQueryData(['list', LIST_ID], previous)
|
||||
})
|
||||
|
||||
|
||||
@@ -181,7 +181,8 @@ export function ListDetail() {
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
// fire-and-forget: cache invalidation; React Query handles the refetch lifecycle
|
||||
void queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -207,7 +208,8 @@ export function ListDetail() {
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
// fire-and-forget: cache invalidation; React Query handles the refetch lifecycle
|
||||
void queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -223,7 +225,8 @@ export function ListDetail() {
|
||||
},
|
||||
// No onError rollback — delete-wins (D-09)
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
// fire-and-forget: cache invalidation; React Query handles the refetch lifecycle
|
||||
void queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -251,7 +254,8 @@ export function ListDetail() {
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
// fire-and-forget: cache invalidation; React Query handles the refetch lifecycle
|
||||
void queryClient.invalidateQueries({ queryKey: ['list', parsedListId] })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -351,7 +355,7 @@ export function ListDetail() {
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={() => navigate('/lists')}
|
||||
onClick={() => { void navigate('/lists') }}
|
||||
aria-label="Back to lists"
|
||||
style={{
|
||||
background: 'none',
|
||||
|
||||
@@ -66,10 +66,11 @@ export function ListsIndex() {
|
||||
// TODO: surface "Couldn't delete. Try again." toast (Plan 06 / notification layer)
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['lists'] })
|
||||
// fire-and-forget: cache invalidation; React Query handles the refetch lifecycle
|
||||
void queryClient.invalidateQueries({ queryKey: ['lists'] })
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate('/lists')
|
||||
void navigate('/lists')
|
||||
setDeleteTarget(null)
|
||||
},
|
||||
})
|
||||
@@ -195,7 +196,7 @@ export function ListsIndex() {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => refetch()}
|
||||
onClick={() => { void refetch() }}
|
||||
style={{
|
||||
background: 'var(--color-member-0)',
|
||||
color: '#fff',
|
||||
|
||||
Reference in New Issue
Block a user