Skip to content

Commit

Permalink
Merge pull request #1447 from ral-facilities/enhancement/rtl-migration
Browse files Browse the repository at this point in the history
Migrate every test to use testing-library
  • Loading branch information
kennethnym authored Mar 13, 2023
2 parents 0700aaa + 3c36cc6 commit 5308f80
Show file tree
Hide file tree
Showing 182 changed files with 12,833 additions and 15,338 deletions.
9 changes: 1 addition & 8 deletions packages/datagateway-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,16 @@
"@testing-library/react": "12.1.3",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/user-event": "14.4.1",
"@types/enzyme": "3.10.10",
"@types/jest": "29.4.0",
"@types/node": "18.11.9",
"@types/react": "17.0.39",
"@types/react-router-dom": "5.3.3",
"@types/react-virtualized": "9.21.10",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.49.0",
"@wojtekmaj/enzyme-adapter-react-17": "0.6.6",
"babel-eslint": "10.1.0",
"enzyme": "3.11.0",
"enzyme-to-json": "3.6.1",
"eslint": "8.32.0",
"eslint-config-prettier": "8.6.0",
"eslint-config-prettier": "8.5.0",
"eslint-config-react-app": "7.0.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-prettier": "4.2.1",
Expand Down Expand Up @@ -106,9 +102,6 @@
]
},
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"collectCoverageFrom": [
"src/**/*.{tsx,ts,js,jsx}",
"!src/index.tsx",
Expand Down
2 changes: 2 additions & 0 deletions packages/datagateway-common/src/api/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ export const useUpdateQueryParam = (
const functionToUse = updateMethod === 'push' ? push : replace;
return React.useCallback(
(param: FiltersType | SortType | number | null) => {
// need to use window.location.search and not useLocation to ensure we have the most
// up to date version of search when useUpdateQueryParam is called
const query = parseSearchToQuery(window.location.search);

if (type === 'filters') {
Expand Down
146 changes: 115 additions & 31 deletions packages/datagateway-common/src/arrowtooltip.component.test.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
import React from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { ArrowTooltip } from '.';
import { Tooltip } from '@mui/material';
import { getTooltipText } from './arrowtooltip.component';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('ArrowTooltip component', () => {
const createWrapper = (
disableHoverListener?: boolean,
open?: boolean
): ReactWrapper => {
return mount(
<ArrowTooltip
title={'test'}
disableHoverListener={disableHoverListener}
open={open}
>
<div />
</ArrowTooltip>
);
};
jest.mock('resize-observer-polyfill', () => ({
__esModule: true,
default: (() => {
// a simple ResizeObserver mock implemented with constructor function
// because jest.mock doesn't allow access to ResizeObserver at this point
// so extending it is impossible.
//
// this is needed because the ResizeObserver polyfill WON'T WORK in jest env.

function MockResizeObserver(callback): void {
this.callback = callback;

this.observe = (target: HTMLElement) => {
this.callback(
[
{
target: {
scrollWidth: 100,
},
borderBoxSize: [
{
inlineSize: Number(target.style.width.replace('px', '')),
},
],
},
],
this
);
};

this.disconnect = () => {
// disconnected
};
}

return MockResizeObserver;
})(),
}));

describe('ArrowTooltip component', () => {
describe('getTooltipText', () => {
it('returns empty string for anything null-ish', () => {
expect(getTooltipText(undefined)).toBe('');
Expand Down Expand Up @@ -58,25 +82,85 @@ describe('ArrowTooltip component', () => {
});
});

// Note that disableHoverListener has the opposite value to isTooltipVisible
it('is enabled when the target of the tooltip is overflowing', async () => {
const user = userEvent.setup();

it('tooltip disabled when tooltipElement null', () => {
// Mock return of createRef to be null
const spyCreateRef = jest
.spyOn(React, 'createRef')
.mockReturnValueOnce(null);
render(
<ArrowTooltip title="tooltip content">
<p style={{ width: 10, height: 10 }}>
Some really long text that will for sure overflow
</p>
</ArrowTooltip>
);

const wrapper = createWrapper();
expect(wrapper.find(Tooltip).props().disableHoverListener).toEqual(true);
await user.hover(
screen.getByText('Some really long text that will for sure overflow')
);

spyCreateRef.mockRestore();
expect(await screen.findByText('tooltip content')).toBeInTheDocument();
});

it('can override disableHoverListener', () => {
let wrapper = createWrapper(true);
expect(wrapper.find(Tooltip).props().disableHoverListener).toEqual(true);
describe('is disabled', () => {
it('when the target of the tooltip is not overflowing', async () => {
const user = userEvent.setup();

render(
<ArrowTooltip title="tooltip content">
<p style={{ width: 1000, height: 10 }}>
Some really long text that will for sure overflow
</p>
</ArrowTooltip>
);

wrapper = createWrapper(false);
expect(wrapper.find(Tooltip).props().disableHoverListener).toEqual(false);
await user.hover(
screen.getByText('Some really long text that will for sure overflow')
);

// tooltip doesn't immediately appear in the DOM after it is triggered
// since queryByText immediately queries the dom after the hover event happens,
// we need to make sure that `queryByText` returns null because
// the tooltip **won't ever** appear, not because the tooltip hasn't appeared yet when queryByText queries the dom
//
// waiting for 2 seconds should be enough

await new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, 2000);
});

expect(screen.queryByText('tooltip content')).toBeNull();
});

it('when it is disabled explicitly', async () => {
const user = userEvent.setup();

render(
<ArrowTooltip title="tooltip content" disableHoverListener>
<p style={{ width: 10, height: 10 }}>
Some really long text that will for sure overflow
</p>
</ArrowTooltip>
);

await user.hover(
screen.getByText('Some really long text that will for sure overflow')
);

// tooltip doesn't immediately appear in the DOM after it is triggered
// since queryByText immediately queries the dom after the hover event happens,
// we need to make sure that `queryByText` returns null because
// the tooltip **won't ever** appear, not because the tooltip hasn't appeared yet when queryByText queries the dom
//
// waiting for 2 seconds should be enough

await new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, 2000);
});

expect(screen.queryByText('tooltip content')).toBeNull();
});
});
});
30 changes: 11 additions & 19 deletions packages/datagateway-common/src/arrowtooltip.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,20 @@ const ArrowTooltip = (

const tooltipResizeObserver = React.useRef<ResizeObserver>(
new ResizeObserver((entries) => {
const tooltipElement = entries[0].target;
const tooltipTargetElement = entries[0].target;
// Check that the element has been rendered and set the viewable
// as false before checking to see the element has exceeded maximum width.
if (
tooltipElement !== null &&
entries.length > 0 &&
entries[0].borderBoxSize.length > 0
) {
if (tooltipTargetElement && entries[0].borderBoxSize.length > 0) {
// Width of the tooltip contents including padding and borders
// This is rounded as window.innerWidth and tooltip.scrollWidth are always integer
const borderBoxWidth = Math.round(
const currentTargetWidth = Math.round(
entries[0].borderBoxSize[0].inlineSize
);
const minWidthToFitContentOfTarget = tooltipTargetElement.scrollWidth;
const isContentOfTargetOverflowing =
minWidthToFitContentOfTarget > currentTargetWidth;

// have tooltip appear only when visible text width is smaller than full text width.
if (tooltipElement && borderBoxWidth < tooltipElement.scrollWidth) {
setTooltipVisible(true);
} else {
setTooltipVisible(false);
}
setTooltipVisible(isContentOfTargetOverflowing);
}
})
);
Expand All @@ -79,16 +73,14 @@ const ArrowTooltip = (
const tooltipRef = React.useCallback((container: HTMLDivElement) => {
if (container !== null) {
tooltipResizeObserver.current.observe(container);
}
// When element is unmounted we know container is null so time to clean up
else {
if (tooltipResizeObserver.current)
tooltipResizeObserver.current.disconnect();
} else if (tooltipResizeObserver.current) {
// When element is unmounted we know container is null so time to clean up
tooltipResizeObserver.current.disconnect();
}
}, []);

let shouldDisableHoverListener = !isTooltipVisible;
//Allow disableHoverListener to be overidden
// Allow disableHoverListener to be overridden
if (disableHoverListener !== undefined)
shouldDisableHoverListener = disableHoverListener;

Expand Down
Loading

0 comments on commit 5308f80

Please sign in to comment.