Skip to content

Commit

Permalink
feat: Scenario Feature (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
minsgy authored Jun 19, 2024
2 parents 77edbc3 + 7fb48ff commit 5661c89
Show file tree
Hide file tree
Showing 23 changed files with 972 additions and 653 deletions.
1,057 changes: 523 additions & 534 deletions example/pnpm-lock.yaml

Large diffs are not rendered by default.

58 changes: 29 additions & 29 deletions example/public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
* - Please do NOT serve this file on production.
*/

const PACKAGE_VERSION = "2.2.13"
const INTEGRITY_CHECKSUM = "26357c79639bfa20d64c0efca2a87423"
const IS_MOCKED_RESPONSE = Symbol("isMockedResponse")
const PACKAGE_VERSION = '2.2.13'
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()

self.addEventListener("install", function () {
self.addEventListener('install', function () {
self.skipWaiting()
})

self.addEventListener("activate", function (event) {
self.addEventListener('activate', function (event) {
event.waitUntil(self.clients.claim())
})

self.addEventListener("message", async function (event) {
self.addEventListener('message', async function (event) {
const clientId = event.source.id

if (!clientId || !self.clients) {
Expand All @@ -35,20 +35,20 @@ self.addEventListener("message", async function (event) {
}

const allClients = await self.clients.matchAll({
type: "window",
type: 'window',
})

switch (event.data) {
case "KEEPALIVE_REQUEST": {
case 'KEEPALIVE_REQUEST': {
sendToClient(client, {
type: "KEEPALIVE_RESPONSE",
type: 'KEEPALIVE_RESPONSE',
})
break
}

case "INTEGRITY_CHECK_REQUEST": {
case 'INTEGRITY_CHECK_REQUEST': {
sendToClient(client, {
type: "INTEGRITY_CHECK_RESPONSE",
type: 'INTEGRITY_CHECK_RESPONSE',
payload: {
packageVersion: PACKAGE_VERSION,
checksum: INTEGRITY_CHECKSUM,
Expand All @@ -57,22 +57,22 @@ self.addEventListener("message", async function (event) {
break
}

case "MOCK_ACTIVATE": {
case 'MOCK_ACTIVATE': {
activeClientIds.add(clientId)

sendToClient(client, {
type: "MOCKING_ENABLED",
type: 'MOCKING_ENABLED',
payload: true,
})
break
}

case "MOCK_DEACTIVATE": {
case 'MOCK_DEACTIVATE': {
activeClientIds.delete(clientId)
break
}

case "CLIENT_CLOSED": {
case 'CLIENT_CLOSED': {
activeClientIds.delete(clientId)

const remainingClients = allClients.filter((client) => {
Expand All @@ -89,17 +89,17 @@ self.addEventListener("message", async function (event) {
}
})

self.addEventListener("fetch", function (event) {
self.addEventListener('fetch', function (event) {
const { request } = event

// Bypass navigation requests.
if (request.mode === "navigate") {
if (request.mode === 'navigate') {
return
}

// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
if (request.cache === "only-if-cached" && request.mode !== "same-origin") {
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
return
}

Expand Down Expand Up @@ -129,7 +129,7 @@ async function handleRequest(event, requestId) {
sendToClient(
client,
{
type: "RESPONSE",
type: 'RESPONSE',
payload: {
requestId,
isMockedResponse: IS_MOCKED_RESPONSE in response,
Expand All @@ -140,7 +140,7 @@ async function handleRequest(event, requestId) {
headers: Object.fromEntries(responseClone.headers.entries()),
},
},
[responseClone.body]
[responseClone.body],
)
})()
}
Expand All @@ -155,18 +155,18 @@ async function handleRequest(event, requestId) {
async function resolveMainClient(event) {
const client = await self.clients.get(event.clientId)

if (client?.frameType === "top-level") {
if (client?.frameType === 'top-level') {
return client
}

const allClients = await self.clients.matchAll({
type: "window",
type: 'window',
})

return allClients
.filter((client) => {
// Get only those clients that are currently visible.
return client.visibilityState === "visible"
return client.visibilityState === 'visible'
})
.find((client) => {
// Find the client ID that's recorded in the
Expand All @@ -188,7 +188,7 @@ async function getResponse(event, client, requestId) {
// Remove internal MSW request header so the passthrough request
// complies with any potential CORS preflight checks on the server.
// Some servers forbid unknown request headers.
delete headers["x-msw-intention"]
delete headers['x-msw-intention']

return fetch(requestClone, { headers })
}
Expand All @@ -211,7 +211,7 @@ async function getResponse(event, client, requestId) {
const clientMessage = await sendToClient(
client,
{
type: "REQUEST",
type: 'REQUEST',
payload: {
id: requestId,
url: request.url,
Expand All @@ -229,15 +229,15 @@ async function getResponse(event, client, requestId) {
keepalive: request.keepalive,
},
},
[requestBuffer]
[requestBuffer],
)

switch (clientMessage.type) {
case "MOCK_RESPONSE": {
case 'MOCK_RESPONSE': {
return respondWithMock(clientMessage.data)
}

case "PASSTHROUGH": {
case 'PASSTHROUGH': {
return passthrough()
}
}
Expand All @@ -259,7 +259,7 @@ function sendToClient(client, message, transferrables = []) {

client.postMessage(
message,
[channel.port2].concat(transferrables.filter(Boolean))
[channel.port2].concat(transferrables.filter(Boolean)),
)
})
}
Expand Down
45 changes: 44 additions & 1 deletion example/src/mocks/browser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
// src/mocks/browser.js
import { setupWorker } from "msw/browser"
import { http, setupWorker } from "msw-devtools"
import { handlers } from "./handlers"
import { HttpResponse } from "msw"

export const worker = setupWorker(...handlers)

worker.scenario([
{
description: "장바구니 상품 추가 시나리오",
handlers: [
http
.get("https://jsonplaceholder.typicode.com/cart", () => {
return HttpResponse.json({
firstName: "111",
lastName: "111",
})
})
.presets([
{
status: 200,
description: "장바구니 상품 추가",
response: {
firstName: "111",
lastName: "111",
},
},
]),
http.post("https://jsonplaceholder.typicode.com/cart/1", () => {
return HttpResponse.json({
firstName: "222",
lastName: "222",
})
}),
],
},
{
description: "장바구니 상품 삭제 시나리오",
handlers: [
http.delete("https://jsonplaceholder.typicode.com/cart/1", () => {
return HttpResponse.json({
firstName: "333",
lastName: "333",
})
}),
],
},
])
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toggle": "^1.0.3",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.6",
"@uiw/codemirror-theme-github": "^4.22.1",
Expand Down
28 changes: 28 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 18 additions & 1 deletion src/app/MSWDevtools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import "@/shared/styles/global.css"
import { MSWDevtoolsProps } from "../types"
import { MswDevToolsProvider } from "@/providers/useMswDevtoolsContext"
import { MSWDevtoolsPanel } from "@/features/MSWDevtoolsPanel"
import { useState } from "react"
import { DevtoolsFloatingButton } from "@/features/DevtoolsFloatingButton"

export const MSWDevtools = ({
isEnabled = false,
Expand All @@ -11,6 +13,8 @@ export const MSWDevtools = ({
position,
initialOpen = false,
}: MSWDevtoolsProps) => {
const [isOpened, setIsOpened] = useState(initialOpen)

if (isEnabled && !worker) {
console.warn(
"worker is not defined. Please pass in a worker instance from setupWorker(...handlers)"
Expand All @@ -28,7 +32,20 @@ export const MSWDevtools = ({
isEnabled={isEnabled}
worker={worker}
onRouteUpdate={onRouteUpdate}>
<MSWDevtoolsPanel position={position} />
{isOpened ? (
<MSWDevtoolsPanel
onCloseDevtools={() => {
setIsOpened(false)
}}
/>
) : (
<DevtoolsFloatingButton
position={position}
onClick={() => {
setIsOpened(true)
}}
/>
)}
</MswDevToolsProvider>
{children}
</>
Expand Down
2 changes: 0 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { HttpMethods } from "msw"

export const ROUTE_METHODS = Object.values(HttpMethods)

export const MENU_TABS = ["handlers", "config"] as const
2 changes: 1 addition & 1 deletion src/features/DevtoolsFloatingButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { match } from "ts-pattern"
import { Position } from ".."

type DevtoolsFloatingButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
position: Position
position?: Position
}

export const DevtoolsFloatingButton = ({
Expand Down
Loading

0 comments on commit 5661c89

Please sign in to comment.