Skip to content

Upstream useSafeTimeout & add tests #1041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9078840
add useSafeTimeout
Feb 9, 2021
958e3b1
add tests
Feb 9, 2021
626a21e
Update index.d.ts
Feb 10, 2021
e0432b3
Create spotty-parents-beam.md
Feb 10, 2021
9389709
Update yarn.lock
Feb 10, 2021
618ba12
Merge branch 'upstream-behaviors' of github.com:primer/components int…
Feb 10, 2021
267db95
first pass of ts-ifying utilitles,.js
Feb 10, 2021
64b3995
fix getComputedStyles types
Feb 11, 2021
b50f743
stopping point
Feb 11, 2021
c7e9ea2
refactor behavesAsComponent
Feb 11, 2021
f73b6b3
refactor all instances of behavesAsComponent
Feb 11, 2021
3f3c0ba
Update testing.tsx
Feb 11, 2021
e6bc7c9
TS tweaks
Feb 11, 2021
62dcaac
type guard for CountMock
Feb 11, 2021
3ad7704
fix syntax
Feb 11, 2021
c53777a
remove test
Feb 11, 2021
44095d8
Update docs/content/useSafeTimeout.mdx
Feb 11, 2021
8641388
Update index.d.ts
Feb 11, 2021
df310e3
fix last test
Feb 11, 2021
a39e6dc
Update src/__tests__/useSafeTimeout.tsx
Feb 11, 2021
e4e85cc
Update src/__tests__/useSafeTimeout.tsx
Feb 11, 2021
fb287b2
Update useSafeTimeout.ts
Feb 11, 2021
490fe50
remove unused eslint disable
Feb 11, 2021
739dffb
Merge branch 'upstream-behaviors' of github.com:primer/components int…
Feb 11, 2021
2b6415d
use a set
Feb 11, 2021
ec4a84c
lint
Feb 11, 2021
ad866bf
Merge branch 'main' into upstream-behaviors
Feb 11, 2021
483b01b
Update SideNav.tsx
Feb 11, 2021
cc85835
Update FilterList.tsx
Feb 16, 2021
b0d2130
Update src/__tests__/FilterListItem.tsx
Feb 16, 2021
ef95b5b
Update src/__tests__/useSafeTimeout.tsx
Feb 16, 2021
32924da
Update src/utils/testing.tsx
Feb 16, 2021
24a2495
Update src/utils/testing.tsx
Feb 16, 2021
0a392a0
Update .changeset/spotty-parents-beam.md
Feb 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/spotty-parents-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/components": minor
---

Adds new `useSafeTimeout` helper Hook
32 changes: 32 additions & 0 deletions docs/content/useSafeTimeout.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: useSafeTimeout
---

`useSafeTimeout` is a utility Hook that allows you to safely call `setTimeout` and `clearTimeout` within a component, ensuring that all timeouts are cleared when the component unmounts.


### Usage

```jsx live
<State>
{([]) => {
const {safeSetTimeout, safeClearTimeout} = useSafeTimeout()
let timeoutId = null

const handleOnClick = () => {
timeoutId = safeSetTimeout(() => window.alert('hello!'), 5000)
}

const cancelTimeout = () => {
safeClearTimeout(timeoutId)
}

return (
<>
<Button onClick={handleOnClick}>Click me</Button>
<Button onClick={cancelTimeout}>Cancel timeout</Button>
</>
)
}}
</State>
```
5 changes: 4 additions & 1 deletion docs/src/@primer/gatsby-theme-doctocat/nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

- title: Overriding Styles
url: /overriding-styles

- title: Hooks
children:
- title: useSafeTimeout
url: /useSafeTimeout
- title: Components
children:
- title: Avatar
Expand Down
10 changes: 10 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ declare module '@primer/components' {
setOpen: (open: boolean) => void
}

export const useSafeTimeout: () => {
safeSetTimeout: typeof window.setTimeout,
safeClearTimeout: typeof window.clearTimeout
}

export const useMouseIntent: () => void

export interface ButtonProps
Expand Down Expand Up @@ -663,6 +668,11 @@ declare module '@primer/components/lib/hooks/useMouseIntent' {
export default useMouseIntent
}

declare module '@primer/components/lib/hooks/useMouseSafeTimeout' {
import {useSafeTimeout} from '@primer/components'
export default useSafeTimeout
}

