wix-style-react
Version:
670 lines (560 loc) • 22.8 kB
JavaScript
import React from 'react';
import { fireEvent } from '@testing-library/react';
import ImageViewer from '../ImageViewer';
import ImageViewerDriver from '../ImageViewer.driver';
import { imageViewerPrivateDriverFactory } from './ImageViewer.private.uni.driver';
import imageViewerPrivateDriver from './ImageViewer.private.driver';
import {
createRendererWithDriver,
createRendererWithUniDriver,
cleanup,
} from '../../../test/utils/react';
describe('ImageViewer', () => {
const imageUrl =
'https://upload.wikimedia.org/wikipedia/commons/d/dd/New_Mela_Ramanputhur_Holy_Family_Church.jpg';
const secondImageUrl =
'https://onlinepngtools.com/images/examples-onlinepngtools/palm-fronds-and-sky.png';
const buildComponent = (props = {}) => <ImageViewer {...props} />;
afterEach(() => cleanup());
describe('[sync]', () => {
runTests(createRendererWithDriver(ImageViewerDriver));
});
describe('[async]', () => {
const render = createRendererWithUniDriver(imageViewerPrivateDriverFactory);
runTests(render);
describe('More Actions menu', () => {
describe('Remove button', () => {
describe('`onRemoveImage` prop', () => {
it('should call callback [when] clicked on remove button', async () => {
const onRemoveImage = jest.fn();
const { driver } = render(
buildComponent({
onRemoveImage,
imageUrl,
showRemoveButton: true,
showUpdateButton: true,
showDownloadButton: true,
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.clickRemove();
expect(onRemoveImage).toHaveBeenCalled();
});
});
});
});
describe('Download button', () => {
describe('`onDownloadImage` prop', () => {
it('should call callback [when] clicked on download button', async () => {
const onDownloadImage = jest.fn();
const { driver } = render(
buildComponent({
onDownloadImage,
imageUrl,
showRemoveButton: true,
showUpdateButton: true,
showDownloadButton: true,
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.clickDownload();
expect(onDownloadImage).toHaveBeenCalled();
});
});
});
describe('ref api', () => {
describe('`focus` method', () => {
it('should focus on addItem when there is no image', async () => {
let ref;
const { driver } = render(buildComponent({ ref: el => (ref = el) }));
expect(await driver.isAddItemVisible()).toBe(true);
ref.focus();
expect(await driver.isAddItemFocused()).toBe(true);
});
describe('should focus on first button when there is image', () => {
it('update button is first', async () => {
let ref;
const { driver } = render(
buildComponent({
imageUrl,
showUpdateButton: true,
showDownloadButton: false,
showRemoveButton: true,
ref: el => (ref = el),
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
ref.focus();
expect(await driver.isUpdateButtonFocused()).toBe(true);
});
it('remove button is first', async () => {
let ref;
const { driver } = render(
buildComponent({
imageUrl,
showUpdateButton: false,
showDownloadButton: false,
showRemoveButton: true,
ref: el => (ref = el),
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
ref.focus();
expect(await driver.isRemoveButtonFocused()).toBe(true);
});
it('download button is first', async () => {
let ref;
const { driver } = render(
buildComponent({
imageUrl,
showUpdateButton: false,
showDownloadButton: true,
showRemoveButton: true,
ref: el => (ref = el),
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
ref.focus();
expect(await driver.isDownloadButtonFocused()).toBe(true);
});
});
});
});
});
function runTests(render) {
describe('`imageUrl` prop', () => {
describe('when a value is given on mount', () => {
it('should render the image with the correct url', async () => {
const { driver } = render(buildComponent({ imageUrl }));
expect(await driver.getImageUrl()).toBe(imageUrl);
});
});
describe('when no value is given on mount', () => {
it('should NOT display the image', async () => {
const { driver } = render(buildComponent({ imageUrl: undefined }));
expect(await driver.isImageVisible()).toBe(false);
expect(await driver.isPreviousImageVisible()).toBe(false);
});
});
describe('when the value changes', () => {
it('should display the previous image until new one is loaded', async () => {
const { driver, rerender } = render(buildComponent({ imageUrl }));
const setProps = props => rerender(buildComponent(props));
// TODO: Merge the drivers into one, instead of using them separately with different render methods
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await setProps({ imageUrl: secondImageUrl });
expect(await driver.getPreviousImageUrl()).toBe(imageUrl);
expect(await driver.isPreviousImageVisible()).toBe(true);
expect(await driver.getImageUrl()).toBe(secondImageUrl);
expect(await driver.isImageVisible()).toBe(false);
expect(await driver.isImageLoaded()).toBe(false); // assertion
});
it('should display the new image after it loads', async () => {
const { driver, rerender } = render(buildComponent({ imageUrl }));
const setProps = props => rerender(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await setProps({ imageUrl: secondImageUrl });
await privateDriver.simulateImageLoad();
expect(await driver.getImageUrl()).toBe(secondImageUrl);
expect(await driver.isImageVisible()).toBe(true);
expect(await driver.getPreviousImageUrl()).toBe(imageUrl);
expect(await driver.isPreviousImageVisible()).toBe(false);
});
});
});
describe('AddItem', () => {
describe('given imageUrl', () => {
it('should be visible before image loaded', async () => {
const { driver } = render(buildComponent({ imageUrl }));
expect(await driver.isAddItemVisible()).toBe(true);
expect(await driver.isImageLoaded()).toBe(false); // assertion
});
it('should NOT be visible after image loaded', async () => {
const { driver } = render(buildComponent({ imageUrl }));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.isAddItemVisible()).toEqual(false);
});
it('should NOT be visible while image is loading and previous image is rendered', async () => {
const { driver, rerender } = render(buildComponent({ imageUrl }));
const setProps = props => rerender(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
setProps({ imageUrl: secondImageUrl });
expect(await driver.isAddItemVisible()).toEqual(false);
});
});
describe('when no imageUrl given', () => {
it('should be visible', async () => {
const { driver } = render(buildComponent({ imageUrl: undefined }));
expect(await driver.isAddItemVisible()).toBe(true);
});
});
it('should show tooltip [when] addImageInfo is given', async () => {
const addImageInfo = 'add image info';
const { driver } = render(
buildComponent({ imageUrl: '', addImageInfo }),
);
expect(await driver.getAddTooltipContent()).toBe(addImageInfo);
});
describe('`onAddImage` prop', () => {
it('should trigger add image [when] onAddImage is given', async () => {
const onAddImage = jest.fn();
const { driver } = render(buildComponent({ onAddImage }));
await driver.clickAdd();
expect(onAddImage).toHaveBeenCalled();
});
});
});
describe('Loader', () => {
describe('given `imageUrl`', () => {
it('should be visible while loading an image', async () => {
const { driver } = render(buildComponent({ imageUrl }));
expect(await driver.isLoaderVisible()).toBe(true);
});
it('should NOT be visible after image loaded', async () => {
const { driver } = render(buildComponent({ imageUrl }));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.isLoaderVisible()).toBe(false);
});
});
describe('given no `imageUrl`', () => {
it('should NOT be visible', async () => {
const { driver } = render(buildComponent({ imageUrl: undefined }));
expect(await driver.isLoaderVisible()).toBe(false);
});
});
});
/* Overlay tests should move to e2e visual */
xdescribe('Overlay', () => {
it('should be visible while loading an image', async () => {
const { driver } = render(buildComponent({ imageUrl }));
expect(await driver.isOverlayVisible()).toBe(true);
});
it('should be visible while hovering an image', async () => {
const { driver } = render(buildComponent({ imageUrl }));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
});
await privateDriver.simulateImageLoad();
await driver.hover();
expect(await driver.isOverlayVisible()).toBe(true);
});
it('should NOT be visible when image is not currently loading and not being hovered', async () => {
const { driver } = render(buildComponent({ imageUrl: undefined }));
expect(await driver.isOverlayVisible()).toBe(false);
});
});
describe('Update Button', () => {
describe('`onUpdateImage` prop', () => {
it('should call callback [when] clicked on update button', async () => {
const onUpdateImage = jest.fn();
const { driver } = render(
buildComponent({ onUpdateImage, imageUrl }),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.clickUpdate();
expect(onUpdateImage).toHaveBeenCalled();
});
});
describe('tooltip', () => {
it('should display provided content', async () => {
const updateImageInfo = 'update image info';
const props = {
imageUrl,
updateImageInfo,
};
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.clickUpdate();
expect(await driver.getUpdateTooltipContent()).toBe(updateImageInfo);
});
});
});
describe('Remove Button', () => {
describe('`onRemoveImage` prop', () => {
it('should call callback [when] clicked on remove button', async () => {
const onRemoveImage = jest.fn();
const { driver } = render(
buildComponent({ onRemoveImage, imageUrl }),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.clickRemove();
expect(onRemoveImage).toHaveBeenCalled();
});
});
describe('`showRemoveButton` prop', () => {
it('should render remove button when prop is not passed', async () => {
const props = { imageUrl };
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.removeButtonExists()).toBe(true);
});
it('should render remove button when prop equals to "true"', async () => {
const props = { showRemoveButton: true, imageUrl };
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.removeButtonExists()).toBe(true);
});
it('should NOT render remove button when prop equals to "false"', async () => {
const props = { showRemoveButton: false, imageUrl };
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.removeButtonExists()).toBe(false);
});
});
describe('tooltip', () => {
it('should display provided content', async () => {
const removeImageInfo = 'remove image info';
const { driver } = render(
buildComponent({ imageUrl, removeImageInfo }),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.hover();
expect(await driver.getRemoveTooltipContent()).toBe(removeImageInfo);
});
});
});
describe('Download Button', () => {
describe('`onDownloadImage` prop', () => {
it('should call callback [when] clicked on download button', async () => {
const onDownloadImage = jest.fn();
const { driver } = render(
buildComponent({
onDownloadImage,
imageUrl,
showDownloadButton: true,
showRemoveButton: false,
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.clickDownload();
expect(onDownloadImage).toHaveBeenCalled();
});
});
describe('`showDownloadButton` prop', () => {
describe('when `showRemoveButton` prop is "false"', () => {
it('should NOT render download button when prop is not passed', async () => {
const props = { imageUrl };
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.downloadButtonExists()).toBe(false);
});
it('should render download button when prop equals to "true"', async () => {
const props = {
showDownloadButton: true,
showRemoveButton: false,
imageUrl,
};
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.downloadButtonExists()).toBe(true);
});
it('should NOT render download button when prop equals to "false"', async () => {
const props = {
showDownloadButton: false,
showRemoveButton: false,
imageUrl,
};
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.downloadButtonExists()).toBe(false);
});
});
});
});
describe('More Actions Button', () => {
it('should render more button when all three actions enabled', async () => {
const props = {
imageUrl,
showRemoveButton: true,
showUpdateButton: true,
showDownloadButton: true,
};
const { driver } = render(buildComponent(props));
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
expect(await driver.moreButtonExists()).toBe(true);
});
describe('tooltip', () => {
it('should display provided content', async () => {
const moreImageInfo = 'more image actions';
const { driver } = render(
buildComponent({
imageUrl,
moreImageInfo,
showRemoveButton: true,
showUpdateButton: true,
showDownloadButton: true,
}),
);
const privateDriver = imageViewerPrivateDriver({
element: await driver.element(),
eventTrigger: fireEvent,
});
await privateDriver.simulateImageLoad();
await driver.hover();
expect(await driver.getMoreTooltipContent()).toBe(moreImageInfo);
});
});
});
describe('status attribute', () => {
it('should have no status', async () => {
const props = {
imageUrl: '',
width: 300,
height: 300,
...test,
};
const { driver } = render(buildComponent(props));
expect(await driver.hasStatus('error')).toBe(false);
});
it.each([
{ status: 'error' },
{ status: 'warning' },
{ status: 'loading' },
])('should display status when %p', async test => {
const props = {
imageUrl: '',
width: 300,
height: 300,
...test,
};
const { driver } = render(buildComponent(props));
expect(await driver.hasStatus(test.status)).toBe(true);
expect(await driver.getStatusMessage()).toBeNull();
});
it.each([
{ status: 'error', statusMessage: 'Error Message' },
{ status: 'warning', statusMessage: 'Warning Message' },
{ status: 'loading', statusMessage: 'Loading Message' },
])('should display status with message when %p', async test => {
const props = {
imageUrl: '',
width: 300,
height: 300,
...test,
};
const { driver } = render(buildComponent(props));
expect(await driver.hasStatus(test.status)).toBe(true);
expect(await driver.getStatusMessage()).toBe(test.statusMessage);
});
});
describe('styles', () => {
describe('height and width', () => {
it('should be added to style attribute when image is not present', async () => {
const props = {
imageUrl: '',
width: 300,
height: 300,
};
const { driver } = render(buildComponent(props));
expect(await driver.getContainerStyles()).toEqual(
'width: 300px; height: 300px;',
);
});
it('should be added to style attribute when image is present', async () => {
const props = {
imageUrl,
width: 300,
height: 300,
};
const { driver } = render(buildComponent(props));
expect(await driver.getContainerStyles()).toEqual(
'width: 300px; height: 300px;',
);
});
it('should not add style attribute when width and height props are not passed', async () => {
const props = { imageUrl };
const { driver } = render(buildComponent(props));
expect(await driver.getContainerStyles()).toEqual(null);
});
});
});
}
});