Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/children-snippet/CardWithChildren.test.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import Card from "./Component.svelte";
</script>

<Card>
<p>Hello World</p>
<span>Multiple elements</span>
</Card>
11 changes: 11 additions & 0 deletions tests/children-snippet/CardWithHeader.test.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script>
import Card from "./Component.svelte";
</script>

<Card>
{#snippet header()}
Card Title
{/snippet}

Card body content
</Card>
7 changes: 7 additions & 0 deletions tests/children-snippet/CardWithoutHeader.test.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
import Card from "./Component.svelte";
</script>

<Card>
Just content
</Card>
35 changes: 35 additions & 0 deletions tests/children-snippet/Component.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<svelte:options runes={true} />

<script>
let { children, header } = $props();
</script>

<div data-testid="card" class="card">
{#if header}
<div data-testid="card-header" class="header">
{@render header()}
</div>
{/if}
<div data-testid="card-content" class="content">
{@render children()}
</div>
</div>

<style>
.card {
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
overflow: hidden;
}

.header {
background-color: #f7fafc;
padding: 1rem;
border-bottom: 1px solid #e2e8f0;
font-weight: bold;
}

.content {
padding: 1rem;
}
</style>
35 changes: 35 additions & 0 deletions tests/children-snippet/Reference.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<svelte:options runes={true} />

<script>
let { children, header } = $props();
</script>

<div data-testid="card" class="card">
{#if header}
<div data-testid="card-header" class="header">
{@render header()}
</div>
{/if}
<div data-testid="card-content" class="content">
{@render children()}
</div>
</div>

<style>
.card {
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
overflow: hidden;
}

.header {
background-color: #f7fafc;
padding: 1rem;
border-bottom: 1px solid #e2e8f0;
font-weight: bold;
}

.content {
padding: 1rem;
}
</style>
5 changes: 5 additions & 0 deletions tests/children-snippet/prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Card Component Task

Create a Svelte 5 Card component that uses the children snippet pattern.

The component should render any content passed to it inside a styled card wrapper. Use `$props` to destructure the `children` snippet and render it with `{@render children()}`. Optionally accept a `header` snippet prop that renders above the main content when provided.
51 changes: 51 additions & 0 deletions tests/children-snippet/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { render, screen } from "@testing-library/svelte";
import { expect, test, describe } from "vitest";
import Card from "./Component.svelte";

// Helper component that uses the Card with children content
import CardWithChildren from "./CardWithChildren.test.svelte";
import CardWithHeader from "./CardWithHeader.test.svelte";
import CardWithoutHeader from "./CardWithoutHeader.test.svelte";

describe("Card component with children snippet", () => {
test("renders children content", () => {
render(CardWithChildren);

const card = screen.getByTestId("card");
const content = screen.getByTestId("card-content");

expect(card).toBeInTheDocument();
expect(content).toBeInTheDocument();
expect(content).toHaveTextContent("Hello World");
});

test("renders header when provided", () => {
render(CardWithHeader);

const header = screen.getByTestId("card-header");
const content = screen.getByTestId("card-content");

expect(header).toBeInTheDocument();
expect(header).toHaveTextContent("Card Title");
expect(content).toHaveTextContent("Card body content");
});

test("does not render header when not provided", () => {
render(CardWithoutHeader);

const header = screen.queryByTestId("card-header");
const content = screen.getByTestId("card-content");

expect(header).not.toBeInTheDocument();
expect(content).toBeInTheDocument();
expect(content).toHaveTextContent("Just content");
});

test("renders multiple children elements", () => {
render(CardWithChildren);

const content = screen.getByTestId("card-content");
expect(content.querySelector("p")).toBeInTheDocument();
expect(content.querySelector("span")).toBeInTheDocument();
});
});
57 changes: 57 additions & 0 deletions tests/state-class/Component.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<svelte:options runes={true} />

<script>
class Counter {
count = $state(0);

increment() {
this.count++;
}

decrement() {
this.count--;
}

reset() {
this.count = 0;
}
}

const counter = new Counter();
</script>

<div class="counter">
<button data-testid="decrement-button" onclick={() => counter.decrement()}>-</button>
<span data-testid="count-value">{counter.count}</span>
<button data-testid="increment-button" onclick={() => counter.increment()}>+</button>
<button data-testid="reset-button" onclick={() => counter.reset()}>Reset</button>
</div>

<style>
.counter {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
}

button {
background-color: #e2e8f0;
border: none;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
font-size: 1.25rem;
cursor: pointer;
}

button:hover {
background-color: #cbd5e0;
}

span {
font-size: 1.5rem;
font-weight: bold;
min-width: 2rem;
text-align: center;
}
</style>
57 changes: 57 additions & 0 deletions tests/state-class/Reference.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<svelte:options runes={true} />

<script>
class Counter {
count = $state(0);

increment() {
this.count++;
}

decrement() {
this.count--;
}

reset() {
this.count = 0;
}
}

const counter = new Counter();
</script>

<div class="counter">
<button data-testid="decrement-button" onclick={() => counter.decrement()}>-</button>
<span data-testid="count-value">{counter.count}</span>
<button data-testid="increment-button" onclick={() => counter.increment()}>+</button>
<button data-testid="reset-button" onclick={() => counter.reset()}>Reset</button>
</div>

<style>
.counter {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
}

button {
background-color: #e2e8f0;
border: none;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
font-size: 1.25rem;
cursor: pointer;
}

button:hover {
background-color: #cbd5e0;
}

span {
font-size: 1.5rem;
font-weight: bold;
min-width: 2rem;
text-align: center;
}
</style>
11 changes: 11 additions & 0 deletions tests/state-class/prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Reactive Class Counter Task

Create a Svelte 5 component that uses a reactive class for state management.

Define a Counter class with:
- A `count` field using `$state` initialized to 0
- An `increment()` method that increases count by 1
- A `decrement()` method that decreases count by 1
- A `reset()` method that sets count back to 0

Instantiate the class and use it to build a counter UI with buttons for each action.
87 changes: 87 additions & 0 deletions tests/state-class/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { render, screen } from "@testing-library/svelte";
import { expect, test, describe } from "vitest";
import userEvent from "@testing-library/user-event";
import Counter from "./Component.svelte";

describe("Counter component with reactive class", () => {
test("renders with initial count of 0", () => {
render(Counter);

const countElement = screen.getByTestId("count-value");
expect(countElement).toHaveTextContent("0");
});

test("increments count when + is clicked", async () => {
const user = userEvent.setup();
render(Counter);

const incrementButton = screen.getByTestId("increment-button");
const countElement = screen.getByTestId("count-value");

await user.click(incrementButton);
expect(countElement).toHaveTextContent("1");

await user.click(incrementButton);
expect(countElement).toHaveTextContent("2");
});

test("decrements count when - is clicked", async () => {
const user = userEvent.setup();
render(Counter);

const decrementButton = screen.getByTestId("decrement-button");
const countElement = screen.getByTestId("count-value");

await user.click(decrementButton);
expect(countElement).toHaveTextContent("-1");

await user.click(decrementButton);
expect(countElement).toHaveTextContent("-2");
});

test("resets count when reset is clicked", async () => {
const user = userEvent.setup();
render(Counter);

const incrementButton = screen.getByTestId("increment-button");
const resetButton = screen.getByTestId("reset-button");
const countElement = screen.getByTestId("count-value");

// Increment a few times
await user.click(incrementButton);
await user.click(incrementButton);
await user.click(incrementButton);
expect(countElement).toHaveTextContent("3");

// Reset
await user.click(resetButton);
expect(countElement).toHaveTextContent("0");
});

test("reset works after decrementing", async () => {
const user = userEvent.setup();
render(Counter);

const decrementButton = screen.getByTestId("decrement-button");
const resetButton = screen.getByTestId("reset-button");
const countElement = screen.getByTestId("count-value");

// Decrement
await user.click(decrementButton);
await user.click(decrementButton);
expect(countElement).toHaveTextContent("-2");

// Reset should go back to 0
await user.click(resetButton);
expect(countElement).toHaveTextContent("0");
});

test("all buttons are present", () => {
render(Counter);

expect(screen.getByTestId("increment-button")).toBeInTheDocument();
expect(screen.getByTestId("decrement-button")).toBeInTheDocument();
expect(screen.getByTestId("reset-button")).toBeInTheDocument();
expect(screen.getByTestId("count-value")).toBeInTheDocument();
});
});