Skip to content

Commit

Permalink
[EuiTextTruncate] Fix timeout clean-up when component unmounts (#7495)
Browse files Browse the repository at this point in the history
Co-authored-by: Marco Antonio Ghiani <[email protected]>
Co-authored-by: Cee Chen <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2024
1 parent a5562b4 commit 3b46c35
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
3 changes: 3 additions & 0 deletions changelogs/upcoming/7495.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Bug fixes**

- Fixed `EuiTextTruncate` component to clean up timer from side effect on unmount
51 changes: 42 additions & 9 deletions src/components/text_truncate/text_truncate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,51 @@ describe('EuiTextTruncate', () => {
expect(container.firstChild).toMatchSnapshot();
});

it('allows delaying truncation calculation by `calculationDelayMs`', () => {
jest.useFakeTimers();
describe('calculationDelayMs', () => {
beforeAll(jest.useFakeTimers);
afterAll(jest.useRealTimers);

const { queryByTestSubject } = render(
<EuiTextTruncate {...props} width={0} calculationDelayMs={50} />
);
expect(queryByTestSubject('truncatedText')).not.toBeInTheDocument();
it('allows delaying truncation calculation by the specified duration', () => {
const { queryByTestSubject } = render(
<EuiTextTruncate {...props} width={0} calculationDelayMs={50} />
);
expect(queryByTestSubject('truncatedText')).not.toBeInTheDocument();

act(() => jest.advanceTimersByTime(50));
expect(queryByTestSubject('truncatedText')).toBeInTheDocument();
});

it('sets and clears the timeout on update or unmount', () => {
const clearTimeoutSpy = jest.spyOn(window, 'clearTimeout');

const { unmount, rerender } = render(
<EuiTextTruncate {...props} width={0} calculationDelayMs={50} />
);
expect(clearTimeoutSpy).toHaveBeenCalledTimes(0);

act(() => jest.advanceTimersByTime(50));
expect(queryByTestSubject('truncatedText')).toBeInTheDocument();
rerender(
<EuiTextTruncate {...props} width={0} calculationDelayMs={100} />
);
expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
expect(clearTimeoutSpy).toHaveBeenLastCalledWith(expect.any(Number));

unmount();
expect(clearTimeoutSpy).toHaveBeenCalledTimes(2);
expect(clearTimeoutSpy).toHaveBeenLastCalledWith(expect.any(Number));
});

it('does not set or clear a timeout if a duration is not passed', () => {
const setTimeoutSpy = jest.spyOn(window, 'setTimeout');
const clearTimeoutSpy = jest.spyOn(window, 'clearTimeout');

jest.useRealTimers();
const { unmount } = render(
<EuiTextTruncate {...props} width={0} calculationDelayMs={0} />
);

expect(setTimeoutSpy).not.toHaveBeenCalled();
unmount();
expect(clearTimeoutSpy).not.toHaveBeenCalled();
});
});

describe('resize observer', () => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/text_truncate/text_truncate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ const EuiTextTruncateWithWidth: FunctionComponent<
const [ready, setReady] = useState(!calculationDelayMs);
useEffect(() => {
if (calculationDelayMs) {
setTimeout(() => setReady(true), calculationDelayMs);
const timerId = setTimeout(() => setReady(true), calculationDelayMs);
return () => clearTimeout(timerId);
}
}, [calculationDelayMs]);

Expand Down

0 comments on commit 3b46c35

Please sign in to comment.