Skip to content

Commit

Permalink
refactor: migrate multiple files in libs to full TS
Browse files Browse the repository at this point in the history
refactor: improve typing for RootNavigation

refactor: rename constants to .ts

refactor: rename localStore index to .ts

refactor: rename multiple files in lib/fn to ts

refactor: update files with typings

some tests will fail, to be fixed next commit

refactor: fix tests after typing
  • Loading branch information
acezard committed Nov 11, 2023
1 parent 7f14dbb commit 04f1438
Show file tree
Hide file tree
Showing 34 changed files with 298 additions and 212 deletions.
2 changes: 1 addition & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { getClient } from '/libs/client'
import { getColors } from '/ui/colors'
import { localMethods } from '/libs/intents/localMethods'
import { persistor, store } from '/redux/store'
import { useAppBootstrap } from '/hooks/useAppBootstrap.js'
import { useAppBootstrap } from '/hooks/useAppBootstrap'
import { useGlobalAppState } from '/hooks/useGlobalAppState'
import { useCookieResyncOnResume } from '/hooks/useCookieResyncOnResume'
import { useCozyEnvironmentOverride } from '/hooks/useCozyEnvironmentOverride'
Expand Down
4 changes: 2 additions & 2 deletions src/components/webviews/CozyWebview.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jest.mock('react-native-file-viewer', () => ({
jest.mock('@react-native-cookies/cookies', () => ({
set: jest.fn()
}))
jest.mock('/libs/RootNavigation.js', () => ({
jest.mock('/libs/RootNavigation', () => ({
navigationRef: {
getCurrentRoute: jest.fn().mockReturnValue({ name: 'home' })
}
Expand Down Expand Up @@ -65,7 +65,7 @@ jest.mock('@react-navigation/native', () => ({
useIsFocused: () => mockUseIsFocused()
}))

jest.mock('../../hooks/useSession.js', () => ({
jest.mock('../../hooks/useSession', () => ({
useSession: () => ({
shouldInterceptAuth: false,
handleInterceptAuth: jest.fn(),
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useAppBootstrap.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jest.mock('/libs/monitoring/Sentry', () => ({
setSentryTag: jest.fn()
}))

jest.mock('/libs/RootNavigation.js', () => ({
jest.mock('/libs/RootNavigation', () => ({
navigate: jest.fn()
}))

Expand Down
21 changes: 0 additions & 21 deletions src/hooks/useSession.js

This file was deleted.

26 changes: 26 additions & 0 deletions src/hooks/useSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useEffect, useMemo, useState } from 'react'

import { useClient, useCapabilities } from 'cozy-client'

import { makeSessionAPI, SessionApi } from '/libs/functions/session'

export const useSession = (): SessionApi => {
const [subdomainType, setSubdomainType] = useState<string>()
const client = useClient()
const { capabilities, fetchStatus } = useCapabilities(client)

useEffect(() => {
fetchStatus === 'loaded' &&
// @ts-expect-error : cozy-client has to be updated
setSubdomainType(capabilities?.flat_subdomains ? 'flat' : 'nested')
}, [capabilities, fetchStatus])

return useMemo(
// We have to assume that client and subdomainType are defined
// Still, this is old code and we should probably refactor it
// Adding a @TODO flag for now
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
() => makeSessionAPI(client!, subdomainType!),
[client, subdomainType]
)
}
18 changes: 11 additions & 7 deletions src/libs/RootNavigation.js → src/libs/RootNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@ import Minilog from 'cozy-minilog'

const log = Minilog('RootNavigation')

export const navigationRef = createNavigationContainerRef()
export const navigationRef =
createNavigationContainerRef<Record<string, unknown>>()

export const getCurrentRouteName = () => {
export const getCurrentRouteName = (): string | null => {
if (!navigationRef.isReady()) {
return null
}

return navigationRef.getCurrentRoute().name
return navigationRef.getCurrentRoute()?.name ?? null
}

const isReady = () => navigationRef.isReady()
const isReady = (): boolean => navigationRef.isReady()

export const goBack = () => navigationRef.goBack()
export const goBack = (): void => navigationRef.goBack()

export const navigate = (name, params) => {
export const navigate = (
name: string,
params?: Record<string, unknown>
): void => {
try {
if (isReady()) return navigationRef.navigate(name, params)

Expand All @@ -34,7 +38,7 @@ export const navigate = (name, params) => {
}
}

export const reset = (name, params = {}) => {
export const reset = (name: string, params = {}): void => {
try {
if (isReady())
return navigationRef.dispatch(
Expand Down
File renamed without changes.
7 changes: 0 additions & 7 deletions src/libs/functions/getHostname.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ it('does not throw if no url key', () => {
it('does not throw if no event at all', () => {
expect(getHostname()).toBeUndefined()
})

it('does not throw if event with empty url', () => {
expect(getHostname({ url: undefined })).toBeUndefined()
})
22 changes: 22 additions & 0 deletions src/libs/functions/getHostname.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getErrorMessage } from 'cozy-intent'

import { devlog } from '/core/tools/env'

export const getHostname = (
nativeEvent?: { url?: string | unknown } | unknown
): string | undefined => {
if (
!nativeEvent ||
typeof nativeEvent !== 'object' ||
!('url' in nativeEvent) ||
typeof nativeEvent.url !== 'string'
)
return

try {
return new URL(nativeEvent.url).hostname
} catch (error) {
devlog('getHostname failed, nativeEvent:', nativeEvent, error)
if (getErrorMessage(error).includes('Invalid URL')) return nativeEvent.url
}
}
5 changes: 0 additions & 5 deletions src/libs/functions/isSecureProtocol.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type CozyClient from 'cozy-client'

import { isSecureProtocol } from './isSecureProtocol'

jest.mock('cozy-client', () => ({
Expand All @@ -6,25 +8,21 @@ jest.mock('cozy-client', () => ({

describe('isSecureProtocol', () => {
it(`shoud return true if cozy-client's URL uses HTTPs protocol`, () => {
const client = {
getStackClient: () => ({
const result = isSecureProtocol({
getStackClient: (): { uri: string } => ({
uri: 'https://localhost:8080'
})
}

const result = isSecureProtocol(client)
} as unknown as jest.Mocked<CozyClient>)

expect(result).toBe(true)
})

it(`shoud return false if cozy-client's URL uses HTTP protocol`, () => {
const client = {
getStackClient: () => ({
const result = isSecureProtocol({
getStackClient: (): { uri: string } => ({
uri: 'http://localhost:8080'
})
}

const result = isSecureProtocol(client)
} as unknown as jest.Mocked<CozyClient>)

expect(result).toBe(false)
})
Expand Down
7 changes: 7 additions & 0 deletions src/libs/functions/isSecureProtocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type CozyClient from 'cozy-client'

export const isSecureProtocol = (client: CozyClient): boolean => {
const instanceUrl = new URL(client.getStackClient().uri)

return instanceUrl.protocol === 'https:'
}
File renamed without changes.
6 changes: 0 additions & 6 deletions src/libs/functions/makeHandlers.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { makeHandlers } from '/libs/functions/makeHandlers'

it('does not throw with bad HOF bad closure', () => {
// @ts-expect-error : we want to test this case
const badHandler = makeHandlers(NaN)
expect(() => badHandler()).not.toThrow()
})
Expand All @@ -17,6 +18,7 @@ it('does not throw with good HOF bad closure 2', () => {

it('does not throw with good HOF bad closure 3', () => {
const goodHandler = makeHandlers({ foo: jest.fn() })
// @ts-expect-error : we want to test this case
expect(() => goodHandler({ nativeEvent: '19' })).not.toThrow()
})

Expand Down
15 changes: 15 additions & 0 deletions src/libs/functions/makeHandlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type makeHandlersType = (
handlers?: Record<string, () => void>
) => (event?: { nativeEvent?: { data?: string | unknown } }) => void

export const makeHandlers: makeHandlersType = handlers => event =>
Object.keys(handlers?.constructor === Object ? handlers : {}).forEach(
handlerName => {
const data = event?.nativeEvent?.data
const isString = typeof data === 'string'

if (!isString) return

return data.includes(handlerName) && handlers?.[handlerName]?.()
}
)
Original file line number Diff line number Diff line change
@@ -1,62 +1,60 @@
import { consumeRouteParameter } from './routeHelpers'
import { NavigationProp, RouteProp } from '@react-navigation/native'

import { consumeRouteParameter } from '/libs/functions/routeHelpers'

const navigation = {
setParams: jest.fn()
} as unknown as NavigationProp<Record<string, object | undefined>, string> & {
setParams: jest.Mock
}

describe('consumeRouteParameter', () => {
beforeEach(() => {
jest.clearAllMocks()
})

it('should return parameter and clear it from navigation when parameter exist', async () => {
it('should return parameter and clear it from navigation when parameter exist', () => {
const route = {
params: {
foo: 'bar'
}
}

const navigation = {
setParams: jest.fn()
}
} as RouteProp<Record<string, object | undefined>, string>

const param = consumeRouteParameter('foo', route, navigation)

expect(param).toBe('bar')
expect(navigation.setParams).toHaveBeenCalled()
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect(navigation.setParams.mock.calls[0][0]).toStrictEqual({
foo: undefined
})
})

it('should return undefined and should not try to clear it from navigation when parameter does not exist', async () => {
it('should return undefined and should not try to clear it from navigation when parameter does not exist', () => {
const route = {
params: {
foo: 'bar'
}
}

const navigation = {
setParams: jest.fn()
}
} as RouteProp<Record<string, object | undefined>, string>

const param = consumeRouteParameter('unexistingParam', route, navigation)

expect(param).toBe(undefined)
expect(navigation.setParams).not.toHaveBeenCalled()
})

it('should return parameter and clear it from navigation when parameter exist but has falsy value', async () => {
it('should return parameter and clear it from navigation when parameter exist but has falsy value', () => {
const route = {
params: {
foo: 0
}
}

const navigation = {
setParams: jest.fn()
}
} as RouteProp<Record<string, object | undefined>, string>

const param = consumeRouteParameter('foo', route, navigation)

expect(param).toBe(0)
expect(navigation.setParams).toHaveBeenCalled()
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect(navigation.setParams.mock.calls[0][0]).toStrictEqual({
foo: undefined
})
Expand Down
Loading

0 comments on commit 04f1438

Please sign in to comment.