Turn your manual testers into automation experts Request a DemoStart testRigor Free

Svelte Testing

Svelte Testing

Svelte is an open-source framework for building front-end applications. Using Svelte, you can quickly construct web applications as it simplifies writing UI components like navigation bars, comment sections, or contact forms. Although Svelte is similar to JavaScript frameworks like React and Vue, it distinguishes itself by converting your application into optimized JavaScript at build time, rather than run time. This strategy helps to mitigate performance costs usually incurred from the abstractions that a framework provides.

With Svelte, you can construct your entire application or create components as standalone packages that can be integrated into existing applications. However, to write an entire application, you need more than just Svelte. By employing SvelteKit, which is built on Svelte, you can utilize features like a router and server-side rendering.

Applications built using Svelte are composed of one or more components. Components are self-contained blocks of code that include HTML, CSS, and JavaScript, which belong together. These components are reusable and written in a .svelte file. You can test these components in the following ways:

Unit Testing

Unit Testing forms the base of the testing pyramid. The primary focus is on testing individual functions and the edge cases of these functions. Your unit test suite needs to be lightweight so it can be run in isolation whenever needed. For this, you ought to mock external dependencies of a function like database calls, API calls, helper and service calls, browser-related UI element calls, or network calls. It's a good practice to write both positive and negative test cases for functions. Since Svelte is about the front end, testing various functions that are part of the UI components you've built is necessary. You can do this using the following tools:

Testing using Vitest

Vitest is a Vite-native unit testing framework. When setting up a SvelteKit project, you have the option to configure Vitest for unit testing. It comes with features like multi-threading via Tinypool, built-in Chai assertions, Jest-compatible APIs, and built-in Tinyspy for mocking, among others. Below is an example using the mock capability of Vitest to perform unit testing. This test verifies that the 'fn' function is a mock function, that it was called with the correct arguments, and that it returns its argument when called with the 'mockImplementation' method.

import { expect, vi } from 'vitest'

const fn = vi.fn()

fn('hello', 1)

expect(vi.isMockFunction(fn)).toBe(true)
expect(fn.mock.calls[0]).toEqual(['hello', 1])

fn.mockImplementation(arg => arg)

fn('world', 2)

expect(fn.mock.results[1].value).toBe('world')

Testing using Jest

Jest is a popular tool for testing JavaScript-based applications. It boasts features like parallel execution of tests, generating code coverage, mocking functions, and handling exceptions effectively. By default, Jest looks for filenames ending with 'test.js'. Below is an example of a test case using Jest. In this test case, after creating a new instance of the component and passing in some props, initial assertions about the rendered output are made. Then, a user interaction is simulated by updating one of the component's props using '$set' and waiting for the component to update using 'await tick()' before making additional assertions about the updated output.

import { tick } from 'svelte';
import MyComponent from './MyComponent.svelte';

describe('MyComponent', () => {
  it('should render correctly', async () => {
    const target = document.createElement('div');
    const props = {
      name: 'John',
      age: 30
    };
    const component = new MyComponent({ target, props });
    
    expect(component).toBeTruthy();
    expect(target.textContent).toContain('Hello John! You are 30 years old.');
    
    // Simulate a user interaction by updating a prop and checking the updated output
    component.$set({ age: 31 });
    await tick();
    expect(target.textContent).toContain('Hello John! You are 31 years old.');
  });
});

Testing using the Svelte Testing Library

The Svelte Testing Library is a lightweight utility built on top of the Svelte and DOM Testing Library. It's used alongside tools like Vitest or Jest to simulate different functions and user interactions.

In the example below, the test uses the Svelte library to test the 'Hello Svelte' component. The test creates a new HTML element and sets it as the target for the 'Hello' component. Then, it asserts that the component was created successfully, the rendered HTML contains the expected content, and the rendered HTML matches a snapshot. The test also simulates user interaction by clicking a button in the rendered HTML and waiting for the component to update using the 'tick' function from the Svelte library. After the component updates, the test asserts that the rendered HTML contains the expected content again.

import { tick } from 'svelte'
import Hello from '../components/Hello.svelte'

let host: HTMLElement

afterEach(() => {
  host.remove()
})

test('mount component', async () => {
  host = document.createElement('div')
  host.setAttribute('id', 'host')
  document.body.appendChild(host)
  const instance = new Hello({ target: host, props: { count: 4 } })
  expect(instance).toBeTruthy()
  expect(host.innerHTML).toContain('4 x 2 = 8')
  expect(host.innerHTML).toMatchSnapshot()
  const btn = host.getElementsByTagName('button')[0]
  btn.click() // or btn.dispatchEvent(new window.Event('click', { bubbles: true }))
  await tick()
  expect(host.innerHTML).toContain('4 x 3 = 12')
  btn.click()
  await tick()
  expect(host.innerHTML).toContain('4 x 4 = 16')
})

Here's another example of how the Svelte Testing Library is used. These tests check the basic functionality of the 'Comp' component by verifying that it renders correctly and that its button updates its text properly when clicked.

import '@testing-library/jest-dom'

import {render, fireEvent, screen} from '@testing-library/svelte'

import Comp from '../Comp'

test('shows proper heading when rendered', () => {
  render(Comp, {name: 'World'})
  const heading = screen.getByText('Hello World!')
  expect(heading).toBeInTheDocument()
})

test('changes button text on click', async () => {
  render(Comp, {name: 'World'})
  const button = screen.getByRole('button')
  
  expect(button).toHaveTextContent('Button Clicked')
})

Using Chai and Mocha

You can also use Mocha and Chai to automate unit tests for your Svelte application. Once the dependencies for Mocha and Chai are installed, you need to add a script in the package.json file of your application to run the tests. The rule to have test files ending with test.js applies here as well.

Integration Testing

Unit tests focus on individual functions, ensuring they behave as expected. Now, let's broaden the scope a bit. Each of these functions needs to integrate smoothly with others and with other dependencies like databases, file systems, and network systems. If we focus on areas where a function exercises its dependencies, we are checking whether the function has been properly integrated into the system—this is integration testing. Unlike unit tests, you needn't write integration tests for every single component. Instead, strategically pick those components where crucial integrations occur. In integration testing, you can use actual resources as well as mocks. This decision depends on the specific integration you are testing. For example, if you're testing the integration of the database with the UI, all other APIs expected to work for that test can be mocked.

You can write your integration tests using Vitest, Jest, and the Svelte Testing Library. Here's an example of a component with a counter. The tests check if the counter increments and whether this is reflected in the footer and header, which are separate components.

// ExampleComponent.test.js
import { render, screen, fireEvent } from '@testing-library/svelte';
import ExampleComponent from './ExampleComponent.svelte';

describe('ExampleComponent', () => {
  it('renders title and count', () => {
    render(ExampleComponent, { title: 'Test Component' });
    const title = screen.getByText('Test Component');
    const count = screen.getByText('Count: 0');
    expect(title).toBeInTheDocument();
    expect(count).toBeInTheDocument();
  });
  
  it('increments count when button is clicked', async () => {
    render(ExampleComponent);
    const button = screen.getByText('Increment Count');
    fireEvent.click(button);
    const count = await screen.findByText('Count: 1');
    expect(count).toBeInTheDocument();
  });
});

Here's another example using the Vitest library, which uses Jest as the test runner and provides additional helpers to simplify testing React applications. The test is designed to check the interaction between multiple components and events. It is testing the behavior of the form component on successful submission, which involves simulating user input events and checking the resulting state of the form's input fields. Additionally, it is using the waitFor function from the @testing-library/react library to wait for a change in the state of the component.

/**
 * @jest-environment jsdom
 */
import { fireEvent, waitFor } from '@testing-library/react';
// note: you can make these globally available from vite.config.js
// see the Vitest docs for more: https://vitest.dev/config/#globals
import { describe, expect, it, vi } from 'vitest';
import { formSetup } from '../client-utils';