declare module '@primer/components/lib/BaseStyles' {
import {BaseStyles} from '@primer/components'
export default BaseStyles
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@
"@storybook/react": "^6.1.17",
"@testing-library/dom": "7.29.0",
"@testing-library/react": "11.2.2",
"@testing-library/react-hooks": "5.0.3",
"@testing-library/user-event": "12.6.0",
"@types/enzyme": "3.10.8",
"@types/jest": "26.0.20",
"@types/jest-axe": "3.5.1",
"@typescript-eslint/eslint-plugin": "4.14.1",
Expand Down
2 changes: 1 addition & 1 deletion src/FilterList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ FilterListItem.propTypes = {
as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
children: PropTypes.node,
className: PropTypes.string,
count: PropTypes.string,
count: PropTypes.number,
selected: PropTypes.bool,
theme: PropTypes.object,
...COMMON.propTypes,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {COMMON} from '../constants'
expect.extend(toHaveNoViolations)

describe('Avatar', () => {
behavesAsComponent(Avatar, [COMMON])
behavesAsComponent({Component: Avatar, systemPropArray: [COMMON]})

checkExports('Avatar', {
default: Avatar
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/AvatarStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const rightAvatarComp = (
)

describe('Avatar', () => {
behavesAsComponent(AvatarStack, [COMMON], () => avatarComp)
behavesAsComponent({Component: AvatarStack, systemPropArray: [COMMON], toRender: () => avatarComp})

checkExports('AvatarStack', {
default: AvatarStack
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/BorderBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('BorderBox', () => {
behavesAsComponent(BorderBox, [LAYOUT, COMMON, BORDER, FLEX])
behavesAsComponent({Component: BorderBox, systemPropArray: [LAYOUT, COMMON, BORDER, FLEX]})

checkExports('BorderBox', {
default: BorderBox
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {behavesAsComponent, checkExports, render} from '../utils/testing'
expect.extend(toHaveNoViolations)

describe('Box', () => {
behavesAsComponent(Box, [COMMON, LAYOUT, FLEX])
behavesAsComponent({Component: Box, systemPropArray: [COMMON, LAYOUT, FLEX]})

checkExports('Box', {
default: Box,
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/BranchName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('BranchName', () => {
behavesAsComponent(BranchName, [COMMON])
behavesAsComponent({Component: BranchName, systemPropArray: [COMMON]})

checkExports('BranchName', {
default: BranchName
Expand Down
10 changes: 1 addition & 9 deletions src/__tests__/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('Breadcrumb', () => {
behavesAsComponent(Breadcrumb, [COMMON])
behavesAsComponent({Component: Breadcrumb, systemPropArray: [COMMON]})

checkExports('Breadcrumb', {
default: Breadcrumb
Expand All @@ -28,12 +28,4 @@ describe('Breadcrumb', () => {
it('adds the Breadcrumb class', () => {
expect(rendersClass(<Breadcrumb />, 'Breadcrumb')).toEqual(true)
})

it('wraps its children in an li', () => {
const children = <Breadcrumb.Item>yo</Breadcrumb.Item>
const wrapper = mount(<Breadcrumb>{children}</Breadcrumb>)
const list = wrapper.find('ol')
expect(list.exists()).toEqual(true)
expect(render(list.childAt(0)).type).toEqual('li')
})
})
2 changes: 1 addition & 1 deletion src/__tests__/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {behavesAsComponent, render} from '../utils/testing'
expect.extend(toHaveNoViolations)

describe('Breadcrumb.Item', () => {
behavesAsComponent(Breadcrumb.Item, [COMMON])
behavesAsComponent({Component: Breadcrumb.Item, systemPropArray:[COMMON]})

it('renders an <a> by default', () => {
expect(render(<Breadcrumb.Item />).type).toEqual('a')
Expand Down
14 changes: 7 additions & 7 deletions src/__tests__/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ expect.extend(toHaveNoViolations)
function noop() {}

describe('Button', () => {
behavesAsComponent(Button, [COMMON, LAYOUT])
behavesAsComponent({Component: Button, systemPropArray: [COMMON, LAYOUT]})

checkExports('Button', {
default: Button,
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('Button', () => {
})

describe('ButtonPrimary', () => {
behavesAsComponent(ButtonPrimary, [COMMON, LAYOUT])
behavesAsComponent({Component: ButtonPrimary, systemPropArray: [COMMON, LAYOUT]})

it('renders a <button>', () => {
expect(render(<ButtonPrimary />).type).toEqual('button')
Expand All @@ -82,7 +82,7 @@ describe('ButtonPrimary', () => {
})

describe('ButtonDanger', () => {
behavesAsComponent(ButtonDanger, [COMMON, LAYOUT])
behavesAsComponent({Component: ButtonDanger, systemPropArray: [COMMON, LAYOUT]})

it('renders a <button>', () => {
expect(render(<ButtonDanger />).type).toEqual('button')
Expand All @@ -95,7 +95,7 @@ describe('ButtonDanger', () => {
})

describe('ButtonOutline', () => {
behavesAsComponent(ButtonOutline, [COMMON, LAYOUT])
behavesAsComponent({Component: ButtonOutline, systemPropArray: [COMMON, LAYOUT]})

it('renders a <button> by default', () => {
expect(render(<ButtonOutline />).type).toEqual('button')
Expand All @@ -108,7 +108,7 @@ describe('ButtonOutline', () => {
})

describe('ButtonInvisible', () => {
behavesAsComponent(ButtonOutline, [COMMON, LAYOUT])
behavesAsComponent({Component: ButtonOutline, systemPropArray: [COMMON, LAYOUT]})

it('renders a <button> by default', () => {
expect(render(<ButtonInvisible />).type).toEqual('button')
Expand All @@ -121,9 +121,9 @@ describe('ButtonInvisible', () => {
})

describe('ButtonGroup', () => {
behavesAsComponent(ButtonGroup, [COMMON, FLEX, LAYOUT])
behavesAsComponent({Component: ButtonGroup, systemPropArray: [COMMON, FLEX, LAYOUT]})
})

describe('ButtonTableList', () => {
behavesAsComponent(ButtonTableList, [COMMON, TYPOGRAPHY, LAYOUT])
behavesAsComponent({Component: ButtonTableList, systemPropArray: [COMMON, TYPOGRAPHY, LAYOUT]})
})
4 changes: 2 additions & 2 deletions src/__tests__/CircleBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ expect.extend(toHaveNoViolations)
const imgInput = <img alt="" src="primer.jpg" />

describe('CircleBadge', () => {
behavesAsComponent(CircleBadge, [COMMON], () => <CircleBadge>{imgInput}</CircleBadge>)
behavesAsComponent({Component: CircleBadge, systemPropArray: [COMMON], toRender: () => <CircleBadge>{imgInput}</CircleBadge>})

checkExports('CircleBadge', {
default: CircleBadge
})

describe('CircleBadge.Icon', () => {
behavesAsComponent(CircleBadge.Icon, [COMMON], () => <CircleBadge.Icon icon={CheckIcon} />)
behavesAsComponent({Component: CircleBadge.Icon, systemPropArray: [COMMON], toRender: () => <CircleBadge.Icon icon={CheckIcon} />})
})

it('should have no axe violations', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/CircleOcticon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('CircleOcticon', () => {
behavesAsComponent(CircleOcticon, [COMMON, FLEX, LAYOUT], () => <CircleOcticon icon={CheckIcon} />)
behavesAsComponent({Component: CircleOcticon, systemPropArray: [COMMON, FLEX, LAYOUT], toRender: () => <CircleOcticon icon={CheckIcon} />})

checkExports('CircleOcticon', {
default: CircleOcticon
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/CounterLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('CounterLabel', () => {
behavesAsComponent(CounterLabel, [COMMON])
behavesAsComponent({Component: CounterLabel, systemPropArray: [COMMON]})

checkExports('CounterLabel', {
default: CounterLabel
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('Details', () => {
behavesAsComponent(Details, [COMMON])
behavesAsComponent({Component: Details, systemPropArray: [COMMON]})

checkExports('Details', {
default: Details
Expand Down
9 changes: 7 additions & 2 deletions src/__tests__/Dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,19 @@ const DialogWithCustomFocusRef = () => {

describe('Dialog', () => {
// because Dialog returns a React fragment the as and sx tests fail always, so they are skipped
behavesAsComponent(Dialog, [COMMON, LAYOUT], () => comp, {skipAs: true, skipSx: true})
behavesAsComponent({
Component: Dialog,
systemPropArray: [COMMON, LAYOUT],
toRender: () => comp,
options: {skipAs: true, skipSx: true}
})

checkExports('Dialog', {
default: Dialog
})

describe('Dialog.Header', () => {
behavesAsComponent(Dialog.Header, [COMMON, FLEX, LAYOUT])
behavesAsComponent({Component: Dialog.Header, systemPropArray: [COMMON, FLEX, LAYOUT]})
})

it('should have no axe violations', async () => {
Expand Down
34 changes: 23 additions & 11 deletions src/__tests__/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('Dropdown', () => {
behavesAsComponent(Dropdown, [COMMON], () => <Dropdown>Hello!</Dropdown>)
behavesAsComponent({Component: Dropdown, systemPropArray: [COMMON], toRender: () => <Dropdown>Hello!</Dropdown>})

checkExports('Dropdown', {
default: Dropdown
Expand All @@ -23,23 +23,35 @@ describe('Dropdown', () => {
})

describe('Dropdown.Item', () => {
behavesAsComponent(Dropdown.Item, [COMMON], () => <Dropdown.Item>Hello!</Dropdown.Item>)
behavesAsComponent({
Component: Dropdown.Item,
systemPropArray: [COMMON],
toRender: () => <Dropdown.Item>Hello!</Dropdown.Item>
})
})

describe('Dropdown.Button', () => {
behavesAsComponent(Dropdown.Button, [COMMON], () => <Dropdown.Button>Hello!</Dropdown.Button>)
behavesAsComponent({
Component: Dropdown.Button,
systemPropArray: [COMMON],
toRender: () => <Dropdown.Button>Hello!</Dropdown.Button>
})
})

describe('Dropdown.Caret', () => {
behavesAsComponent(Dropdown.Caret, [COMMON])
behavesAsComponent({Component: Dropdown.Caret, systemPropArray: [COMMON]})
})

describe('Dropdown.Menu', () => {
behavesAsComponent(Dropdown.Menu, [COMMON], () => (
<Dropdown.Menu>
<li key="a">1</li>
<li key="b">2</li>
<li key="c">3</li>
</Dropdown.Menu>
))
behavesAsComponent({
Component: Dropdown.Menu,
systemPropArray: [COMMON],
toRender: () => (
<Dropdown.Menu>
<li key="a">1</li>
<li key="b">2</li>
<li key="c">3</li>
</Dropdown.Menu>
)
})
})
6 changes: 1 addition & 5 deletions src/__tests__/FilterList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('FilterList', () => {
behavesAsComponent(FilterList, [COMMON])
behavesAsComponent({Component: FilterList, systemPropArray: [COMMON]})

checkExports('FilterList', {
default: FilterList
Expand All @@ -24,8 +24,4 @@ describe('FilterList', () => {
it('renders a <ul>', () => {
expect(render(<FilterList />).type).toEqual('ul')
})

it('wraps children in <li>', () => {
expect(render(<FilterList>Hello</FilterList>).children.pop().type).toEqual('li')
})
})
8 changes: 5 additions & 3 deletions src/__tests__/FilterListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {COMMON} from '../constants'
import {render as HTMLRender, cleanup} from '@testing-library/react'
import {axe, toHaveNoViolations} from 'jest-axe'
import 'babel-polyfill'
import { ReactTestRendererJSON } from 'react-test-renderer'
expect.extend(toHaveNoViolations)


describe('FilterList.Item', () => {
behavesAsComponent(FilterList.Item, [COMMON])
behavesAsComponent({Component: FilterList.Item, systemPropArray: [COMMON]})

it('should have no axe violations', async () => {
const {container} = HTMLRender(<FilterList.Item>stuff</FilterList.Item>)
Expand All @@ -26,7 +28,7 @@ describe('FilterList.Item', () => {
})

it('respects "count" prop', () => {
const CountMock = render(<FilterList.Item count={400} />).children.pop()
expect(CountMock.type).toEqual('span')
const {getByText} = HTMLRender(<FilterList.Item count={400} />)
expect(getByText("400")).toBeTruthy()
})
})
2 changes: 1 addition & 1 deletion src/__tests__/FilteredSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'babel-polyfill'
expect.extend(toHaveNoViolations)

describe('FilteredSearch', () => {
behavesAsComponent(FilteredSearch, [COMMON])
behavesAsComponent({Component: FilteredSearch, systemPropArray: [COMMON]})

checkExports('FilteredSearch', {
default: FilteredSearch
Expand Down
Loading