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

Testing slots? #48

Closed
Tracked by #296
bestguy opened this issue Aug 15, 2019 · 30 comments · Fixed by testing-library/testing-library-docs#1366
Closed
Tracked by #296

Testing slots? #48

bestguy opened this issue Aug 15, 2019 · 30 comments · Fixed by testing-library/testing-library-docs#1366

Comments

@bestguy
Copy link

bestguy commented Aug 15, 2019

Perhaps this is more svelte API question, but it's not clear how to test component slots, for example:

Badge.svelte:

<span class="badge">
  <slot />
</span>

Badge.spec.js:

describe('Badge', () => {
  test('should render text', () => {
   // Where to pass child text?
    const { container } = render(Badge, { props: { color: 'primary' } }); 
  });
});

Looking for default slots primarily, and do not want to add props for this.

@ematipico
Copy link
Contributor

ematipico commented Aug 16, 2019

Yes it's more a svelte API question that should be redirected to their repository.

Anyway:

import Button from './Button.svelte';

const { container } = render(Badge, { props: { color: 'primary' }, slots: { default: Button } }); 

@oieduardorabelo
Copy link
Contributor

oieduardorabelo commented Aug 16, 2019

afaik is still wip, there's no way to declare slots from the Component API, see:

we could patch the workaround until it is merged to the main api, what do you think?

something like:

import Badge from './Badge.svelte';
import Button from './Button.svelte';

const { container } = render(
  Badge, 
  { props: { color: 'primary' } }, // component props
  { slots: { default: Button } } // component ctx
);

ping @benmonro @EmilTholin

@benmonro
Copy link
Member

benmonro commented Aug 16, 2019

2684 looks like it would work and I'm of the opinion that we should wait for that to be merged but I'll defer to @EmilTholin

@EmilTholin
Copy link
Contributor

I agree with the rest of you that it's a Svelte API issue and that 2684 will resolve it.

In the meantime you could do the less than ideal solution of creating a test-specific component that renders Badge with a Button child component.

<!-- TestBadgeSlot.svelte -->
<Badge>
  <Button />
</Badge>
// Badge.test.js
import TestBadgeSlot from './TestBadgeSlot.svelte';

const { container } = render(
  TestBadgeSlot, 
  { props: { color: 'primary' } }
);

@bestguy
Copy link
Author

bestguy commented Aug 16, 2019

Thanks for the info, I'll wait until sveltejs/svelte#2684 is merged.
Feel free to close this if you prefer, or open if you'd like to track status.

If by chance it's not merged for some reason a patch in this lib would be very useful 🙏

@benmonro
Copy link
Member

Closing for now not feel free to reopen if that doesn't get merged in svelte

@tlux
Copy link

tlux commented Oct 12, 2020

