Skip to content

Commit

Permalink
feat: add deprecated prop decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
HendrikThePendric committed May 23, 2022
1 parent a334471 commit 5c5133b
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
118 changes: 118 additions & 0 deletions src/__tests__/deprecated.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import propTypes from 'prop-types'
import { deprecated } from '../deprecated'

describe('deprecated', () => {
jest.spyOn(console, 'error').mockImplementation(() => null)
jest.spyOn(console, 'warn').mockImplementation(() => null)

afterEach(() => {
console.error.mockClear()
console.warn.mockClear()
})

it('warns when props are valid', () => {
const propType = {
deprecatedBool: deprecated(
propTypes.bool,
'Please do not use anymore'
),
}
const props = {
deprecatedBool: false,
}

propTypes.checkPropTypes(
propType,
props,
'deprecatedMandatoryBool',
'TestComponent'
)

expect(console.error).toBeCalledTimes(0)
expect(console.warn).toBeCalledTimes(1)
})
it('warns when props are invalid', () => {
const propType = {
deprecatedBool: deprecated(
propTypes.bool,
'Please do not use anymore'
),
}
const props = {
deprecatedBool: 'I aint no bool',
}

propTypes.checkPropTypes(
propType,
props,
'deprecatedBool',
'TestComponent'
)

expect(console.error).toBeCalledTimes(1)
expect(console.warn).toBeCalledTimes(1)
})
it('produces one warning per deprecated prop', () => {
const propType = {
a: deprecated(propTypes.bool, 'Please do not use anymore'),
b: deprecated(propTypes.bool, 'Please do not use anymore'),
c: deprecated(propTypes.bool, 'Please do not use anymore'),
}
const props = {
a: true,
b: true,
c: true,
}

propTypes.checkPropTypes(
propType,
props,
'deprecatedBool',
'TestComponent'
)

expect(console.error).toBeCalledTimes(0)
expect(console.warn).toBeCalledTimes(3)

expect(console.warn).toHaveBeenCalledWith(
'"a" property of "TestComponent" has been deprecated. Please do not use anymore'
)
expect(console.warn).toHaveBeenCalledWith(
'"b" property of "TestComponent" has been deprecated. Please do not use anymore'
)
expect(console.warn).toHaveBeenCalledWith(
'"c" property of "TestComponent" has been deprecated. Please do not use anymore'
)
})

it('does not repeat warnings when props are re-validated', () => {
const spy = jest.spyOn(propTypes, 'checkPropTypes')
const propType = {
deprecatedBool: deprecated(
propTypes.bool,
'Please do not use anymore'
),
}
const props = {
deprecatedBool: 'I aint no bool',
}

propTypes.checkPropTypes(
propType,
props,
'deprecatedBool',
'TestComponent'
)
propTypes.checkPropTypes(
propType,
props,
'deprecatedBool',
'TestComponent'
)

// Can't explain why the spy is called 4 times, but at least
// this does verify that the warning will only be showed once
expect(spy).toBeCalledTimes(4)
expect(console.warn).toBeCalledTimes(1)
})
})
23 changes: 23 additions & 0 deletions src/deprecated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import propTypes from 'prop-types'

export const deprecated = (propType, explanation) => {
const emmittedWarnings = new Set()

return (props, propName, componentName) => {
const message = `"${propName}" property of "${componentName}" has been deprecated. ${explanation}`

if (!emmittedWarnings.has(message)) {
console.warn(message)
emmittedWarnings.add(message)
}

propTypes.checkPropTypes(
{ [propName]: propType },
props,
'prop',
componentName
)

return null
}
}

0 comments on commit 5c5133b

Please sign in to comment.