Skip to content

Commit

Permalink
test: utilities for unit testing components (#23)
Browse files Browse the repository at this point in the history
* test: add utils

* test: typecheck tests

* test: clean type coercions

* test: add @testing-library/user-event
  • Loading branch information
zzmp authored Jun 2, 2022
1 parent 6dda04c commit 3aaf1f4
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 13 deletions.
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ module.exports = {
moduleNameMapper: {
'.scss$': '<rootDir>/test/scssStub',
'.(png|svg)$': '<rootDir>/test/imageStub',

// Jest does not always resolve src/test (probably because of babel's TypeScript transpilation):
'^test/*': '<rootDir>/src/test',
},
setupFiles: ['<rootDir>/test/setup.ts'],
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"prepare": "yarn contracts:compile && yarn i18n:compile",
"prepublishOnly": "yarn build",
"start": "cosmos",
"build": "tsc && rollup --config --failAfterWarnings",
"build": "tsc -p tsconfig.build.json && rollup --config --failAfterWarnings",
"release": "semantic-release",
"lint": "eslint .",
"test": "jest src",
Expand Down Expand Up @@ -128,6 +128,7 @@
"@semantic-release/git": "^10.0.1",
"@svgr/rollup": "^6.2.1",
"@testing-library/react": "^12",
"@testing-library/user-event": "^14.2.0",
"@typechain/ethers-v5": "^7.0.0",
"@types/jest": "^25.2.1",
"@types/lingui__core": "^2.7.1",
Expand All @@ -148,7 +149,6 @@
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"@uniswap/default-token-list": "^3.2.0",
"jest-environment-hardhat": "^1.1.4",
"@uniswap/v2-core": "1.0.0",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v3-core": "1.0.0",
Expand All @@ -175,6 +175,7 @@
"html-webpack-plugin": "^5.5.0",
"inter-ui": "^3.13.1",
"jest": "^27.5.1",
"jest-environment-hardhat": "^1.1.4",
"jest-fetch-mock": "^3.0.3",
"jest-styled-components": "^7.0.5",
"json-loader": "^0.5.7",
Expand Down
4 changes: 2 additions & 2 deletions src/cosmos/useJsonRpcEndpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export const INFURA_NETWORK_URLS: { [key in SupportedChainId]?: string } = INFUR
: {}

export default function useJsonRpcEndpoint() {
const endpoints = Object.entries(INFURA_NETWORK_URLS).reduce(
const endpoints = Object.entries(INFURA_NETWORK_URLS).reduce<{ [chainId: string]: string }>(
(acc, [chainId, url]) => ({
...acc,
[SupportedChainId[chainId]]: url,
[SupportedChainId[Number(chainId)]]: url,
}),
{}
)
Expand Down
24 changes: 24 additions & 0 deletions src/cosmos/useOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@ import { useSelect } from 'react-cosmos/fixture'

export const NONE = 'None'

export default function useOption<T extends string>(
label: string,
{
options,
defaultValue,
nullable,
}: {
options: T[]
defaultValue?: T
nullable?: boolean
}
): T | undefined
export default function useOption<T>(
label: string,
{
options,
defaultValue,
nullable,
}: {
options: Record<string, T>
defaultValue?: string
nullable?: boolean
}
): T | undefined
export default function useOption<T>(
label: string,
{
Expand Down
4 changes: 2 additions & 2 deletions src/cosmos/useProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ enum Wallet {
}
const [metaMask] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
const [walletConnect] = initializeConnector<WalletConnect>(
(actions) => new WalletConnect(actions, { rpc: INFURA_NETWORK_URLS })
(actions) => new WalletConnect(actions, { rpc: INFURA_NETWORK_URLS as { [chainId: number]: string } })
)

export default function useProvider() {
const connectorType = useOption<Wallet | undefined>('provider', { options: [Wallet.MetaMask, Wallet.WalletConnect] })
const connectorType = useOption('provider', { options: [Wallet.MetaMask, Wallet.WalletConnect] })
const [connector, setConnector] = useState<Connector>()
useEffect(() => {
let stale = false
Expand Down
5 changes: 3 additions & 2 deletions src/hooks/useTokenList/fetchTokenList.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import defaultTokenList from '@uniswap/default-token-list'
import { fetch } from 'test/utils'

import fetchTokenList from './fetchTokenList'

Expand All @@ -8,7 +9,7 @@ describe('fetchTokenList', () => {

it('throws on an invalid list url', async () => {
const url = 'https://example.com/invalid-tokenlist.json'
fetchMock.mockIf(url, () => {
fetch.mockIf(url, () => {
throw new Error()
})
await expect(fetchTokenList(url, resolver)).rejects.toThrowError(`failed to fetch list: ${url}`)
Expand All @@ -27,7 +28,7 @@ describe('fetchTokenList', () => {

it('fetches and validates the default token list', async () => {
const url = 'https://example.com/default-tokenlist.json'
fetchMock.mockIf(url, () => Promise.resolve(JSON.stringify(defaultTokenList)))
fetch.mockIf(url, () => Promise.resolve(JSON.stringify(defaultTokenList)))
await expect(fetchTokenList(url, resolver)).resolves.toStrictEqual(defaultTokenList)
expect(resolver).not.toHaveBeenCalled()
})
Expand Down
40 changes: 40 additions & 0 deletions src/test/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { i18n } from '@lingui/core'
import { I18nProvider } from '@lingui/react'
import { render as baseRender, RenderOptions, RenderResult } from '@testing-library/react'
import { dynamicActivate } from 'i18n'
import fetch from 'jest-fetch-mock'
import { Provider as AtomProvider } from 'jotai'
import { PropsWithChildren, ReactElement } from 'react'
import { ThemeProvider } from 'theme'

export type { RenderResult } from '@testing-library/react'
export { act } from '@testing-library/react'
export { default as user } from '@testing-library/user-event'
export { default as fetch } from 'jest-fetch-mock'

fetch.enableMocks()

beforeAll(async () => {
await dynamicActivate('en-US')
})

function TestProvider({ children }: PropsWithChildren<unknown>) {
return (
<ThemeProvider>
<I18nProvider i18n={i18n}>
<AtomProvider>{children}</AtomProvider>
</I18nProvider>
</ThemeProvider>
)
}

export function render(ui: ReactElement, options?: RenderOptions): RenderResult {
const result = baseRender(<TestProvider>{ui}</TestProvider>, options)

const rerender = result.rerender
result.rerender = function (this, ui) {
return rerender.call(this, <TestProvider>{ui}</TestProvider>)
}

return result
}
3 changes: 0 additions & 3 deletions test/setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import fetchMock from 'jest-fetch-mock'
import { TextDecoder, TextEncoder } from 'util'

fetchMock.enableMocks()

global.TextDecoder = TextDecoder
global.TextEncoder = TextEncoder
32 changes: 32 additions & 0 deletions tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"compilerOptions": {
"allowJs": true,
"alwaysStrict": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "src",
"declaration": true,
"declarationDir": "dts",
"downlevelIteration": true,
"emitDeclarationOnly": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"strictNullChecks": true,
"target": "es5",
"useUnknownInCatchVariables": false
},
"exclude": ["node_modules"],
"include": ["src/**/*.d.ts", "src/index.tsx"]
}
7 changes: 5 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": false,
"paths": {
"@uniswap/widgets": ["index"]
},
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
Expand All @@ -28,6 +31,6 @@
"types": ["jest"],
"useUnknownInCatchVariables": false
},
"exclude": ["node_modules", "src/**/*.test.*"],
"include": ["src/**/*.d.ts", "src/index.tsx"]
"exclude": ["node_modules"],
"include": ["src/"]
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3030,6 +3030,11 @@
"@testing-library/dom" "^8.0.0"
"@types/react-dom" "<18.0.0"

"@testing-library/user-event@^14.2.0":
version "14.2.0"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.2.0.tgz#8293560f8f80a00383d6c755ec3e0b918acb1683"
integrity sha512-+hIlG4nJS6ivZrKnOP7OGsDu9Fxmryj9vCl8x0ZINtTJcCHs2zLsYif5GzuRiBF2ck5GZG2aQr7Msg+EHlnYVQ==

"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
Expand Down

1 comment on commit 3aaf1f4

@vercel
Copy link

@vercel vercel bot commented on 3aaf1f4 Jun 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

widgets – ./

widgets-uniswap.vercel.app
widgets-seven-tau.vercel.app
widgets-git-main-uniswap.vercel.app

Please sign in to comment.