describe('Form', () => {
  it('resets on successful submission', async () => {
    const { nameInput, hexCodeInput, submitButton } = formSetup(vi);
    fireEvent.input(nameInput, { target: { value: 'Evan Who?' } });
    fireEvent.input(hexCodeInput, { target: { value: '#ccc' } });
    expect(nameInput.value).toEqual('Evan Who?');
    expect(hexCodeInput.value).toEqual('#ccc');
    
    await waitFor(() => {
      fireEvent.click(submitButton);
      expect(nameInput.value).toEqual('');
      expect(hexCodeInput.value).toEqual('');
    });
  });
});

Component Testing

When it comes to Svelte, we deal with components. It's necessary to test each of them before they interact with the entire application system, for which we use component testing. Svelte considers the context of the test important. This means if a component is tested in isolation—its scenarios are checked without dependence on any other resources like components or APIs—then it is a component test. A component test may exercise one or more functions of the component.

Using Svelte Testing Library, Jest or Vitest

You can use Jest, Vitest along with the Svelte Testing Library to write component tests.

Here is an example of a to-do list application. In this test, the render function from @testing-library/svelte is used to render the component, and the fireEvent function is used to simulate user interaction with the component. The test verifies that a new todo is added correctly by checking the length of the todo list after clicking the "Add" button, and that the new todo appears in the list.

import { render, screen, fireEvent } from "@testing-library/svelte";
import App from "./App.svelte";

describe("App", () => {
  const PREDEFINED_TODOS = 3;
  	
  // other stuff
  	
  test("should add a todo", async () => {
    render(App);
    const input = screen.getByLabelText("Todo");
    const value = "Buy milk";
    await fireEvent.input(input, { target: { value } });
    await fireEvent.click(screen.getByText("Add"));
    const todoListItems = screen.getAllByRole("listitem");
    expect(screen.getByText(value)).toBeInTheDocument();
    expect(todoListItems.length).toEqual(PREDEFINED_TODOS + 1);
  });
		
});

Using Cypress

Cypress is a well-known end-to-end testing tool that can also be used for component testing in Svelte. It supports writing tests with Vite or Webpack. Once you install Cypress into your project, you will be guided by Cypress's UI to set up component tests. If you're using Vite, you need to update the same in the cypress.config.js file, and the same applies to other bundlers like Webpack. Here's a simple example of a component test for a Stepper component that has zero dependencies and one internal state: a counter that can be incremented or decremented.

import Stepper from './Stepper.svelte'

describe('Stepper', () => {
  it('mounts', () => {
    cy.mount(Stepper)
  })
})

Using WebdriverIO

WebdriverIO is built on the WebDriver protocol and allows you to control a browser using the same APIs as a user. It supports multiple programming languages and test runners and provides many useful features such as synchronization, smart selectors, and a fluent API that simplifies writing and organizing tests. WebdriverIO is commonly used for end-to-end testing, but it can also be used for other types of tests such as integration and component testing.

End-to-End Testing

Until now, we've been testing the code to ensure it produces the expected results. Let's now focus on testing the application as a whole to ensure it behaves as expected. With end-to-end testing, the focus is on user scenarios to see if the modules or components function together to deliver the desired outcome.

Here are some tools you can use to test your application developed with Svelte or SvelteKit:

  • Playwright
  • Cypress
  • WebdriverIO
  • testRigor

Playwright

Playwright is a testing tool that allows developers to write end-to-end tests simulating user interactions with web browsers like Chrome, Firefox, and Safari. It provides a high-level API that enables developers to write tests in JavaScript, TypeScript, Python, or C#.

Here's an example of how a test using Playwright might look:

import { test, expect } from '@playwright/experimental-ct-svelte';
import HelloWorld from './HelloWorld.svelte';

test.use({ viewport: { width: 500, height: 500 } });

test('should work', async ({ mount }) => {
  const component = await mount(HelloWorld, {
    props: {
      msg: 'Greetings',
    },
  });
  
  await expect(component).toContainText('Greetings');
});

