diff --git a/src/internal/base-component/__tests__/validate-props-production.test.tsx b/src/internal/base-component/__tests__/validate-props-production.test.tsx new file mode 100644 index 0000000..fc04059 --- /dev/null +++ b/src/internal/base-component/__tests__/validate-props-production.test.tsx @@ -0,0 +1,12 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { validateProps } from '../validate-props'; +import { isDevelopment } from '../../is-development'; + +jest.mock('../../is-development', () => ({ isDevelopment: false })); + +test('does nothing in production builds', () => { + expect(isDevelopment).toBe(false); + expect(() => validateProps('TestComponent', { variant: 'foo' }, ['variant'], {}, 'default')).not.toThrow(); +}); diff --git a/src/internal/base-component/__tests__/validate-props.test.tsx b/src/internal/base-component/__tests__/validate-props.test.tsx new file mode 100644 index 0000000..61861b1 --- /dev/null +++ b/src/internal/base-component/__tests__/validate-props.test.tsx @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { validateProps } from '../validate-props'; + +test('should pass validation', () => { + expect(() => validateProps('TestComponent', {}, [], {}, 'default')).not.toThrow(); + expect(() => + validateProps('TestComponent', { variant: 'foo' }, ['bar'], { variant: ['foo'] }, 'default') + ).not.toThrow(); + expect(() => + validateProps('TestComponent', { variant: undefined }, ['bar'], { variant: ['foo'] }, 'default') + ).not.toThrow(); +}); + +test('should throw error when excluded prop is used', () => { + expect(() => validateProps('TestComponent', { variant: 'foo' }, ['variant'], {}, 'default')).toThrow( + new Error('TestComponent does not support "variant" property when used in default system') + ); +}); + +test('should throw error when invalid prop is used', () => { + expect(() => validateProps('TestComponent', { variant: 'foo' }, [], { variant: ['bar'] }, 'default')).toThrow( + new Error('TestComponent does not support "variant" with value "foo" when used in default system') + ); +}); diff --git a/src/internal/base-component/validate-props.ts b/src/internal/base-component/validate-props.ts new file mode 100644 index 0000000..a1b32be --- /dev/null +++ b/src/internal/base-component/validate-props.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { isDevelopment } from '../is-development'; + +export function validateProps( + componentName: string, + props: Record, + excludedProps: Array, + allowedEnums: Record>, + systemName: string +) { + if (!isDevelopment) { + return; + } + for (const [prop, value] of Object.entries(props)) { + if (excludedProps.includes(prop)) { + throw new Error(`${componentName} does not support "${prop}" property when used in ${systemName} system`); + } + if (value && allowedEnums[prop] && !allowedEnums[prop].includes(value)) { + throw new Error( + `${componentName} does not support "${prop}" with value "${value}" when used in ${systemName} system` + ); + } + } +} diff --git a/src/internal/index.ts b/src/internal/index.ts index a1da11f..9a277fa 100644 --- a/src/internal/index.ts +++ b/src/internal/index.ts @@ -39,3 +39,4 @@ export { default as circleIndex } from './utils/circle-index'; export { default as Portal, PortalProps } from './portal'; export { useMergeRefs } from './use-merge-refs'; export { useRandomId, useUniqueId } from './use-unique-id'; +export { validateProps } from './base-component/validate-props';