about summary refs log tree commit diff
path: root/src/state/persisted/__tests__/migrate.test.ts
blob: d42580efdf103b9af5b806d582bae1ff64273ae6 (plain) (blame)
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
import {jest, expect, test, afterEach} from '@jest/globals'
import AsyncStorage from '@react-native-async-storage/async-storage'

import {defaults, schema} from '#/state/persisted/schema'
import {transform, migrate} from '#/state/persisted/legacy'
import * as store from '#/state/persisted/store'
import {logger} from '#/logger'
import * as fixtures from '#/state/persisted/__tests__/fixtures'

const write = jest.mocked(store.write)
const read = jest.mocked(store.read)

jest.mock('#/logger')
jest.mock('#/state/persisted/store', () => ({
  write: jest.fn(),
  read: jest.fn(),
}))

afterEach(() => {
  jest.clearAllMocks()
  AsyncStorage.clear()
})

test('migrate: fresh install', async () => {
  await migrate()

  expect(AsyncStorage.getItem).toHaveBeenCalledWith('root')
  expect(read).toHaveBeenCalledTimes(1)
  expect(logger.log).toHaveBeenCalledWith(
    'persisted state: no migration needed',
  )
})

test('migrate: fresh install, existing new storage', async () => {
  read.mockResolvedValueOnce(defaults)

  await migrate()

  expect(AsyncStorage.getItem).toHaveBeenCalledWith('root')
  expect(read).toHaveBeenCalledTimes(1)
  expect(logger.log).toHaveBeenCalledWith(
    'persisted state: no migration needed',
  )
})

test('migrate: fresh install, AsyncStorage error', async () => {
  const prevGetItem = AsyncStorage.getItem

  const error = new Error('test error')

  AsyncStorage.getItem = jest.fn(() => {
    throw error
  })

  await migrate()

  expect(AsyncStorage.getItem).toHaveBeenCalledWith('root')
  expect(logger.error).toHaveBeenCalledWith(error, {
    message: 'persisted state: error migrating legacy storage',
  })

  AsyncStorage.getItem = prevGetItem
})

test('migrate: has legacy data', async () => {
  await AsyncStorage.setItem('root', JSON.stringify(fixtures.LEGACY_DATA_DUMP))

  await migrate()

  expect(write).toHaveBeenCalledWith(transform(fixtures.LEGACY_DATA_DUMP))
  expect(logger.log).toHaveBeenCalledWith(
    'persisted state: migrated legacy storage',
  )
})

test('migrate: has legacy data, fails validation', async () => {
  const legacy = fixtures.LEGACY_DATA_DUMP
  // @ts-ignore
  legacy.shell.colorMode = 'invalid'
  await AsyncStorage.setItem('root', JSON.stringify(legacy))

  await migrate()

  const transformed = transform(legacy)
  const validate = schema.safeParse(transformed)

  expect(write).not.toHaveBeenCalled()
  expect(logger.error).toHaveBeenCalledWith(
    'persisted state: legacy data failed validation',
    // @ts-ignore
    {error: validate.error},
  )
})