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:
Lucas Berger
2026-06-11 20:23:38 -04:00
parent 39e26561cf
commit 03e953158a
31 changed files with 176 additions and 121 deletions
+34 -33
View File
@@ -175,8 +175,8 @@ describe('createEvent', () => {
const mockFetch = vi.mocked(fetch)
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'test-uid-123' }),
} as Response)
json: () => ({ uid: 'test-uid-123' }),
} as unknown as Response)
const { createEvent } = await import('./client.js')
const payload = {
@@ -193,6 +193,7 @@ describe('createEvent', () => {
expect.objectContaining({
method: 'POST',
credentials: 'include',
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- expect.objectContaining returns 'any' (Vitest asymmetric matcher); safe in assertion context
headers: expect.objectContaining({ 'Content-Type': 'application/json' }),
}),
)
@@ -201,8 +202,8 @@ describe('createEvent', () => {
it('returns { uid } from 202 response', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'returned-uid-456' }),
} as Response)
json: () => ({ uid: 'returned-uid-456' }),
} as unknown as Response)
const { createEvent } = await import('./client.js')
const result = await createEvent({
@@ -220,8 +221,8 @@ describe('createEvent', () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: false,
status: 400,
json: async () => ({ error: 'Bad Request' }),
} as Response)
json: () => ({ error: 'Bad Request' }),
} as unknown as Response)
const { createEvent } = await import('./client.js')
await expect(
@@ -250,8 +251,8 @@ describe('updateEvent', () => {
const mockFetch = vi.mocked(fetch)
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'edit-uid-789' }),
} as Response)
json: () => ({ uid: 'edit-uid-789' }),
} as unknown as Response)
const { updateEvent } = await import('./client.js')
await updateEvent('edit-uid-789', {
@@ -274,8 +275,8 @@ describe('updateEvent', () => {
it('returns { uid } on success', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'patched-uid' }),
} as Response)
json: () => ({ uid: 'patched-uid' }),
} as unknown as Response)
const { updateEvent } = await import('./client.js')
const result = await updateEvent('some-uid', {
@@ -303,12 +304,12 @@ describe('fetchWritableCalendars', () => {
it('GETs /api/events/writable-calendars with credentials:include', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({
json: () => ({
calendars: [
{ url: 'https://caldav.fastmail.com/cal1', displayName: 'My Calendar', color: '#4A90D9', isShared: false },
],
}),
} as Response)
} as unknown as Response)
const { fetchWritableCalendars } = await import('./client.js')
await fetchWritableCalendars()
@@ -326,8 +327,8 @@ describe('fetchWritableCalendars', () => {
]
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ calendars: mockCalendars }),
} as Response)
json: () => ({ calendars: mockCalendars }),
} as unknown as Response)
const { fetchWritableCalendars } = await import('./client.js')
const result = await fetchWritableCalendars()
@@ -340,7 +341,7 @@ describe('fetchWritableCalendars', () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: false,
status: 401,
} as Response)
} as unknown as Response)
const { fetchWritableCalendars } = await import('./client.js')
await expect(fetchWritableCalendars()).rejects.toThrow()
@@ -361,8 +362,8 @@ describe('deleteEvent', () => {
const mockFetch = vi.mocked(fetch)
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({}),
} as Response)
json: () => ({}),
} as unknown as Response)
const { deleteEvent } = await import('./client.js')
await deleteEvent('uid-to-delete')
@@ -379,8 +380,8 @@ describe('deleteEvent', () => {
it('resolves void on success (204/202)', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({}),
} as Response)
json: () => ({}),
} as unknown as Response)
const { deleteEvent } = await import('./client.js')
const result = await deleteEvent('uid-abc')
@@ -391,7 +392,7 @@ describe('deleteEvent', () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: false,
status: 404,
} as Response)
} as unknown as Response)
const { deleteEvent } = await import('./client.js')
await expect(deleteEvent('missing-uid')).rejects.toThrow()
@@ -411,8 +412,8 @@ describe('fetchSyncStatus', () => {
it('GETs /api/events/sync-status?uid= with credentials:include', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'my-uid', status: 'pending' }),
} as Response)
json: () => ({ uid: 'my-uid', status: 'pending' }),
} as unknown as Response)
const { fetchSyncStatus } = await import('./client.js')
await fetchSyncStatus('my-uid')
@@ -426,8 +427,8 @@ describe('fetchSyncStatus', () => {
it('returns SyncStatus object with uid and status', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'test-uid', status: 'done' }),
} as Response)
json: () => ({ uid: 'test-uid', status: 'done' }),
} as unknown as Response)
const { fetchSyncStatus } = await import('./client.js')
const result = await fetchSyncStatus('test-uid')
@@ -437,8 +438,8 @@ describe('fetchSyncStatus', () => {
it('returns SyncStatus with error field for failed status', async () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: true,
json: async () => ({ uid: 'fail-uid', status: 'failed', error: '412 Conflict' }),
} as Response)
json: () => ({ uid: 'fail-uid', status: 'failed', error: '412 Conflict' }),
} as unknown as Response)
const { fetchSyncStatus } = await import('./client.js')
const result = await fetchSyncStatus('fail-uid')
@@ -449,7 +450,7 @@ describe('fetchSyncStatus', () => {
vi.mocked(fetch).mockResolvedValueOnce({
ok: false,
status: 500,
} as Response)
} as unknown as Response)
const { fetchSyncStatus } = await import('./client.js')
await expect(fetchSyncStatus('any-uid')).rejects.toThrow()
@@ -471,8 +472,8 @@ describe('fetchMe', () => {
ok: true,
type: 'basic',
status: 200,
json: async () => ({ user: { id: 2, displayName: 'Me', color: '#E8734A' } }),
} as Response)
json: () => ({ user: { id: 2, displayName: 'Me', color: '#E8734A' } }),
} as unknown as Response)
const { fetchMe } = await import('./client.js')
await fetchMe()
@@ -488,8 +489,8 @@ describe('fetchMe', () => {
ok: true,
type: 'basic',
status: 200,
json: async () => ({ user: { id: 2, displayName: 'Me', color: '#E8734A' } }),
} as Response)
json: () => ({ user: { id: 2, displayName: 'Me', color: '#E8734A' } }),
} as unknown as Response)
const { fetchMe } = await import('./client.js')
const result = await fetchMe()
@@ -503,7 +504,7 @@ describe('fetchMe', () => {
ok: false,
type: 'opaqueredirect',
status: 0,
json: async () => {
json: () => {
throw new Error('body not accessible on opaqueredirect')
},
} as unknown as Response)
@@ -517,7 +518,7 @@ describe('fetchMe', () => {
ok: false,
type: 'basic',
status: 401,
} as Response)
} as unknown as Response)
const { fetchMe } = await import('./client.js')
await expect(fetchMe()).rejects.toThrow(/authentication required/i)