Skip to content
Closed
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
106 changes: 87 additions & 19 deletions __tests__/components/DropListItemContentMediaImage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,116 @@
import { render, screen, fireEvent } from '@testing-library/react';
import React from 'react';
import DropListItemContentMediaImage from '@/components/drops/view/item/content/media/DropListItemContentMediaImage';
import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import DropListItemContentMediaImage from "@/components/drops/view/item/content/media/DropListItemContentMediaImage";

jest.mock('@/helpers/image.helpers', () => ({
jest.mock("@/helpers/image.helpers", () => ({
getScaledImageUri: (_src: string) => _src,
ImageScale: { AUTOx450: 'AUTOx450', AUTOx1080: 'AUTOx1080' },
responsiveDropImageLoader: jest.fn(),
ImageScale: { AUTOx450: "AUTOx450", AUTOx1080: "AUTOx1080" },
}));

jest.mock('@/helpers/Helpers', () => ({
jest.mock("@/helpers/Helpers", () => ({
fullScreenSupported: () => true,
}));

jest.mock('@/hooks/useCapacitor', () => ({ __esModule: true, default: () => ({ isCapacitor: false }) }));
jest.mock("@/components/common/FallbackImage", () => {
const React = require("react");

jest.mock('@/hooks/useInView', () => ({
return {
FallbackImage: React.forwardRef(
(
{
alt,
primarySrc,
fallbackSrc,
optimize,
loader,
onClick,
onError,
onLoad,
}: any,
ref: any
) => (
<img
ref={ref}
alt={alt}
src={primarySrc}
data-fallback-src={fallbackSrc}
data-optimize={optimize === undefined ? "" : String(optimize)}
data-has-loader={loader ? "true" : "false"}
onClick={onClick}
onError={onError}
onLoad={onLoad}
/>

Check warning on line 43 in __tests__/components/DropListItemContentMediaImage.test.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Non-interactive elements should not be assigned mouse or keyboard event listeners.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZ4Hf6XDZI-r4lnZzyn6&open=AZ4Hf6XDZI-r4lnZzyn6&pullRequest=2360

Check warning on line 43 in __tests__/components/DropListItemContentMediaImage.test.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Visible, non-interactive elements with click handlers must have at least one keyboard listener.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZ4Hf6XDZI-r4lnZzyn7&open=AZ4Hf6XDZI-r4lnZzyn7&pullRequest=2360
)
),
};
});

jest.mock("@/hooks/useCapacitor", () => ({
__esModule: true,
default: () => ({ isCapacitor: false }),
}));

jest.mock("@/hooks/useInView", () => ({
useInView: () => [jest.fn(), true],
}));

beforeEach(() => {
(global as any).ResizeObserver = class { observe(){} disconnect(){} };
(global as any).ResizeObserver = class {

Check warning on line 59 in __tests__/components/DropListItemContentMediaImage.test.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `global`.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZ4Hf6XDZI-r4lnZzyn8&open=AZ4Hf6XDZI-r4lnZzyn8&pullRequest=2360
observe() {}

Check failure on line 60 in __tests__/components/DropListItemContentMediaImage.test.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected empty method 'observe'.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZ4Hf6XDZI-r4lnZzyn9&open=AZ4Hf6XDZI-r4lnZzyn9&pullRequest=2360
disconnect() {}

Check failure on line 61 in __tests__/components/DropListItemContentMediaImage.test.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected empty method 'disconnect'.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZ4Hf6XDZI-r4lnZzyn-&open=AZ4Hf6XDZI-r4lnZzyn-&pullRequest=2360
};
});

describe('DropListItemContentMediaImage', () => {
it('calls onContainerClick from modal button', () => {
describe("DropListItemContentMediaImage", () => {
it("calls onContainerClick from modal button", () => {
const onContainerClick = jest.fn();
render(<DropListItemContentMediaImage src="img" maxRetries={1} onContainerClick={onContainerClick} />);
const img = screen.getByAltText('Drop media');
render(
<DropListItemContentMediaImage
src="img"
maxRetries={1}
onContainerClick={onContainerClick}
/>
);
const img = screen.getByAltText("Drop media");
fireEvent.load(img);
fireEvent.click(img);
fireEvent.click(screen.getByLabelText('View drop details'));
fireEvent.click(screen.getByLabelText("View drop details"));
expect(onContainerClick).toHaveBeenCalled();
});

it('does not open modal when disableModal is true', () => {
it("does not open modal when disableModal is true", () => {
render(<DropListItemContentMediaImage src="img" disableModal />);
const img = screen.getByAltText('Drop media');
const img = screen.getByAltText("Drop media");
fireEvent.load(img);
fireEvent.click(img);
expect(screen.queryByLabelText('View drop details')).not.toBeInTheDocument();
expect(
screen.queryByLabelText("View drop details")
).not.toBeInTheDocument();
});

it("keeps normal images unoptimized without a custom loader", () => {
render(<DropListItemContentMediaImage src="img" />);

const img = screen.getByAltText("Drop media");
expect(img).toHaveAttribute("data-optimize", "false");
expect(img).toHaveAttribute("data-has-loader", "false");
expect(img).toHaveAttribute("data-fallback-src", "img");
});

it("uses the responsive loader only when responsive srcset mode is enabled", () => {
render(
<DropListItemContentMediaImage src="img" useResponsiveImageSrcSet />
);

const img = screen.getByAltText("Drop media");
expect(img).toHaveAttribute("data-optimize", "true");
expect(img).toHaveAttribute("data-has-loader", "true");
});
});

describe('DropListItemContentMediaImage retry', () => {
it('shows error and retries manually', () => {
describe("DropListItemContentMediaImage retry", () => {
it("shows error and retries manually", () => {
render(<DropListItemContentMediaImage src="img" maxRetries={-1} />);
expect(screen.getByText("Couldn’t load image.")).toBeInTheDocument();
});
Expand Down
112 changes: 109 additions & 3 deletions __tests__/components/common/FallbackImage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,50 @@ import { forwardRef, type ComponentProps } from "react";
type MockNextImageProps = ComponentProps<"img"> & {
readonly fill?: boolean | undefined;
readonly unoptimized?: boolean | undefined;
readonly loader?:
| ((props: {
readonly src: string;
readonly width: number;
readonly quality?: number | undefined;
}) => string)
| undefined;
};

jest.mock("next/image", () => ({
__esModule: true,
default: forwardRef<HTMLImageElement, MockNextImageProps>(
// eslint-disable-next-line react/display-name
({ fill: _fill, unoptimized: _unoptimized, alt, ...rest }, ref) => (
<img ref={ref} alt={alt ?? ""} {...rest} />
)
({ fill: _fill, unoptimized, loader, alt, src, ...rest }, ref) => {
const shouldUseLoader =
typeof src === "string" && !!loader && !unoptimized;
const renderedSrc = shouldUseLoader ? loader({ src, width: 1080 }) : src;
const srcSet = shouldUseLoader
? `${loader({ src, width: 450 })} 450w, ${loader({
src,
width: 1080,
})} 1080w`
: undefined;

return (
<img
ref={ref}
alt={alt ?? ""}
src={renderedSrc}
srcSet={srcSet}
data-unoptimized={unoptimized ? "true" : "false"}
{...rest}
/>
);
}
),
}));

jest.mock("@/components/ipfs/IPFSContext", () => ({
resolveIpfsUrlSync: (url: string) => url,
}));

import { FallbackImage } from "../../../components/common/FallbackImage";
import { responsiveDropImageLoader } from "@/helpers/image.helpers";

describe("FallbackImage", () => {
afterEach(() => {
Expand Down Expand Up @@ -75,4 +106,79 @@ describe("FallbackImage", () => {
expect(onPrimaryError).toHaveBeenCalledTimes(1);
expect(onError).toHaveBeenCalledTimes(1);
});

it("resets fallback state when the primary source changes", async () => {
const { rerender } = render(
<FallbackImage
primarySrc="primary-a.gif"
fallbackSrc="fallback-a.gif"
alt="rerender fallback example"
/>
);

const image = screen.getByRole("img", {
name: "rerender fallback example",
});
expect(image).toHaveAttribute("src", "primary-a.gif");

fireEvent.error(image);

await waitFor(() => {
expect(image).toHaveAttribute("src", "fallback-a.gif");
});

rerender(
<FallbackImage
primarySrc="primary-b.gif"
fallbackSrc="fallback-b.gif"
alt="rerender fallback example"
/>
);

const resetImage = screen.getByRole("img", {
name: "rerender fallback example",
});
expect(resetImage).toHaveAttribute("src", "primary-b.gif");
});

it("uses the custom loader for responsive primary urls and direct fallback urls", async () => {
const primarySrc =
"https://d3lqz0a4bldqgf.cloudfront.net/drops/drop-id/AUTOx450/art.png";
const fallbackSrc =
"https://d3lqz0a4bldqgf.cloudfront.net/drops/drop-id/art.png";

render(
<FallbackImage
primarySrc={primarySrc}
fallbackSrc={fallbackSrc}
alt="responsive fallback example"
optimize={true}
loader={responsiveDropImageLoader}
sizes="(max-width: 767px) 100vw, 33vw"
/>
);

const image = screen.getByRole("img", {
name: "responsive fallback example",
});

expect(image).toHaveAttribute(
"src",
"https://d3lqz0a4bldqgf.cloudfront.net/drops/drop-id/AUTOx1080/art.png"
);
expect(image).toHaveAttribute(
"srcset",
"https://d3lqz0a4bldqgf.cloudfront.net/drops/drop-id/AUTOx450/art.png 450w, https://d3lqz0a4bldqgf.cloudfront.net/drops/drop-id/AUTOx1080/art.png 1080w"
);
expect(image.getAttribute("srcset")).not.toContain("/_next/image");

fireEvent.error(image);

await waitFor(() => {
expect(image).toHaveAttribute("src", fallbackSrc);
});

expect(image).not.toHaveAttribute("srcset");
expect(image).toHaveAttribute("data-unoptimized", "true");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@ import DropListItemContentMedia from "@/components/drops/view/item/content/media

jest.mock(
"@/components/drops/view/item/content/media/DropListItemContentMediaImage",
() => ({ __esModule: true, default: () => <div data-testid="image" /> })
() => ({
__esModule: true,
default: (props: any) => (
<div
data-testid="image"
data-image-sizes={props.imageSizes ?? ""}
data-responsive-srcset={
props.useResponsiveImageSrcSet ? "true" : "false"
}
/>
),
})
);
jest.mock(
"@/components/drops/view/item/content/media/DropListItemContentMediaVideo",
Expand Down Expand Up @@ -45,6 +56,35 @@ describe("DropListItemContentMedia", () => {
expect(screen.getByTestId("image")).toBeInTheDocument();
});

it("forwards image sizes to the image component", () => {
render(
<DropListItemContentMedia
media_mime_type="image/png"
media_url="img"
imageSizes="(max-width: 767px) 100vw, 33vw"
/>
);
expect(screen.getByTestId("image")).toHaveAttribute(
"data-image-sizes",
"(max-width: 767px) 100vw, 33vw"
);
});

it("forwards responsive srcset mode to the image component", () => {
render(
<DropListItemContentMedia
media_mime_type="image/png"
media_url="img"
useResponsiveImageSrcSet
/>
);

expect(screen.getByTestId("image")).toHaveAttribute(
"data-responsive-srcset",
"true"
);
});

it("renders video component", () => {
render(
<DropListItemContentMedia media_mime_type="video/mp4" media_url="vid" />
Expand Down
Loading
Loading