I need some help on mocking the tag from next/image in cypress component tests.
I am using Nextjs 15.1.6, cypress 14.1.0, and turbo for nextjs instead of webpack.
After a lot of hard work, I ended up with this:
describe('<Home />', () => {
it('renders', () => {
cy.readFile('src/assets/bard.webp', null).then((img) => {
// Intercept requests to Next.js backend image endpoint
cy.intercept('_next/image*', {
statusCode: 200,
headers: { 'Content-Type': 'image/webp' },
body: img.buffer,
})
})
cy.mount(<Home />)
})
})
where the image tag in a child component loaded by looks like this:
<Image
src={imageSrc}
alt={alt}
width={width}
height={0}
className="rounded"
priority={isPriority}
/>
This loads the bard.webp image just fine in the cypress test, however the problem is there's multiple images on the page. The above code means that all images are loaded as bard.webp, instead of being loaded as their own image.
I don't know how to make cy.readFile / cy.intercept work for multiple images, since readFile expects a string and not a regex.
I tried using chatgpt to help me out, and it kept giving me broken responses. The final result I got before running out of free messages was:
const imageFiles: string[] = ['bard.webp', 'elf.webp', 'dnddice.webp'];
interface ImageData {
fileName: string;
img: ArrayBuffer;
}
it('renders with multiple images', () => {
cy.wrap([] as ImageData[]).then((images) => {
return Cypress._.reduce(
imageFiles,
(prevChain, fileName) => {
return prevChain.then((collectedImages) =>
cy.readFile(`src/assets/${fileName}`, null).then((img: ArrayBuffer) => {
collectedImages.push({ fileName, img });
return collectedImages;
})
);
},
cy.wrap([] as ImageData[])
);
}).then((images: ImageData[]) => {
images.forEach(({ fileName, img }) => {
// Match Next.js image request with regex, ensuring query params are intercepted
cy.intercept(new RegExp(`_next/image\\?.*url=.*${fileName}.*`), {
statusCode: 200,
headers: { 'Content-Type': 'image/webp' },
body: img,
});
});
// Mount the component after setting up intercepts
cy.mount(<Home />);
});
});
This didn't let the images load at all, they were back to a 404.
I can't find any helpful examples online on how to do this; I found but nothing here worked. Most answers I saw were based on using webpack, not turbo.
The cypress blog post linked, , doesn't work for me.
The example in that blog post gives the error "Cannot redefine property: default"
import * as NextImage from 'next/image'
const OriginalNextImage = NextImage.default
Object.defineProperty(NextImage, 'default', {
configurable: true,
// Add `unoptimized` to any use of `next/image` in our tests
value: props => <OriginalNextImage {...props} unoptimized />,
});
cy.mount(<MyComponent />)
I'm at a loss of where to go.
I need some help on mocking the tag from next/image in cypress component tests.
I am using Nextjs 15.1.6, cypress 14.1.0, and turbo for nextjs instead of webpack.
After a lot of hard work, I ended up with this:
describe('<Home />', () => {
it('renders', () => {
cy.readFile('src/assets/bard.webp', null).then((img) => {
// Intercept requests to Next.js backend image endpoint
cy.intercept('_next/image*', {
statusCode: 200,
headers: { 'Content-Type': 'image/webp' },
body: img.buffer,
})
})
cy.mount(<Home />)
})
})
where the image tag in a child component loaded by looks like this:
<Image
src={imageSrc}
alt={alt}
width={width}
height={0}
className="rounded"
priority={isPriority}
/>
This loads the bard.webp image just fine in the cypress test, however the problem is there's multiple images on the page. The above code means that all images are loaded as bard.webp, instead of being loaded as their own image.
I don't know how to make cy.readFile / cy.intercept work for multiple images, since readFile expects a string and not a regex.
I tried using chatgpt to help me out, and it kept giving me broken responses. The final result I got before running out of free messages was:
const imageFiles: string[] = ['bard.webp', 'elf.webp', 'dnddice.webp'];
interface ImageData {
fileName: string;
img: ArrayBuffer;
}
it('renders with multiple images', () => {
cy.wrap([] as ImageData[]).then((images) => {
return Cypress._.reduce(
imageFiles,
(prevChain, fileName) => {
return prevChain.then((collectedImages) =>
cy.readFile(`src/assets/${fileName}`, null).then((img: ArrayBuffer) => {
collectedImages.push({ fileName, img });
return collectedImages;
})
);
},
cy.wrap([] as ImageData[])
);
}).then((images: ImageData[]) => {
images.forEach(({ fileName, img }) => {
// Match Next.js image request with regex, ensuring query params are intercepted
cy.intercept(new RegExp(`_next/image\\?.*url=.*${fileName}.*`), {
statusCode: 200,
headers: { 'Content-Type': 'image/webp' },
body: img,
});
});
// Mount the component after setting up intercepts
cy.mount(<Home />);
});
});
This didn't let the images load at all, they were back to a 404.
I can't find any helpful examples online on how to do this; I found https://github/cypress-io/cypress/issues/18064 but nothing here worked. Most answers I saw were based on using webpack, not turbo.
The cypress blog post linked, https://www.cypress.io/blog/component-testing-next-js-with-cypress#helper-components, doesn't work for me.
The example in that blog post gives the error "Cannot redefine property: default"
import * as NextImage from 'next/image'
const OriginalNextImage = NextImage.default
Object.defineProperty(NextImage, 'default', {
configurable: true,
// Add `unoptimized` to any use of `next/image` in our tests
value: props => <OriginalNextImage {...props} unoptimized />,
});
cy.mount(<MyComponent />)
I'm at a loss of where to go.
Share Improve this question asked Mar 3 at 0:27 user1779418user1779418 5051 gold badge10 silver badges26 bronze badges1 Answer
Reset to default 3Use a callback version of cy.intercept()
RouteHandler.
It will look something like this
cy.readFile('src/assets/bard.webp', null).then((img) => {
cy.intercept('_next/image*', (req) => {
if (req.url.includes('bard') { // some condition that is relevant
req.reply({
statusCode: 200,
headers: { 'Content-Type': 'image/webp' },
body: img.buffer,
})
}
})
})
Or handling many images, set specific intercepts
const images = ['bard', 'beard', 'bad', 'bored']
images.forEach(image => {
cy.readFile(`src/assets/${image}.webp`, null).then((img) => {
cy.intercept(`_next/image/${image}.webp`, (req) => {
req.reply({
...
})
})
})
For reference, the documentation is here Request/Response Modification with routeHandler
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745113813a4612006.html
评论列表(0条)