Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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 pages with layout dependencies. #425

Closed
niemyjski opened this issue Feb 22, 2025 · 1 comment
Closed

Testing pages with layout dependencies. #425

niemyjski opened this issue Feb 22, 2025 · 1 comment

Comments

@niemyjski
Copy link

Is there a best practice or a good way to test code that has setup in a parent layout. For example, I used svelte kit latest sample and then tested a page that was using svelte query provider defined in the parent layout.

import { render, screen } from '@testing-library/svelte';
import '@testing-library/jest-dom/vitest';
import { describe, expect, test } from 'vitest';

import Page from './+page.svelte';

describe('/+page.svelte', () => {
    test('should render h1', () => {
        render(Page);
        expect(screen.getByRole('heading', { level: 1 })).toBeInTheDocument();
    });
});

This fails with:

 FAIL   client  src/routes/status/page.svelte.test.ts > /+page.svelte > should render h1
Error: No QueryClient was found in Svelte context. Did you forget to wrap your component with QueryClientProvider?
 ❯ getQueryClientContext node_modules/@tanstack/svelte-query/dist/context.js:7:15
      5|     const client = getContext(_contextKey);
      6|     if (!client) {
      7|         throw new Error('No QueryClient was found in Svelte context. Did you forget to wrap your component with QueryClientProvider?');
       |               ^
      8|     }

I'm also noticing other things like dynamic env's are causing issues too.

@mcous
Copy link
Collaborator

mcous commented Feb 22, 2025

@niemyjski this is a very good question! Thanks for taking the time to post it.

I lead a team maintaining a large SvelteKit app that uses svelte-query for its client-side API state management. This is a recommendation from me personally rather than anything "official," but I've found the best1 strategy for component tests is pretty classic Uncle Bob: separate the stuff you want to test away from the framework glue. In practice, this means:

  • No component-level tests for +page.svelte/+layout.svelte
  • No component-level tests for anything that wires into createQuery, createMutation, etc.
  • No/few component-level tests for components that subscribe to context
  • Structure these "framework" components so they delegate all interesting work to props-driven components and/or pure functions, and write tests for those units instead of the glue
  • Include small Playwright E2E suites to validate proper wire-up of your framework glue
    • TypeScript and static analysis are also a great, if incomplete, tools to validate framework wire-up

For a simple, if slightly contrived example, if I wanted to test a user dashboard page's heading, I might write something like:

<!-- dashboard/+page.svelte -->
<script>
import { createUserQuery } from '$lib/api'
import DashboardHeading from './dashboard-heading.svelte'

const userQuery = createUserQuery()
</script>

<DashboardHeading user={$userQuery.data} />
<!-- dashboard/dashboard-heading.svelte -->
<script>
import type { User } from '$lib/api';

const { user }: { user: User | undefined } = $props();
</script>

<h1>Hello {user?.name ?? 'friend'}!</h1>
// dashboard-heading.spec.ts
// ...
it('renders level 1 heading with user name', () => {
  render(DashboardHeading, { user: { name: 'Alice' } })

  const heading = screen.getByRole('heading', { level: 1, name: /hello alice/iu })
  expect(heading).toBeInTheDocument()
})

From there, I would also make sure that I had an E2E test for this page that also checked that there was a level-1 heading on the page matching.

I've seen a number of guides online that recommend mocking out SvelteKit imports in your tests, but I definitely recommend your try to minimize or eliminate mocking in component tests. I'm a huge fan of mocking, but I've gone down the mock-heavy-component-tests path with React and RTL, and all it got me was a very brittle test suite that slowed my team down. Instead, I prefer to acknowledge that component tests are, by nature, highly integrated with code outside my control, and then do my best to minimize how many layers get tested in a given component test.

Footnotes

  1. "Best" meaning "high test coverage of interesting, product-specific logic while prioritizing development speed."

@testing-library testing-library locked and limited conversation to collaborators Feb 26, 2025
@mcous mcous converted this issue into discussion #426 Feb 26, 2025

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants