testing question: TypeError: undefined is not a function

Does anyone know how to solve this error? I don't understand this error message at all. Why is the error thrown on the render line? The props are clearly defined on line 18 and 19.
ColorCarouselImages
renders all images into the document & all have correct src attribute (350 ms)

Client: ColorCarousel › ColorCarouselImages › renders all images into the document & all have correct src attribute

TypeError: undefined is not a function
at Array.map (<anonymous>)

18 | const gender = "kids"
19 | const images = ['blue.jpg', 'green.jpg', 'purple.jpg', 'red.jpg', 'yellow.jpg', 'pink.jpg', 'black.jpg', 'white.jpg']
> 20 | render(<ColorCarouselImages gender={gender} images={images} />)
| ^
21 |
22 | const onScreenImages = await screen.findAllByRole('img')
ColorCarouselImages
renders all images into the document & all have correct src attribute (350 ms)

Client: ColorCarousel › ColorCarouselImages › renders all images into the document & all have correct src attribute

TypeError: undefined is not a function
at Array.map (<anonymous>)

18 | const gender = "kids"
19 | const images = ['blue.jpg', 'green.jpg', 'purple.jpg', 'red.jpg', 'yellow.jpg', 'pink.jpg', 'black.jpg', 'white.jpg']
> 20 | render(<ColorCarouselImages gender={gender} images={images} />)
| ^
21 |
22 | const onScreenImages = await screen.findAllByRole('img')
i also tried getAllBy() and without async but same error. I'm using the shadcn carousel in the component I'm testing, could that have messed the test up? the carousel was done manually before resorting to shadcn, where i didn't have any problems with the tests.
24 Replies
michaeldrotar
michaeldrotar9mo ago
first thought was ColorCarouselImages being undefined, maybe a missed import but it also mentions Array.map, is there something undefined wherever that is?
beroer
beroerOP9mo ago
there's no missed import no because i'm defining everything the component needs on lines 17 and 18. this is the test:
it('renders all images into the document & all have correct src attribute', () => {
const gender = "kids"
const images = ['blue.jpg', 'green.jpg', 'purple.jpg', 'red.jpg', 'yellow.jpg', 'pink.jpg', 'black.jpg', 'white.jpg']
render(<ColorCarouselImages gender={gender} images={images} />)

const onScreenImages = screen.getAllByRole('img')

images.forEach((filename, i) => {
expect(onScreenImages[i]).toBeInTheDocument()
expect(onScreenImages[i]).toHaveAttribute('src', `/images/color_carousel/${gender}/${filename}`)
})
})
it('renders all images into the document & all have correct src attribute', () => {
const gender = "kids"
const images = ['blue.jpg', 'green.jpg', 'purple.jpg', 'red.jpg', 'yellow.jpg', 'pink.jpg', 'black.jpg', 'white.jpg']
render(<ColorCarouselImages gender={gender} images={images} />)

const onScreenImages = screen.getAllByRole('img')

images.forEach((filename, i) => {
expect(onScreenImages[i]).toBeInTheDocument()
expect(onScreenImages[i]).toHaveAttribute('src', `/images/color_carousel/${gender}/${filename}`)
})
})
and ColorCarouselImage:
"use client"
import { Gender } from "@/types/link"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/app/components/ui/carousel"
import ColorCarouselImage from "@/app/components/home/ColorCarouselImage";


type ColorCarouselImagesProps = {
images: string[]
gender: Gender
}

export default function ColorCarouselImages({ images, gender }: ColorCarouselImagesProps) {

return (
<Carousel className="mx-auto w-full sm:w-[94%] mt-[1.5625rem]">
<CarouselContent className="mx-auto -ml-3">

{images.map((filename, i) => (
<CarouselItem
key={filename}
className="basis-1/2 sm:basis-1/3 xl:basis-1/4"
>

<ColorCarouselImage
index={i}
filename={filename}
gender={gender}
/>

</CarouselItem>
))}

</CarouselContent>

<CarouselPrevious variant={'ghost'} />
<CarouselNext variant={'ghost'} />

</Carousel>
)
}
"use client"
import { Gender } from "@/types/link"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/app/components/ui/carousel"
import ColorCarouselImage from "@/app/components/home/ColorCarouselImage";


type ColorCarouselImagesProps = {
images: string[]
gender: Gender
}

