Skip to content

Commit

Permalink
chore: Clean up Field tests and story imports in preparation of movin…
Browse files Browse the repository at this point in the history
…g to individual packages (microsoft#25594)

* Remove custom `isConformant` function for Field tests, and instead inline the customizations in each call to `isConformant`
* Disable the `exported-top-level` test because the components will be exported as e.g. `InputField_unstable` from the component packages.
* Change the stories to import from `@fluentui/react-components/unstable`, instead of the individual package.
* Rename the `FieldComponent` type to `FieldControl` to correspond to the `control` slot name.
  • Loading branch information
behowell authored and NotWoods committed Nov 18, 2022
1 parent cd407bf commit 693c3e9
Show file tree
Hide file tree
Showing 46 changed files with 213 additions and 95 deletions.
10 changes: 5 additions & 5 deletions apps/vr-tests-react-components/src/stories/Field.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ import {
TextareaField,
} from '@fluentui/react-field';
import { SparkleFilled } from '@fluentui/react-icons';
import { FieldComponent, FieldPropsWithOptionalComponentProps } from '@fluentui/react-field/src/Field';
import { FieldControl, FieldPropsWithOptionalComponentProps } from '@fluentui/react-field/src/Field';

type FieldComponentProps = Pick<
FieldPropsWithOptionalComponentProps<FieldComponent>,
type FieldControlProps = Pick<
FieldPropsWithOptionalComponentProps<FieldControl>,
'orientation' | 'required' | 'label' | 'validationState' | 'validationMessage' | 'validationMessageIcon' | 'hint'
>;

/**
* Common VR tests for all field components. Pass the given Field component (or a wrapper around it).
*/
const storiesOfField = (name: string, Field: React.VoidFunctionComponent<FieldComponentProps>) =>
const storiesOfField = (name: string, Field: React.VoidFunctionComponent<FieldControlProps>) =>
storiesOf(name, module)
.addDecorator(story => <Screener steps={new Steps().snapshot('default').end()}>{story()}</Screener>)
.addDecorator(story => (
Expand Down Expand Up @@ -65,7 +65,7 @@ const storiesOfField = (name: string, Field: React.VoidFunctionComponent<FieldCo
*/
const storiesOfFieldWithSize = (
name: string,
Field: React.VoidFunctionComponent<FieldComponentProps & { size?: 'small' | 'medium' | 'large' }>,
Field: React.VoidFunctionComponent<FieldControlProps & { size?: 'small' | 'medium' | 'large' }>,
) =>
storiesOfField(name, Field)
.addStory('size:small', () => <Field label="Example field" size="small" />)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "chore: Clean up Field tests and story imports in preparation of moving to individual packages",
"packageName": "@fluentui/react-field",
"email": "[email protected]",
"dependentChangeType": "patch"
}
36 changes: 18 additions & 18 deletions packages/react-components/react-field/etc/react-field.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Textarea } from '@fluentui/react-textarea';
export const CheckboxField: ForwardRefComponent<CheckboxFieldProps>;

// @public (undocumented)
export const checkboxFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const checkboxFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type CheckboxFieldProps = Omit<FieldProps<typeof Checkbox>, 'label'> & {
Expand All @@ -43,27 +43,27 @@ export type CheckboxFieldProps = Omit<FieldProps<typeof Checkbox>, 'label'> & {
export const ComboboxField: ForwardRefComponent<ComboboxFieldProps>;

// @public (undocumented)
export const comboboxFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const comboboxFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type ComboboxFieldProps = FieldProps<typeof Combobox>;

// @public
export type FieldConfig<T extends FieldComponent> = {
export type FieldConfig<T extends FieldControl> = {
component: T;
classNames: SlotClassNames<FieldSlots<T>>;
labelConnection?: 'htmlFor' | 'aria-labelledby';
ariaInvalidOnError?: boolean;
};

// @public
export type FieldProps<T extends FieldComponent> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
export type FieldProps<T extends FieldControl> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
orientation?: 'vertical' | 'horizontal';
validationState?: 'error' | 'warning' | 'success';
};

// @public
export type FieldSlots<T extends FieldComponent> = {
export type FieldSlots<T extends FieldControl> = {
root: NonNullable<Slot<'div'>>;
control: SlotComponent<T>;
label?: Slot<typeof Label>;
Expand All @@ -73,18 +73,18 @@ export type FieldSlots<T extends FieldComponent> = {
};

// @public
export type FieldState<T extends FieldComponent> = ComponentState<Required<FieldSlots<T>>> & Pick<FieldProps<T>, 'orientation' | 'validationState'> & {
export type FieldState<T extends FieldControl> = ComponentState<Required<FieldSlots<T>>> & Pick<FieldProps<T>, 'orientation' | 'validationState'> & {
classNames: SlotClassNames<FieldSlots<T>>;
};

// @public (undocumented)
export const getFieldClassNames: (name: string) => SlotClassNames<FieldSlots<FieldComponent>>;
export const getFieldClassNames: (name: string) => SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export const InputField: ForwardRefComponent<InputFieldProps>;

// @public (undocumented)
export const inputFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const inputFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type InputFieldProps = FieldProps<typeof Input>;
Expand All @@ -93,7 +93,7 @@ export type InputFieldProps = FieldProps<typeof Input>;
export const ProgressField: ForwardRefComponent<ProgressFieldProps>;

// @public (undocumented)
export const progressFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const progressFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type ProgressFieldProps = FieldProps<typeof Progress>;
Expand All @@ -102,19 +102,19 @@ export type ProgressFieldProps = FieldProps<typeof Progress>;
export const RadioGroupField: ForwardRefComponent<RadioGroupFieldProps>;

// @public (undocumented)
export const radioGroupFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const radioGroupFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type RadioGroupFieldProps = FieldProps<typeof RadioGroup>;

// @public
export const renderField_unstable: <T extends FieldComponent>(state: FieldState<T>) => JSX.Element;
export const renderField_unstable: <T extends FieldControl>(state: FieldState<T>) => JSX.Element;

// @public (undocumented)
export const SelectField: ForwardRefComponent<SelectFieldProps>;

// @public (undocumented)
export const selectFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const selectFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type SelectFieldProps = FieldProps<typeof Select>;
Expand All @@ -123,7 +123,7 @@ export type SelectFieldProps = FieldProps<typeof Select>;
export const SliderField: ForwardRefComponent<SliderFieldProps>;

// @public (undocumented)
export const sliderFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const sliderFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type SliderFieldProps = FieldProps<typeof Slider>;
Expand All @@ -132,7 +132,7 @@ export type SliderFieldProps = FieldProps<typeof Slider>;
export const SpinButtonField: ForwardRefComponent<SpinButtonFieldProps>;

// @public (undocumented)
export const spinButtonFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const spinButtonFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type SpinButtonFieldProps = FieldProps<typeof SpinButton>;
Expand All @@ -141,7 +141,7 @@ export type SpinButtonFieldProps = FieldProps<typeof SpinButton>;
export const SwitchField: ForwardRefComponent<SwitchFieldProps>;

// @public (undocumented)
export const switchFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const switchFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type SwitchFieldProps = Omit<FieldProps<typeof Switch>, 'labelPosition'>;
Expand All @@ -150,16 +150,16 @@ export type SwitchFieldProps = Omit<FieldProps<typeof Switch>, 'labelPosition'>;
export const TextareaField: ForwardRefComponent<TextareaFieldProps>;

// @public (undocumented)
export const textareaFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
export const textareaFieldClassNames: SlotClassNames<FieldSlots<FieldControl>>;

// @public (undocumented)
export type TextareaFieldProps = FieldProps<typeof Textarea>;

// @public
export const useField_unstable: <T extends FieldComponent>(props: FieldPropsWithOptionalComponentProps<T>, ref: React_2.Ref<HTMLElement>, params: FieldConfig<T>) => FieldState<T>;
export const useField_unstable: <T extends FieldControl>(props: FieldPropsWithOptionalComponentProps<T>, ref: React_2.Ref<HTMLElement>, params: FieldConfig<T>) => FieldState<T>;

// @public
export const useFieldStyles_unstable: <T extends FieldComponent>(state: FieldState<T>) => void;
export const useFieldStyles_unstable: <T extends FieldControl>(state: FieldState<T>) => void;

// (No @packageDocumentation comment for this package)

Expand Down
17 changes: 0 additions & 17 deletions packages/react-components/react-field/src/common/isConformant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,6 @@ export function isConformant<TProps = {}>(
const defaultOptions: Partial<IsConformantOptions<TProps>> = {
componentPath: require.main?.filename.replace('.test', ''),
extraTests: griffelTests as TestObject<TProps>,

// Field-specific defaults
primarySlot: 'control' as keyof TProps,
testOptions: testInfo.testOptions?.['has-static-classnames']
? undefined
: {
'has-static-classnames': [
{
props: {
label: 'label text',
validationState: 'error',
validationMessage: 'validation message text',
hint: 'hint text',
},
},
],
},
};

baseIsConformant(defaultOptions, testInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('CheckboxField', () => {
isConformant({
Component: CheckboxField,
displayName: 'CheckboxField',
primarySlot: 'control',
testOptions: {
'has-static-classnames': [
{
Expand All @@ -20,6 +21,7 @@ describe('CheckboxField', () => {
},
],
},
disabledTests: ['exported-top-level'], // TODO re-enable once component is exported without _unstable
});

// Most functionality is tested by Field.test.tsx, and Checkbox's tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ describe('ComboboxField', () => {
isConformant({
Component: ComboboxField,
displayName: 'ComboboxField',
primarySlot: 'control',
testOptions: {
'has-static-classnames': [
{
props: {
label: 'label text',
validationState: 'error',
validationMessage: 'validation message text',
hint: 'hint text',
},
},
],
},
disabledTests: ['exported-top-level'], // TODO re-enable once component is exported without _unstable
});

// Most functionality is tested by Field.test.tsx, and Combobox's tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { SlotComponent } from './SlotComponent.types';
* Note: the use of VoidFunctionComponent means that component is not *required* to have a children prop,
* but it is still allowed to have a children prop.
*/
export type FieldComponent = React.VoidFunctionComponent<
export type FieldControl = React.VoidFunctionComponent<
Pick<
React.HTMLAttributes<HTMLElement>,
'id' | 'className' | 'style' | 'aria-labelledby' | 'aria-describedby' | 'aria-invalid' | 'aria-errormessage'
Expand All @@ -19,7 +19,7 @@ export type FieldComponent = React.VoidFunctionComponent<
/**
* Slots added by Field
*/
export type FieldSlots<T extends FieldComponent> = {
export type FieldSlots<T extends FieldControl> = {
root: NonNullable<Slot<'div'>>;

/**
Expand Down Expand Up @@ -54,7 +54,7 @@ export type FieldSlots<T extends FieldComponent> = {
/**
* Field Props
*/
export type FieldProps<T extends FieldComponent> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
export type FieldProps<T extends FieldControl> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
/**
* The orientation of the label relative to the field component.
* This only affects the label, and not the validationMessage or hint (which always appear below the field component).
Expand All @@ -79,7 +79,7 @@ export type FieldProps<T extends FieldComponent> = ComponentProps<Partial<FieldS
* This allows Field to forward the required and size props to the label if the underlying component supports them,
* but doesn't add them to the public API of fields that don't support them.
*/
export type FieldPropsWithOptionalComponentProps<T extends FieldComponent> = FieldProps<T> & {
export type FieldPropsWithOptionalComponentProps<T extends FieldControl> = FieldProps<T> & {
/**
* Whether the field label should be marked as required.
*/
Expand All @@ -96,7 +96,7 @@ export type FieldPropsWithOptionalComponentProps<T extends FieldComponent> = Fie
/**
* Configuration parameters for a Field class, passed to useField_unstable
*/
export type FieldConfig<T extends FieldComponent> = {
export type FieldConfig<T extends FieldControl> = {
/**
* The underlying input component that this field is wrapping.
*/
Expand Down Expand Up @@ -129,7 +129,7 @@ export type FieldConfig<T extends FieldComponent> = {
/**
* State used in rendering Field
*/
export type FieldState<T extends FieldComponent> = ComponentState<Required<FieldSlots<T>>> &
export type FieldState<T extends FieldControl> = ComponentState<Required<FieldSlots<T>>> &
Pick<FieldProps<T>, 'orientation' | 'validationState'> & {
classNames: SlotClassNames<FieldSlots<T>>;
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as React from 'react';
import { getSlots } from '@fluentui/react-utilities';
import type { FieldComponent, FieldSlots, FieldState } from './Field.types';
import type { FieldControl, FieldSlots, FieldState } from './Field.types';

/**
* Render the final JSX of Field
*/
export const renderField_unstable = <T extends FieldComponent>(state: FieldState<T>) => {
const { slots, slotProps } = getSlots<FieldSlots<FieldComponent>>(state as FieldState<FieldComponent>);
export const renderField_unstable = <T extends FieldControl>(state: FieldState<T>) => {
const { slots, slotProps } = getSlots<FieldSlots<FieldControl>>(state as FieldState<FieldControl>);

return (
<slots.root {...slotProps.root}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { CheckmarkCircle12Filled, ErrorCircle12Filled, Warning12Filled } from '@
import { Label } from '@fluentui/react-label';
import { getNativeElementProps, resolveShorthand, useId } from '@fluentui/react-utilities';
import type {
FieldComponent,
FieldConfig,
FieldControl,
FieldProps,
FieldPropsWithOptionalComponentProps,
FieldState,
Expand All @@ -19,7 +19,7 @@ const validationMessageIcons = {
/**
* Partition the props used by the Field itself, from the props that are passed to the underlying field component.
*/
export const getPartitionedFieldProps = <Props extends FieldProps<FieldComponent>>(props: Props) => {
export const getPartitionedFieldProps = <Props extends FieldProps<FieldControl>>(props: Props) => {
const {
className,
control,
Expand Down Expand Up @@ -60,7 +60,7 @@ export const getPartitionedFieldProps = <Props extends FieldProps<FieldComponent
* @param ref - Ref to the control slot (primary slot)
* @param params - Configuration parameters for this Field
*/
export const useField_unstable = <T extends FieldComponent>(
export const useField_unstable = <T extends FieldControl>(
props: FieldPropsWithOptionalComponentProps<T>,
ref: React.Ref<HTMLElement>,
params: FieldConfig<T>,
Expand Down Expand Up @@ -134,7 +134,7 @@ export const useField_unstable = <T extends FieldComponent>(
}
}

const state: FieldState<FieldComponent> = {
const state: FieldState<FieldControl> = {
orientation,
validationState,
classNames: params.classNames,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { makeStyles, mergeClasses } from '@griffel/react';
import type { FieldComponent, FieldProps, FieldSlots, FieldState } from './Field.types';
import type { FieldControl, FieldProps, FieldSlots, FieldState } from './Field.types';
import type { SlotClassNames } from '@fluentui/react-utilities';
import { tokens, typographyStyles } from '@fluentui/react-theme';

export const getFieldClassNames = (name: string): SlotClassNames<FieldSlots<FieldComponent>> => ({
export const getFieldClassNames = (name: string): SlotClassNames<FieldSlots<FieldControl>> => ({
root: `fui-${name}`,
control: `fui-${name}__control`,
label: `fui-${name}__label`,
Expand Down Expand Up @@ -81,9 +81,9 @@ const useValidationMessageIconStyles = makeStyles({
/**
* Apply styling to the Field slots based on the state
*/
export const useFieldStyles_unstable = <T extends FieldComponent>(state: FieldState<T>) => {
export const useFieldStyles_unstable = <T extends FieldControl>(state: FieldState<T>) => {
const classNames = state.classNames;
const validationState: FieldProps<FieldComponent>['validationState'] = state.validationState;
const validationState: FieldProps<FieldControl>['validationState'] = state.validationState;
const horizontal = state.orientation === 'horizontal';

const rootStyles = useRootStyles();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ describe('InputField', () => {
isConformant({
Component: InputField,
displayName: 'InputField',
primarySlot: 'control',
testOptions: {
'has-static-classnames': [
{
props: {
label: 'label text',
validationState: 'error',
validationMessage: 'validation message text',
hint: 'hint text',
},
},
],
},
disabledTests: ['exported-top-level'], // TODO re-enable once component is exported without _unstable
});

// Most functionality is tested by Field.test.tsx, and Input's tests
Expand Down
Loading

0 comments on commit 693c3e9

Please sign in to comment.