Skip to content
Merged
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
5 changes: 5 additions & 0 deletions websites/mswjs.io/src/content/buildDocsNavTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export function buildDocsNavTree(
title: 'Mocking HTTP',
children: builder.get('http/**/*.mdx'),
},
{
kind: 'group',
title: 'Mocking SSE',
children: builder.get('sse/**/*.mdx'),
},
{
kind: 'group',
title: 'Mocking GraphQL',
Expand Down
2 changes: 1 addition & 1 deletion websites/mswjs.io/src/content/docs/api/http-response.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 5
order: 6
title: HttpResponse
keywords:
- response
Expand Down
11 changes: 6 additions & 5 deletions websites/mswjs.io/src/content/docs/api/http.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,12 @@ export const handlers = [

The response resolver function for every `http.*` method has the following keys in its argument object:

| Name | Type | Description |
| --------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `request` | [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) | Entire request reference. |
| `params` | `object` | Request's [path parameters](/docs/http#reading-path-parameters). |
| `cookies` | `object` | Request's [cookies](/docs/http#reading-request-cookies). |
| Name | Type | Description |
| ----------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `request` | [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) | Entire request reference. |
| `requestId` | `string` | Unique ID of the intercepted request. |
| `params` | `object` | Request's [path parameters](/docs/http#reading-path-parameters). |
| `cookies` | `object` | Request's [cookies](/docs/http#reading-request-cookies). |

You access these arguments on the response resolver argument object.

Expand Down
111 changes: 111 additions & 0 deletions websites/mswjs.io/src/content/docs/api/sse.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
order: 5
title: sse
description: Intercept Server-Sent Events.
keywords:
- sse
- event
- server
- handler
- api
---

The `sse` function is a subset of the [`http`](/docs/api/http) namespace that helps you create request handlers to intercept Server-Sent Events.

## Call signature

```ts
sse<EventMap, Params>(predicate: Path, resolver: ServerSentEventResolver<EventMap, Params>)
```

import { PageCard } from '../../../components/react/pageCard'
import { CodeBracketSquareIcon } from '@heroicons/react/24/outline'

<PageCard
icon={CodeBracketSquareIcon}
url="https://github.com/mswjs/msw/tree/main/src/core/sse.ts"
title="sse.ts"
description="Source code for the `sse` function."
/>

## Resolver argument

In addition to all the arguments exposed by the [`http`](/docs/api/http/#resolver-argument) namespace, the `sse` handler has the following response resolver properties:

| Name | Type | Description |
| -------- | ------------------------------------------------- | --------------------------------------------------------- |
| `client` | [`ServerSentEventClient`](#serversenteventclient) | Representation of the intercepted `EventSource` instance. |
| `server` | [`ServerSentEventServer`](#serversenteventserver) | Actual server connection object. |

## `ServerSentEventClient`

The `ServerSentEventClient` object represents the intercepted `EventSource` instance. You use this object to send mock messages to the client, close or error the underlying connection.

### `.send(payload)`

- `payload`
- `id`, `string` (Optional), a custom event ID.
- `data`, `string`, the sent data of this event.
- `event`, `string` (Optional), a custom event type.
- `retry`, `number` (Optional), a custom reconnection time. If this option is provided, no other properties must be set on the `payload` argument.

Sends a mocked event to the client.

```ts
// Send a default "message" event.
client.send({ data: 'hello world' })

// Send a custom "greeting" event.
client.send({
event: 'greeting'
data: 'Hello, John!',
})

// Send an event with a custom ID.
client.send({
id: 'abc-123',
event: 'greeting'
data: 'Hello, John!',
})
```

### `.error()`

Errors the underlying HTTP connection.

```ts
client.error()
```

### `.close()`

Gracefully closes the underlying HTTP connection.

```ts
client.close()
```

## `ServerSentEventServer`

The `ServerSentEventClient` object represents a connection to the actual server. Use it to establish that connection and listen to the received events from the server.

### `.connect()`

...TODO

```ts
const source = server.connect()
```

> ...TODO What is returned as `source` and what you can use it for (listen to messages, close the connection).

## Related materials

import { NodejsIcon } from '../../../components/react/icons/nodejs'

<PageCard
icon={NodejsIcon}
url="/docs/http"
title="Describing REST API"
description="Learn about describing RESTful APIs."
/>
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ import { GraphQLIcon } from '../../../../components/react/icons/graphql'

<PageCard
icon={GraphQLIcon}
url="/docs/graphql/mocking-responses"
url="/docs/graphql/mocking-responses/"
title="Mocking responses"
description="Different ways to handle an intercepted GraphQL operation."
/>
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ http.get('/resource', () => {})

A predicate decides which requests to intercept, and a resolver decides what to do with those requests. On this page, we will take a look at the different ways to define a predicate for your request handlers. You can learn more about handling requests in the "Mocked responses" section:

import { ServerIcon } from '@heroicons/react/24/outline'
import { ServerIcon } from '@heroicons/react/24/solid'
import { PageCard } from '@mswjs/shared/components/react/pageCard'

<PageCard
Expand Down Expand Up @@ -143,12 +143,12 @@ http.get(

The following properties are available on the response resolver object argument for `http.*` handlers:

| Property | Type | Description |
| ----------- | ------------------------------------ | --------------------------------------------------------------------------------------------- |
| `request` | [`Request`](#) | Fetch API `Request` representation of the intercepted request. |
| `requestId` | `string` | UUID representing the intercepted request. |
| `params` | `Record<string, string \| string[]>` | Request [path parameters](/docs/http/intercepting-requests/path-parameters) (e.g. `:userId`). |
| `cookies` | `Record<string, string>` | Parsed [request cookies](/docs/http/intercepting-requests/cookies). |
| Property | Type | Description |
| ----------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `request` | [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) | Fetch API `Request` representation of the intercepted request. |
| `requestId` | `string` | UUID representing the intercepted request. |
| `params` | `Record<string, string \| string[]>` | Request [path parameters](/docs/http/intercepting-requests/path-parameters) (e.g. `:userId`). |
| `cookies` | `Record<string, string>` | Parsed [request cookies](/docs/http/intercepting-requests/cookies). |

```ts /request/ /params/#g /cookies/#v
http.get('/resource', ({ request, params, cookies }) => {})
Expand All @@ -160,7 +160,7 @@ Now that you know how to intercept HTTP requests, proceed by learning how to han

<PageCard
icon={ServerIcon}
url="/docs/http/mocking-responses"
url="/docs/http/mocking-responses/"
title="Mocking responses"
description="Different ways to handle an intercepted HTTP request."
/>
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ http.get('/resource', () => {

Please explore the "Mocking HTTP" section for more recipes and advanced mocking scenarios. Here are a few noteworthy ones:

import { ServerIcon } from '@heroicons/react/24/outline'
import { ServerIcon } from '@heroicons/react/24/solid'

<div className="grid md:grid-cols-2 gap-x-8">
<PageCard
Expand Down
2 changes: 1 addition & 1 deletion websites/mswjs.io/src/content/docs/runbook.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ If unsure, please read about mocking responses with MSW:

<PageCard
icon={NewspaperIcon}
url="/docs/http/mocking-responses"
url="/docs/basics/mocking-responses/"
title="Mocking responses"
description="Learn about response resolvers and the different ways to respond to a request."
/>
Expand Down
100 changes: 100 additions & 0 deletions websites/mswjs.io/src/content/docs/sse/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
order: -1
standalone: true
title: Introduction
displayTitle: Mocking Server-Sent Events
description: Intercept and mock Server-Sent Events (SSE).
keywords:
- sse
- server-sent events
- eventsource
- mock
- intercept
- api
---

Mock Service Worker ships with a first-class API for intercepting and mocking [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) (SSE) via the `sse` namespace provided by the library:

```ts
import { sse } from 'msw'
```

import { PageCard } from '@mswjs/shared/components/react/pageCard'
import { CubeTransparentIcon } from '@heroicons/react/24/outline'

<PageCard
icon={CubeTransparentIcon}
url="/docs/api/sse"
title="sse"
description="API reference for the `sse` namespace."
/>

## Difference from `http`

The stream of server events is still a regular HTTP connection, which means you can intercept and mock with the `http` namespace as you would any other HTTP request:

```ts {5-10} /stream/2,3
import { http } from 'msw'

export const handlers = [
http.get('/stream', ({ request }) => {
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode('data: Hello World\n\n'))
controller.close()
},
})

return new Response(stream, {
headers: {
connection: 'keep-alive',
'content-type': 'text/event-stream',
'cache-control': 'no-cache',
},
})
}),
]
```

Handling SSE via the `http` namespace, however, has a number of disadvantages:

- You have to manually construct the stream;
- You have to encode sent messages and make sure they adhere to the standard;

In comparison, the `sse` namespace provides you a type-safe, high-level experience of working with SSE:

```ts {5,8} /sse/
import { sse } from 'msw'

export const handlers = [
sse<{ message: string }>('/stream', ({ client }) => {
client.send({ data: 'hello world' })

queueMicrotask(() => {
client.close()
})
}),
]
```

The implementation details of the comnunication, such as managing the stream and queuing messages, are abstracted away, allowing you to focus on describing the network behavior you want. The `sse` namespace also enables additional feature otherwise unavailable when working with `EventSource` directly, such as forwarding of the original server events with ambiguous names.

## Next steps

The following sections will guide you through everything you need to know about intercepting and mocking Server-Sent Events:

import { CloudArrowDownIcon } from '@heroicons/react/24/solid'

<PageCard
icon={CloudArrowDownIcon}
url="/docs/sse/intercepting-sources/"
title="Intercepting sources"
description="Intercepting and handling event sources."
/>

<PageCard
icon={CloudArrowDownIcon}
url="/docs/sse/server-events/"
title="Server events"
description="Mocking Server-Sent Events."
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
order: 2
title: Intercepting sources
description: Intercepting and handling event sources.
---

You can intercept any `EventSource` in your applicatio by defining a request handler for it using the `sse` namespace. For example, consider this event source:

```ts
new EventSource('https://api.example.com/events')
```

Intercept it by its URL and start handling the connection:

```ts
import { sse } from 'msw'

export const handlers = [
sse('https://api.example.com/events', ({ request, client, server }) => {
client.send({ data: 'hello world' })
}),
]
```

## Predicate

You can use the same predicate types for Server-Sent Events as you would use for [HTTP requests](/docs/http/intercepting-requests/#predicate), which includes:

- Relative URLs;
- Absolute URLs;
- Regular expressions.

For example, here's how you can intercept an `EventSource` to a remote server with a dynamic path segment `id`:

```ts /:id/1#g /id/2#g
sse('https://api.example.com/events/:id', ({ params }) => {
console.log(params.id)
})
```

## Response resolver

The following properties are available on the response resolver object argument for the `sse` handler:

| Property | Type | Description |
| ----------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `client` | `ServerSentEventClient` | Intercepted `EventSource` client connection object. |
| `server` | `ServerSentEventServer` | Actual `EventSource` server connection object. |
| `request` | [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) | Fetch API representation of the intercepted request. |
| `requestId` | `string` | UUID representing the intercepted request. |
| `params` | `Record<string, string \| string[]>` | Request [path parameters](/docs/http/intercepting-requests/path-parameters) (e.g. `:userId`). |
| `cookies` | `Record<string, string>` | Parsed [request cookies](/docs/http/intercepting-requests/cookies). |

## Related materials

Much like Server-Sent Events utilize HTTP, working with the `sse` namespace has a significant overlap with the `http` namespace. We highly recommend getting yourself familiar with intercepting HTTP requests with MSW since that will answer a lot of questions you might have around Server-Sent Events.

<PageCard
icon={ServerIcon}
url="/docs/http/intercepting-requests/"
title="Intercepting requests"
description="Learn how to intercept outgoing requests."
/>

## Next steps

Now that you know how to intercept `EventSource` connections, it's time to learn more about handling them (sending mock events, connecting to the real server, etc).

import { ServerIcon, CloudArrowDownIcon } from '@heroicons/react/24/solid'
import { PageCard } from '@mswjs/shared/components/react/pageCard'

<PageCard
icon={CloudArrowDownIcon}
url="/docs/sse/server-events/"
title="Server events"
description="Mocking Server-Sent Events."
/>
Loading