Cypress

Cypress offers many capabilities that facilitate writing end-to-end tests. Below is an example of a test that clicks on the increment and decrement buttons while asserting that the output is as expected.

import Stepper from './Stepper.svelte'

describe('Stepper', () => {

  it('when the increment button is pressed, the counter is incremented', () => {
    cy.mount(Stepper)
    cy.get('[data-cy=increment]').click()
    cy.get('[data-cy=counter]').should('have.text', '1')
  })
  it('when the decrement button is pressed, the counter is decremented', () => {
    cy.mount(Stepper)
    cy.get('[data-cy=decrement]').click()
    cy.get('[data-cy=counter]').should('have.text', '-1')
  }) 

})

WebDriver I/O

You can use WebDriverIO to write end-to-end tests for your Svelte application. In this example, the test simulates a long press on a button, waits for 2.5 seconds, and then checks if a paragraph element is displayed. It then moves the cursor out of the button and back in, and checks if the paragraph element is no longer displayed.

import { $, browser, expect } from '@wdio/globals'
import { render } from '@testing-library/svelte'
import Longpress from '../lib/Longpress.svelte'

describe('Svelte Component Testing', () => {
  it('increments value on click', async () => {
    const { getByText } = render(Longpress)
    const $btn = await $(getByText('press and hold'))
    
    await expect($('p')).not.toBeExisting()
    
    await browser.action('pointer')
      .move({ origin: $btn })
      .down()
      .pause(2500)
      .up()
      .perform()
    	
    await expect($('p')).toBeExisting()
    
    await browser.action('pointer')
      .move({ x: 0, y: 0 }) // move out
      .move({ origin: $btn }) // move back in
      .perform()
    
    await expect($('p')).not.toBeExisting()
  })
})

testRigor

While the tools mentioned above effectively accomplish their tasks, they all require coding knowledge. However, for scenarios where a cloud-based, scalable solution is needed or where input is desired in the form of test cases and reviews from manual testers and business team members, these tools might fall short. For these scenarios, a tool like testRigor can be an invaluable asset.

testRigor is an AI-driven, codeless test automation platform that enables teams to develop complex end-to-end test automation without requiring coding skills. This no-code tool allows for ease of collaboration without dependence on other tools to act as intermediaries. It allows you to write tests in plain English, without needing to define the behavior of these English sentences, as long as you refer to the documentation guide on their website. Locating UI elements becomes hassle-free: simply refer to any element how you see it on the screen.

With testRigor, organizations can experience significant enhancements in software testing and a reduction in defect escape rate. Its advanced AI engine allows for plain English test statements, generative AI test creation, simplified test creation and execution, and minimal maintenance. Furthermore, testRigor can test a comprehensive set of functionalities such as web, native and hybrid mobile applications, native desktop applications, emails, SMS, phone calls, 2FA, downloaded files, databases, and more.

Here is the testRigor equivalent of the test scenario mentioned under Cypress:

//navigate to the page having the 2 buttons
grab value from "counter" and save it as "currentCount"
click "increase" to the left of "counter"
check that page contains expression "${currentCount}+1" 
click "decrease" to the right of "counter"
check that page contains stored value "currentCount"

Here is another example of a purchase on an e-commerce website.

login
click "Cart" 
click "Proceed to payment" 
check that url is "https://www.snapdeal.com/proceedToCheckoutPage#makePayment"
click "Credit Card"
enter stored value "cardnumber" into "Card Number" roughly above the "/"
click "MM" on the left of "/"
click "04" below "MM"
click "YY" on the right of "/"
click "27" below "YY"
enter stored value "cvv" into "CVV" 
click "Pay" 
check that url contains value "https://api.juspay.in/v2/txns"

Conclusion

Using Svelte with SvelteKit is a great choice for developing frontend components. As you do so, be sure to give equal importance to testing your work using the appropriate test tools. Remember, the tool you choose will depend on your specific requirements.

Join the next wave of functional testing now.
A testRigor specialist will walk you through our platform with a custom demo.