--- title: "Testing web apps" description: "A comprehensive guide to testing web applications with Deno" url: "/examples/web_testing_tutorial/" --- Deno is a JavaScript runtime that operates outside of the browser, as such, you cannot directly manipulate the Document Object Model in Deno as you would in a browser. However you can use a library like [deno-dom](https://jsr.io/@b-fuze/deno-dom), [JSDom](https://github.com/jsdom/jsdom) or [LinkeDOM](https://www.npmjs.com/package/linkedom) to work with the DOM. This tutorial will guide you through how to effectively test your web applications using Deno. ## Testing UI components and DOM manipulation Let's say you have a website that shows a uers's profile, you can set up a test function to verify that the DOM element creation works correctly. This code sets up a basic card element then tests whether the created DOM structure matches what was expected. ```ts import { assertEquals } from "jsr:@std/assert"; import { DOMParser, Element } from "jsr:@b-fuze/deno-dom"; // Component or function that manipulates the DOM function createUserCard(user: { name: string; email: string }): Element { const doc = new DOMParser().parseFromString("
", "text/html")!; const card = doc.createElement("div"); card.className = "user-card"; const name = doc.createElement("h2"); name.textContent = user.name; card.appendChild(name); const email = doc.createElement("p"); email.textContent = user.email; email.className = "email"; card.appendChild(email); return card; } Deno.test("DOM manipulation test", () => { // Create a test user const testUser = { name: "Test User", email: "test@example.com" }; // Call the function const card = createUserCard(testUser); // Assert the DOM structure is correct assertEquals(card.className, "user-card"); assertEquals(card.children.length, 2); assertEquals(card.querySelector("h2")?.textContent, "Test User"); assertEquals(card.querySelector(".email")?.textContent, "test@example.com"); }); ``` ## Testing Event Handling Web applications often handle user interactions through events. Here's how to test event handlers. This code sets up a button that tracks its active/inactive state and updates its appearance when clicked. The accompanying test verifies the toggle functionality by creating a button, checking its initial state, simulating clicks, and asserting that the button correctly updates its state after each interaction: ```ts import { DOMParser } from "jsr:@b-fuze/deno-dom"; import { assertEquals } from "jsr:@std/assert"; // Component with event handling function createToggleButton(text: string) { const doc = new DOMParser().parseFromString("", "text/html")!; const button = doc.createElement("button"); button.textContent = text; button.dataset.active = "false"; button.addEventListener("click", () => { const isActive = button.dataset.active === "true"; button.dataset.active = isActive ? "false" : "true"; button.classList.toggle("active", !isActive); }); return button; } Deno.test("event handling test", () => { // Create button const button = createToggleButton("Toggle Me"); // Initial state assertEquals(button.dataset.active, "false"); assertEquals(button.classList.contains("active"), false); // Simulate click event button.dispatchEvent(new Event("click")); // Test after first click assertEquals(button.dataset.active, "true"); assertEquals(button.classList.contains("active"), true); // Simulate another click button.dispatchEvent(new Event("click")); // Test after second click assertEquals(button.dataset.active, "false"); assertEquals(button.classList.contains("active"), false); }); ``` ## Testing Fetch Requests Testing components that make network requests requires mocking the fetch API. In the below example we will [mock](/examples/mocking_tutorial/) the `fetch` API to test a function that retrieves user data from an external API. The test creates a spy function that returns predefined responses based on the requested URL, allowing you to test both successful requests and error handling without making actual network calls: ```ts import { assertSpyCalls, spy } from "jsr:@std/testing/mock"; import { assertEquals } from "jsr:@std/assert"; // Component that fetches data async function fetchUserData( userId: string, ): Promise<{ name: string; email: string }> { const response = await fetch(`https://api.example.com/users/${userId}`); if (!response.ok) { throw new Error(`Failed to fetch user: ${response.status}`); } return await response.json(); } Deno.test("fetch request test", async () => { // Mock fetch response const originalFetch = globalThis.fetch; const mockFetch = spy(async (input: RequestInfo | URL): Promise