Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 75 additions & 12 deletions src/components/controls/ScrollableImages.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { Meta, StoryObj } from "@storybook/react";
import { useEffect, useState } from "react";

import { ImageInfo, ScrollableImages } from "./ScrollableImages";

import diamond from "../../public/images/diamond.jpg";
import soleil from "../../public/images/soleil.jpg";
import bessy from "../../public/images/bessy.jpg";
import shanghai from "../../public/images/shanghai.jpg";
import { useEffect, useState } from "react";

const meta: Meta<typeof ScrollableImages> = {
title: "Components/Controls/ScrollableImages",
component: ScrollableImages,
tags: ["autodocs"],
argTypes: {
mode: {
options: ["viewer", "scroll"],
},
},
};

export default meta;
Expand All @@ -31,34 +36,94 @@ const tiffImage: ImageInfo[] = [
},
];

// CS - Standard mode
export const All: Story = {
args: { images: imagesList, width: 300, height: 300 },
args: {
images: imagesList,
width: 300,
height: 300,
},
};

export const NoButtons: Story = {
args: { images: imagesList, buttons: false },
args: {
images: imagesList,
buttons: false,
},
};

export const NoWrap: Story = {
args: { images: imagesList, wrapAround: false },
args: {
images: imagesList,
wrapAround: false,
},
};

export const NoSlider: Story = {
args: { images: imagesList, slider: false },
args: {
images: imagesList,
slider: false,
},
};

export const NoNumbers: Story = {
args: { images: imagesList, numeration: false },
args: {
images: imagesList,
numeration: false,
},
};

export const DifferentBackgroundColour: Story = {
args: { images: imagesList, backgroundColor: "#166" },
args: {
images: imagesList,
backgroundColor: "#166",
},
};

export const OneImage: Story = {
args: { images: imagesList[0] },
args: {
images: imagesList[0],
},
};

export const TiffImage: Story = {
args: {
images: tiffImage,
},
};
// CE - Standard mode

// CS - Scroll mode
export const ScrollModeBasic: Story = {
name: "Scroll Mode",
args: {
images: imagesList,
mode: "scroll",
width: 300,
height: 300,
},
};

export const ScrollModeWideImages: Story = {
args: {
images: imagesList,
mode: "scroll",
width: 400,
height: 250,
},
};

export const ScrollModeWithTiff: Story = {
args: {
images: tiffImage,
mode: "scroll",
width: 300,
height: 300,
},
};
// CE - Scroll mode

