Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte 5 feedback and support #284

Open
stefanhoelzl opened this issue Dec 17, 2023 · 87 comments
Open

Svelte 5 feedback and support #284

stefanhoelzl opened this issue Dec 17, 2023 · 87 comments

Comments

@stefanhoelzl
Copy link

stefanhoelzl commented Dec 17, 2023

Hello, @mcous has hijacked this post! We've launched experimental Svelte 5 support in @testing-library/svelte. See the Svelte 5 section in the README for setup instructions. No special setup is required to use Svelte 5 if you are using Vitest.

If you find bugs or have other Svelte 5 testing feedback, please add it to this thread! Svelte 5 is still changing rapidly at the time of writing, so feedback is appreciated!

Original post below


Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch @testing-library/svelte@4.0.5 for the project I'm working on to use svelte 5.

This patches some breaking changes but there might be more work to do for a proper PR (are tests still working? support svelte 4 and 5, maybe more)

But for everyone who likes to try out svelte 5 this patch should be a good starting point.

Here is the diff that solved my problem:

diff --git a/node_modules/@testing-library/svelte/src/pure.js b/node_modules/@testing-library/svelte/src/pure.js
index 04d3cb0..2f041e0 100644
--- a/node_modules/@testing-library/svelte/src/pure.js
+++ b/node_modules/@testing-library/svelte/src/pure.js
@@ -3,7 +3,7 @@ import {
   getQueriesForElement,
   prettyDOM
 } from '@testing-library/dom'
-import { tick } from 'svelte'
+import { tick, createRoot } from 'svelte'
 
 const containerCache = new Set()
 const componentCache = new Set()
@@ -54,18 +54,15 @@ const render = (
     return { props: options }
   }
 
