diff --git a/apps/public-docsite-resources/src/components/DemoPage.types.ts b/apps/public-docsite-resources/src/components/DemoPage.types.ts
index 70f1a613de210..9679bbdf971a9 100644
--- a/apps/public-docsite-resources/src/components/DemoPage.types.ts
+++ b/apps/public-docsite-resources/src/components/DemoPage.types.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-extraneous-dependencies
export { IDocPageProps as IDemoPageProps } from '@fluentui/react-internal/lib/common/DocPage.types';
diff --git a/change/@fluentui-react-2020-10-21-16-15-31-tests-act.json b/change/@fluentui-react-2020-10-21-16-15-31-tests-act.json
new file mode 100644
index 0000000000000..339e461d046fc
--- /dev/null
+++ b/change/@fluentui-react-2020-10-21-16-15-31-tests-act.json
@@ -0,0 +1,8 @@
+{
+ "type": "none",
+ "comment": "Remove incorrect usage of expect.toBeDefined",
+ "packageName": "@fluentui/react",
+ "email": "elcraig@microsoft.com",
+ "dependentChangeType": "none",
+ "date": "2020-10-21T23:14:57.115Z"
+}
diff --git a/change/@fluentui-react-experiments-2020-10-21-16-15-31-tests-act.json b/change/@fluentui-react-experiments-2020-10-21-16-15-31-tests-act.json
new file mode 100644
index 0000000000000..e3ef47a39e3d0
--- /dev/null
+++ b/change/@fluentui-react-experiments-2020-10-21-16-15-31-tests-act.json
@@ -0,0 +1,8 @@
+{
+ "type": "none",
+ "comment": "Remove incorrect usage of expect.toBeDefined",
+ "packageName": "@fluentui/react-experiments",
+ "email": "elcraig@microsoft.com",
+ "dependentChangeType": "none",
+ "date": "2020-10-21T23:14:12.634Z"
+}
diff --git a/change/@fluentui-react-internal-2020-10-21-16-15-31-tests-act.json b/change/@fluentui-react-internal-2020-10-21-16-15-31-tests-act.json
new file mode 100644
index 0000000000000..db7b494d47ae8
--- /dev/null
+++ b/change/@fluentui-react-internal-2020-10-21-16-15-31-tests-act.json
@@ -0,0 +1,8 @@
+{
+ "type": "none",
+ "comment": "Remove incorrect usage of expect.toBeDefined + add missing act() in tests",
+ "packageName": "@fluentui/react-internal",
+ "email": "elcraig@microsoft.com",
+ "dependentChangeType": "none",
+ "date": "2020-10-21T23:14:42.523Z"
+}
diff --git a/change/@fluentui-react-next-2020-10-21-16-15-31-tests-act.json b/change/@fluentui-react-next-2020-10-21-16-15-31-tests-act.json
new file mode 100644
index 0000000000000..09286f1811279
--- /dev/null
+++ b/change/@fluentui-react-next-2020-10-21-16-15-31-tests-act.json
@@ -0,0 +1,8 @@
+{
+ "type": "none",
+ "comment": "Properly log and propagate async exceptions from tests",
+ "packageName": "@fluentui/react-next",
+ "email": "elcraig@microsoft.com",
+ "dependentChangeType": "none",
+ "date": "2020-10-21T23:14:51.914Z"
+}
diff --git a/change/@uifabric-date-time-2020-10-21-16-15-31-tests-act.json b/change/@uifabric-date-time-2020-10-21-16-15-31-tests-act.json
new file mode 100644
index 0000000000000..b47ca8fff4005
--- /dev/null
+++ b/change/@uifabric-date-time-2020-10-21-16-15-31-tests-act.json
@@ -0,0 +1,8 @@
+{
+ "type": "none",
+ "comment": "Remove incorrect usage of expect.toBeDefined",
+ "packageName": "@fluentui/react-date-time",
+ "email": "elcraig@microsoft.com",
+ "dependentChangeType": "none",
+ "date": "2020-10-21T23:13:49.132Z"
+}
diff --git a/change/@uifabric-utilities-2020-10-21-16-15-31-tests-act.json b/change/@uifabric-utilities-2020-10-21-16-15-31-tests-act.json
new file mode 100644
index 0000000000000..b57977d4b5966
--- /dev/null
+++ b/change/@uifabric-utilities-2020-10-21-16-15-31-tests-act.json
@@ -0,0 +1,8 @@
+{
+ "type": "prerelease",
+ "comment": "Async: update setTimeout to use internal error logging method",
+ "packageName": "@fluentui/utilities",
+ "email": "elcraig@microsoft.com",
+ "dependentChangeType": "patch",
+ "date": "2020-10-21T23:15:31.423Z"
+}
diff --git a/packages/a11y-testing/src/validators/validate.ts b/packages/a11y-testing/src/validators/validate.ts
index 53be7bc9c079d..40bbceaa97025 100644
--- a/packages/a11y-testing/src/validators/validate.ts
+++ b/packages/a11y-testing/src/validators/validate.ts
@@ -5,7 +5,6 @@ import { SlotRule } from './../rules/rules';
export const validateSlot = (rule: SlotRule, baseTestFacade: TestFacade): void => {
const slot = rule.getData();
const slotProps = slot.props || [{}];
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
slotProps.forEach((props: Props) => {
const testFacade = baseTestFacade.forProps(props);
diff --git a/packages/fluentui/e2e/.eslintrc.json b/packages/fluentui/e2e/.eslintrc.json
index b34ec5c034040..d18060309a88a 100644
--- a/packages/fluentui/e2e/.eslintrc.json
+++ b/packages/fluentui/e2e/.eslintrc.json
@@ -3,11 +3,7 @@
"root": true,
"rules": {
"import/no-default-export": "off",
- "import/no-extraneous-dependencies": [
- "error",
- {
- "devDependencies": true
- }
- ]
+ "import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
+ "no-console": "off"
}
}
diff --git a/packages/react-date-time/src/components/DatePicker/DatePicker.test.tsx b/packages/react-date-time/src/components/DatePicker/DatePicker.test.tsx
index 93a78f66f8a7b..c559e43076406 100644
--- a/packages/react-date-time/src/components/DatePicker/DatePicker.test.tsx
+++ b/packages/react-date-time/src/components/DatePicker/DatePicker.test.tsx
@@ -97,7 +97,7 @@ describe('DatePicker', () => {
const datePicker = mount();
const textField = datePicker.find('input');
- expect(textField).toBeDefined();
+ expect(textField).toHaveLength(1);
textField.simulate('change', { target: { value: 'Jan 1 2030' } }).simulate('blur');
textField.simulate('change', { target: { value: '' } }).simulate('blur');
diff --git a/packages/react-experiments/src/components/FloatingSuggestions/Suggestions/SuggestionsControl.tests.tsx b/packages/react-experiments/src/components/FloatingSuggestions/Suggestions/SuggestionsControl.test.tsx
similarity index 100%
rename from packages/react-experiments/src/components/FloatingSuggestions/Suggestions/SuggestionsControl.tests.tsx
rename to packages/react-experiments/src/components/FloatingSuggestions/Suggestions/SuggestionsControl.test.tsx
diff --git a/packages/react-experiments/src/components/SelectedItemsList/SelectedItemsList.test.tsx b/packages/react-experiments/src/components/SelectedItemsList/SelectedItemsList.test.tsx
index cf6d8a10f1dd4..f13545b793302 100644
--- a/packages/react-experiments/src/components/SelectedItemsList/SelectedItemsList.test.tsx
+++ b/packages/react-experiments/src/components/SelectedItemsList/SelectedItemsList.test.tsx
@@ -41,7 +41,7 @@ describe('SelectedItemsList', () => {
]}
/>,
);
- expect(wrapper).toBeDefined();
+ expect(wrapper.exists()).toBeTruthy();
expect(wrapper.find('div').length).toEqual(3);
expect(
wrapper
@@ -75,7 +75,7 @@ describe('SelectedItemsList', () => {
onItemsRemoved={removeItems}
/>,
);
- expect(wrapper).toBeDefined();
+ expect(wrapper.exists()).toBeTruthy();
expect(wrapper.find('div').length).toEqual(3);
expect(
wrapper
@@ -102,7 +102,7 @@ describe('SelectedItemsList', () => {
]}
/>,
);
- expect(wrapper).toBeDefined();
+ expect(wrapper.exists()).toBeTruthy();
expect(wrapper.find('div').length).toEqual(3);
expect(
wrapper
diff --git a/packages/react-internal/__mocks__/@fluentui/utilities.ts b/packages/react-internal/__mocks__/@fluentui/utilities.ts
index e88d4290a834c..e0c338e3413dc 100644
--- a/packages/react-internal/__mocks__/@fluentui/utilities.ts
+++ b/packages/react-internal/__mocks__/@fluentui/utilities.ts
@@ -41,6 +41,12 @@ class MockAsync extends Async {
super.dispose();
}
+
+ protected _logError(e: any) {
+ super._logError(e);
+ // Don't eat errors thrown from async callbacks
+ throw e;
+ }
}
export { MockAsync as Async };
diff --git a/packages/react-internal/src/compat/components/Button/Button.test.tsx b/packages/react-internal/src/compat/components/Button/Button.test.tsx
index e1cd21a6fed88..3b7b78669eb57 100644
--- a/packages/react-internal/src/compat/components/Button/Button.test.tsx
+++ b/packages/react-internal/src/compat/components/Button/Button.test.tsx
@@ -208,10 +208,8 @@ describe('Button', () => {
expect(button.getAttribute('aria-label')).toBeNull();
expect(button.getAttribute('aria-labelledby')).toEqual(button.querySelector(`.ms-Button-label`)!.id);
- expect(button.getAttribute('aria-labelledby')).toBeDefined();
expect(button.getAttribute('aria-describedby')).toEqual(button.querySelector('.some-screenreader-class')!.id);
- expect(button.getAttribute('aria-describedby')).toBeDefined();
});
it('applies aria-describedby to an IconButton', () => {
@@ -226,10 +224,8 @@ describe('Button', () => {
expect(button.getAttribute('aria-label')).toBeNull();
expect(button.getAttribute('aria-labelledby')).toBeNull();
- expect(button.getAttribute('aria-labelledby')).toBeDefined();
expect(button.getAttribute('aria-describedby')).toEqual(button.querySelector('.some-screenreader-class')!.id);
- expect(button.getAttribute('aria-describedby')).toBeDefined();
});
it('applies aria-labelledby and aria-describedby to a CompoundButton with ariaDescription', () => {
@@ -246,10 +242,8 @@ describe('Button', () => {
expect(button.getAttribute('aria-label')).toBeNull();
expect(button.getAttribute('aria-labelledby')).toEqual(button.querySelector('.ms-Button-label')!.id);
- expect(button.getAttribute('aria-labelledby')).toBeDefined();
expect(button.getAttribute('aria-describedby')).toEqual(button.querySelector('.some-screenreader-class')!.id);
- expect(button.getAttribute('aria-describedby')).toBeDefined();
});
it(
@@ -263,10 +257,8 @@ describe('Button', () => {
expect(button.getAttribute('aria-label')).toBeNull();
expect(button.getAttribute('aria-labelledby')).toEqual(button.querySelector('.ms-Button-label')!.id);
- expect(button.getAttribute('aria-labelledby')).toBeDefined();
expect(button.getAttribute('aria-describedby')).toEqual(button.querySelector('.ms-Button-description')!.id);
- expect(button.getAttribute('aria-describedby')).toBeDefined();
},
);
@@ -983,15 +975,14 @@ describe('Button', () => {
const button = render(element);
- expect(button).toBeDefined();
ReactTestUtils.Simulate.click(button);
// get the menu id from the button's aria attribute
const menuId = button.getAttribute('aria-owns');
- expect(menuId).toBeDefined();
+ expect(menuId).toBeTruthy();
const menuDOM = button.ownerDocument!.getElementById(menuId as string);
- expect(menuDOM).toBeDefined();
+ expect(menuDOM).toBeTruthy();
return menuDOM as HTMLElement;
}
@@ -1001,7 +992,7 @@ describe('Button', () => {
expect(contextualMenuElement).not.toBeNull();
expect(contextualMenuElement.getAttribute('aria-label')).toBeNull();
- expect(contextualMenuElement.getAttribute('aria-labelledBy')).toBeDefined();
+ expect(contextualMenuElement.getAttribute('aria-labelledBy')).toBeTruthy();
});
it('If button has a text child, contextual menu has aria-labelledBy attribute set', () => {
@@ -1048,12 +1039,11 @@ describe('Button', () => {
const button = render(element);
- expect(button).toBeDefined();
ReactTestUtils.Simulate.click(button);
// get the menu id from the button's aria attribute
const menuId = button.getAttribute('aria-owns');
- expect(menuId).toBeDefined();
+ expect(menuId).toBeTruthy();
const contextualMenuElement = button.ownerDocument!.getElementById(menuId as string);
expect(contextualMenuElement).not.toBeNull();
diff --git a/packages/react-internal/src/components/ChoiceGroup/ChoiceGroup.test.tsx b/packages/react-internal/src/components/ChoiceGroup/ChoiceGroup.test.tsx
index fb7cf60cd9f9b..a3f96781adf79 100644
--- a/packages/react-internal/src/components/ChoiceGroup/ChoiceGroup.test.tsx
+++ b/packages/react-internal/src/components/ChoiceGroup/ChoiceGroup.test.tsx
@@ -53,7 +53,7 @@ describe('ChoiceGroup', () => {
it('does not use className prop from parent on label', () => {
choiceGroup = mount();
const label = choiceGroup.getDOMNode().querySelector('label');
- expect(label).toBeDefined();
+ expect(label).toBeTruthy();
expect(label!.textContent).toBe('test label');
expect(label!.className).not.toContain('testClassName');
});
diff --git a/packages/react-internal/src/components/ColorPicker/ColorRectangle/ColorRectangle.test.tsx b/packages/react-internal/src/components/ColorPicker/ColorRectangle/ColorRectangle.test.tsx
index 79b3fa63fbe89..ae8e33577e1d2 100644
--- a/packages/react-internal/src/components/ColorPicker/ColorRectangle/ColorRectangle.test.tsx
+++ b/packages/react-internal/src/components/ColorPicker/ColorRectangle/ColorRectangle.test.tsx
@@ -71,7 +71,7 @@ describe('ColorRectangle', () => {
const descriptionId = element.getAttribute('aria-describedby');
expect(descriptionId).toBeTruthy();
const descriptionEl = element.querySelectorAll('#' + descriptionId)[0];
- expect(descriptionEl).toBeDefined();
+ expect(descriptionEl).toBeTruthy();
expect(descriptionEl.textContent).toBe(
'Use left and right arrow keys to set saturation. Use up and down arrow keys to set brightness.',
);
diff --git a/packages/react-internal/src/components/CommandBar/CommandBar.deprecated.test.tsx b/packages/react-internal/src/components/CommandBar/CommandBar.deprecated.test.tsx
index f5dbc01e12535..5fbccca86b73a 100644
--- a/packages/react-internal/src/components/CommandBar/CommandBar.deprecated.test.tsx
+++ b/packages/react-internal/src/components/CommandBar/CommandBar.deprecated.test.tsx
@@ -58,7 +58,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('keeps menu open after update if item is still present', () => {
@@ -87,7 +87,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
// Make sure the menu is open before the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
// Update the props, and re-render
commandBar.setProps({
@@ -100,7 +100,7 @@ describe('CommandBar', () => {
});
// Make sure the menu is still open after the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('closes menu after update if item is not longer present', () => {
@@ -129,7 +129,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
// Make sure the menu is open before the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
// Update the props, and re-render
commandBar.setProps({
@@ -164,7 +164,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
// Make sure the menu is open before the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
// Update the props
items[0].subMenuProps.items[0].className = 'SubMenuClassUpdate';
@@ -175,6 +175,6 @@ describe('CommandBar', () => {
});
// Make sure the menu is still open after the re-render
- expect(document.querySelector('.SubMenuClassUpdate')).toBeDefined();
+ expect(document.querySelector('.SubMenuClassUpdate')).toBeTruthy();
});
});
diff --git a/packages/react-internal/src/components/CommandBar/CommandBar.test.tsx b/packages/react-internal/src/components/CommandBar/CommandBar.test.tsx
index 5829f8892ed77..60206beeb7cb2 100644
--- a/packages/react-internal/src/components/CommandBar/CommandBar.test.tsx
+++ b/packages/react-internal/src/components/CommandBar/CommandBar.test.tsx
@@ -84,7 +84,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('passes event and item to button onClick callbacks', () => {
@@ -137,7 +137,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
// Make sure the menu is open before the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
// Update the props, and re-render
commandBar.setProps({
@@ -150,7 +150,7 @@ describe('CommandBar', () => {
});
// Make sure the menu is still open after the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('closes menu after update if item is not longer present', () => {
@@ -179,7 +179,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
// Make sure the menu is open before the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
// Update the props, and re-render
commandBar.setProps({
@@ -254,7 +254,7 @@ describe('CommandBar', () => {
menuItem.simulate('click');
// Make sure the menu is open before the re-render
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
// Update the props
items[0].subMenuProps.items[0].className = 'SubMenuClassUpdate';
@@ -265,6 +265,6 @@ describe('CommandBar', () => {
});
// Make sure the menu is still open after the re-render
- expect(document.querySelector('.SubMenuClassUpdate')).toBeDefined();
+ expect(document.querySelector('.SubMenuClassUpdate')).toBeTruthy();
});
});
diff --git a/packages/react-internal/src/components/ContextualMenu/ContextualMenu.deprecated.test.tsx b/packages/react-internal/src/components/ContextualMenu/ContextualMenu.deprecated.test.tsx
index a79818b1ced1e..917028627d10a 100644
--- a/packages/react-internal/src/components/ContextualMenu/ContextualMenu.deprecated.test.tsx
+++ b/packages/react-internal/src/components/ContextualMenu/ContextualMenu.deprecated.test.tsx
@@ -50,7 +50,10 @@ describe('ContextualMenu', () => {
});
it('includes the classNames on ContextualMenuItem(s)', () => {
- const items: IContextualMenuItem[] = [{ name: 'Test 1', key: 'Test1' }];
+ const items: IContextualMenuItem[] = [
+ { text: 'Header', key: 'Header', itemType: ContextualMenuItemType.Header },
+ { name: 'Test 1', key: 'Test1' },
+ ];
const getClassNames = () => {
return {
@@ -64,7 +67,7 @@ describe('ContextualMenu', () => {
};
ReactTestUtils.renderIntoDocument(
- ,
+ ,
);
const container = document.querySelector('.containerFoo') as HTMLElement;
@@ -73,11 +76,11 @@ describe('ContextualMenu', () => {
const header = document.querySelector('.headerFoo') as HTMLElement;
const title = document.querySelector('.titleFoo') as HTMLElement;
- expect(container).toBeDefined();
- expect(rootEl).toBeDefined();
- expect(list).toBeDefined();
- expect(header).toBeDefined();
- expect(title).toBeDefined();
+ expect(container).toBeTruthy();
+ expect(rootEl).toBeTruthy();
+ expect(list).toBeTruthy();
+ expect(header).toBeTruthy();
+ expect(title).toBeTruthy();
});
it('applies in-line style property if present on ContextualMenuItem', () => {
@@ -260,7 +263,7 @@ describe('ContextualMenu', () => {
ReactTestUtils.Simulate.keyDown(menuItem, { which: KeyCodes.right });
});
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
});
@@ -291,7 +294,7 @@ describe('getItemClassNames', () => {
iconClassName,
);
- expect(itemClassNames).toBeDefined();
+ expect(itemClassNames).toBeTruthy();
});
it('applies custom classNames to style slots', () => {
diff --git a/packages/react-internal/src/components/ContextualMenu/ContextualMenu.test.tsx b/packages/react-internal/src/components/ContextualMenu/ContextualMenu.test.tsx
index 18b873f7d991f..217017172164a 100644
--- a/packages/react-internal/src/components/ContextualMenu/ContextualMenu.test.tsx
+++ b/packages/react-internal/src/components/ContextualMenu/ContextualMenu.test.tsx
@@ -314,7 +314,7 @@ describe('ContextualMenu', () => {
ReactTestUtils.Simulate.keyDown(menuItem, { which: KeyCodes.right });
});
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('opens a submenu item on click', () => {
@@ -344,7 +344,7 @@ describe('ContextualMenu', () => {
ReactTestUtils.Simulate.click(menuItem);
});
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('opens a submenu item on alt+Down', () => {
@@ -372,7 +372,7 @@ describe('ContextualMenu', () => {
ReactTestUtils.Simulate.keyDown(menuItem, { which: KeyCodes.down, altKey: true });
});
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('closes a submenu item on alt+up', () => {
@@ -525,7 +525,7 @@ describe('ContextualMenu', () => {
menuList = document.querySelectorAll('ul.ms-ContextualMenu-list');
expect(menuList.length).toEqual(2);
- expect(document.querySelector('.SubMenuClass')).toBeDefined();
+ expect(document.querySelector('.SubMenuClass')).toBeTruthy();
});
it('opens a splitbutton submenu item on touch start', () => {
@@ -909,7 +909,7 @@ describe('ContextualMenu', () => {
});
const callout = document.querySelector('.ms-Callout') as HTMLElement;
- expect(callout).toBeDefined();
+ expect(callout).toBeTruthy();
expect(callout.classList.contains('ms-ContextualMenu-Callout')).toBeTruthy();
expect(callout.classList.contains('foo')).toBeTruthy();
});
@@ -1440,6 +1440,7 @@ describe('ContextualMenu', () => {
const items: IContextualMenuItem[] = [
{ text: 'TestText 1', key: 'TestKey1', canCheck: true, isChecked: true },
{ text: 'TestText 2', key: 'TestKey2', canCheck: true, isChecked: true },
+ { text: 'Header', key: 'Header', itemType: ContextualMenuItemType.Header },
{ text: 'TestText 3', key: 'TestKey3', canCheck: true, isChecked: true },
{ text: 'TestText 4', key: 'TestKey4', canCheck: true, isChecked: true },
];
@@ -1457,7 +1458,7 @@ describe('ContextualMenu', () => {
ReactTestUtils.act(() => {
ReactTestUtils.renderIntoDocument(
- ,
+ ,
);
});
@@ -1467,11 +1468,11 @@ describe('ContextualMenu', () => {
const header = document.querySelector('.ms-ContextualMenu-header') as HTMLElement;
const title = document.querySelector('.ms-ContextualMenu-title') as HTMLElement;
- expect(container).toBeDefined();
- expect(rootEl).toBeDefined();
- expect(list).toBeDefined();
- expect(header).toBeDefined();
- expect(title).toBeDefined();
+ expect(container).toBeTruthy();
+ expect(rootEl).toBeTruthy();
+ expect(list).toBeTruthy();
+ expect(header).toBeTruthy();
+ expect(title).toBeTruthy();
});
it('applies styles per ContextualMenuItem if provided', () => {
diff --git a/packages/react-internal/src/components/FloatingPicker/Suggestions/SuggestionsControl.tests.tsx b/packages/react-internal/src/components/FloatingPicker/Suggestions/SuggestionsControl.test.tsx
similarity index 100%
rename from packages/react-internal/src/components/FloatingPicker/Suggestions/SuggestionsControl.tests.tsx
rename to packages/react-internal/src/components/FloatingPicker/Suggestions/SuggestionsControl.test.tsx
diff --git a/packages/react-internal/src/components/HoverCard/HoverCard.test.tsx b/packages/react-internal/src/components/HoverCard/HoverCard.test.tsx
index e3b9a82840f0a..2839440588109 100644
--- a/packages/react-internal/src/components/HoverCard/HoverCard.test.tsx
+++ b/packages/react-internal/src/components/HoverCard/HoverCard.test.tsx
@@ -149,7 +149,7 @@ describe('HoverCard', () => {
);
jest.useFakeTimers();
- expect(hoverCard).toBeDefined();
+ expect(hoverCard).toBeTruthy();
// firing the onCardVisible callback after the component is updated.
component.setState({ isHoverCardVisible: true });
diff --git a/packages/react-internal/src/components/Image/Image.test.tsx b/packages/react-internal/src/components/Image/Image.test.tsx
index 86a4e0ec66ae1..94160851ec65e 100644
--- a/packages/react-internal/src/components/Image/Image.test.tsx
+++ b/packages/react-internal/src/components/Image/Image.test.tsx
@@ -3,7 +3,7 @@ import * as React from 'react';
import { create } from '@fluentui/utilities/lib/test';
import { Image } from './Image';
import { ImageBase } from './Image.base';
-import { ImageFit } from './Image.types';
+import { ImageFit, ImageCoverStyle } from './Image.types';
import { act } from 'react-dom/test-utils';
import { isConformant } from '../../common/isConformant';
@@ -68,7 +68,13 @@ describe('Image', () => {
it('can cover a landscape (wide) parent element with a square image', () => {
const component = mount(
-
+
,
);
@@ -79,13 +85,19 @@ describe('Image', () => {
component.find('img').simulate('load');
});
- expect(component.getDOMNode().querySelector('.ms-Image-image--portrait')).toBeDefined();
+ expect(component.getDOMNode().querySelector('.ms-Image-image--portrait')).toBeTruthy();
});
it('can cover a portrait (tall) parent element with a square image', () => {
const component = mount(
-
+
,
);
@@ -96,7 +108,7 @@ describe('Image', () => {
act(() => {
component.find('img').simulate('load');
});
- expect(component.getDOMNode().querySelector('.ms-Image-image--landscape')).toBeDefined();
+ expect(component.getDOMNode().querySelector('.ms-Image-image--landscape')).toBeTruthy();
});
it('renders ImageFit.centerContain correctly', () => {
diff --git a/packages/react-internal/src/components/Layer/Layer.test.tsx b/packages/react-internal/src/components/Layer/Layer.test.tsx
index a9bcbc4fd6527..eb3ecb7772ac1 100644
--- a/packages/react-internal/src/components/Layer/Layer.test.tsx
+++ b/packages/react-internal/src/components/Layer/Layer.test.tsx
@@ -74,8 +74,8 @@ describe('Layer', () => {
const parentElement = appElement.querySelector('#parent');
- expect(parentElement).toBeDefined();
- expect(parentElement!.ownerDocument).toBeDefined();
+ expect(parentElement).toBeTruthy();
+ expect(parentElement!.ownerDocument).toBeTruthy();
const childElement = appElement.querySelector('#child') as Element;
diff --git a/packages/react-internal/src/components/OverflowSet/OverflowSet.test.tsx b/packages/react-internal/src/components/OverflowSet/OverflowSet.test.tsx
index c3adca70ec0dd..6af2be8a00ba3 100644
--- a/packages/react-internal/src/components/OverflowSet/OverflowSet.test.tsx
+++ b/packages/react-internal/src/components/OverflowSet/OverflowSet.test.tsx
@@ -2,6 +2,7 @@ import { shallow } from 'enzyme';
import { ReactWrapper, mount } from 'enzyme';
import * as React from 'react';
import { create } from '@fluentui/utilities/lib/test';
+import * as ReactTestUtils from 'react-dom/test-utils';
import * as sinon from 'sinon';
import { CommandBarButton } from '../../compat/Button';
import { IKeytipProps } from '../../Keytip';
@@ -33,6 +34,11 @@ function getPersistedKeytip(keytipManager: KeytipManager, keySequences: string[]
return ktp ? ktp.keytip : undefined;
}
+const runAllTimers = () =>
+ ReactTestUtils.act(() => {
+ jest.runAllTimers();
+ });
+
describe('OverflowSet', () => {
describe('snapshot tests', () => {
test('basicSnapshot', () => {
@@ -287,7 +293,7 @@ describe('OverflowSet', () => {
keytipTree.currentKeytip = keytipTree.root;
// Open the overflow menu
layerRef.current!.processInput('x');
- jest.runAllTimers();
+ runAllTimers();
// Opening the submenu should register the two keytips for those items
const keytip3 = getKeytip(keytipManager, ['c']);
@@ -328,7 +334,7 @@ describe('OverflowSet', () => {
keytipTree.currentKeytip = keytipTree.root;
// Open the overflow menu
layerRef.current!.processInput('x');
- jest.runAllTimers();
+ runAllTimers();
// item3
const item3Keytip = getKeytip(keytipManager, overflowKeytips.overflowItemKeytip3.keySequences);
@@ -509,7 +515,7 @@ describe('OverflowSet', () => {
const subMenu6Keytip = getKeytip(keytipManager, modifiedKeytip6Sequence);
expect(subMenu6Keytip).toBeDefined();
expect(subMenu6Keytip!.overflowSetSequence![0]).toEqual('x');
- jest.runAllTimers();
+ runAllTimers();
// Those two keytips should now be visible in the Layer and have overflowSetSequence set
const submenuKeytips = layerRef.current!.state.visibleKeytips;
@@ -605,7 +611,7 @@ describe('OverflowSet', () => {
keytipTree.currentKeytip = keytipTree.root;
layerRef.current!.processInput('d');
// Wait for the menu to open
- jest.runAllTimers();
+ runAllTimers();
// Those two keytips should now be visible in the Layer and have overflowSetSequence set
const submenuKeytips = layerRef.current!.state.visibleKeytips;
@@ -688,7 +694,6 @@ describe('OverflowSet', () => {
keytipTree.currentKeytip = keytipTree.root;
layerRef.current!.processInput('d');
- jest.runAllTimers();
// Those two keytips should now be visible in the Layer and have overflowSetSequence set
const submenuKeytips = layerRef.current!.state.visibleKeytips;
diff --git a/packages/react-internal/src/components/TeachingBubble/TeachingBubble.test.tsx b/packages/react-internal/src/components/TeachingBubble/TeachingBubble.test.tsx
index de1dab77740ba..8f611094899d4 100644
--- a/packages/react-internal/src/components/TeachingBubble/TeachingBubble.test.tsx
+++ b/packages/react-internal/src/components/TeachingBubble/TeachingBubble.test.tsx
@@ -138,7 +138,7 @@ describe('TeachingBubble', () => {
ReactTestUtils.renderIntoDocument();
setTimeout(() => {
const callout = document.querySelector('.ms-Callout') as HTMLElement;
- expect(callout).toBeDefined();
+ expect(callout).toBeTruthy();
expect(callout.classList.contains('ms-TeachingBubble')).toBeTruthy();
expect(callout.classList.contains('foo')).toBeTruthy();
}, 0);
diff --git a/packages/react-internal/src/components/TextField/TextField.test.tsx b/packages/react-internal/src/components/TextField/TextField.test.tsx
index a7207b5925b83..9763d82935bfb 100644
--- a/packages/react-internal/src/components/TextField/TextField.test.tsx
+++ b/packages/react-internal/src/components/TextField/TextField.test.tsx
@@ -202,7 +202,7 @@ describe('TextField basic props', () => {
const labelDOM = wrapper.getDOMNode().querySelector('label');
// Assert the input ID and label FOR attribute are the same.
- expect(inputDOM!.id).toBeDefined();
+ expect(inputDOM!.id).toBeTruthy();
expect(inputDOM!.id).toEqual(labelDOM!.htmlFor);
});
@@ -769,7 +769,7 @@ describe('TextField', () => {
const onSelect = () => {
const selectedText = window.getSelection();
- expect(selectedText).toBeDefined();
+ expect(selectedText).toBeTruthy();
expect(selectedText!.toString()).toEqual(initialValue);
};
diff --git a/packages/react-internal/src/components/pickers/BasePicker.test.tsx b/packages/react-internal/src/components/pickers/BasePicker.test.tsx
index 863d8380194de..ceb81aca15562 100644
--- a/packages/react-internal/src/components/pickers/BasePicker.test.tsx
+++ b/packages/react-internal/src/components/pickers/BasePicker.test.tsx
@@ -68,6 +68,11 @@ describe('BasePicker', () => {
{basicRenderer(props)}
);
+ const runAllTimers = () =>
+ ReactTestUtils.act(() => {
+ jest.runAllTimers();
+ });
+
it('renders correctly', () => {
const component = renderer.create(
{
input.focus();
input.value = 'bl';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
- expect(getSuggestions(document)).toBeDefined();
+ expect(getSuggestions(document)).toBeTruthy();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
expect(suggestionOptions.length).toEqual(2);
@@ -169,9 +174,9 @@ describe('BasePicker', () => {
input.focus();
input.value = 'asdff';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
- expect(getSuggestions(document)).toBeDefined();
+ expect(getSuggestions(document)).toBeTruthy();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
expect(suggestionOptions.length).toEqual(0);
@@ -220,9 +225,9 @@ describe('BasePicker', () => {
input.focus();
input.value = 'asdff';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
- expect(getSuggestions(document)).toBeDefined();
+ expect(getSuggestions(document)).toBeTruthy();
const forceButton = document.querySelectorAll('[data-automationid=sug-forceResolve]');
expect(forceButton.length).toEqual(1);
@@ -254,7 +259,7 @@ describe('BasePicker', () => {
input.focus();
input.value = 'bl';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
ReactTestUtils.Simulate.click(suggestionOptions[0]);
@@ -330,7 +335,7 @@ describe('BasePicker', () => {
const input = document.querySelector('.ms-BasePicker-input') as HTMLInputElement;
input.focus();
- expect(getSuggestions(document)).toBeDefined();
+ expect(getSuggestions(document)).toBeTruthy();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
expect(suggestionOptions.length).toEqual(15);
@@ -359,7 +364,7 @@ describe('BasePicker', () => {
input.focus();
input.value = 'asdff';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
expect(getSuggestions(document)).toBeTruthy();
@@ -388,7 +393,7 @@ describe('BasePicker', () => {
input.focus();
input.value = 'asdff';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
expect(getSuggestions(document)).toBeTruthy();
@@ -397,12 +402,13 @@ describe('BasePicker', () => {
expect(getSuggestions(document)).toBeFalsy();
ReactTestUtils.Simulate.click(input, { button: 0 });
- jest.runAllTimers();
+ runAllTimers();
expect(getSuggestions(document)).toBeTruthy();
});
it('Opens menu when input refocused after search has happened', () => {
+ expect(getSuggestions(document)).toBeFalsy();
jest.useFakeTimers();
document.body.appendChild(root);
@@ -425,7 +431,10 @@ describe('BasePicker', () => {
input.focus();
input.value = 'bl';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ // For some reason with act() this has to be run twice to make the callout dismiss callback
+ // actually be called?
+ runAllTimers();
+ runAllTimers();
expect(getSuggestions(document)).toBeTruthy();
@@ -434,9 +443,9 @@ describe('BasePicker', () => {
// Implicit test to ensure suggestions are dismissed when focus lost
expect(getSuggestions(document)).toBeFalsy();
- jest.runAllTimers();
+ runAllTimers();
input.focus();
- jest.runAllTimers();
+ runAllTimers();
expect(getSuggestions(document)).toBeTruthy();
});
@@ -465,7 +474,7 @@ describe('BasePicker', () => {
const input = document.querySelector('.ms-BasePicker-input') as HTMLInputElement;
input.focus();
- jest.runAllTimers();
+ runAllTimers();
expect(count).toEqual(1);
@@ -507,9 +516,9 @@ describe('BasePicker', () => {
input.focus();
input.value = 'b';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
- expect(getSuggestions(document)).toBeDefined();
+ expect(getSuggestions(document)).toBeTruthy();
const moreButton = document.querySelector('[data-automationid=sug-searchForMore]') as HTMLElement;
expect(moreButton).toBeTruthy();
diff --git a/packages/react-internal/src/components/pickers/PeoplePicker/PeoplePicker.test.tsx b/packages/react-internal/src/components/pickers/PeoplePicker/PeoplePicker.test.tsx
index 9d5d1cb006d47..ace1c125c5524 100644
--- a/packages/react-internal/src/components/pickers/PeoplePicker/PeoplePicker.test.tsx
+++ b/packages/react-internal/src/components/pickers/PeoplePicker/PeoplePicker.test.tsx
@@ -47,10 +47,12 @@ describe('PeoplePicker', () => {
input.value = 'Valentyna';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ ReactTestUtils.act(() => {
+ jest.runAllTimers();
+ });
const suggestions = document.querySelector('.ms-Suggestions') as HTMLInputElement;
- expect(suggestions).toBeDefined();
+ expect(suggestions).toBeTruthy();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
expect(suggestionOptions.length).toEqual(1);
@@ -61,7 +63,7 @@ describe('PeoplePicker', () => {
expect(currentPicker![0].text).toEqual('Valentyna Lovrique');
const removeButton = document.querySelector('.ms-PickerItem-removeButton') as HTMLButtonElement;
- expect(removeButton).toBeDefined();
+ expect(removeButton).toBeTruthy();
ReactTestUtils.Simulate.click(removeButton);
const currentPickerAfterRemove = picker.current!.items;
@@ -70,7 +72,7 @@ describe('PeoplePicker', () => {
ReactDOM.unmountComponentAtNode(root);
});
- it('can not remove people when disabled', () => {
+ it('cannot remove people when disabled', () => {
const root = document.createElement('div');
document.body.appendChild(root);
@@ -90,7 +92,7 @@ describe('PeoplePicker', () => {
expect(currentPicker).toHaveLength(1);
const removeButton = document.querySelector('.ms-PickerItem-removeButton') as HTMLButtonElement;
- expect(removeButton).toBeDefined();
+ expect(removeButton).toBeTruthy();
ReactTestUtils.Simulate.click(removeButton);
const currentPickerAfterClick = picker.current!.items;
diff --git a/packages/react-internal/src/components/pickers/TagPicker/TagPicker.test.tsx b/packages/react-internal/src/components/pickers/TagPicker/TagPicker.test.tsx
index 3da3f24aec14a..6a1187abb80d8 100644
--- a/packages/react-internal/src/components/pickers/TagPicker/TagPicker.test.tsx
+++ b/packages/react-internal/src/components/pickers/TagPicker/TagPicker.test.tsx
@@ -31,6 +31,11 @@ function onResolveSuggestions(text: string): ITag[] {
.map(item => ({ key: item, name: item }));
}
+const runAllTimers = () =>
+ ReactTestUtils.act(() => {
+ jest.runAllTimers();
+ });
+
describe('TagPicker', () => {
beforeEach(() => {
resetIds();
@@ -74,11 +79,11 @@ describe('TagPicker', () => {
input.value = 'bl';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
const suggestions = document.querySelector('.ms-Suggestions') as HTMLInputElement;
- expect(suggestions).toBeDefined();
+ expect(suggestions).toBeTruthy();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
expect(suggestionOptions.length).toEqual(2);
@@ -108,7 +113,7 @@ describe('TagPicker', () => {
input.focus();
input.value = 'bl';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
@@ -152,7 +157,7 @@ describe('TagPicker', () => {
input.focus();
input.value = 'bl';
ReactTestUtils.Simulate.input(input);
- jest.runAllTimers();
+ runAllTimers();
const suggestionOptions = document.querySelectorAll('.ms-Suggestions-itemButton');
diff --git a/packages/react-internal/src/utilities/decorators/withResponsiveMode.test.tsx b/packages/react-internal/src/utilities/decorators/withResponsiveMode.test.tsx
index 5a2e69d078d6c..1117de25e57fd 100644
--- a/packages/react-internal/src/utilities/decorators/withResponsiveMode.test.tsx
+++ b/packages/react-internal/src/utilities/decorators/withResponsiveMode.test.tsx
@@ -15,7 +15,7 @@ describe('withResponsiveMode', () => {
setSSR(true);
setResponsiveMode(ResponsiveMode.large);
- expect(() => ReactTestUtils.renderIntoDocument()).toBeDefined();
+ expect(() => ReactTestUtils.renderIntoDocument()).toBeTruthy();
setSSR(false);
});
diff --git a/packages/react-next/__mocks__/@fluentui/utilities.ts b/packages/react-next/__mocks__/@fluentui/utilities.ts
index e88d4290a834c..07031ae7eaa0d 100644
--- a/packages/react-next/__mocks__/@fluentui/utilities.ts
+++ b/packages/react-next/__mocks__/@fluentui/utilities.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
export * from '@fluentui/utilities';
import { Async } from '@fluentui/utilities';
@@ -41,6 +42,12 @@ class MockAsync extends Async {
super.dispose();
}
+
+ protected _logError(e: any) {
+ super._logError(e);
+ // Don't eat errors thrown from async callbacks
+ throw e;
+ }
}
export { MockAsync as Async };
diff --git a/packages/react/__mocks__/@fluentui/utilities.ts b/packages/react/__mocks__/@fluentui/utilities.ts
index e88d4290a834c..e0c338e3413dc 100644
--- a/packages/react/__mocks__/@fluentui/utilities.ts
+++ b/packages/react/__mocks__/@fluentui/utilities.ts
@@ -41,6 +41,12 @@ class MockAsync extends Async {
super.dispose();
}
+
+ protected _logError(e: any) {
+ super._logError(e);
+ // Don't eat errors thrown from async callbacks
+ throw e;
+ }
}
export { MockAsync as Async };
diff --git a/packages/react/src/components/ComboBox/ComboBox.test.tsx b/packages/react/src/components/ComboBox/ComboBox.test.tsx
index 4986bf030d389..386513426c66a 100644
--- a/packages/react/src/components/ComboBox/ComboBox.test.tsx
+++ b/packages/react/src/components/ComboBox/ComboBox.test.tsx
@@ -80,7 +80,7 @@ describe('ComboBox', () => {
it(`renders`, () => {
safeCreate(, wrapper => {
- expect(wrapper.root).toBeDefined();
+ expect(wrapper.root).toBeTruthy();
});
});
@@ -693,7 +693,7 @@ describe('ComboBox', () => {
});
const callout = container.root.find(node => node.props?.className?.split?.(' ').includes?.('ms-Callout'));
- expect(callout).toBeDefined();
+ expect(callout).toBeTruthy();
expect(callout.props.className.includes('ms-ComboBox-callout')).toBeTruthy();
expect(callout.props.className.includes('foo')).toBeTruthy();
},
@@ -922,7 +922,7 @@ describe('ComboBox', () => {
// Find menu
const calloutBeforeOpen = findNodeWithClass(container, 'ms-Callout');
- expect(calloutBeforeOpen).toBeDefined();
+ expect(calloutBeforeOpen).toBeTruthy();
expect(calloutBeforeOpen?.props?.className?.includes?.('ms-ComboBox-callout')).toBeTruthy();
// Open combobox
@@ -940,7 +940,7 @@ describe('ComboBox', () => {
// Ensure menu is still there
const calloutAfterClose = findNodeWithClass(container, 'ms-Callout');
- expect(calloutAfterClose).toBeDefined();
+ expect(calloutAfterClose).toBeTruthy();
expect(calloutBeforeOpen?.props?.className?.includes?.('ms-ComboBox-callout')).toBeTruthy();
},
);
diff --git a/packages/react/src/components/DetailsList/DetailsList.test.tsx b/packages/react/src/components/DetailsList/DetailsList.test.tsx
index 7ea396bc76fa1..f1bfd502b5d57 100644
--- a/packages/react/src/components/DetailsList/DetailsList.test.tsx
+++ b/packages/react/src/components/DetailsList/DetailsList.test.tsx
@@ -168,7 +168,7 @@ describe('DetailsList', () => {
it('focuses row by index', () => {
jest.useFakeTimers();
- let component: any;
+ let component: IDetailsList | null;
safeMount(
{
onShouldVirtualize={() => false}
/>,
() => {
- expect(component).toBeDefined();
- (component as IDetailsList).focusIndex(2);
+ expect(component).toBeTruthy();
+ component!.focusIndex(2);
setTimeout(() => {
expect(
(document.activeElement as HTMLElement).querySelector('[data-automationid=DetailsRowCell]')!.textContent,
@@ -330,7 +330,7 @@ describe('DetailsList', () => {
jest.useFakeTimers();
- let component: any;
+ let component: IDetailsList | null;
safeMount(
{
getCellValueKey={getCellValueKey}
/>,
() => {
- expect(component).toBeDefined();
- (component as IDetailsList).focusIndex(3);
+ expect(component).toBeTruthy();
+ component!.focusIndex(3);
jest.runOnlyPendingTimers();
expect(
(document.activeElement as HTMLElement).querySelector('[data-automationid=DetailsRowCell]')!.textContent,
@@ -379,7 +379,7 @@ describe('DetailsList', () => {
onShouldVirtualize={() => false}
/>,
(wrapper: ReactWrapper) => {
- expect(component).toBeDefined();
+ expect(component).toBeTruthy();
component.setState({ focusedItemIndex: 3 });
setTimeout(() => {
expect(component.state.focusedItemIndex).toEqual(3);
diff --git a/packages/utilities/src/Async.ts b/packages/utilities/src/Async.ts
index 74185e4e09be7..c457053a6ac4a 100644
--- a/packages/utilities/src/Async.ts
+++ b/packages/utilities/src/Async.ts
@@ -109,9 +109,7 @@ export class Async {
}
callback.apply(this._parent);
} catch (e) {
- if (this._onErrorHandler) {
- this._onErrorHandler(e);
- }
+ this._logError(e);
}
}, duration);
diff --git a/packages/utilities/src/BaseComponent.test.tsx b/packages/utilities/src/BaseComponent.test.tsx
index 49215a39f1c44..74bb466872515 100644
--- a/packages/utilities/src/BaseComponent.test.tsx
+++ b/packages/utilities/src/BaseComponent.test.tsx
@@ -20,6 +20,6 @@ describe('BaseComponent', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any;
- expect(component.root).toBeDefined();
+ expect(component.root).toBeTruthy();
});
});
diff --git a/scripts/jest/jest-setup.js b/scripts/jest/jest-setup.js
index 5ad4372a938de..f82e510743c67 100644
--- a/scripts/jest/jest-setup.js
+++ b/scripts/jest/jest-setup.js
@@ -14,10 +14,37 @@ function customError(type, ...args) {
consoleError(...args);
}
- if (args.length === 1 && typeof args[0] === 'object' && args[0].stack) {
+ let processedArgs = args;
+ // console.log messages can include substitution tokens such as %s (React uses this).
+ // Attempt a very naive replacement of those tokens when throwing the error.
+ if (args.length > 1 && typeof args[0] === 'string' && /%[dfioOs]/.test(args[0])) {
+ let unprocessedArgs = args.slice(1);
+ let message = /** @type {string} */ (args[0]);
+ if (message.startsWith('Warning: An update to %s inside a test was not wrapped in act')) {
+ // trim less-useful parts of this message from the exception (they'll still be in the log)
+ message = message.replace(
+ /^Warning: [\s\S]+would see in the browser\./,
+ `Warning: An update to ${args[1]} inside a test was not wrapped in act(...).`,
+ );
+ unprocessedArgs = [];
+ }
+ processedArgs = [
+ message.replace(/%[dfioOs]/g, () => {
+ const nextArg = unprocessedArgs.shift();
+ return nextArg === undefined
+ ? ''
+ : nextArg && typeof nextArg === 'object'
+ ? JSON.stringify(nextArg, null, 2) // avoid "[object Object]"
+ : nextArg; // everything else just use default formatting
+ }),
+ ];
+ processedArgs.push(...unprocessedArgs);
+ }
+
+ if (processedArgs.length === 1 && typeof processedArgs[0] === 'object' && processedArgs[0].stack) {
// If the "message" was an exception, re-throw it to get the full stack trace
- throw args[0];
+ throw processedArgs[0];
} else {
- throw new Error(`[console.${type}] ${args.join(' ')}`);
+ throw new Error(`[console.${type}] ${processedArgs.join(' ')}`);
}
}