// CS - Dynamic images
export const DynamicImages: StoryObj = {
render: () => {
const [visibleImages, setVisibleImages] = useState(imagesList);
Expand All @@ -69,6 +134,7 @@ export const DynamicImages: StoryObj = {
const interval = setInterval(() => {
setVisibleImages(imagesList.slice(0, nImages));
nImages += increment;

if (nImages === imagesList.length) {
increment = -1;
} else if (nImages === 1) {
Expand All @@ -91,7 +157,4 @@ export const DynamicImages: StoryObj = {
);
},
};

export const TiffImage: Story = {
args: { images: tiffImage },
};
// CE - Dynamic images
167 changes: 91 additions & 76 deletions src/components/controls/ScrollableImages.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,128 +8,143 @@ const imagesList: ImageInfo[] = [
{ src: "four", alt: "four" },
];

describe("ScrollableImages", () => {
describe("ScrollableImages – viewer mode", () => {
it("should render", () => {
const { getByTestId } = render(<ScrollableImages images={imagesList} />);
expect(getByTestId("scrollable-images")).toBeInTheDocument();
expect(getByTestId("image-container")).toBeInTheDocument();
});

it("should render buttons by default", () => {
const { getByTestId } = render(<ScrollableImages images={imagesList} />);
expect(getByTestId("prev-button")).toBeInTheDocument();
expect(getByTestId("next-button")).toBeInTheDocument();
render(<ScrollableImages images={imagesList} />);
expect(screen.getByTestId("prev-button")).toBeInTheDocument();
expect(screen.getByTestId("next-button")).toBeInTheDocument();
});

it("should not render buttons when buttons is false", () => {
const { queryByTestId } = render(
<ScrollableImages images={imagesList} buttons={false} />,
);
expect(queryByTestId("prev-button")).not.toBeInTheDocument();
expect(queryByTestId("next-button")).not.toBeInTheDocument();
render(<ScrollableImages images={imagesList} buttons={false} />);
expect(screen.queryByTestId("prev-button")).not.toBeInTheDocument();
expect(screen.queryByTestId("next-button")).not.toBeInTheDocument();
});

it("should render slider by default", () => {
const { getByTestId } = render(<ScrollableImages images={imagesList} />);
expect(getByTestId("slider")).toBeInTheDocument();
render(<ScrollableImages images={imagesList} />);
expect(screen.getByTestId("slider")).toBeInTheDocument();
});

it("should not render slider when slider is false", () => {
const { queryByTestId } = render(
<ScrollableImages images={imagesList} slider={false} />,
);
expect(queryByTestId("slider")).not.toBeInTheDocument();
render(<ScrollableImages images={imagesList} slider={false} />);
expect(screen.queryByTestId("slider")).not.toBeInTheDocument();
});

it("should render numeration by default", () => {
const { getByTestId } = render(<ScrollableImages images={imagesList} />);
expect(getByTestId("numeration")).toBeInTheDocument();
render(<ScrollableImages images={imagesList} />);
expect(screen.getByTestId("numeration")).toBeInTheDocument();
});

it("should not render numeration when numeration is false", () => {
const { queryByTestId } = render(
<ScrollableImages images={imagesList} numeration={false} />,
);
expect(queryByTestId("numeration")).not.toBeInTheDocument();
render(<ScrollableImages images={imagesList} numeration={false} />);
expect(screen.queryByTestId("numeration")).not.toBeInTheDocument();
});

it("should wrap from first image to last", () => {
it("should wrap around by default", () => {
render(<ScrollableImages images={imagesList} />);
const prevButton = screen.getByTestId("prev-button");
fireEvent.click(prevButton);
const imageContainer = screen.getByTestId("image-container");
expect(imageContainer).toHaveAttribute("data-index", "3");
fireEvent.click(screen.getByTestId("prev-button"));
expect(screen.getByTestId("image-container")).toHaveAttribute(
"data-index",
"3",
);
});

it("should wrap from last image to first", () => {
render(<ScrollableImages images={imagesList} />);
const nextButton = screen.getByTestId("next-button");
fireEvent.click(nextButton);
fireEvent.click(nextButton);
fireEvent.click(nextButton);
fireEvent.click(nextButton);
it("should not wrap when wrapAround is false", () => {
render(<ScrollableImages images={imagesList} wrapAround={false} />);
const imageContainer = screen.getByTestId("image-container");

fireEvent.click(screen.getByTestId("prev-button"));
expect(imageContainer).toHaveAttribute("data-index", "0");

fireEvent.click(screen.getByTestId("next-button"));
fireEvent.click(screen.getByTestId("next-button"));
fireEvent.click(screen.getByTestId("next-button"));
fireEvent.click(screen.getByTestId("next-button"));

expect(imageContainer).toHaveAttribute("data-index", "3");
});

it("should not render controls with only one image", () => {
render(<ScrollableImages images={[imagesList[0]]} />);
expect(screen.queryByTestId("numeration")).not.toBeInTheDocument();
expect(screen.queryByTestId("slider")).not.toBeInTheDocument();
expect(screen.queryByTestId("prev-button")).not.toBeInTheDocument();
expect(screen.queryByTestId("next-button")).not.toBeInTheDocument();
});

it("should wrap from first image to last", () => {
it("should respond to arrow keys when focused", () => {
render(<ScrollableImages images={imagesList} />);
const prevButton = screen.getByTestId("prev-button");
fireEvent.click(prevButton);
const imageContainer = screen.getByTestId("image-container");
expect(imageContainer).toHaveAttribute("data-index", "3");
const container = screen.getByTestId("image-container");
container.focus();

fireEvent.keyDown(container, { key: "ArrowRight" });
expect(container).toHaveAttribute("data-index", "1");

fireEvent.keyDown(container, { key: "ArrowLeft" });
expect(container).toHaveAttribute("data-index", "0");
});

it("should not wrap when wrapAround is false", () => {
render(<ScrollableImages images={imagesList} wrapAround={false} />);
const nextButton = screen.getByTestId("next-button");
const prevButton = screen.getByTestId("prev-button");
const imageContainer = screen.getByTestId("image-container");
it("should not respond to arrow keys when not focused", () => {
render(<ScrollableImages images={imagesList} />);
const container = screen.getByTestId("image-container");

expect(imageContainer).toHaveAttribute("data-index", "0");
fireEvent.keyDown(window, { key: "ArrowRight" });
expect(container).toHaveAttribute("data-index", "0");
});
});

fireEvent.click(prevButton);
expect(imageContainer).toHaveAttribute("data-index", "0");
describe("ScrollableImages – scroll mode", () => {
it("should render scroll container", () => {
render(<ScrollableImages images={imagesList} mode="scroll" />);
expect(screen.getByTestId("image-scroll-container")).toBeInTheDocument();
});

fireEvent.click(nextButton);
fireEvent.click(nextButton);
fireEvent.click(nextButton);
fireEvent.click(nextButton);
expect(imageContainer).toHaveAttribute("data-index", "3");
it("should render left and right scroll buttons", () => {
render(<ScrollableImages images={imagesList} mode="scroll" />);
expect(screen.getByTestId("scroll-left-button")).toBeInTheDocument();
expect(screen.getByTestId("scroll-right-button")).toBeInTheDocument();
});

it("should not render these components when only one image given", () => {
const { queryByTestId } = render(
<ScrollableImages images={[imagesList[0]]} />,
);
expect(queryByTestId("numeration")).not.toBeInTheDocument();
expect(queryByTestId("slider")).not.toBeInTheDocument();
expect(queryByTestId("prev-button")).not.toBeInTheDocument();
expect(queryByTestId("next-button")).not.toBeInTheDocument();
it("should render all images in scroll mode", () => {
render(<ScrollableImages images={imagesList} mode="scroll" />);

imagesList.forEach((_, index) => {
expect(
screen.getByTestId(`scroll-image-${index + 1}`),
).toBeInTheDocument();
});
});

it("should be able to scroll with arrow keys", () => {
render(<ScrollableImages images={imagesList} />);
const imageContainer = screen.getByTestId("image-container");
it.skip("should call scrollBy when clicking scroll buttons", () => {
render(<ScrollableImages images={imagesList} mode="scroll" />);

const container = screen.getByTestId("image-scroll-container");

fireEvent.keyDown(imageContainer, {
key: "ArrowRight",
code: "ArrowRight",
Object.defineProperty(container, "scrollBy", {
value: vi.fn(),
writable: true,
});
expect(imageContainer).toHaveAttribute("data-index", "1");

fireEvent.keyDown(imageContainer, { key: "ArrowLeft", code: "ArrowLeft" });
expect(imageContainer).toHaveAttribute("data-index", "0");
fireEvent.click(screen.getByTestId("scroll-right-button"));
expect(container.scrollBy).toHaveBeenCalled();

fireEvent.click(screen.getByTestId("scroll-left-button"));
expect(container.scrollBy).toHaveBeenCalled();
});

it("should not scroll with arrow keys if the component is not targeted", () => {
render(<ScrollableImages images={imagesList} />);
const imageContainer = screen.getByTestId("image-container");
it("should not render viewer-only controls in scroll mode", () => {
render(<ScrollableImages images={imagesList} mode="scroll" />);

expect(imageContainer).toHaveAttribute("data-index", "0");
fireEvent.keyDown(window, { key: "ArrowRight", code: "ArrowRight" });
expect(imageContainer).toHaveAttribute("data-index", "0");
fireEvent.keyDown(window, { key: "ArrowLeft", code: "ArrowLeft" });
expect(imageContainer).toHaveAttribute("data-index", "0");
expect(screen.queryByTestId("slider")).not.toBeInTheDocument();
expect(screen.queryByTestId("numeration")).not.toBeInTheDocument();
expect(screen.queryByTestId("prev-button")).not.toBeInTheDocument();
expect(screen.queryByTestId("next-button")).not.toBeInTheDocument();
});
});
Loading