diff --git a/packages/mui-base/src/Field/Root/FieldRoot.test.tsx b/packages/mui-base/src/Field/Root/FieldRoot.test.tsx index 9ffdc0696..ea6cf99dc 100644 --- a/packages/mui-base/src/Field/Root/FieldRoot.test.tsx +++ b/packages/mui-base/src/Field/Root/FieldRoot.test.tsx @@ -1,687 +1,687 @@ -// import * as React from 'react'; -// import { Field } from '@base_ui/react/Field'; -// import { Checkbox } from '@base_ui/react/Checkbox'; -// import { Switch } from '@base_ui/react/Switch'; -// import { NumberField } from '@base_ui/react/NumberField'; -// import { Slider } from '@base_ui/react/Slider'; -// import { RadioGroup } from '@base_ui/react/RadioGroup'; -// import { Radio } from '@base_ui/react/Radio'; -// import { Select } from '@base_ui/react/Select'; -// import userEvent from '@testing-library/user-event'; -// import { act, fireEvent, flushMicrotasks, screen, waitFor } from '@mui/internal-test-utils'; -// import { expect } from 'chai'; -// import { createRenderer, describeConformance } from '#test-utils'; - -// const user = userEvent.setup(); - -// describe('', () => { -// const { render } = createRenderer(); - -// describeConformance(, () => ({ -// refInstanceof: window.HTMLDivElement, -// render, -// })); - -// describe('prop: disabled', () => { -// it('should add data-disabled style hook to all components', async () => { -// await render( -// -// -// -// -// , -// ); - -// const field = screen.getByTestId('field'); -// const control = screen.getByTestId('control'); -// const label = screen.getByTestId('label'); -// const message = screen.getByTestId('message'); - -// expect(field).to.have.attribute('data-disabled', 'true'); -// expect(control).to.have.attribute('data-disabled', 'true'); -// expect(label).to.have.attribute('data-disabled', 'true'); -// expect(message).to.have.attribute('data-disabled', 'true'); -// }); -// }); - -// describe('prop: validate', () => { -// it('should validate the field on blur', async () => { -// await render( -// 'error'}> -// -// -// , -// ); - -// const control = screen.getByRole('textbox'); -// const message = screen.queryByText('error'); - -// expect(message).to.equal(null); - -// fireEvent.focus(control); -// fireEvent.blur(control); - -// expect(screen.queryByText('error')).not.to.equal(null); -// }); - -// it('supports async validation', async () => { -// await render( -// Promise.resolve('error')}> -// -// -// , -// ); - -// const control = screen.getByRole('textbox'); -// const message = screen.queryByText('error'); - -// expect(message).to.equal(null); - -// fireEvent.focus(control); -// fireEvent.blur(control); - -// await flushMicrotasks(); - -// await waitFor(() => { -// expect(screen.queryByText('error')).not.to.equal(null); -// }); -// }); - -// it('should apply [data-field] style hooks to field components', async () => { -// await render( -// -// Label -// Description -// -// -// , -// ); - -// const control = screen.getByTestId('control'); -// const label = screen.getByTestId('label'); -// const description = screen.getByTestId('description'); -// let error = screen.queryByTestId('error'); - -// expect(control).not.to.have.attribute('data-field'); -// expect(label).not.to.have.attribute('data-field'); -// expect(description).not.to.have.attribute('data-field'); -// expect(error).to.equal(null); - -// fireEvent.focus(control); -// fireEvent.change(control, { target: { value: 'a' } }); -// fireEvent.change(control, { target: { value: '' } }); -// fireEvent.blur(control); - -// error = screen.getByTestId('error'); - -// expect(control).to.have.attribute('data-field', 'invalid'); -// expect(label).to.have.attribute('data-field', 'invalid'); -// expect(description).to.have.attribute('data-field', 'invalid'); -// expect(error).to.have.attribute('data-field', 'invalid'); - -// act(() => { -// control.value = 'value'; -// control.focus(); -// control.blur(); -// }); - -// error = screen.queryByTestId('error'); - -// expect(control).to.have.attribute('data-field', 'valid'); -// expect(label).to.have.attribute('data-field', 'valid'); -// expect(description).to.have.attribute('data-field', 'valid'); -// expect(error).to.equal(null); -// }); - -// it('should apply aria-invalid prop to control once validated', async () => { -// await render( -// 'error'}> -// -// -// , -// ); - -// const control = screen.getByRole('textbox'); - -// expect(control).not.to.have.attribute('aria-invalid'); - -// fireEvent.focus(control); -// fireEvent.blur(control); - -// expect(control).to.have.attribute('aria-invalid', 'true'); -// }); - -// describe('component integration', () => { -// it('supports Checkbox', async () => { -// await render( -// 'error'}> -// -// -// , -// ); - -// const button = screen.getByTestId('button'); - -// expect(button).not.to.have.attribute('aria-invalid'); - -// fireEvent.focus(button); -// fireEvent.blur(button); - -// expect(button).to.have.attribute('aria-invalid', 'true'); -// }); - -// it('supports Switch', async () => { -// await render( -// 'error'}> -// -// -// , -// ); - -// const button = screen.getByTestId('button'); - -// expect(button).not.to.have.attribute('aria-invalid'); - -// fireEvent.focus(button); -// fireEvent.blur(button); - -// expect(button).to.have.attribute('aria-invalid', 'true'); -// }); - -// it('supports NumberField', async () => { -// await render( -// 'error'}> -// -// -// -// -// , -// ); - -// const input = screen.getByRole('textbox'); - -// expect(input).not.to.have.attribute('aria-invalid'); - -// fireEvent.focus(input); -// fireEvent.blur(input); - -// expect(input).to.have.attribute('aria-invalid', 'true'); -// }); - -// it('supports Slider', async () => { -// const { container } = await render( -// 'error'}> -// -// -// -// -// -// -// , -// ); - -// // eslint-disable-next-line testing-library/no-node-access -// const input = container.querySelector('input')!; -// const thumb = screen.getByTestId('thumb'); - -// expect(input).not.to.have.attribute('aria-invalid'); - -// fireEvent.focus(thumb); -// fireEvent.blur(thumb); - -// expect(input).to.have.attribute('aria-invalid', 'true'); -// }); - -// it('supports RadioGroup', async () => { -// await render( -// 'error'}> -// -// One -// Two -// -// -// , -// ); +import * as React from 'react'; +import { Field } from '@base_ui/react/Field'; +import { Checkbox } from '@base_ui/react/Checkbox'; +import { Switch } from '@base_ui/react/Switch'; +import { NumberField } from '@base_ui/react/NumberField'; +import { Slider } from '@base_ui/react/Slider'; +import { RadioGroup } from '@base_ui/react/RadioGroup'; +import { Radio } from '@base_ui/react/Radio'; +import { Select } from '@base_ui/react/Select'; +import userEvent from '@testing-library/user-event'; +import { act, fireEvent, flushMicrotasks, screen, waitFor } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { createRenderer, describeConformance } from '#test-utils'; + +const user = userEvent.setup(); + +describe('', () => { + const { render } = createRenderer(); + + describeConformance(, () => ({ + refInstanceof: window.HTMLDivElement, + render, + })); + + describe('prop: disabled', () => { + it('should add data-disabled style hook to all components', async () => { + await render( + + + + + , + ); + + const field = screen.getByTestId('field'); + const control = screen.getByTestId('control'); + const label = screen.getByTestId('label'); + const message = screen.getByTestId('message'); + + expect(field).to.have.attribute('data-disabled', 'true'); + expect(control).to.have.attribute('data-disabled', 'true'); + expect(label).to.have.attribute('data-disabled', 'true'); + expect(message).to.have.attribute('data-disabled', 'true'); + }); + }); + + describe('prop: validate', () => { + it('should validate the field on blur', async () => { + await render( + 'error'}> + + + , + ); + + const control = screen.getByRole('textbox'); + const message = screen.queryByText('error'); + + expect(message).to.equal(null); + + fireEvent.focus(control); + fireEvent.blur(control); + + expect(screen.queryByText('error')).not.to.equal(null); + }); + + it('supports async validation', async () => { + await render( + Promise.resolve('error')}> + + + , + ); + + const control = screen.getByRole('textbox'); + const message = screen.queryByText('error'); + + expect(message).to.equal(null); + + fireEvent.focus(control); + fireEvent.blur(control); + + await flushMicrotasks(); + + await waitFor(() => { + expect(screen.queryByText('error')).not.to.equal(null); + }); + }); + + it('should apply [data-field] style hooks to field components', async () => { + await render( + + Label + Description + + + , + ); + + const control = screen.getByTestId('control'); + const label = screen.getByTestId('label'); + const description = screen.getByTestId('description'); + let error = screen.queryByTestId('error'); + + expect(control).not.to.have.attribute('data-field'); + expect(label).not.to.have.attribute('data-field'); + expect(description).not.to.have.attribute('data-field'); + expect(error).to.equal(null); + + fireEvent.focus(control); + fireEvent.change(control, { target: { value: 'a' } }); + fireEvent.change(control, { target: { value: '' } }); + fireEvent.blur(control); + + error = screen.getByTestId('error'); + + expect(control).to.have.attribute('data-field', 'invalid'); + expect(label).to.have.attribute('data-field', 'invalid'); + expect(description).to.have.attribute('data-field', 'invalid'); + expect(error).to.have.attribute('data-field', 'invalid'); + + act(() => { + control.value = 'value'; + control.focus(); + control.blur(); + }); + + error = screen.queryByTestId('error'); + + expect(control).to.have.attribute('data-field', 'valid'); + expect(label).to.have.attribute('data-field', 'valid'); + expect(description).to.have.attribute('data-field', 'valid'); + expect(error).to.equal(null); + }); + + it('should apply aria-invalid prop to control once validated', async () => { + await render( + 'error'}> + + + , + ); + + const control = screen.getByRole('textbox'); + + expect(control).not.to.have.attribute('aria-invalid'); + + fireEvent.focus(control); + fireEvent.blur(control); + + expect(control).to.have.attribute('aria-invalid', 'true'); + }); + + describe('component integration', () => { + it('supports Checkbox', async () => { + await render( + 'error'}> + + + , + ); + + const button = screen.getByTestId('button'); + + expect(button).not.to.have.attribute('aria-invalid'); + + fireEvent.focus(button); + fireEvent.blur(button); + + expect(button).to.have.attribute('aria-invalid', 'true'); + }); + + it('supports Switch', async () => { + await render( + 'error'}> + + + , + ); + + const button = screen.getByTestId('button'); + + expect(button).not.to.have.attribute('aria-invalid'); + + fireEvent.focus(button); + fireEvent.blur(button); + + expect(button).to.have.attribute('aria-invalid', 'true'); + }); + + it('supports NumberField', async () => { + await render( + 'error'}> + + + + + , + ); + + const input = screen.getByRole('textbox'); + + expect(input).not.to.have.attribute('aria-invalid'); + + fireEvent.focus(input); + fireEvent.blur(input); + + expect(input).to.have.attribute('aria-invalid', 'true'); + }); + + it('supports Slider', async () => { + const { container } = await render( + 'error'}> + + + + + + + , + ); + + // eslint-disable-next-line testing-library/no-node-access + const input = container.querySelector('input')!; + const thumb = screen.getByTestId('thumb'); + + expect(input).not.to.have.attribute('aria-invalid'); + + fireEvent.focus(thumb); + fireEvent.blur(thumb); + + expect(input).to.have.attribute('aria-invalid', 'true'); + }); + + it('supports RadioGroup', async () => { + await render( + 'error'}> + + One + Two + + + , + ); -// const group = screen.getByTestId('group'); + const group = screen.getByTestId('group'); -// expect(group).not.to.have.attribute('aria-invalid'); + expect(group).not.to.have.attribute('aria-invalid'); -// fireEvent.focus(group); -// fireEvent.blur(group); + fireEvent.focus(group); + fireEvent.blur(group); -// expect(group).to.have.attribute('aria-invalid', 'true'); -// }); - -// it('supports Select', async () => { -// await render( -// 'error'}> -// -// -// -// -// , -// ); - -// const trigger = screen.getByTestId('trigger'); - -// expect(trigger).not.to.have.attribute('aria-invalid'); - -// fireEvent.focus(trigger); -// fireEvent.blur(trigger); - -// await flushMicrotasks(); - -// expect(trigger).to.have.attribute('aria-invalid', 'true'); -// }); -// }); -// }); - -// describe('prop: validationMode', () => { -// it('should validate the field on change', async () => { -// await render( -// { -// const str = value as string; -// return str.length < 3 ? 'error' : null; -// }} -// > -// -// -// , -// ); - -// const control = screen.getByRole('textbox'); -// const message = screen.queryByText('error'); - -// expect(message).to.equal(null); - -// fireEvent.change(control, { target: { value: 't' } }); - -// expect(control).to.have.attribute('data-field', 'invalid'); -// expect(control).to.have.attribute('aria-invalid', 'true'); -// }); -// }); - -// describe('prop: validateDebounceTime', () => { -// const { clock, render: renderFakeTimers } = createRenderer(); - -// clock.withFakeTimers(); - -// it('should debounce validation', async () => { -// await renderFakeTimers( -// { -// const str = value as string; -// return str.length < 3 ? 'error' : null; -// }} -// > -// -// -// , -// ); - -// const control = screen.getByRole('textbox'); -// const message = screen.queryByText('error'); - -// expect(message).to.equal(null); - -// fireEvent.change(control, { target: { value: 't' } }); - -// expect(control).not.to.have.attribute('aria-invalid'); - -// clock.tick(99); - -// fireEvent.change(control, { target: { value: 'te' } }); - -// clock.tick(99); - -// expect(control).not.to.have.attribute('aria-invalid'); - -// clock.tick(1); - -// expect(control).to.have.attribute('aria-invalid', 'true'); -// expect(screen.queryByText('error')).not.to.equal(null); -// }); -// }); - -// describe('style hooks', () => { -// describe('touched', () => { -// it('should apply [data-touched] style hook to all components when touched', async () => { -// await render( -// -// -// -// -// -// , -// ); - -// const root = screen.getByTestId('root'); -// const control = screen.getByTestId('control'); -// const label = screen.getByTestId('label'); -// const description = screen.getByTestId('description'); -// const error = screen.queryByTestId('error'); - -// expect(root).not.to.have.attribute('data-touched'); -// expect(control).not.to.have.attribute('data-touched'); -// expect(label).not.to.have.attribute('data-touched'); -// expect(description).not.to.have.attribute('data-touched'); -// expect(error).to.equal(null); - -// fireEvent.focus(control); -// fireEvent.blur(control); - -// expect(root).to.have.attribute('data-touched', 'true'); -// expect(control).to.have.attribute('data-touched', 'true'); -// expect(label).to.have.attribute('data-touched', 'true'); -// expect(description).to.have.attribute('data-touched', 'true'); -// expect(error).to.equal(null); -// }); - -// it('supports Checkbox', async () => { -// await render( -// -// -// , -// ); - -// const button = screen.getByTestId('button'); - -// fireEvent.focus(button); -// fireEvent.blur(button); - -// expect(button).to.have.attribute('data-touched', 'true'); -// }); - -// it('supports Switch', async () => { -// await render( -// -// -// , -// ); - -// const button = screen.getByTestId('button'); - -// fireEvent.focus(button); -// fireEvent.blur(button); - -// expect(button).to.have.attribute('data-touched', 'true'); -// }); - -// it('supports NumberField', async () => { -// await render( -// -// -// -// -// , -// ); - -// const input = screen.getByRole('textbox'); - -// fireEvent.focus(input); -// fireEvent.blur(input); - -// expect(input).to.have.attribute('data-touched', 'true'); -// }); - -// it('supports Slider', async () => { -// await render( -// -// -// -// -// -// -// , -// ); - -// const root = screen.getByTestId('root'); -// const thumb = screen.getByTestId('thumb'); - -// fireEvent.focus(thumb); -// fireEvent.blur(thumb); - -// expect(root).to.have.attribute('data-touched', 'true'); -// }); - -// it('supports Select', async () => { -// await render( -// -// -// -// -// -// Select -// Option 1 -// -// -// -// , -// ); - -// const trigger = screen.getByTestId('trigger'); - -// expect(trigger).not.to.have.attribute('data-dirty'); - -// fireEvent.focus(trigger); -// fireEvent.blur(trigger); - -// await flushMicrotasks(); - -// expect(trigger).to.have.attribute('data-touched', 'true'); -// }); - -// it('supports RadioGroup (click)', async () => { -// await render( -// -// -// -// One -// -// Two -// -// , -// ); - -// const group = screen.getByTestId('group'); -// const control = screen.getByTestId('control'); - -// fireEvent.click(control); - -// expect(group).to.have.attribute('data-touched', 'true'); -// expect(control).to.have.attribute('data-touched', 'true'); -// }); - -// it('supports RadioGroup (blur)', async () => { -// await render( -// -// -// -// One -// -// Two -// -//