export default function ColorCarouselImages({ images, gender }: ColorCarouselImagesProps) {

return (
<Carousel className="mx-auto w-full sm:w-[94%] mt-[1.5625rem]">
<CarouselContent className="mx-auto -ml-3">

{images.map((filename, i) => (
<CarouselItem
key={filename}
className="basis-1/2 sm:basis-1/3 xl:basis-1/4"
>

<ColorCarouselImage
index={i}
filename={filename}
gender={gender}
/>

</CarouselItem>
))}

</CarouselContent>

<CarouselPrevious variant={'ghost'} />
<CarouselNext variant={'ghost'} />

</Carousel>
)
}
michaeldrotar
michaeldrotar9mo ago
It all looks right. The one .map(...) looks right. And you said it worked before so I wouldn't expect an env config issue. If you did render(<div />) does that throw? I would pair it down to the very simplest thing and if that works then add more until it throws again.
beroer
beroerOP9mo ago
i did render(div />) and it didn't throw on the render line, it got all the way to the .getAllByRole() line. i caught something that i didn't notice before, it has to do with the shadcn Carousel component:
The above error occurred in the <Carousel> component:

at orientation (/home/wixur/Projects/thrifty/app/components/ui/carousel.tsx:51:7)
at images (/home/wixur/Projects/thrifty/app/components/home/ColorCarouselImages.tsx:18:47)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
The above error occurred in the <Carousel> component:

at orientation (/home/wixur/Projects/thrifty/app/components/ui/carousel.tsx:51:7)
at images (/home/wixur/Projects/thrifty/app/components/home/ColorCarouselImages.tsx:18:47)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
carousel.tsx:51:7 points to a line which as far as i can tell, defines a prop orientation with a default value of horizontal -> i tried setting this myself where i'm calling the component, but it didn't change anything. ColorCarouselImages.tsx:18:48 points to the first line of the definition of the exported react component, specifically to the images prop that it receives, destructured in the params. the parent component of ColorCarouselImages, ColorCarousel is an async react server component. could that be an issue, i wonder? afaik react-testing-library doesn't work with RSCs yet. however since i'm testing only a client component i'd expect it to work. i see what the errors are pointing to but i don't understand it better. i tried setting a default array value for the images prop of ColorCarouselImages but it didn't change anything either. this test:
it('renders an image into the document with correct alt text', () => {
render(<ColorCarouselImage index={0} filename='black.jpg' gender='kids' />)
const image = screen.getByRole('img')
expect(image).toHaveAttribute('alt', 'a kid in black clothes')
expect
})
it('renders an image into the document with correct alt text', () => {
render(<ColorCarouselImage index={0} filename='black.jpg' gender='kids' />)
const image = screen.getByRole('img')
expect(image).toHaveAttribute('alt', 'a kid in black clothes')
expect
})
for ColorCarouselImage is the smallest component of the whole ColorCarousel component that doesn't throw an error in tests.
michaeldrotar
michaeldrotar9mo ago
yeah I'm pretty sure the stack traces are broken inside the render() call. I checked the shad ui code and there's no reason for the default assignment on the orientation prop to throw I don't see ColorCarousel in your earlier code samples but if that's an async function then we definitely don't want it involved. By parent component do you just mean in the normal app use case? Or is it somehow involved in the test that I'm not seeing? if render(<ColorCarouselImage ... />) works, what's the error on render(<CarouselItem ...><ColorCarouselImage ... /></CarouselItem>)? And is it the same error as just render(<CarouselItem ... />)?
beroer
beroerOP9mo ago
no, the ColorCarousel parent component not mentioned before is not involved in the test in any way. for render(<CarouselItem ...><ColorCarouselImage ... /></CarouselItem>) the error is: useCarousel must be used within a <Carousel /> and the same goes for render(<CarouselItem ... />) alone it throws the same error (undefined is not a function) whether i render it like this:
it('renders CarouselItem in Carousel', () => {
render(<Carousel><CarouselContent><CarouselItem></CarouselItem></CarouselContent></Carousel>)
})
it('renders CarouselItem in Carousel', () => {
render(<Carousel><CarouselContent><CarouselItem></CarouselItem></CarouselContent></Carousel>)
})
or whether my <ColorCarouselImage /> is in between the <CarouselItem></CarouselItem> tags. so it must be the shadcn carousel, right?
michaeldrotar
michaeldrotar9mo ago
That seems unlikely. I'd try to make a simple reproduction at this point. The context error makes sense. If render(<Carousel />) doesn't work then that's not some odd edge case issue you'd be catching but something fundamental. That seems like some dependency or env config issue on your end, so reproducing it somewhere like codesandbox might help or at least provide further context for triage.
beroer
beroerOP9mo ago
sorry i'm not too familiar with codesandbox. it tells me i need to convert the sandbox to a devbox if i want to use the terminal (which i suppose i'd need) but it'll charge me credits to spin up a vm. i'm not sure if i can do this free of charge... ? sorry to bother you with this. it also tells me i've used 0% of my credits. does this mean i can still do it for free?
michaeldrotar
michaeldrotar9mo ago
hm I didn't run into that stackblitz has a next.js template and console looks to work to install packages and run jest https://stackblitz.com/
beroer
beroerOP9mo ago
i set it up as much as i could, but unfortunately can't get it to that state mine was in. it runs into an error, says it can't find a module from the carousel file that got installed, when i run npm run test now. (it looks for a weird ../../../../.././ path) https://stackblitz.com/edit/stackblitz-starters-oajgju?file=__tests__%2FColorCarousel.test.tsx
waikoo
StackBlitz
Next.js Starter - StackBlitz
The React framework for production
No description
beroer
beroerOP9mo ago
* before even getting to the render() line.
michaeldrotar
michaeldrotar9mo ago
it's not mapping @/components/* correctly - could swap it to a relative path - or these nextjs docs on tsconfig might help: https://nextjs.org/docs/app/building-your-application/configuring/absolute-imports-and-module-aliases
beroer
beroerOP9mo ago
ok i got to undefined is not a function thanks, i changed them to relative, since the absolute paths were the same as in my project but still didn't work. https://stackblitz.com/edit/stackblitz-starters-oajgju?file=__tests__%2FColorCarousel.test.tsx
waikoo
StackBlitz
Next.js Starter - StackBlitz
The React framework for production
michaeldrotar
michaeldrotar9mo ago
so render(<Carousel />) works.. render(<Carousel><CarouselContent /></Carousel>) errors undefined is not a function :thinkies: if I start gutting CarouselContent and I get it down to this:
const { carouselRef, orientation } = useCarousel();
return <div ref={carouselRef} className="overflow-hidden"></div>;
const { carouselRef, orientation } = useCarousel();
return <div ref={carouselRef} className="overflow-hidden"></div>;
Then I get this error in the actual app (not test):
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'children')
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'children')
Which might be the same error the test is hitting but with some extra detail.. but adding children doesn't seem to fix it. I thought that adding children to <CarouselContent /> or removing them from App should hit the same error even with the code restored, but it does not the gutted version in app and the test both refer to embla's storeElements function, which does access root.children[0] - so that could be where it throws if root is undefined https://github.com/davidjerleke/embla-carousel/blob/09da7a68fd7629958f1271e5b3c9c04acbce704b/packages/embla-carousel/src/components/EmblaCarousel.ts#L65
beroer
beroerOP9mo ago
meaning that i can't test anything higher than ColorCarouselImage, cause it's the library underneath the library that's throwing the error?
michaeldrotar
michaeldrotar9mo ago
lol it's an interesting issue, I wouldn't give up here. I'm not seeing anything obvious myself but now that you have the stackblitz link and we've reasonably isolated to where the error is coming from, you can submit that to embla carousel's issue thread. Hopefully someone there is familiar enough to triage it better. Would be great if you post the answer back here when you get it post the issue link too when you make it
beroer
beroerOP9mo ago
okay, will do, thanks a lot for your help!!!
michaeldrotar
michaeldrotar9mo ago
yw! 🙌
beroer
beroerOP9mo ago
lol i found a previous issue closed 7 hours ago with the exact same error i was getting: https://github.com/davidjerleke/embla-carousel/issues/837 the maintainer said there are a couple of apis to be mocked to solve the problem.
GitHub
[Bug]: Jest testing bug return TypeError: undefined is not a functi...
Which variants of Embla Carousel are you using? embla-carousel (Core) embla-carousel-react embla-carousel-vue embla-carousel-svelte embla-carousel-autoplay embla-carousel-auto-scroll embla-carousel...
beroer
beroerOP9mo ago
but i'm just getting started with testing and this seems too complicated, i don't even know what to do with these files or how to use them...
michaeldrotar
michaeldrotar9mo ago
wow so the error still wasn't even what it appeared to be and I'm really surprised the docs didn't seem to call this out anywhere if you search for jest and one of those 3 functions (matchMedia, ResizeObserver, IntersectionObserver) you should find some explanations minimum thing to do is copy the 3 Object.defineProperty(window, ...) calls to the top of your *.test.tsx file. I tried it out and your tests do pass after that. If you ever hit more things that need these then extract them to another file and import the file. Since they just execute, you only import the file itself and rather than importing some variable from the file and nice find btw!
beroer
beroerOP9mo ago
i have the mocks directly in my file. i also tried having them in their own modules mimicking the structure __tests/mocks/ like in the embla repo and i imported the file itself as you said, but when i ran the tests, it said it should have a test in it, and i didn't know what to do about that but it's fine, i don't think i'll need these mocks in any other test file thanks a lot for your help, i have my tests passing and i can continue to learn testing now. (even setting things up took me a couple of days and asking for help) i'm surprised i was able to set up the stackblitz environment quite fast (doing it a 2nd time)). 😄 you helped out a great deal, much appreciated!!!
michaeldrotar
michaeldrotar9mo ago
Yeah stackblitz is pretty cool, that was a new one for me. Glad I could help! I learned some new things too. gl on it!
beroer
beroerOP9mo ago
gl to you too!
Want results from more Discord servers?
Add your server