-  let component = new ComponentConstructor({
+  let component = createRoot(ComponentConstructor, {
     target,
-    ...checkProps(options)
+    ...checkProps(options),
+    ondestroy: () => componentCache.delete(component)
   })
 
   containerCache.add({ container, target, component })
   componentCache.add(component)
 
-  component.$$.on_destroy.push(() => {
-    componentCache.delete(component)
-  })
-
   return {
     container,
     component,
@@ -73,18 +70,14 @@ const render = (
     rerender: (options) => {
       if (componentCache.has(component)) component.$destroy()
 
-      // eslint-disable-next-line no-new
-      component = new ComponentConstructor({
+      component = createRoot(ComponentConstructor, {
         target,
-        ...checkProps(options)
+        ...checkProps(options),
+        ondestroy: () => componentCache.delete(component)
       })
 
       containerCache.add({ container, target, component })
       componentCache.add(component)
-
-      component.$$.on_destroy.push(() => {
-        componentCache.delete(component)
-      })
     },
     unmount: () => {
       if (componentCache.has(component)) component.$destroy()

This issue body was partially generated by patch-package.

@jsorb84
Copy link

jsorb84 commented Dec 20, 2023

Thank you for this, this works flawlessly, you should def. make a pull request , cheers my friend.

@bottrall
Copy link

Thanks @stefanhoelzl, this is working a treat! Any ideas on how to test snippets? So far I haven't managed to figure out how to provide a snippet to the props API. So it's back to the old slots hack of making a wrapping component for tests.

@sureshjoshi
Copy link

Anyone have any luck with snippets? The wrapper components are boilerplate-laden - was hoping to not have to do that.

If anyone has any pointers, I'm happy to give it a shot myself.

@sureshjoshi
Copy link

sureshjoshi commented Feb 6, 2024

EDIT: Ignore this part - after a LOT of debugging, this seems to be a problem when using happy-dom instead of jsdom - which is insane, since I use happy-dom in all of my other projects... But that's a problem for another day :)

Also, @yanick - for this patch, does screen.debug() work anymore? I can't seem to even get the most basic Svelte component to work due to:

PrettyFormatPluginError: Cannot read properties of null (reading 'toLowerCase')

And that's even with a component which is just <div></div>

@mcous
Copy link
Collaborator

mcous commented Feb 12, 2024

I've been messing around with Svelte 5 in our existing test suite, and have encountered the following issues so far. I didn't see any of these explicitly called out in the change log, but I'm assuming at the moment that they're all intentional.

  • onMount and onDestroy are attached / called asynchronously, outside of the component creation / DOM mount
    • Judicious addition of act() can get the tests passing; if you render then unmount immediately, neither onMount nor onDestroy will be called
    • If we want to guarantee that render will call onMount, we'll need to make render async
  • anchor option has been removed from createRoot
  • Element.animate seems to be required to run animations at all, which will require faking something in jsdom/happy-dom to test components with animations
  • Weird happy-dom issue mentioned in comments above

@sysmat
Copy link

sysmat commented Feb 16, 2024

  • in which version of this library is this?
  • @testing-library/svelte: 4.1.0, "svelte": "5.0.0-next.55", tests not working
Instantiating a component with `new` is no longer valid in Svelte 5

@mcous
Copy link
Collaborator

mcous commented Feb 16, 2024

Rudimentary support for Svelte 5 has been released on the next tag

npm install —-save-dev @testing-library/svelte@next

Since Svelte 5 itself is not ready, expect issues and breaking changes if you try it out!

@sysmat
Copy link

sysmat commented Feb 16, 2024

@mcous thx, so @testing-library/svelte@next is "@testing-library/svelte": "^4.2.0",

with this version it works

@mcous
Copy link
Collaborator

mcous commented Feb 19, 2024

FYI for those following along: as of the latest svelte prerelease, our own Svelte 5 support will no longer work due to sveltejs/svelte#10516, which removed the API we were using to mount components. Will do our best to adjust accordingly

@yanick
Copy link
Collaborator

yanick commented Feb 20, 2024

as of the latest svelte prerelease, our own Svelte 5 support will no longer work due to sveltejs/svelte#10516

:darth vader big NOOO:

@sureshjoshi
Copy link

@mcous If you have any suggestions for directed ways to help, I'm all ears :) Though, less familiar with the internals of the lib.

Is the issue that they removed the API call we use? And that it needs to be migrated to the new one? Or is the new mount API a no-go?

@pboling
Copy link

pboling commented Mar 31, 2024

Anyone know of any updates?

@mcous
Copy link
Collaborator

mcous commented Apr 2, 2024

Experimental Svelte v5 support is available on the next dist tag

npm install --save-dev @testing-library/svelte@next

In your test files:

import { render } from '@testing-library/svelte/svelte5'

@yanick how would you feel about bumping the next branch to 5 (to account for breaking changes semantic-release missed) and merging into main? Are there any more breaks - e.g. dropping svelte@3 - that you'd like to collect on next first?

The svelte@5 support is appropriately marked as experimental and it seems like something we can promote in a minor release whenever svelte@5 goes into production

@pboling
Copy link

pboling commented Apr 2, 2024

Your previous update noted that Svelte 5 support did not work at all. It isn't clear from this update if it has been fixed.

@yanick
Copy link
Collaborator

yanick commented Apr 2, 2024

Fwiw, I'm kinda busy today, but I'll try to turn my attention to deployment tomorrow.

@mcous
Copy link
Collaborator

mcous commented Apr 2, 2024

Your previous update noted that Svelte 5 support did not work at all. It isn't clear from this update if it has been fixed.

It has been fixed for now, it may be broken tomorrow. With the very-in-progress nature of Svelte v5, the best way to find out if it's currently working will be to try it yourself

@sureshjoshi
Copy link

sureshjoshi commented Apr 2, 2024

When I tried testing-lib out a week or so ago, it was working - but also note that there are still bugs depending on whether you're using JSDom vs Happy-Dom, or from svelte itself, or any related libraries.

I've been working on a Svelte 5 headless UI port, and Svelte5 + interop is a bit messy at the moment (to say the least) :)

@mcous
Copy link
Collaborator

mcous commented Apr 18, 2024

Experimental Svelte 5 support has landed in main! We'll do our best to stay on top of things, but here there be dragons 🐉

npm install --save-dev @testing-library/svelte@latest now includes Svelte v5 support

@mcous mcous changed the title Patch for svelte 5 support Svelte 5 feedback and support Apr 24, 2024
@mcous mcous pinned this issue Apr 24, 2024
@MatthewTFarley
Copy link

MatthewTFarley commented Apr 28, 2024

When using svelteTesting Vitest setup function with Svelte 5, the autoCleanup option does not work because the function imports the Svelte 4 cleanup function by way of vitest.js.

I have also run into the Element.animate issue @mcous identified. Here's an example repository demonstrating it. It also has some comments mentioning the cleanup issue in the vite.config.ts file. Using vitest globals: true is a workaround since it will cause the correct cleanup to run here.

@mcous
Copy link
Collaborator

mcous commented Apr 29, 2024

When using svelteTesting Vitest setup function with Svelte 5, the `autoCleanup option does not work because the function imports the Svelte 4 cleanup function by way of vitest.js.

...Using vitest globals: true is a workaround...

@MatthewTFarley auto-cleanup via plugin works if you use the suggested Svelte 5 alias setup from the README! Otherwise, globals mode is probably your best bet. This awkwardness will go away once Svelte 5 is out of prerelease and the svelte5 import is no longer needed.

export default defineConfig({
  plugins: [svelte(), svelteTesting()],
  test: {
    alias: {
      '@testing-library/svelte': '@testing-library/svelte/svelte5',
    },
  },
})

I have also run into the Element.animate issue

I wonder what's going to happen here! The animations work in the browser, but neither jsdom nor happy-dom support Element.animate. I don't know if Svelte's intention is to require Element.animate or include some sort of fallback.

We may have to start thinking about shipping our own Element.animate stub, but faking out browser APIs in this library gets into some iffy-mocking-practices territory

@pboling
Copy link

pboling commented Apr 30, 2024

@mcous I don't know enough to know if what I have should be working, or is expected to be broken. I am on latest versions as of this second of all packages, and latest "next" versions where possible (e.g. Svelte 5 next 118). I have some basic tests working, following the patterns of the internal tests of this actual library (testing-library/svelte-testing-library). I'm trying to ensure my config remains working as Svelte5 nears release, and as I add more complex tests to my test suite, so I am following this issue.

When I use the alias mentioned above and in the readme, my test suite doesn't run:

 FAIL  src/lib/components/forms/input.test.ts [ src/lib/components/forms/input.test.ts ]
Error: Missing "./svelte5/vitest" specifier in "@testing-library/svelte" package
 ❯ e node_modules/.pnpm/vite@5.2.10_@types+node@20.12.7/node_modules/vite/dist/node/chunks/dep-DkOS1hkm.js:47596:25

My config (after adding the alias):

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
import { paraglide } from '@inlang/paraglide-sveltekit/vite';
import { svelteTesting } from '@testing-library/svelte/vite';
export default defineConfig(({ mode }) => ({
	plugins: [
		paraglide({
			// recommended
			project: './project.inlang',
			outdir: './src/lib/paraglide',
		}),
		sveltekit(),
		svelteTesting(),
	],
	resolve: {
		conditions: mode === 'test' ? ['browser'] : [],
	},
	test: {
		include: ['src/**/*.{test,spec}.{js,ts}'],
		environment: 'jsdom',
		setupFiles: ['./vitest-setup.ts'],
		alias: {
			'@testing-library/svelte': '@testing-library/svelte/svelte5',
		},
	},
}));

When I remove the alias property from test I am able to run my test suite. Hopefully this is helpful feedback!

@mcous
Copy link
Collaborator

mcous commented Apr 30, 2024

@pboling Looks like maybe our alias needs to be more specific; it's replacing imports it shouldn't. I'll experiment with this a little and update the README shortly. Upon further inspection, I think the problem might lie with a couple updates you should make to your config now that you're using the new svelteTesting plugin.

  • Remove import '@testing-library/svelte/vitest' from your ./vitest-setup.ts file
  • Remove the manual configuration of resolve.conditions

Both of these jobs the plugin now handles for you. I find that this configuration - as listed in the README - behaves well with Svelte 5:

// vite.config.ts
// ...
export default defineConfig({
  plugins: [sveltekit(), svelteTesting()],
  test: {
    include: ['src/**/*.{test,spec}.{js,ts}'],
    environment: "jsdom",
    alias: {
      "@testing-library/svelte": "@testing-library/svelte/svelte5",
    },
    setupFiles: ["./vitest-setup.ts"],
  },
});
// vitest-setup.ts
// Only needed to configure `@testing-library/jest-dom`
import '@testing-library/jest-dom/vitest`

If this doesn't work, you could try using a more specific alias. In my own projects, this is necessary only if I'm not using the svelteTesting plugin.

{
  // ...
  test: {
    // ...
    alias: [
      {
        find: /^@testing-library\/svelte$/,
        replacement: '@testing-library/svelte/svelte5',
      },
    ],
  // ...
  },
}

(All this being said, something feels off to me here. I think having a separate Svelte 5 import path is probably causing more trouble than it's worth. I don't think the situation will stick around too much longer, though)

@pboling
Copy link

pboling commented May 1, 2024

@mcous The top suggestions you gave are working! I did not need the more specific alternative alias.

@peterpeterparker
Copy link

peterpeterparker commented Dec 9, 2024

I'm facing a similar issue to the one someone reported on SO today. The unit test works fine until I add a <style></style> to the component. Does anyone know how to solve this?

FAIL src/tests/lib/components/Back.spec.ts [ src/tests/lib/components/Back.spec.ts ]
TypeError: Error while preprocessing src/lib/components/Back.svelte - Cannot create proxy with a non-object as target or handler
❯ new PartialEnvironment node_modules/vite/dist/node/chunks/dep-yUJfKD1i.js:16766:19
❯ preprocessCSS node_modules/vite/dist/node/chunks/dep-yUJfKD1i.js:48447:23
❯ node_modules/@sveltejs/vite-plugin-svelte/src/preprocess.js:114:10
❯ style node_modules/@sveltejs/vite-plugin-svelte/src/preprocess.js:77:37
❯ process_single_tag node_modules/svelte/src/compiler/preprocess/index.js:283:21
❯ replace_in_code node_modules/svelte/src/compiler/preprocess/replace_in_code.js:70:23
❯ process_tag node_modules/svelte/src/compiler/preprocess/index.js:300:26
❯ Module.preprocess node_modules/svelte/src/compiler/preprocess/index.js:363:25
❯ compileSvelte node_modules/@sveltejs/vite-plugin-svelte/src/utils/compile.js:85:20

I can reproduce the issue with a Svelte sample lib repo: https://github.com/peterpeterparker/svelte-vite-testing-library-css

@mcous
Copy link
Collaborator

mcous commented Dec 9, 2024

@peterpeterparker i don't see the svelteTesting plugin in your reproduction repo - was that intentional?

I also don't see any testing library code in the stacktrace - it seems to be failing at the compile step. Is this issue reproducible without testing-library, just using the basic testing setup from the Svelte docs? If so, this may be an issue to file with the Svelte itself or their Vite plugin.


I took a closer look at your reproduction, and realized it does not include testing-library nor does it follow the instructions in the Svelte doc. You may want to consider updating it to see if you get the same behavior

@peterpeterparker
Copy link

peterpeterparker commented Dec 9, 2024

You're absolutely right, @mcous — there's no svelteTesting in the setup. I had it in my original branch (PR) and naively assumed it was installed by default when I created the sample repo from scratch with the Svelte CLI to reproduce the issue. A bit of a silly mistake on my part 🙈! That said, it does help us rule out Svelte Testing as a root cause of the isse. Sorry for the noise. I'll go ahead and open an issue in the Svelte repo (Updated: I’ve reported it here which happens to be a duplicate of this issue).

P.S. Thanks for the basic testing setup suggestion as well. I tried it earlier this morning, but unfortunately, it didn’t resolve the issue either.

@drewrygh
Copy link

drewrygh commented Dec 18, 2024

For those running into this animation error:

TypeError: element.animate is not a function
 ❯ animate node_modules/svelte/src/internal/client/dom/elements/transitions.js:377:26

A few folks have suggested splitting out the business logic and animation code, so that it's easier to test things independently. I've managed with this approach, with the addition of a conditional check that controls whether the animation should run. It has the added benefit of making animation related code more reusable. If you are working with other developers, you can keep animations in one central place, as opposed to having hardcoded transitions scattered across various components.

// Animations/FlyInOutAnimation.svelte
<script lang="ts">
    import {fly} from "svelte/transition";

    const {className = "", ...rest} = $props();

    const isTestEnv = process?.env?.NODE_ENV === "test";
    const inFlyOptions = {x: 1000, duration: 250};
    const outFlyOptions = { x: 1000, duration: 750};

   // This conditionally applies the transition, so that it still works in the browser, but won't run in a test environment
    function transition(node, options) {
        if (!isTestEnv) {
            return fly(node, options);
        }
    }

</script>

<div class={className} in:transition={inFlyOptions} out:transition={outFlyOptions} {...rest}>
    <slot></slot>
</div>

With this, instead of doing something like:

<div in:fly={{ x: 1000, duration: 250 }} out:fly={{ x: 1000, duration: 500 }}> ... </div>

You could use the animation component

<FlyInOutAnimation> ... </FlyInOutAnimation>

Obviously this won't work in all scenarios, and it may make more sense to use service functions to abstract this away depending on how your code is organized ... but you get the idea. Hopefully this helps.

@peterpeterparker
Copy link

peterpeterparker commented Feb 4, 2025

I'm migrating a large codebase with thousands of tests and encountering multiple instances of the error: Cannot set properties of undefined (setting 'onfinish').

I've tracked the issue to transitions being set as global in the UI components but haven't found a solution yet. I'm already faking Element.prototype.animate. Has anyone faced this issue and found a workaround?

@webJose
Copy link

webJose commented Feb 4, 2025

@peterpeterparker I have never heard of onfinish. Also, when you say transactions, do you mean transitions? From which version of Svelte are you migrating from?

@peterpeterparker
Copy link

peterpeterparker commented Feb 4, 2025

Thanks, @webJose! "Transactions" was a typo (🤦‍♂️), corrected to "transitions".

I'm migrating a codebase from v4 to v5.

As I did not find any mocking or config solution, ultimately, I tried my luck with something similar as @drewrygh's approach shared above. I created wrappers for the global events and skipped those for testing purposes. I just ran the CI, and it seems to have done the trick.

Update: t's actually not just global; I also found some local instances with the same issue.

import {
  fade as svelteFade,
  type FadeParams,
  type TransitionConfig,
} from "svelte/transition";

export const fade = (
  node: HTMLElement,
  params?: FadeParams | undefined,
): TransitionConfig => {
  if (process.env.NODE_ENV === "test") {
    return {};
  }

  return svelteFade(node, params);
};

UPDATE 👉 Way better solution provided below #284 (comment)

peterpeterparker added a commit to dfinity/gix-components that referenced this issue Feb 4, 2025
# Motivation

Svelte requires require the [web animations
API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API),
and neither [jsdom](https://github.com/jsdom/jsdom) nor
[happy-dom](https://github.com/capricorn86/happy-dom) implements it.

While in Gix-cmp or OISY we are able to apply some mocks in the
configuration, this is insuffisent for the existing large test suite of
NNS dapp for which many tests fail, when migrating to Svelte v5, with
the error:

> TypeError: Cannot set properties of undefined (setting 'onfinish')

As suggested in one of the related issues (see linked below), we can
overcome the problem by disabling animations in test mode.

# References

-
testing-library/svelte-testing-library#284 (comment)
- testing-library/svelte-testing-library#416

# CI issues

-
https://github.com/dfinity/nns-dapp/actions/runs/13129931873/job/36632946426

# Changes

- Implement utils for fade, fly and scale that returns an empty
transition configuration for test mode
- Expose utils to make to re-usable by consumers as well

# Tests

Errors do not happen anymore in NNS dapp - Svelte v5 wip branch running
in the CI.

-
https://github.com/dfinity/nns-dapp/actions/runs/13131104521/job/36636304026?pr=6020

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
@mcous
Copy link
Collaborator

mcous commented Feb 11, 2025

I'm migrating a large codebase with thousands of tests and encountering multiple instances of the error: Cannot set properties of undefined (setting 'onfinish').

@peterpeterparker I just ran into this same issue while experimenting, and for me the problem was that:

  • The Element.prototype.animate stub was created with vi.fn()
  • I had my tests configured to reset all mocks after each test

So, after the first test, the stub implementation would be wiped out. The error went away with this change:

- Element.prototype.animate = vi
-   .fn()
-   .mockImplementation(() => ({ cancel: vi.fn(), finished: Promise.resolve() }));
+ Element.prototype.animate = () => ({ cancel: vi.fn(), finished: Promise.resolve() })

github-merge-queue bot pushed a commit to dfinity/nns-dapp that referenced this issue Feb 12, 2025
# Motivation

Revert #6396 because thanks to a different way of mocking the
transitions for test purposes (without vite), those workaround are not
needed anymore when migrating to Svelte v5.

# Resources

New solution to mock the animation for test purposes with Svelte v5
providing by Testing Library in
testing-library/svelte-testing-library#284 (comment)

# Changes

Revert #6396

# Tests

I tested the revert and new way of mocking with Svelte v5 in #6404. The
tests did not throw the keyword `TypeError: Cannot set properties of
undefined (setting 'onfinish')`.

Signed-off-by: David Dal Busco <david.dalbusco@dfinity.org>
peterpeterparker added a commit to dfinity/gix-components that referenced this issue Feb 12, 2025
# Motivation

Revert #574 because thanks to a different way of mocking the transitions
for test purposes (without vite), those workaround are not needed
anymore.

# Resources

- Mock tested in dfinity/nns-dapp#6404
- New solution to mock the animation for test purposes with Svelte v5
providing by Testing Library in
testing-library/svelte-testing-library#284 (comment)

# Changes

- Revert #574 and use Svelte transitions

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
@peterpeterparker
Copy link

Amazing!! Thanks, @mcous! We reverted the workaround I shared previously and used the mock you suggested. CI is happy. It prevents the issues in a much nicer way.

@webJose
Copy link

webJose commented Feb 12, 2025

You can do vi.fn(() => ...) and then the implementation doesn't get wiped out. Think about this as "constructing" vs "modifying". Resetting returns to factory default, when it was constructed.

@niemyjski
Copy link

I'm seeing errors with just simple tests like :

TypeError: Cannot read properties of undefined (reading 'env')

@mcous
Copy link
Collaborator

mcous commented Feb 22, 2025

@niemyjski I'd be happy to help you diagnose if you could provide a minimal reproduction repository (or similar)!

@neo-noire
Copy link

Hi folks, I got a question regarding render and svelte5.
Maybe someone can advise me how to handle it. I want to use bits-ui and tanstack in my svelte5, both of them require me to add some sort of Providers on root layout. And here I'm facing issue cause when I test some components in isolation, I got error in my test that Tooltip(or whatever) is missing Provider.

So my question is, is there a way to pass some wrapper to render function (same way as it's done in testing-library-react), so that I could make a reusable renderFn.
I know that technically I can make a TestWrapper.svelte that would contain all those providers, but I feel like it's not the cleanest approach.

@mcous
Copy link
Collaborator

mcous commented Feb 24, 2025

@neo-noire you can use the context option of render to pass in the contexts that a given provider component would have provided. That being said, I don't think tanstack-query nor bits-ui provide public interfaces to access those context keys.

Due to the compiled nature of Svelte, a wrapper component option is quite a bit more difficult than it is in React, where JSX maps to simple function calls, so unfortunately, for now, you're stuck with the default of "manually create a wrapper Svelte component yourself." I agree that it's not clean, but due to the limited client-side runtime API provided by Svelte, it's the best we've been able to do. I'll look into adding a wrapper component option, regardless, just in case Svelte 5 has made things easier.

This comment applies more to tanstack-query than to bits-ui, because I'm unfamiliar with bits-ui, but in my team's testing practice, we steadfastly avoid writing component tests for components that hook into the query layer. Instead, we create logic-less "collaborator" components that are only in charge of wire-up (e.g. calling createQuery, hooking into SvelteKit, etc.) and push interesting logic to completely props-driven components and/or pure functions. From there, we only write component tests for those props-driven components and unit tests for the pure functions, side-stepping the question of providers and contexts entirely. See this comment in another issue thread for more details

@neo-noire
Copy link

Okay, for someone who'd be looking for some option, that's what I decided to end up with:

// renderUtil.ts

import { render, type RenderOptions } from '@testing-library/svelte'
import type { Component, ComponentProps } from 'svelte'
import TestWrapper from './TestWrapper.svelte'

type WrapperRenderOptions<T extends Component> = Omit<
	RenderOptions<ComponentProps<T>>,
	'props'
> & {
	props?: ComponentProps<T>
}

export function renderWithProviders<T extends Component<any>>(
	component: T,
	{ props, ...rest }: WrapperRenderOptions<T> = {}
) {
	return render(TestWrapper, {
		...rest,
		props: {
			Component: component,
			...props
		}
	})
}
// TestWrapper.svelte

<script lang="ts">
	import { Tooltip } from 'bits-ui'
	import type { Component as ComponentType } from 'svelte'

	interface IProps {
		Component: ComponentType
	}

	let { Component, ...restProps }: IProps = $props()
</script>

<!-- Add any extra provider needed to wrap component -->
<Tooltip.Provider>
	<Component {...restProps} />
</Tooltip.Provider>

And after that you could just call your components this way and it'd have autocompletes for types and looks a bit cleaner:

renderWithProviders(TargetComponent, {
			props: { ...props will go here, TS will yell if some prop is missing }
		})

@niemyjski
Copy link

niemyjski commented Feb 27, 2025

@niemyjski I'd be happy to help you diagnose if you could provide a minimal reproduction repository (or similar)!

Thanks, I haven't had time to create a small repo but my svelte app is here: https://github.com/exceptionless/Exceptionless/tree/main/src/Exceptionless.Web/ClientApp I was running into this while trying to test a component that imported the accessToken here https://github.com/exceptionless/Exceptionless/blob/main/src/Exceptionless.Web/ClientApp/src/lib/features/auth/index.svelte.ts

If I get some more time (probably next weekend) I can see if I can create a smaller sample. But should just have to import a file that has dynamic env's into a component and test it. I generally don't test things/have dependencies like this but was playing around with this after copying over the setup from sveltekit cli.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests