---
robots: noindex, nofollow
tags: build, internship
---
# Conformance tests
[toc]
Esteban will be starting to work on this as part of this as part of [this project](/7GwG8N0nSIyUaXxZ2N7z6g). We'll initially target what can be done in **2-4 weeks**, primarily focusing on converged components, but listing out other rules which would be included in an "ideal" state is okay too.
Rules may be implemented in either ESLint or Jest depending on what's feasible for the scenario.
✅✅✅ = done
✅ = good to implement
❓ = unclear (need more info about purpose of test and/or whether it's relevant to converged approach)
❌ = irrelevant or low-pri to converge
~~🧹 = possible as lint rule~~ (probably not doing lint rules)
## Prioritized list of rules
TBD :)
## v0 existing rules
https://github.com/microsoft/fluentui/blob/master/packages/fluentui/react-northstar/test/specs/commonTests/isConformant.tsx
* ✅✅✅🧹 Component file exports a valid React element type
* Could detect at runtime (try to render it) or maybe lint time
* Lint considerations:
* How to tell if the current file is a component file? eslint overrides: run component file-specific rules only on component file glob
* How to tell if something is a component:
* only look at exported things
* classes: does it extend React.Component or React.PureComponent
* arrow functions: is it typed as React.FunctionComponent/FC/StatelessComponent/SFC
* functions: skip?
* ✅✅✅🧹 Constructor/component is a named function (or has `displayName`)
* ✅✅✅🧹 Has a docblock, ❓ 5 to 25 words
* This one won't be relevant for v7/v8 because we handle component docs a different way.
* ✅✅✅🧹 Constructor/component name matches filename
* ✅✅✅(🧹?) Is exported at top level (unless opted out)
* ✅✅✅(🧹?) For sub-component, is a static property of its parent component. This ensures CardBody is exposed as Card.Body.
* This may not apply or be needed with compose
* ✅ "Spreads user props" This pattern will move to the v7 pattern of plucking native props instead of spreading all unknown props. Data and aria props are always applied.
* ❓ If it has `as` prop *(probably worth testing if compose has something similar)*
* ✅✅✅ "Renders the component as HTML tags"
* For a given list of HTML tags, ensure: `<Button as='a|div|button|...' />` works.
* ✅✅✅ "Renders as a functional component or passes `as` to the next component" (?)
* Functional components don't support refs by default without properly integrating the hooks or forwardRef (see React docs). Also refer to <Ref /> in v0. `<Popup><Button as={BadRefComponent} /></Popup>` Popup measures button HTML element position through use of ref. If Button renders `as` another component that does not support refs, or has a bad ref implementation, then it breaks. Levi's not sure if this is required for latest React community expectations. Can sync with Shift as well for latest.
* ✅✅✅ "Renders as a ReactClass or passes `as` to the next component"
* Same as previous test, except using a class component to render `as`, instead of functional. Levi's not sure if this is required for latest React community expectations. Can sync with Shift as well for latest.
* ❓ If the component does not render any DOM, ensure it passes the `as` value to the next component. Check and see iif we need this test any more. Are there any components using it? Believe it was for utility components that did not render DOM, but added functionality to a React.Children.only() and needed to pass down the `as` value.
* ✅✅✅ Passes extra props to the component it renders as
* <Button as={FancyButton} data-foo /> should render as a FancyButon and FancyButton should receive data-foo prop.
* ✅ Ensure auto controlled props behave as expected (should work like a vanilla React `<input />` `value` and `defaultValue`.) ~~Each auto-controlled prop should have prop, default prop, and change handler in `handledProps` *(probably irrelevant to compose)*~~
* Should throw if both default and prop are provided
* Component manages state for prop when there is no user prop passed
* Uses the default[A-Z] prop for the initial value on the first render
* Should resume internal control when user removes controlled prop
* Should defer control to user prop when passed after initial render
* Require `defaultFoo` for each auto controlled `foo` prop
* Callbacks should have the signature (event, data) where data is an object of relevant props and state, including any "new" values such as an updated `value` or `checked` prop
* Warn if only controlled prop is passed without callback handler or readOnly if applicable (as React does)
* Refer to: https://reactjs.org/docs/uncontrolled-components.html
* ❌ `handledProps` Not required, see spreading native props above. This was a test to ensure build steps and custom components were built correctly in v0.
* 🧹 defines `handledProps`
* 🧹 includes `styles`
* 🧹 includes `variables`
* (🧹?) `handledProps` includes all props specified in autocontrolled props, default props, and prop types
* 🧹 if FC, uses `useUnhandledProps` hook
* if it has `accessibility` prop:
* 🧹 includes `accessibility` in `handledProps`
* spreads accessibility `attributes` on root
* client's accessibility attributes override ones provided by component
* handles `onKeyDown`, `onKeyPress`, `onKeyUp` transparently (?)
* Handles events transparently
> Events should be handled transparently, working just as they would in vanilla React. Example, both of these handler()s should be called with the same event:
> `<Button onClick={handler} />`
> `<button onClick={handler} />`
> This test catches the case where a developer forgot to call the event prop after handling it internally. It also catch cases where the synthetic event was not passed back.
```jsx
function Button() {
const handleClick = () => {
// do some work, state
// Common issues:
// - Forget to call users onClick !!
// - Call it when you shouldn't (disabled, prevented, etc)
// - Call it at the wrong time, before/after this component work.
// - Called with wrong signature or argument types.
setActive(true)
}
return (
<button {...props} onClick={handleClick}>
</button>
);
}
```
* Default `className` for all components:
* Exports a const `${displayName}ClassName` from root
* ✅ Is applied to the root element
* ✅ Also applies user-provided `className` to root element
* ✅ User-provided `className` does not override default
* ✅✅✅🧹 Has static `displayName` matching constructor name
* ✅ Reports telemetry to its Provider
```json
[
"instances",
"renders",
"msTotal",
"msMin",
"msMax",
"stylesRootCacheHits",
"stylesSlotsCacheHits"
]
```
* For composed components:
* ✅🧹 Overrides default `displayName`
* Shift? - Overrides default debug name for accessibility
* Overrides default name for telemetry
* Overrides default `className`
* Allows definining additional style props
* Passes a ref to root element (uses forward ref?)
(There are also behavior conformance tests https://github.com/microsoft/fluentui/blob/master/packages/fluentui/accessibility/test/behaviors/behavior-test.tsx)
## v7 existing rules
https://github.com/microsoft/fluentui/blob/master/packages/office-ui-fabric-react/src/components/ComponentConformance.test.tsx
* ✅✅✅ File exports a valid React component
* Applies provided `className` to root
* ✅✅✅ Has a corresponding top-level file (`src/<component>`)
* Top-level file imports the package version file
## Ideas for rules
Not covered by v0 or v7 today
- ✅✅✅ Aria attributes should be kebab-cased and not camelCased
- ✅ (partially implemented) Ensure custom callback names are consistent (e.g. on[Part][Event] == onItemClick, onChanged vs onChange, etc)
- Opt-in if component is controlled: has symmetrical `<value>` and `default<Value>` with matching name for `<value>`, and does not have a prop `initial<Value>` (bad pattern in some components)
- onChange handler signature (where applicable):
- event as first arg
- value as second arg (possibly with additional args as needed)
- name is preferably `onChange`, or `on<Value>Change` if there are multiple change handlers for the control
- does not have onChange**d** prop (or variant)
- `/^on(\w+)Change(d)?$/`
- Component props interfaces/types and any other interfaces they reference have a `{@docCategory}` (for anything that needs to work on dev.msft website)
- Component props must be documented
- Render component with `as="foo"`, get html, validate root element is of type "foo"
- Validate that the component uses compose correctly
- Most components will receive children and render them, but some might not, test but allow opt out. (`doesNotAllowChildren`)
- If the component has slots, validate that slots can take in string, jsx, objects, children functions
## Examples of how a dev would use the test-based conformance test
```tsx
import { isConformant } ...
describe("Foo", () => {
it("is conformant", () => {
isConformant(Foo, {
/* options */
});
})
});
```