Unverified Commit 349ece1d authored by Andrey Azov's avatar Andrey Azov Committed by GitHub
Browse files

Use CloseButton component consistently (#439)

parent 67ff6727
Pipeline #124397 passed with stages
in 4 minutes and 18 seconds
......@@ -30,12 +30,4 @@
display: inline-block;
color: $blue;
cursor: pointer;
svg {
height: 16px;
}
}
.contentSwitcherClose {
font-size: 0; // to make the height of this container be defined exclusively by the height of its content
}
......@@ -80,7 +80,7 @@ describe('BrowserNavBarMain', () => {
userEvent.click(changeButton);
const closeButton = container.querySelector(
'.contentSwitcherClose'
'.closeButton'
) as HTMLSpanElement;
userEvent.click(closeButton);
......
......@@ -16,7 +16,6 @@
import React, { useState } from 'react';
import { connect } from 'react-redux';
import classNames from 'classnames';
import { RootState } from 'src/store';
import { getBreakpointWidth } from 'src/global/globalSelectors';
......@@ -24,8 +23,7 @@ import { BreakpointWidth } from 'src/global/globalConfig';
import ChromosomeNavigator from 'src/content/app/browser/chromosome-navigator/ChromosomeNavigator';
import BrowserNavBarRegionSwitcher from './BrowserNavBarRegionSwitcher';
import { ReactComponent as CloseIcon } from 'static/img/shared/close.svg';
import CloseButton from 'src/shared/components/close-button/CloseButton';
import styles from './BrowserNavBarMain.scss';
......@@ -73,9 +71,6 @@ type ContentSwitcherProps = {
};
const ContentSwitcher = (props: ContentSwitcherProps) => {
const switcherContent =
props.currentView === Content.CHROMOSOME ? 'Change' : <CloseIcon />;
const handleClick = () => {
const newView =
props.currentView === Content.CHROMOSOME
......@@ -84,17 +79,16 @@ const ContentSwitcher = (props: ContentSwitcherProps) => {
props.onSwitch(newView);
};
const contentSwitcherStyles = classNames(styles.contentSwitcher, {
[styles.contentSwitcherClose]: props.currentView === Content.REGION_SWITCHER
});
return (
<div className={styles.contentSwitcherArea}>
<span className={contentSwitcherStyles} onClick={handleClick}>
{switcherContent}
const switcherContent =
props.currentView === Content.CHROMOSOME ? (
<span className={styles.contentSwitcher} onClick={handleClick}>
Change
</span>
</div>
);
) : (
<CloseButton onClick={handleClick} />
);
return <div className={styles.contentSwitcherArea}>{switcherContent}</div>;
};
const mapStateToProps = (state: RootState) => ({
......
......@@ -33,9 +33,4 @@
position: absolute;
right: 10px;
top: 5px;
cursor: pointer;
img {
height: 15px;
width: 15px;
}
}
......@@ -17,7 +17,7 @@
import React from 'react';
import classNamesMerger from 'classnames';
import closeIcon from 'static/img/shared/close.svg';
import CloseButton from 'src/shared/components/close-button/CloseButton';
import styles from './CustomDownloadInfoCard.scss';
......@@ -51,8 +51,8 @@ const CustomDownloadInfoCard = (props: Props) => {
<div className={bodyClassNames}>
<div>{props.children}</div>
{onClose && (
<span className={styles.closeButton} onClick={onClose}>
<img src={closeIcon}></img>
<span className={styles.closeButton}>
<CloseButton onClick={onClose} />
</span>
)}
</div>
......
......@@ -51,8 +51,6 @@
}
.closeButton {
height: 15px;
width: 15px;
position: absolute;
right: 20px;
top: 20px;
......
......@@ -18,12 +18,6 @@ import React from 'react';
import get from 'lodash/get';
import { connect } from 'react-redux';
import { RootState } from 'src/store';
import ImageButton from 'src/shared/components/image-button/ImageButton';
import { ReactComponent as closeIcon } from 'static/img/shared/close.svg';
import CustomDownloadInfoCard from 'src/content/app/custom-download/components/info-card/CustomDownloadInfoCard';
import PreviewCard from 'src/content/app/custom-download/containers/content/preview-card/PreviewCard';
import { getCommaSeparatedNumber } from 'src/shared/helpers/formatters/numberFormatter';
import { getCommittedSpeciesById } from 'src/content/app/species-selector/state/speciesSelectorSelectors';
import { setShowPreview } from 'src/content/app/custom-download/state/customDownloadActions';
......@@ -35,7 +29,13 @@ import {
} from 'src/content/app/custom-download/state/customDownloadSelectors';
import { getSelectedAttributes } from 'src/content/app/custom-download/state/attributes/attributesSelector';
import { getSelectedFilters } from 'src/content/app/custom-download/state/filters/filtersSelector';
import CloseButton from 'src/shared/components/close-button/CloseButton';
import CustomDownloadInfoCard from 'src/content/app/custom-download/components/info-card/CustomDownloadInfoCard';
import PreviewCard from 'src/content/app/custom-download/containers/content/preview-card/PreviewCard';
import { CommittedItem } from 'src/content/app/species-selector/types/species-search';
import { RootState } from 'src/store';
import JSONValue from 'src/shared/types/JSON';
import styles from './PreviewDownload.scss';
......@@ -65,13 +65,7 @@ const PreviewDownload = (props: PreviewDownloadProps) => {
return (
<div className={styles.previewDownload}>
<span className={styles.closeButton}>
<ImageButton
description={'Close preview'}
image={closeIcon}
onClick={() => {
props.setShowPreview(false);
}}
/>
<CloseButton onClick={() => props.setShowPreview(false)} />
</span>
<table className={styles.previewDownloadTable}>
<tbody>
......
......@@ -62,9 +62,8 @@
border-top: 1px solid $dark-grey;
}
.closeIcon {
cursor: pointer;
height: 16px;
.closeButton {
display: inline-block;
}
.viewInApp {
......
......@@ -36,14 +36,14 @@ import { InstantDownloadTranscript } from 'src/shared/components/instant-downloa
import ViewInApp from 'src/shared/components/view-in-app/ViewInApp';
import { toggleTranscriptDownload } from 'src/content/app/entity-viewer/state/gene-view/transcripts/geneViewTranscriptsSlice';
import { clearExpandedProteins } from 'src/content/app/entity-viewer/state/gene-view/proteins/geneViewProteinsSlice';
import { ReactComponent as CloseIcon } from 'static/img/shared/close.svg';
import CloseButton from 'src/shared/components/close-button/CloseButton';
import { Gene } from 'src/content/app/entity-viewer/types/gene';
import { Transcript } from 'src/content/app/entity-viewer/types/transcript';
import { View } from 'src/content/app/entity-viewer/state/gene-view/view/geneViewViewSlice';
import transcriptsListStyles from '../DefaultTranscriptsList.scss';
import styles from './TranscriptsListItemInfo.scss';
import { View } from 'src/content/app/entity-viewer/state/gene-view/view/geneViewViewSlice';
export type TranscriptsListItemInfoProps = {
gene: Gene;
......@@ -135,8 +135,8 @@ export const TranscriptsListItemInfo = (
</div>
<div className={styles.downloadLink}>
{props.expandDownload ? (
<CloseIcon
className={styles.closeIcon}
<CloseButton
className={styles.closeButton}
onClick={() =>
props.toggleTranscriptDownload(transcript.stable_id)
}
......
......@@ -42,11 +42,6 @@
}
}
.closeIcon {
cursor: pointer;
height: 16px;
}
.filterContent {
display: grid;
grid-template-columns: 210px 210px 210px;
......
......@@ -35,7 +35,7 @@ import RadioGroup, {
import Checkbox from 'src/shared/components/checkbox/Checkbox';
import { ReactComponent as CloseIcon } from 'static/img/shared/close.svg';
import CloseButton from 'src/shared/components/close-button/CloseButton';
import { ReactComponent as ChevronUp } from 'static/img/shared/chevron-up.svg';
import { Transcript } from 'src/content/app/entity-viewer/types/transcript';
......@@ -150,7 +150,7 @@ const TranscriptsFilter = (props: Props) => {
<div className={styles.filterColumn}>{checkboxes}</div>
</div>
</div>
<CloseIcon className={styles.closeIcon} onClick={props.toggleFilter} />
<CloseButton onClick={props.toggleFilter} />
</div>
</div>
);
......
......@@ -162,7 +162,4 @@ $drawerWindowWidth: 45px;
position: absolute;
right: calc(#{$drawerWindowWidth} + 10px);
top: 10px;
width: 18px;
height: 18px;
cursor: pointer;
}
......@@ -15,7 +15,8 @@
*/
import React from 'react';
import { mount, render } from 'enzyme';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import faker from 'faker';
import StandardAppLayout from './StandardAppLayout';
......@@ -65,54 +66,57 @@ const minimalProps = {
};
describe('StandardAppLayout', () => {
afterEach(() => {
beforeEach(() => {
jest.resetAllMocks();
});
describe('rendering', () => {
it('renders the main content in the main section', () => {
const wrapper = render(<StandardAppLayout {...minimalProps} />);
expect(wrapper.find('.main').find('.mainContent').length).toBe(1);
const { container } = render(<StandardAppLayout {...minimalProps} />);
const mainSection = container.querySelector('.main') as HTMLElement;
expect(mainSection.querySelector('.mainContent')).toBeTruthy();
});
it('renders the top bar content in the top bar', () => {
const wrapper = render(<StandardAppLayout {...minimalProps} />);
expect(wrapper.find('.topbar').find('.topbarContent').length).toBe(1);
const { container } = render(<StandardAppLayout {...minimalProps} />);
const topBar = container.querySelector('.topbar') as HTMLElement;
expect(topBar.querySelector('.topbarContent')).toBeTruthy();
});
it('renders the sidebar content in the sidebar', () => {
const wrapper = render(<StandardAppLayout {...minimalProps} />);
expect(wrapper.find('.sidebar').find('.sidebarContent').length).toBe(1);
const { container } = render(<StandardAppLayout {...minimalProps} />);
const sidebar = container.querySelector('.sidebar') as HTMLElement;
expect(sidebar.querySelectorAll('.sidebarContent')).toBeTruthy();
});
it('renders sidebar navigation in appropriate slot', () => {
const wrapper = render(<StandardAppLayout {...minimalProps} />);
expect(wrapper.find('.topbar').find('.sidebarNavigation').length).toBe(1);
const { container } = render(<StandardAppLayout {...minimalProps} />);
const topBar = container.querySelector('.topbar') as HTMLElement;
expect(topBar.querySelector('.sidebarNavigation')).toBeTruthy();
});
it('renders sidebar toolstrip content in the sidebar toolstrip', () => {
const wrapper = render(<StandardAppLayout {...minimalProps} />);
expect(
wrapper.find('.sidebarToolstripContent').find('.toolstripContent')
.length
).toBe(1);
const { container } = render(<StandardAppLayout {...minimalProps} />);
const sidebarToolstrip = container.querySelector(
'.sidebarToolstripContent'
) as HTMLElement;
expect(sidebarToolstrip.querySelector('.toolstripContent')).toBeTruthy();
});
it('applies correct classes to the main section depending on whether sidebar is open', () => {
// sidebar is open; main section is narrower
let wrapper, mainContent;
wrapper = render(<StandardAppLayout {...minimalProps} />);
mainContent = wrapper.find('.main');
expect(mainContent.hasClass('mainDefault')).toBe(true);
expect(mainContent.hasClass('mainFullWidth')).toBe(false);
const { container, rerender } = render(
<StandardAppLayout {...minimalProps} />
);
const mainSection = container.querySelector('.main') as HTMLElement;
expect(mainSection.classList.contains('mainDefault')).toBe(true);
expect(mainSection.classList.contains('mainFullWidth')).toBe(false);
// sidebar is closed; main section is wider
wrapper = render(
<StandardAppLayout {...minimalProps} isSidebarOpen={false} />
);
mainContent = wrapper.find('.main');
expect(mainContent.hasClass('mainDefault')).toBe(false);
expect(mainContent.hasClass('mainFullWidth')).toBe(true);
rerender(<StandardAppLayout {...minimalProps} isSidebarOpen={false} />);
expect(mainSection.classList.contains('mainDefault')).toBe(false);
expect(mainSection.classList.contains('mainFullWidth')).toBe(true);
});
describe('with drawer', () => {
......@@ -124,38 +128,58 @@ describe('StandardAppLayout', () => {
};
it('renders drawer content in the drawer', () => {
const wrapper = render(<StandardAppLayout {...props} />);
expect(wrapper.find('.drawer').find('.drawerContent').length).toBe(1);
const { container } = render(<StandardAppLayout {...props} />);
const drawer = container.querySelector('.drawer') as HTMLElement;
expect(drawer.querySelector('.drawerContent')).toBeTruthy();
});
it('applies correct classes to the sidebar/drawer wrapper', () => {
let wrapper, sidebarWrapper;
const closedSidebarProps = {
...props,
isSidebarOpen: false
};
wrapper = render(<StandardAppLayout {...closedSidebarProps} />);
sidebarWrapper = wrapper.find('.sidebarWrapper');
expect(sidebarWrapper.hasClass('sidebarWrapperOpen')).toBe(false);
expect(sidebarWrapper.hasClass('sidebarWrapperClosed')).toBe(true);
expect(sidebarWrapper.hasClass('sidebarWrapperDrawerOpen')).toBe(false);
const { container, rerender } = render(
<StandardAppLayout {...closedSidebarProps} />
);
const sidebarWrapper = container.querySelector(
'.sidebarWrapper'
) as HTMLElement;
expect(sidebarWrapper.classList.contains('sidebarWrapperOpen')).toBe(
false
);
expect(sidebarWrapper.classList.contains('sidebarWrapperClosed')).toBe(
true
);
expect(
sidebarWrapper.classList.contains('sidebarWrapperDrawerOpen')
).toBe(false);
const openSidebarProps = props;
wrapper = render(<StandardAppLayout {...openSidebarProps} />);
sidebarWrapper = wrapper.find('.sidebarWrapper');
expect(sidebarWrapper.hasClass('sidebarWrapperOpen')).toBe(true);
expect(sidebarWrapper.hasClass('sidebarWrapperClosed')).toBe(false);
expect(sidebarWrapper.hasClass('sidebarWrapperDrawerOpen')).toBe(false);
rerender(<StandardAppLayout {...openSidebarProps} />);
expect(sidebarWrapper.classList.contains('sidebarWrapperOpen')).toBe(
true
);
expect(sidebarWrapper.classList.contains('sidebarWrapperClosed')).toBe(
false
);
expect(
sidebarWrapper.classList.contains('sidebarWrapperDrawerOpen')
).toBe(false);
const openDrawerProps = {
...props,
isDrawerOpen: true
};
wrapper = render(<StandardAppLayout {...openDrawerProps} />);
sidebarWrapper = wrapper.find('.sidebarWrapper');
expect(sidebarWrapper.hasClass('sidebarWrapperOpen')).toBe(true);
expect(sidebarWrapper.hasClass('sidebarWrapperClosed')).toBe(false);
expect(sidebarWrapper.hasClass('sidebarWrapperDrawerOpen')).toBe(true);
rerender(<StandardAppLayout {...openDrawerProps} />);
expect(sidebarWrapper.classList.contains('sidebarWrapperOpen')).toBe(
true
);
expect(sidebarWrapper.classList.contains('sidebarWrapperClosed')).toBe(
false
);
expect(
sidebarWrapper.classList.contains('sidebarWrapperDrawerOpen')
).toBe(true);
});
});
});
......@@ -172,18 +196,18 @@ describe('StandardAppLayout', () => {
const props = { ...commonProps, isSidebarOpen: false };
test('sidebar navigation tabs are rendered for desktop viewport and larger', () => {
const wrapper = mount(<StandardAppLayout {...props} />);
expect(wrapper.find('.sidebarNavigation').length).toBe(1);
const { container } = render(<StandardAppLayout {...props} />);
expect(container.querySelector('.sidebarNavigation')).toBeTruthy();
});
test('sidebar navigation tabs are not rendered for laptop viewport and smaller', () => {
const wrapper = mount(
const { container } = render(
<StandardAppLayout
{...props}
viewportWidth={BreakpointWidth.LAPTOP}
/>
);
expect(wrapper.find('.sidebarNavigation').length).toBe(0);
expect(container.querySelector('.sidebarNavigation')).toBeFalsy();
});
});
......@@ -191,14 +215,17 @@ describe('StandardAppLayout', () => {
const props = commonProps;
it('calls onSidebarToggle when sidebar toggle button is clicked', () => {
const wrapper = mount(<StandardAppLayout {...props} />);
wrapper.find('.sidebarModeToggleChevron').simulate('click');
const { rerender } = render(<StandardAppLayout {...props} />);
const sidebarToggleButton = screen.getByTestId(
'sidebarModeToggle'
) as HTMLElement;
userEvent.click(sidebarToggleButton);
expect(props.onSidebarToggle).toHaveBeenCalledTimes(1);
// do the same for closed sidebar
wrapper.setProps({ isSidebarOpen: false });
wrapper.find('.sidebarModeToggleChevron').simulate('click');
rerender(<StandardAppLayout {...props} isSidebarOpen={false} />);
userEvent.click(sidebarToggleButton);
expect(props.onSidebarToggle).toHaveBeenCalledTimes(2);
expect(props.onDrawerClose).not.toHaveBeenCalled();
......@@ -209,23 +236,32 @@ describe('StandardAppLayout', () => {
const props = { ...commonProps, isDrawerOpen: true };
it('closes drawer when sidebar toggle button is clicked', () => {
const wrapper = mount(<StandardAppLayout {...props} />);
wrapper.find('.sidebarModeToggleChevron').simulate('click');
render(<StandardAppLayout {...props} />);
const sidebarToggleButton = screen.getByTestId(
'sidebarModeToggle'
) as HTMLElement;
userEvent.click(sidebarToggleButton);
expect(props.onDrawerClose).toHaveBeenCalledTimes(1);
expect(props.onSidebarToggle).not.toHaveBeenCalled();
});
it('closes drawer when drawer close button is clicked', () => {
const wrapper = mount(<StandardAppLayout {...props} />);
wrapper.find('.drawerClose').simulate('click');
const { container } = render(<StandardAppLayout {...props} />);
const closeDrawerButton = container.querySelector(
'.drawerClose'
) as HTMLElement;
userEvent.click(closeDrawerButton);
expect(props.onDrawerClose).toHaveBeenCalledTimes(1);
});
it('closes drawer when drawer’s transparent window is clicked', () => {
const wrapper = mount(<StandardAppLayout {...props} />);
wrapper.find('.drawerWindow').simulate('click');
const { container } = render(<StandardAppLayout {...props} />);
const drawerWindow = container.querySelector(
'.drawerWindow'
) as HTMLElement;
userEvent.click(drawerWindow);
expect(props.onDrawerClose).toHaveBeenCalledTimes(1);
});
......
......@@ -21,8 +21,8 @@ import noop from 'lodash/noop';
import { BreakpointWidth } from 'src/global/globalConfig';
import usePrevious from 'src/shared/hooks/usePrevious';
import CloseButton from 'src/shared/components/close-button/CloseButton';
import { ReactComponent as Chevron } from 'static/img/shared/chevron-right.svg';
import { ReactComponent as CloseIcon } from 'static/img/shared/close.svg';
import styles from './StandardAppLayout.scss';
......@@ -104,7 +104,7 @@ const StandardAppLayout = (props: StandardAppLayoutProps) => {
</div>
<div className={styles.sidebar}>{props.sidebarContent}</div>
<div className={styles.drawer}>
<CloseIcon
<CloseButton
className={styles.drawerClose}
onClick={props.onDrawerClose}
/>
......@@ -129,7 +129,11 @@ const SidebarModeToggle = (props: SidebarModeToggleProps) => {
return (
<div className={styles.sidebarModeToggle}>
<Chevron className={chevronClasses} onClick={props.onClick} />
<Chevron
className={chevronClasses}
onClick={props.onClick}
data-test-id="sidebarModeToggle"
/>
</div>
);
};
......
......@@ -35,9 +35,5 @@
position: absolute;
right: 10px;
top: 45px;
cursor: pointer;
img {
height: 15px;
width: 15px;
}
z-index: 1;
}
......@@ -15,14 +15,15 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import faker from 'faker';
import Panel, { PanelProps } from './Panel';
const panelContent = <p>{faker.lorem.words()}</p>;
const panelBodyContent = 'This content goes into the panel’s body';