-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
1,819 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { | ||
getByLabelText, | ||
getByText, | ||
getByTestId, | ||
queryByTestId, | ||
// Tip: all queries are also exposed on an object | ||
// called "queries" which you could import here as well | ||
waitFor, | ||
} from '@testing-library/dom'; | ||
// adds special assertions like toHaveTextContent | ||
import '@testing-library/jest-dom/extend-expect'; | ||
|
||
function getExampleDOM() { | ||
// This is just a raw example of setting up some DOM | ||
// that we can interact with. Swap this with your UI | ||
// framework of choice 😉 | ||
const div = document.createElement('div'); | ||
div.innerHTML = ` | ||
<label for="username">Username</label> | ||
<input id="username" /> | ||
<button>Print Username</button> | ||
`; | ||
const button = div.querySelector('button'); | ||
const input = div.querySelector('input'); | ||
button.addEventListener('click', () => { | ||
// let's pretend this is making a server request, so it's async | ||
// (you'd want to mock this imaginary request in your unit tests)... | ||
setTimeout(() => { | ||
const printedUsernameContainer = document.createElement('div'); | ||
printedUsernameContainer.innerHTML = ` | ||
<div data-testid="printed-username">${input.value}</div> | ||
`; | ||
div.appendChild(printedUsernameContainer); | ||
}, Math.floor(Math.random() * 200)); | ||
}); | ||
return div; | ||
} | ||
|
||
test('examples of some things', async () => { | ||
const famousWomanInHistory = 'Ada Lovelace'; | ||
const container = getExampleDOM(); | ||
|
||
// Get form elements by their label text. | ||
// An error will be thrown if one cannot be found (accessibility FTW!) | ||
const input = getByLabelText(container, 'Username'); | ||
input.value = famousWomanInHistory; | ||
|
||
// Get elements by their text, just like a real user does. | ||
getByText(container, 'Print Username').click(); | ||
|
||
await waitFor(() => expect(queryByTestId(container, 'printed-username')).toBeTruthy()); | ||
|
||
// getByTestId and queryByTestId are an escape hatch to get elements | ||
// by a test id (could also attempt to get this element by its text) | ||
expect(getByTestId(container, 'printed-username')).toHaveTextContent(famousWomanInHistory); | ||
// jest snapshots work great with regular DOM nodes! | ||
expect(container).toMatchSnapshot(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
import { useRef, useEffect, Ref } from 'react'; | ||
|
||
const useCombinedRefs = <T>(...refs: (Ref<T> | null)[]) => { | ||
const targetRef = useRef<T>(null); | ||
|
||
useEffect(() => { | ||
refs.forEach(ref => { | ||
if (!ref) return; | ||
|
||
if (typeof ref === 'function') { | ||
// @ts-ignore | ||
ref(targetRef.current); | ||
} else { | ||
// @ts-ignore | ||
// eslint-disable-next-line no-param-reassign | ||
ref.current = targetRef.current; | ||
} | ||
}); | ||
}, [refs]); | ||
|
||
return targetRef; | ||
}; | ||
|
||
export default useCombinedRefs; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
/** | ||
* Debounce the change of given value | ||
* | ||
* @param value value changes will only be returned after timeout | ||
* @param timeout timeout in ms passed to setTimeout() | ||
*/ | ||
const useDebounce = <T>(value: T, timeout: number) => { | ||
const [state, setState] = useState(value); | ||
|
||
useEffect(() => { | ||
const handler = setTimeout(() => setState(value), timeout); | ||
|
||
return () => clearTimeout(handler); | ||
}, [value]); | ||
|
||
return state; | ||
}; | ||
|
||
export default useDebounce; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { useState, useEffect, RefObject } from 'react'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const useFocus = <T extends Element | any>(ref: RefObject<T>) => { | ||
const [value, setValue] = useState(false); | ||
|
||
const handleFocus = () => setValue(true); | ||
const handleBlur = () => setValue(false); | ||
|
||
useEffect( | ||
// eslint-disable-next-line consistent-return | ||
() => { | ||
const node = ref.current; | ||
if (node) { | ||
node.addEventListener('focus', handleFocus); | ||
node.addEventListener('blur', handleBlur); | ||
|
||
return () => { | ||
node.removeEventListener('focus', handleFocus); | ||
node.removeEventListener('blur', handleBlur); | ||
}; | ||
} | ||
}, | ||
[ref], | ||
); | ||
|
||
return value; | ||
}; | ||
|
||
export default useFocus; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React, { RefObject, FC, useRef } from 'react'; | ||
import { fireEvent } from '@testing-library/dom'; | ||
import { render, act } from '@testing-library/react'; | ||
|
||
import useHover from './useHover'; | ||
|
||
interface RenderHookProps { | ||
callback: (isHovering: boolean, ref: RefObject<HTMLDivElement>) => void; | ||
} | ||
|
||
const RenderHook: FC<RenderHookProps> = ({ callback }) => { | ||
const ref = useRef(null); | ||
const isHovering = useHover(ref); | ||
|
||
callback(isHovering, ref); | ||
|
||
return <div ref={ref}>test</div>; | ||
}; | ||
|
||
it('should update return value on hover', () => { | ||
jest.useFakeTimers(); | ||
|
||
let hasHover = false; | ||
let currentReference: RefObject<HTMLDivElement> | null = null; | ||
render( | ||
<RenderHook | ||
callback={(isHovering, ref) => { | ||
hasHover = isHovering; | ||
currentReference = ref; | ||
}} | ||
/>, | ||
); | ||
|
||
expect(hasHover).toBe(false); | ||
|
||
act(() => { | ||
if (!currentReference || !currentReference.current) { | ||
throw new Error('ref is null'); | ||
} | ||
fireEvent.mouseOver(currentReference.current); | ||
}); | ||
|
||
act(() => { | ||
jest.runOnlyPendingTimers(); | ||
}); | ||
|
||
expect(hasHover).toBe(true); | ||
|
||
act(() => { | ||
if (!currentReference || !currentReference.current) { | ||
throw new Error('ref is null'); | ||
} | ||
fireEvent.mouseOut(currentReference.current); | ||
}); | ||
|
||
expect(hasHover).toBe(false); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { useState, useEffect, RefObject } from 'react'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const useHover = <T extends Element | any>(ref: RefObject<T>): boolean => { | ||
const [value, setValue] = useState(false); | ||
|
||
const handleMouseOver = () => setValue(true); | ||
const handleMouseOut = () => setValue(false); | ||
|
||
useEffect( | ||
// eslint-disable-next-line consistent-return | ||
() => { | ||
const node = ref.current; | ||
if (node) { | ||
node.addEventListener('mouseover', handleMouseOver); | ||
node.addEventListener('mouseout', handleMouseOut); | ||
|
||
return () => { | ||
node.removeEventListener('mouseover', handleMouseOver); | ||
node.removeEventListener('mouseout', handleMouseOut); | ||
}; | ||
} | ||
}, | ||
[ref], | ||
); | ||
|
||
return value; | ||
}; | ||
|
||
export default useHover; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { useState, useEffect, useCallback } from 'react'; | ||
import { Key } from 'ts-key-enum'; | ||
|
||
const useKeyPress = (targetKey: Key | string | number): boolean => { | ||
const [keyPressed, setKeyPressed] = useState(false); | ||
|
||
const downHandler = useCallback( | ||
({ key }: KeyboardEvent) => { | ||
if (key === targetKey) { | ||
setKeyPressed(true); | ||
} | ||
}, | ||
[targetKey], | ||
); | ||
|
||
const upHandler = useCallback( | ||
({ key }: KeyboardEvent) => { | ||
if (key === targetKey) { | ||
setKeyPressed(false); | ||
} | ||
}, | ||
[targetKey], | ||
); | ||
|
||
useEffect(() => { | ||
window.addEventListener('keydown', downHandler); | ||
window.addEventListener('keyup', upHandler); | ||
|
||
return () => { | ||
window.removeEventListener('keydown', downHandler); | ||
window.removeEventListener('keyup', upHandler); | ||
}; | ||
}, [downHandler, upHandler]); | ||
|
||
return keyPressed; | ||
}; | ||
|
||
export default useKeyPress; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { useRef, useEffect } from 'react'; | ||
|
||
const usePrevious = <T>(value: T) => { | ||
const ref = useRef<T>(); | ||
|
||
useEffect(() => { | ||
ref.current = value; | ||
}); | ||
|
||
return ref.current; | ||
}; | ||
|
||
export default usePrevious; |
Oops, something went wrong.