diff --git a/packages/react-aria-components/test/Select.test.js b/packages/react-aria-components/test/Select.test.js
index df4906037d2..a14bfb2cbce 100644
--- a/packages/react-aria-components/test/Select.test.js
+++ b/packages/react-aria-components/test/Select.test.js
@@ -95,6 +95,112 @@ describe('Select', () => {
expect(trigger).toHaveTextContent('Dog');
});
+ it('should bubble a change event from the hidden select when a ListBox option is selected', async () => {
+ let onChange = jest.fn();
+ let {getByTestId} = render(
+
+ );
+ let wrapper = getByTestId('select');
+ let selectTester = testUtilUser.createTester('Select', {root: wrapper});
+ let hiddenSelect = document.querySelector('select[name="animal"]');
+
+ await selectTester.toggleOptionSelection({option: 'Dog'});
+
+ expect(onChange).toHaveBeenCalledTimes(1);
+ expect(onChange).toHaveBeenCalledWith(hiddenSelect);
+ expect(hiddenSelect).toHaveValue('dog');
+ });
+
+ it('should bubble a native change event from the hidden select only once', async () => {
+ let onChange = jest.fn();
+ render(
+
+ );
+ let hiddenSelect = document.querySelector('select[name="animal"]');
+
+ await user.selectOptions(hiddenSelect, 'dog');
+
+ expect(onChange).toHaveBeenCalledTimes(1);
+ expect(onChange).toHaveBeenCalledWith(hiddenSelect);
+ expect(hiddenSelect).toHaveValue('dog');
+ });
+
+ it('should bubble a change event for a controlled select', async () => {
+ let onChange = jest.fn();
+ let values = [];
+
+ function ControlledSelect() {
+ let [value, setValue] = useState('cat');
+ return (
+ {
+ onChange(value);
+ setValue(value);
+ }}
+ />
+ );
+ }
+
+ let {getByTestId} = render(
+
+ );
+ let wrapper = getByTestId('select');
+ let selectTester = testUtilUser.createTester('Select', {root: wrapper});
+ let hiddenSelect = document.querySelector('select[name="animal"]');
+
+ await selectTester.toggleOptionSelection({option: 'Dog'});
+
+ expect(onChange).toHaveBeenCalledWith('dog');
+ expect(values).toEqual(['dog']);
+ expect(hiddenSelect).toHaveValue('dog');
+ });
+
+ it('should not bubble a change event when the form is reset', async () => {
+ let onChange = jest.fn();
+ let formRef = React.createRef();
+ let {getByTestId} = render(
+
+ );
+ let wrapper = getByTestId('select');
+ let selectTester = testUtilUser.createTester('Select', {root: wrapper});
+ let hiddenSelect = document.querySelector('select[name="animal"]');
+
+ await selectTester.toggleOptionSelection({option: 'Dog'});
+ expect(onChange).toHaveBeenCalledTimes(1);
+ onChange.mockClear();
+
+ act(() => formRef.current.reset());
+
+ expect(onChange).not.toHaveBeenCalled();
+ expect(hiddenSelect).toHaveValue('cat');
+ });
+
+ it('should bubble change events with the selected options for multiple selection', async () => {
+ let values = [];
+ let {getByTestId} = render(
+
+ );
+ let wrapper = getByTestId('select');
+ let selectTester = testUtilUser.createTester('Select', {root: wrapper});
+
+ await selectTester.toggleOptionSelection({option: 'Cat'});
+ await selectTester.toggleOptionSelection({option: 'Dog'});
+
+ expect(values).toEqual([['cat'], ['cat', 'dog']]);
+ });
+
it('should support slot', () => {
let {getByTestId} = render(
@@ -748,12 +854,16 @@ describe('Select', () => {
it('should support multiple selection form integration with many items', async () => {
let items = [];
+ let values = [];
for (let i = 0; i < 320; i++) {
items.push({id: i, name: 'item' + i});
}
let {getByTestId} = render(
-