Skip to content

Commit

Permalink
fix: display returned function names correctly in stack traces (#528)
Browse files Browse the repository at this point in the history
Refactors for consistency.

* refactor: change functions to be more consistent between regular functions and arrow functions
* refactor: rename testHook to be testHarness for consistency
* refactor: remove default exports for consistency
* fix: display returned function names correctly in stack traces
* refactor: remove variable assignment in function name workaround

Co-authored-by: Jonathan Peyper <jpeyper@gmail.com>
Co-authored-by: Jonathan Peyper <jpeyper@gmail.com>
  • Loading branch information
mpeyper and jpeyper committed Jan 8, 2021
1 parent 4786242 commit a82d5ef
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/core/asyncUtils.ts
Expand Up @@ -95,4 +95,4 @@ function asyncUtils(act: Act, addResolver: (callback: () => void) => void): Asyn
}
}

export default asyncUtils
export { asyncUtils }
62 changes: 36 additions & 26 deletions src/core/index.ts
@@ -1,7 +1,7 @@
import { CreateRenderer, Renderer, RenderResult, RenderHook, RenderHookOptions } from '../types'
import { ResultContainer } from '../types/internal'

import asyncUtils from './asyncUtils'
import { asyncUtils } from './asyncUtils'
import { cleanup, addCleanup, removeCleanup } from './cleanup'

function resultContainer<TValue>(): ResultContainer<TValue> {
Expand Down Expand Up @@ -40,39 +40,49 @@ function resultContainer<TValue>(): ResultContainer<TValue> {
}
}

