wip - claude --resume 742969c2-ab50-4a79-b7bd-3971e9fd314d

This commit is contained in:
Samuel Newman
2026-05-15 21:58:48 +03:00
parent f04b350f05
commit 1c60734e84
40 changed files with 1209 additions and 1571 deletions
+25 -23
View File
@@ -1,39 +1,41 @@
jest.mock('#/storage', () => ({
import {beforeEach, describe, expect, it, vi} from 'vitest'
vi.mock('#/storage', () => ({
device: {
get: jest.fn(),
set: jest.fn(),
get: vi.fn(),
set: vi.fn(),
},
}))
jest.mock('#/analytics/identifiers/util', () => ({
isSessionIdExpired: jest.fn(),
vi.mock('#/analytics/identifiers/util', () => ({
isSessionIdExpired: vi.fn(),
}))
jest.mock('#/lib/appState', () => ({
onAppStateChange: jest.fn(() => ({remove: jest.fn()})),
vi.mock('#/lib/appState', () => ({
onAppStateChange: vi.fn(() => ({remove: vi.fn()})),
}))
beforeEach(() => {
jest.resetModules()
jest.clearAllMocks()
vi.resetModules()
vi.clearAllMocks()
})
function getMocks() {
const {device} = require('#/storage')
const {isSessionIdExpired} = require('#/analytics/identifiers/util')
async function getMocks() {
const {device} = await import('#/storage')
const {isSessionIdExpired} = await import('#/analytics/identifiers/util')
return {
device: jest.mocked(device),
isSessionIdExpired: jest.mocked(isSessionIdExpired),
device: vi.mocked(device),
isSessionIdExpired: vi.mocked(isSessionIdExpired),
}
}
describe('session initialization', () => {
it('creates new session and sets timestamp when none exists', () => {
const {device, isSessionIdExpired} = getMocks()
it('creates new session and sets timestamp when none exists', async () => {
const {device, isSessionIdExpired} = await getMocks()
device.get.mockReturnValue(undefined)
isSessionIdExpired.mockReturnValue(false)
const {getInitialSessionId} = require('./session')
const {getInitialSessionId} = await import('./session')
const id = getInitialSessionId()
expect(id).toBeDefined()
@@ -45,8 +47,8 @@ describe('session initialization', () => {
)
})
it('reuses existing session when not expired', () => {
const {device, isSessionIdExpired} = getMocks()
it('reuses existing session when not expired', async () => {
const {device, isSessionIdExpired} = await getMocks()
const existingId = 'existing-session-id'
device.get.mockImplementation((key: string[]) => {
if (key[0] === 'nativeSessionId') return existingId
@@ -55,13 +57,13 @@ describe('session initialization', () => {
})
isSessionIdExpired.mockReturnValue(false)
const {getInitialSessionId} = require('./session')
const {getInitialSessionId} = await import('./session')
expect(getInitialSessionId()).toBe(existingId)
})
it('creates new session when existing is expired', () => {
const {device, isSessionIdExpired} = getMocks()
it('creates new session when existing is expired', async () => {
const {device, isSessionIdExpired} = await getMocks()
const existingId = 'existing-session-id'
device.get.mockImplementation((key: string[]) => {
if (key[0] === 'nativeSessionId') return existingId
@@ -70,7 +72,7 @@ describe('session initialization', () => {
})
isSessionIdExpired.mockReturnValue(true)
const {getInitialSessionId} = require('./session')
const {getInitialSessionId} = await import('./session')
const id = getInitialSessionId()
expect(id).not.toBe(existingId)
+23 -21
View File
@@ -1,26 +1,28 @@
import {afterEach, beforeEach, describe, expect, it, type Mock, vi} from 'vitest'
import {MetricsClient} from './client'
let appStateCallback: (state: string) => void
jest.mock('#/lib/appState', () => ({
onAppStateChange: jest.fn(cb => {
vi.mock('#/lib/appState', () => ({
onAppStateChange: vi.fn(cb => {
appStateCallback = cb
return {remove: jest.fn()}
return {remove: vi.fn()}
}),
}))
jest.mock('#/logger', () => ({
vi.mock('#/logger', () => ({
Logger: {
create: () => ({
info: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
info: vi.fn(),
debug: vi.fn(),
error: vi.fn(),
}),
Context: {Metric: 'metric'},
},
}))
jest.mock('#/env', () => ({
vi.mock('#/env', () => ({
METRICS_API_HOST: 'https://test.metrics.api',
IS_WEB: false,
}))
@@ -31,13 +33,13 @@ type TestEvents = {
}
describe('MetricsClient', () => {
let fetchMock: jest.Mock
let fetchMock: Mock
let fetchRequests: {body: any}[]
beforeEach(() => {
jest.useFakeTimers({advanceTimers: true})
vi.useFakeTimers({shouldAdvanceTime: true})
fetchRequests = []
fetchMock = jest.fn().mockImplementation(async (_url, options) => {
fetchMock = vi.fn().mockImplementation(async (_url, options) => {
const body = JSON.parse(options.body)
fetchRequests.push({body})
return {ok: true, status: 200}
@@ -46,8 +48,8 @@ describe('MetricsClient', () => {
})
afterEach(() => {
jest.useRealTimers()
jest.clearAllMocks()
vi.useRealTimers()
vi.clearAllMocks()
})
it('flushes events on interval', async () => {
@@ -58,7 +60,7 @@ describe('MetricsClient', () => {
expect(fetchRequests).toHaveLength(0)
// Advance past the 10 second interval
await jest.advanceTimersByTimeAsync(10_000)
await vi.advanceTimersByTimeAsync(10_000)
expect(fetchRequests).toHaveLength(1)
expect(fetchRequests[0].body.events).toHaveLength(2)
@@ -81,7 +83,7 @@ describe('MetricsClient', () => {
client.track('click', {button: 'btn-trigger'})
// Allow microtasks to run
await jest.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(0)
expect(fetchRequests).toHaveLength(1)
expect(fetchRequests[0].body.events).toHaveLength(6)
@@ -112,14 +114,14 @@ describe('MetricsClient', () => {
client.track('click', {button: 'submit'})
// Trigger flush via interval
await jest.advanceTimersByTimeAsync(10_000)
await vi.advanceTimersByTimeAsync(10_000)
expect(requestCount).toBe(1)
expect(fetchRequests).toHaveLength(0)
// Simulate app coming to foreground to trigger retry
appStateCallback('active')
await jest.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(0)
expect(requestCount).toBe(2)
expect(fetchRequests).toHaveLength(1)
@@ -144,19 +146,19 @@ describe('MetricsClient', () => {
client.track('click', {button: 'submit'})
// First flush fails
await jest.advanceTimersByTimeAsync(10_000)
await vi.advanceTimersByTimeAsync(10_000)
expect(requestCount).toBe(1)
// Retry also fails
appStateCallback('active')
await jest.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(0)
expect(requestCount).toBe(2)
// Another foreground event should not retry again (events are dropped)
appStateCallback('active')
await jest.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(0)
expect(requestCount).toBe(2) // No additional requests
})
@@ -169,7 +171,7 @@ describe('MetricsClient', () => {
// Simulate app going to background
appStateCallback('background')
await jest.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(0)
expect(fetchRequests).toHaveLength(1)
})