Skip to content

Commit 1f65ed3

Browse files
committed
docs: import AuthService in mocking tutorial
1 parent 00ef432 commit 1f65ed3

1 file changed

Lines changed: 53 additions & 52 deletions

File tree

examples/tutorials/mocking.md

Lines changed: 53 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -548,25 +548,20 @@ authentication service that:
548548
2. Calls an API to authenticate
549549
3. Stores tokens with expiration times
550550

551-
In the example below, we'll create a full `AuthService` class that handles user
552-
login, token management, and authentication. We'll test it thoroughly using
553-
various mocking techniques covered earlier: stubbing fetch requests, spying on
554-
methods, and manipulating time to test token expiration - all within organized
555-
test steps.
551+
In the example below, we'll create a full `AuthService` class in an application
552+
module that handles user login, token management, and authentication. Then we'll
553+
import it from a test module and test it thoroughly using various mocking
554+
techniques covered earlier: stubbing fetch requests, spying on methods, and
555+
manipulating time to test token expiration, all within organized test steps.
556556

557557
Deno's testing API provides a useful `t.step()` function that allows you to
558558
organize your tests into logical steps or sub-tests. This makes complex tests
559559
more readable and helps pinpoint exactly which part of a test is failing. Each
560560
step can have its own assertions and will be reported separately in the test
561-
output.
561+
output. First, define the service in its own module:
562562

563-
```ts
564-
import { assertEquals, assertRejects } from "jsr:@std/assert";
565-
import { spy, stub } from "jsr:@std/testing/mock";
566-
import { FakeTime } from "jsr:@std/testing/time";
567-
568-
// The service we want to test
569-
class AuthService {
563+
```ts title="auth_service.ts"
564+
export class AuthService {
570565
private token: string | null = null;
571566
private expiresAt: Date | null = null;
572567

@@ -587,13 +582,13 @@ class AuthService {
587582
throw new Error(`Authentication failed: ${response.status}`);
588583
}
589584

590-
const data = await response.json();
585+
const data: { token: string } = await response.json();
591586

592587
// Store token with expiration (1 hour)
593588
this.token = data.token;
594589
this.expiresAt = new Date(Date.now() + 60 * 60 * 1000);
595590

596-
return this.token;
591+
return data.token;
597592
}
598593

599594
getToken(): string {
@@ -615,6 +610,15 @@ class AuthService {
615610
this.expiresAt = null;
616611
}
617612
}
613+
```
614+
615+
Then import the service from your test file:
616+
617+
```ts title="auth_service_test.ts"
618+
import { assertEquals, assertRejects, assertThrows } from "jsr:@std/assert";
619+
import { assertSpyCalls, spy, stub } from "jsr:@std/testing/mock";
620+
import { FakeTime } from "jsr:@std/testing/time";
621+
import { AuthService } from "./auth_service.ts";
618622

619623
Deno.test("AuthService comprehensive test", async (t) => {
620624
await t.step("login should validate credentials", async () => {
@@ -657,52 +661,49 @@ Deno.test("AuthService comprehensive test", async (t) => {
657661
}
658662
});
659663

660-
await t.step("token expiration should work correctly", () => {
661-
using fakeTime = new FakeTime();
662-
664+
await t.step("token expiration should work correctly", async () => {
665+
using time = new FakeTime(new Date("2023-01-01T12:00:00Z"));
663666
const authService = new AuthService();
664-
const time = fakeTime(new Date("2023-01-01T12:00:00Z"));
667+
668+
const fetchStub = stub(
669+
globalThis,
670+
"fetch",
671+
() =>
672+
Promise.resolve(
673+
new Response(JSON.stringify({ token: "fake-token" }), {
674+
status: 200,
675+
headers: { "Content-Type": "application/json" },
676+
}),
677+
),
678+
);
679+
680+
const getTokenSpy = spy(authService, "getToken");
665681

666682
try {
667-
// Mock the login process to set token directly
668-
authService.login = spy(
669-
authService,
670-
"login",
671-
async () => {
672-
(authService as any).token = "fake-token";
673-
(authService as any).expiresAt = new Date(
674-
Date.now() + 60 * 60 * 1000,
675-
);
676-
return "fake-token";
677-
},
683+
await authService.login("user", "pass");
684+
assertEquals(authService.getToken(), "fake-token");
685+
assertSpyCalls(getTokenSpy, 1);
686+
687+
// Advance time past expiration
688+
time.tick(61 * 60 * 1000);
689+
690+
// Token should now be expired
691+
assertThrows(
692+
() => authService.getToken(),
693+
Error,
694+
"Token expired",
678695
);
679-
680-
// Login and verify token
681-
authService.login("user", "pass").then(() => {
682-
const token = authService.getToken();
683-
assertEquals(token, "fake-token");
684-
685-
// Advance time past expiration
686-
time.tick(61 * 60 * 1000);
687-
688-
// Token should now be expired
689-
assertRejects(
690-
() => {
691-
authService.getToken();
692-
},
693-
Error,
694-
"Token expired",
695-
);
696-
});
696+
assertSpyCalls(getTokenSpy, 2);
697697
} finally {
698-
time.restore();
699-
(authService.login as any).restore();
698+
fetchStub.restore();
699+
getTokenSpy.restore();
700700
}
701701
});
702702
});
703703
```
704704

705-
This code defines `AuthService` class with three main functionalities:
705+
The `auth_service.ts` module defines an `AuthService` class with three main
706+
functionalities:
706707

707708
- Login - Validates credentials, calls an API, and stores a token with an
708709
expiration time
@@ -711,7 +712,7 @@ This code defines `AuthService` class with three main functionalities:
711712

712713
The testing structure is organized as a single main test with three logical
713714
**steps**, each testing a different aspect of the service; credential
714-
validation, API call handling and token expiration.
715+
validation, API call handling, and token expiration.
715716

716717
🦕 Effective mocking is essential for writing reliable, maintainable unit tests.
717718
Deno provides several powerful tools to help you isolate your code during

0 commit comments

Comments
 (0)