const createRenderHook = <TProps, TResult, TOptions extends {}, TRenderer extends Renderer<TProps>>(
function createRenderHook<TProps, TResult, TOptions extends {}, TRenderer extends Renderer<TProps>>(
createRenderer: CreateRenderer<TProps, TResult, TOptions, TRenderer>
) => (
callback: (props: TProps) => TResult,
options: RenderHookOptions<TProps, TOptions> = {} as RenderHookOptions<TProps, TOptions>
): RenderHook<TProps, TResult, TRenderer> => {
const { result, setValue, setError, addResolver } = resultContainer<TResult>()
const renderProps = { callback, setValue, setError }
let hookProps = options.initialProps
) {
const renderHook = (
callback: (props: TProps) => TResult,
options: RenderHookOptions<TProps, TOptions> = {} as RenderHookOptions<TProps, TOptions>
): RenderHook<TProps, TResult, TRenderer> => {
const { result, setValue, setError, addResolver } = resultContainer<TResult>()
const renderProps = { callback, setValue, setError }
let hookProps = options.initialProps

const { render, rerender, unmount, act, ...renderUtils } = createRenderer(renderProps, options)
const { render, rerender, unmount, act, ...renderUtils } = createRenderer(renderProps, options)

render(hookProps)
render(hookProps)

function rerenderHook(newProps = hookProps) {
hookProps = newProps
rerender(hookProps)
}
const rerenderHook = (newProps = hookProps) => {
hookProps = newProps
rerender(hookProps)
}

function unmountHook() {
removeCleanup(unmountHook)
unmount()
}
const unmountHook = () => {
removeCleanup(unmountHook)
unmount()
}

addCleanup(unmountHook)
addCleanup(unmountHook)

return {
result,
rerender: rerenderHook,
unmount: unmountHook,
...asyncUtils(act, addResolver),
...renderUtils
return {
result,
rerender: rerenderHook,
unmount: unmountHook,
...asyncUtils(act, addResolver),
...renderUtils
}
}

// If the function name does not get used before it is returned,
// it's name is removed by babel-plugin-minify-dead-code-elimination.
// This dummy usage works around that.
renderHook.name // eslint-disable-line @typescript-eslint/no-unused-expressions


return renderHook
}

export { createRenderHook, cleanup, addCleanup, removeCleanup }
6 changes: 3 additions & 3 deletions src/dom/pure.ts
Expand Up @@ -13,18 +13,18 @@ function createDomRenderer<TProps, TResult>(
) {
const container = document.createElement('div')

const testHook = createTestHarness(rendererProps, wrapper)
const testHarness = createTestHarness(rendererProps, wrapper)

return {
render(props?: TProps) {
document.body.appendChild(container)
act(() => {
ReactDOM.render(testHook(props), container)
ReactDOM.render(testHarness(props), container)
})
},
rerender(props?: TProps) {
act(() => {
ReactDOM.render(testHook(props), container)
ReactDOM.render(testHarness(props), container)
})
},
unmount() {
Expand Down
15 changes: 12 additions & 3 deletions src/helpers/createTestHarness.tsx
Expand Up @@ -24,12 +24,12 @@ function TestComponent<TProps, TResult>({
return null
}

export const createTestHarness = <TProps, TResult>(
function createTestHarness<TProps, TResult>(
rendererProps: RendererProps<TProps, TResult>,
Wrapper?: WrapperComponent<TProps>,
suspense: boolean = true
) => {
return (props?: TProps) => {
) {
const testHarness = (props?: TProps) => {
let component = <TestComponent hookProps={props} {...rendererProps} />
if (Wrapper) {
component = <Wrapper {...(props as TProps)}>{component}</Wrapper>
Expand All @@ -39,4 +39,13 @@ export const createTestHarness = <TProps, TResult>(
}
return component
}

// If the function name does not get used before it is returned,
// it's name is removed by babel-plugin-minify-dead-code-elimination.
// This dummy usage works around that.
testHarness.name // eslint-disable-line @typescript-eslint/no-unused-expressions

return testHarness
}

export { createTestHarness }
10 changes: 6 additions & 4 deletions src/helpers/promises.ts
@@ -1,9 +1,11 @@
const resolveAfter = (ms: number) =>
new Promise((resolve) => {
function resolveAfter(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}

const isPromise = <T>(value: unknown): boolean =>
typeof (value as PromiseLike<T>).then === 'function'
function isPromise<T>(value: unknown): boolean {
return typeof (value as PromiseLike<T>).then === 'function'
}

export { isPromise, resolveAfter }
8 changes: 4 additions & 4 deletions src/native/pure.ts
Expand Up @@ -7,22 +7,22 @@ import { createRenderHook, cleanup, addCleanup, removeCleanup } from '../core'
import { createTestHarness } from '../helpers/createTestHarness'

function createNativeRenderer<TProps, TResult>(
testHookProps: RendererProps<TProps, TResult>,
rendererProps: RendererProps<TProps, TResult>,
{ wrapper }: RendererOptions<TProps>
) {
let container: ReactTestRenderer

const testHook = createTestHarness(testHookProps, wrapper)
const testHarness = createTestHarness(rendererProps, wrapper)

return {
render(props?: TProps) {
act(() => {
container = create(testHook(props))
container = create(testHarness(props))
})
},
rerender(props?: TProps) {
act(() => {
container.update(testHook(props))
container.update(testHarness(props))
})
},
unmount() {
Expand Down
8 changes: 4 additions & 4 deletions src/server/pure.ts
Expand Up @@ -14,7 +14,7 @@ function createServerRenderer<TProps, TResult>(
) {
const container = document.createElement('div')

const testHook = createTestHarness(rendererProps, wrapper, false)
const testHarness = createTestHarness(rendererProps, wrapper, false)

let renderProps: TProps | undefined
let hydrated = false
Expand All @@ -23,7 +23,7 @@ function createServerRenderer<TProps, TResult>(
render(props?: TProps) {
renderProps = props
act(() => {
const serverOutput = ReactDOMServer.renderToString(testHook(props))
const serverOutput = ReactDOMServer.renderToString(testHarness(props))
container.innerHTML = serverOutput
})
},
Expand All @@ -33,7 +33,7 @@ function createServerRenderer<TProps, TResult>(
} else {
document.body.appendChild(container)
act(() => {
ReactDOM.hydrate(testHook(renderProps), container)
ReactDOM.hydrate(testHarness(renderProps), container)
})
hydrated = true
}
Expand All @@ -43,7 +43,7 @@ function createServerRenderer<TProps, TResult>(
throw new Error('You must hydrate the component before you can rerender')
}
act(() => {
ReactDOM.render(testHook(props), container)
ReactDOM.render(testHarness(props), container)
})
},
unmount() {
Expand Down

0 comments on commit a82d5ef

Please sign in to comment.