svelte-tdd Svelte Themes

Svelte Tdd

Svelte Test Driven Development by Daniel Irvine

Chapters

  • Preface [2023-11-13]
  • Part 1: Learning the TDD Cycle [2023-11-14]
    • Chapter 01: Setting up for Testing [2023-11-13]
    • Chapter 02: Introducing the Red-Green-Refactor Workflow [2023-11-13]
    • Chapter 03: Loading Data into a Route [2023-11-14]
    • Chapter 04: Saving Form Data [2023-11-14]
    • Chapter 05: Validating Form Data [2023-11-14]
    • Chapter 06: Editing Form Data [2023-11-14]
  • Part 2: Refactoring Tests and Application Code [2023-11-17]
    • Chapter 07: Tidying up Test Suites [2023-11-16]
    • Chapter 08: Creating Matchers to Simplify Tests [2023-11-16]
    • Chapter 09: Extracting Logic Out of the Framework [2023-11-16]
    • Chapter 10: Test-Driving API Endpoints [2023-11-16]
    • Chapter 11: Replacing Behavior with a Side-By-Side Implementation [2023-11-17]
    • Chapter 12: Using Component Mocks to Clarify Tests [2023-11-17]
    • Chapter 13: Adding Cucumber Tests [2023-11-17]
  • Part 3: Testing SvelteKit Features
    • Chapter 14: Testing Authentication
    • Chapter 15: Test-Driving Svelte Stores [2023-11-19]
    • Chapter 16: Test-Driving Service Workers

Notes

Preface

  • "It wasn't long before I discovered TDD and how it could help me have a simpler, quieter, calmer life."

Chapter 03 - Loading Data into a Route

  • Template for testing SvelteKit server-side page load functionality
import { describe, it, expect } from "vitest";
import { load } from "./+page.server.js";

describe("/birthdays - load", () => {
  it("returns a fixture of two items", () => {
    const result = load();
    expect(result).toEqual({
      people: [
        { name: "Hercules", dob: "2021-01-01" },
        { name: "Athena", dob: "2021-01-02" },
      ],
    });
  }) - [];
});

Chapter 04 - Saving Form Data

  • Template for testing SvelteKit server-side form actions functionality
// mocking form data request object
const createFormDataFromObject = (obj) => {
  const formData = new FormData();
  Object.entries(obj).forEach(([key, value]) => {
    formData.append(key, value);
  });
  return formData;
};

export const createFormDataRequest = (obj) => ({
  formData: () =>
    new Promise((resolve) => resolve(createFormDataFromObject(obj))),
});
// assertion on actions object
import { load, actions } from "./+page.server.js";

const request = createFormDataRequest({
  name: "Zeus",
  dob: "1992-01-01",
});
await actions.default({ request });
expect(load().birthdays).toContainEqual(
  expect.objectContaining({ name: "Zeus", dob: "1992-01-01" })
);

Chapter 05 - Validating Form Data

  • Template for testing SvelteKit component displays form prop error messages
describe("validation errors", () => {
  it("displays a message", () => {
    render(BirthdayForm, {
      form: {
        error: "An error",
      },
    });
    expect(screen.queryByText("An error")).toBeVisible();
  });
});

Chapter 06 - Editing Form Data

  • Added ability to edit birthday data in addition to creation.
  • Changed data structure from a list to a Map.
  • Added an edit state to the page component

Chapter 07 - Tidying up Test Suites

  • Ways to keep your test suites tidy.
  • Application code requires building abstractions and encapsulating details, with deep layers of connecting objects.
  • "Test benefit from being shallow, with each test statement having a clear effect.
  • Test suites have just one flow
  • The primary mechanism you have to control complexity in test suites is abstracting functions that hide detail.
  • Hiding necessary but irrelevant data is a key method for keeping unit tests succinct and clear.
  • Three Tips:
      1. Page Object Models for Playwright end-to-end tests
      1. Action helps for Act phase of Vitest unit tests
      1. Factories for Arrange phase of Vitest unit tests (might be)

Chapter 08 - Creating Matchers to Simply Tests

  • Custom Matcher:
    • toBeUnprocessableEntity
      • Does not save data
      • Returns error code (e.g. 422)
      • Returns error message
      • Returns unprocessed values
  • Basic structure of a matcher:
export function toTestSomething(received, expected) {
  const pass = ...
  const message = () => "..."

  return {
    pass,message
  }
}
  • Negated Matcher: true value for pass means expectation failed
  • It's important that the custom matcher is defined using the function keyword in order for it to gain access to utility function provided via Vite
    • this.equals
    • this.utils.diff
    • this.utils.stringify
    • this.isNot

Chapter 09 - Extracting Logic Out of the Framework

  • The design of application code should make it easy to write automated unit tests

Chapter 10 - Test-Driving API Endpoints

  • Playwright can be used to make HTTP Request via the request parameter
test('title', async ({request}) => {
  const response = await request.get(url, {data: {...}})
})
  • Use expect.hasAssertions() to require expect assertions to be called in a catch of a try-catch block

Chapter 11 - Replacing Behavior with a Side-By-Side Implementation

  • side-by-side implementation - is a way to use tests to replace the existing code while ensuring the test suite remains on Green
  • In Vitest, a spy is created by calling vi.fn
  • Incredibly confused by this chapters implementation, but going to brush it off and continue forward

Chapter 12 - Using Component Mocks to Clarify Tests - 15 pages

  • The number-one rule when using component mocks, and test doubles in general, is to avoid building any control logic into them.
    • mockReturnValue and mockResolvedValue always return fixed values
    • Avoid setting up a test double in a beforeEach block
  • Hand-rolled component stubs rely on Vitest's vi.mock function and __mocks__ directory
  • JSON.stringify is a handy method to use in component mocks when you just want to verify that the correct prop structure is passed to a mock from its parent
  • BIG NEGATIVE WITH MOCKING COMPONENTS:
    • it's challenging to keep the mock aligned with real implementations.
  • If needed, use svelte-component-double package to mock components and gain access to useful custom matchers: toBeRendered and toBeRenderedWithProps
  • Avoid component mocks if possible because they added complexity to the testing suite

Chapter 13 - Adding Cucumber Tests - 10 pages

  • Cucumber tests are not written in JavaScript code. They use a special syntax known as Gherkin within feature files
  • Given, When, Then
  • The Gherkin syntax allows for product features to be specified by non-coders in a more human-friendly format, but eventually code re-enters the scene within the step definitions
  • Semi-useful to now, but feels just like Playwright E2E tests with more steps.

Chapter 14 - Testing Authentication - 10 pages

Chapter 15 - Test-Driving Svelte Stores - 5 pages

  • vi.useFakeTimers and vi
  • writable([])
  • Three things to test:
      1. Setting the initial value
      1. Displaying the value (1. On Initial load and 2. On update)
      1. Updating the value

Chapter 16 - Test-Driving Service Workers - 10 pages

Top categories

Loading Svelte Themes