Skip to content

Commit

Permalink
fix: updates should be synchronous in unit tests (microsoft#30014)
Browse files Browse the repository at this point in the history
* fix: updates should be synchronous in unit tests

React testing platforms will often output errors when state updates happen outside `act`
Since there is nothing obvious to wait for we just avoid debouncing
in unit test environments.

Adds tests to make sure that the synchronous update only happens in test
environment

* changefile

* Update packages/react-components/react-overflow/src/components/Overflow.test.tsx
  • Loading branch information
ling1726 committed Dec 7, 2023
1 parent a704aac commit 841ad6a
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: updates should be synchronous in unit tests",
"packageName": "@fluentui/priority-overflow",
"email": "lingfangao@hotmail.com",
"dependentChangeType": "patch"
}
35 changes: 35 additions & 0 deletions packages/react-components/priority-overflow/src/debounce.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { debounce } from './debounce';

describe('debounce', () => {
const tick = () => new Promise(res => setTimeout(res, 0));

beforeAll(() => {
// Remove NODE_ENV = 'test' to properly test debounce feature
process.env.NODE_ENV = 'production';
});

afterAll(() => {
process.env.NODE_ENV = 'test';
});

it('will only run once per tick', async () => {
let count = 0;
const debounced = debounce(() => count++);

for (let i = 0; i < 1000; i++) {
debounced();
}

await tick();

expect(count).toBe(1);

for (let i = 0; i < 1000; i++) {
debounced();
}

await tick();

expect(count).toBe(2);
});
});
7 changes: 7 additions & 0 deletions packages/react-components/priority-overflow/src/debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
*/
export function debounce(fn: Function) {
let pending: boolean;

// React testing platforms will often output errors when state updates happen outside `act`
// Since there is nothing obvious to wait for we just avoid debouncing in unit test environments
if (process.env.NODE_ENV === 'test') {
return fn as () => void;
}

return () => {
if (!pending) {
pending = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { Overflow } from './Overflow';
import { OverflowItem } from './OverflowItem';
describe('Overflow', () => {
beforeAll(() => {
// https://github.com/jsdom/jsdom/issues/3368
global.ResizeObserver = class ResizeObserver {
public observe() {
// do nothing
}
public unobserve() {
// do nothing
}
public disconnect() {
// do nothing
}
};
});

it('should not throw on console.error', async () => {
// Updates to overflow state are batched with a microtask debouncer (see createOverflowManager)
// This means that unit tests will often warn on updates happening outside of act
// There's no real way to fix this nicely because there's nothing obvious to wait for since the
// update happens in a microtask.
//
// The current debounce implementation is synchronous when NODE_ENV === 'test'
// This test is a canary to make sure unit tests don't emit warnings
console.error = message => {
throw new Error(message);
};

render(
<Overflow minimumVisible={1}>
<div>
<OverflowItem id="1">
<button>foo</button>
</OverflowItem>
<OverflowItem id="2">
<button>foo</button>
</OverflowItem>
<OverflowItem id="3">
<button>foo</button>
</OverflowItem>
</div>
</Overflow>,
);
});
});

0 comments on commit 841ad6a

Please sign in to comment.