The mentioned issue (sveltejs/svelte#268) has been closed in favor of another refactoring in the svelte repo (which is still open!). Are there any news on how slots can be tested?

@oieduardorabelo
Copy link
Contributor

the new pr to svelte api is still open: sveltejs/svelte#4296

this suggestion still stands: #48 (comment)

@bestguy
Copy link
Author

bestguy commented Oct 12, 2020

If it helps, I worked around this by adding an optional children prop ala React:

https://github.com/bestguy/sveltestrap/blob/master/src/Alert.svelte#L37
that will conditionally render the slot unless children is passed.

Allows testing like:
https://github.com/bestguy/sveltestrap/blob/master/src/__test__/Alert.spec.js#L8

Not perfect 🤷‍♂️ but helps until there is a better option

@cbbfcd
Copy link

cbbfcd commented Apr 26, 2021

wait for the pr merged.

@gyurielf
Copy link

Still actual.

@brettinternet
Copy link

Should this be reopened until sveltejs/svelte#4296 is merged?

@Akolyte01
Copy link

It has been a year with no movement on that svelte PR. Can we open this again?

@benmonro
Copy link
Member

Sure

@benmonro benmonro reopened this Dec 30, 2021
@rgossiaux
Copy link

FWIW I discovered this library recently: https://github.com/DockYard/svelte-inline-compile which I am now using in svelte-headlessui. I think something like this library seems to me to be the nicest way of dealing with this, though it's not perfect.

@cibernox
Copy link

cibernox commented Jan 5, 2022

@rgossiaux @Akolyte01 I am one of the developers of https://github.com/DockYard/svelte-inline-compile. This week we plan to make it work for Vitest, a new trending test runner better suited for sveltekit apps than jest. We are working with the core team to make the testing experience nicer out of the box.
But it will remain usable in jest. The current syntax makes almost impossible to test slots and multiple components cooperating among them.

@cibernox
Copy link

cibernox commented Jan 11, 2022

For whoever is interested, we've released two packages that make testing components much nicer than the current state of things in Jest. It is similar to https://github.com/DockYard/svelte-inline-compile but less complicated internally and with less drawbacks.

Right now the experience of testing components that take slots, actions or that must interact with other components was pretty bad. Essentially the only way was to create a on-off component in the test folder that used your component in the way you wanted and render that component instead.

Our package https://github.com/dockyard/svelte-inline-component allows to define components inline in the test itself.
This is an example using sveltekit/vitest and this package:

import { render } from '@testing-library/svelte'
import { svelte } from 'svelte-inline-component';

describe('DefinitionEntry.svelte', () => {
  it('renders a link with the given href', async () => {
    const { getByTestId } = render(await svelte`
      <script>import DefinitionEntry from '$lib/DefinitionEntry.svelte';</script>
      <DefinitionEntry background="gray">
        <svelte:fragment slot="dt">I'm the description term</svelte:fragment>
        <svelte:fragment slot="dd">I'm the description definition</svelte:fragment>
      </DefinitionEntry>
    `);
    expect(getByTestId('definition-entry')).to.have.class('bg-gray-50');
    expect(getByTestId('dt')).to.have.text("I'm the description term");
    expect(getByTestId('dd')).to.have.text("I'm the description definition");
  });
});

I'm biased but IMO it is SO. MUCH. NICER to invoke components in tests with the same syntax you use in regular app code that I can't go back.

There are some downsides that we're working on to polish, like publishing VSCode plugin that enables svelte syntax and intellisense inside the strings for better developer experience. But it's very functional.

@benmonro
Copy link
Member

@cibernox I agree that is nice. feel free to update the testing-library.com docs to list this as an alternative, that will help raise awareness of your library too

@cibernox
Copy link

@benmonro I'll take a look. I'm not sure how to frame it within the docs of testing-library, because right now there's a lot of "if"s. Namely, that your app must use vitest, which is, as their own documentation takes great care of explaining, not production ready (although in my opinion, neither is jest and yet everyone uses it).

@benmonro
Copy link
Member

I would frame it just like that, maybe put a yellow warning at the top stating this is still early in development. But in my opinion, it's totally fine to offer alternative runners/environments. Additionally, you could also put it in the 'ecosystem' section and maybe just link to it there.
image

@PClmnt
Copy link

PClmnt commented Jan 28, 2022

How are we currently supposed to test something that is like this currently? It just doesn't work. The Layout component takes a slot ands obviously this library doesn't support that, right? Is the workaround to use something like svelte-inline-compile?

ParentComponent.svelte

<div
  class="position"
  in:fade={{ duration: 200 }}
  out:fade|local={{ duration: 200 }}
>
  <div
    class="feedback-frame"
    in:fly={{ y: 30, duration: 200 }}
    out:fly|local={{ y: 30, duration: 200 }}
  >
    <div class="close">
      <ClearButton on:click={cancelFeedback} />
    </div>
    <Layout gap="XS">
      {#if step === 0}
        <div class="ratings">
          {#each ratings as number}
            <ActionButton
              size="L"
              emphasized
              selected={number === rating}
              on:click={() => (step = 1)}
            >
              {number}
            </ActionButton>
          {/each}
        </div>
      {:else if step === 1}
        <Heading size="XS">What could be improved most in Budibase?</Heading>
        <Divider />
        <RadioGroup bind:value={improvements} {options} />
        <div class="footer">
          <Detail size="S">STEP 2 OF 3</Detail>
          <ButtonGroup>
            <Button secondary on:click={() => (step -= 1)}>Previous</Button>
            <Button primary on:click={() => (step += 1)}>Next</Button>
          </ButtonGroup>
        </div>

      {/if}
    </Layout>
  </div>
</div>

Layout.svelte

<div
  style="align-content:{alignContent};justify-items:{justifyItems};"
  class:horizontal
  class="container paddingX-{!noPadding && paddingX} paddingY-{!noPadding &&
    paddingY} gap-{!noGap && gap}"
>
  <slot />
</div>

@hnrq
Copy link

hnrq commented Apr 5, 2022

Any news on this?

@tobiasbueschel
Copy link

For whoever is interested, we've released two packages that make testing components much nicer than the current state of things in Jest. It is similar to https://github.com/DockYard/svelte-inline-compile but less complicated internally and with less drawbacks.

This is great, thank you for your efforts with the library @cibernox - it would be amazing if the render() function would natively support taking Svelte inline components as an argument. In the React world, I've written so many tests using the same approach (using jSX) and I couldn't go without it:

render(<Button>Click me</Button>)

@ivanhofer
Copy link

I'm currently using svelte-htm and it works well 👍

@wd-David
Copy link

I'm currently using svelte-htm and it works well 👍

@ivanhofer Can you share how you use svelte-htm?
This error pops out when I try to pass component to the html template literals:

render(html`<${MyComponent} //>`)

TypeError: Cannot read properties of undefined (reading '$$')
It seems this issue hasn't been addressed sveltejs/svelte#6584

@ivanhofer
Copy link

@davipon it worked fine until we upgraded our dependencies a few weeks back.
Now we use patch-package to work around the issue.
Changing parent_component.$$.root to parent_component?.$$.root will not have any side effects when running an application normally, but fixex the tests.

@benmccann
Copy link
Contributor

benmccann commented Sep 8, 2022

@davipon that looks like an issue in https://github.com/kenoxa/svelte-htm. I filed an issue there to see if the author can resolve it: kenoxa/svelte-htm#234

@wd-David
Copy link

wd-David commented Sep 8, 2022

@benmccann Thank you for your input. I'll dive into the issue and see how I can help to resolve that.

deboer-tim added a commit to deboer-tim/desktop that referenced this issue Jul 10, 2023
Changes almost all of the remaining pages to FormPages, using the existing icons
that are used in the actions to open the form and the form button:
- Build image
- Pull image
- Play Kube YAML
- Create Pod from containers

Adds a new 'actions' slot for the PullImage page's Manage registries button.
Adds 'missing' pull image action to the button to match other pages.
Makes Kube play icon resizable so that a larger form can be used in the header.

Svelte has no API to test slots directly (see below), so a FormPageSpec component is
added solely to be able to test that the icon/actions/content slots work correctly.
The actions section is also tested by confirming the pull image registry button.

testing-library/svelte-testing-library#48
https://stackoverflow.com/questions/60771586/testing-svelte-components-that-use-slots

Signed-off-by: Tim deBoer <git@tdeboer.ca>
deboer-tim added a commit to containers/podman-desktop that referenced this issue Jul 11, 2023
Changes almost all of the remaining pages to FormPages, using the existing icons
that are used in the actions to open the form and the form button:
- Build image
- Pull image
- Play Kube YAML
- Create Pod from containers

Adds a new 'actions' slot for the PullImage page's Manage registries button.
Adds 'missing' pull image action to the button to match other pages.
Makes Kube play icon resizable so that a larger form can be used in the header.

Svelte has no API to test slots directly (see below), so a FormPageSpec component is
added solely to be able to test that the icon/actions/content slots work correctly.
The actions section is also tested by confirming the pull image registry button.

testing-library/svelte-testing-library#48
https://stackoverflow.com/questions/60771586/testing-svelte-components-that-use-slots

Signed-off-by: Tim deBoer <git@tdeboer.ca>
@tomolenet
Copy link

Any news on this? svelte-htm does not support Svelte 4 kenoxa/svelte-htm#269

How do you test slots?

@winston0410
Copy link

same as looking for new solution for sveltev4

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

Successfully merging a pull request may close this issue.