Files
supabase/apps/studio/tests/lib/msw.ts
T
Drake CostaandTerry Sutton d6fe8476f3 Refactor EditSecretModal to use shadcn components (#37258)
* chore: Refactor `NewAccessTokenButton` to use shadcn components

This brings `NewAccessTokenButton` into conformance with the latest UI patterns of using shadcn based components, zod schemas, and react-hook-form for form submission.

I based this refactor on the implementation of `CreateSecretAPIKeyDialog`, which already made use of the above.

* add success and failure toasts

* add smoke test for `NewAccessTokenButton`, fix vitest config

This adds a minimal test for `NewAccessTokenButton` but more importantly fixes a critical bug in the vitest configuration for `studio`.

Because `restoreMocks: true` was set in the config, this meant that the mock implementation for `window.matchMedia` defined in the `tests/vitestSetup.ts` file was being **reset** to an empty function before each test suite was run. While this didn't appear to be a problem before, that appears to be because none of the existing tests had `motion.div` in their component trees. Since `motion.div` calls `addListener` on a media query as part of it's lifecycle, that meant that any test which included it would fail as `addListener` would be undefined in this situation. Removing `restoreMocks: true` from the config results in the desired mocking behavior.

This change is necessary in order to test any component that has the `FormItemLayout` component, as it uses `framer-motion` to animate in error messages for input elements.

* add warning comment in case of future config regression

* update test cases, reset form on dialog close, testing setup fixes

This fixes an issue with the polyfills for the testing environment, where a call to `useMutation` would fail as a result of `TransformStream` being set to `null`.

Basic tests for access token creation and form resetting added. Adds `@faker-js/faker` to the studio app devDependencies to generate mock data for `msw` endpoint response.

Adds `shx` to the docs app devDependencies to ensure that the `codegen:examples` script runs cross-platform.

* ensure mocked date is a string

* update testing setup, pollyfills and add rich type support to addAPIMock

* add missing changes

* Move `EditSecretModal` to be child of `SecretRow`

In the accompanying PR for `DeleteSecretModal`, that one will also be moved over to `SecretRow`

* Update studio testing setup files

Improves API mocking type safety and polyfills browser APIs necessary to run tests with framer-motion components

* chore: Refactor `NewAccessTokenButton` to use shadcn components

This brings `NewAccessTokenButton` into conformance with the latest UI patterns of using shadcn based components, zod schemas, and react-hook-form for form submission.

I based this refactor on the implementation of `CreateSecretAPIKeyDialog`, which already made use of the above.

* add success and failure toasts

* add smoke test for `NewAccessTokenButton`, fix vitest config

This adds a minimal test for `NewAccessTokenButton` but more importantly fixes a critical bug in the vitest configuration for `studio`.

Because `restoreMocks: true` was set in the config, this meant that the mock implementation for `window.matchMedia` defined in the `tests/vitestSetup.ts` file was being **reset** to an empty function before each test suite was run. While this didn't appear to be a problem before, that appears to be because none of the existing tests had `motion.div` in their component trees. Since `motion.div` calls `addListener` on a media query as part of it's lifecycle, that meant that any test which included it would fail as `addListener` would be undefined in this situation. Removing `restoreMocks: true` from the config results in the desired mocking behavior.

This change is necessary in order to test any component that has the `FormItemLayout` component, as it uses `framer-motion` to animate in error messages for input elements.

* update test cases, reset form on dialog close, testing setup fixes

This fixes an issue with the polyfills for the testing environment, where a call to `useMutation` would fail as a result of `TransformStream` being set to `null`.

Basic tests for access token creation and form resetting added. Adds `@faker-js/faker` to the studio app devDependencies to generate mock data for `msw` endpoint response.

Adds `shx` to the docs app devDependencies to ensure that the `codegen:examples` script runs cross-platform.

* ensure mocked date is a string

* update testing setup, pollyfills and add rich type support to addAPIMock

* add missing changes

* Move `EditSecretModal` to be child of `SecretRow`

In the accompanying PR for `DeleteSecretModal`, that one will also be moved over to `SecretRow`

* fix imports

* Update test, fix rebase errors

* remove unnecessary code

* resolve type errors

* fix missing listen call for msw, resolve test type error

* fix imports

* Update studio testing setup files

Improves API mocking type safety and polyfills browser APIs necessary to run tests with framer-motion components

* fix missing listen call for msw, resolve test type error

* fix imports

* remove duplicate test

* update testing setup

* implement requested changes

* cleanup unnecessary conditional logic for undefined `secret` prop

* remove unused import

* remove unnecessary code

* cleanup, replace lodash import with JS

* add required router mock

* fix broken lockfile

---------

Co-authored-by: Terry Sutton <saltcod@gmail.com>
2025-08-08 15:42:06 -02:30

70 lines
2.3 KiB
TypeScript

import { setupServer } from 'msw/node'
import { GlobalAPIMocks } from './msw-global-api-mocks'
import { http, HttpResponse, HttpResponseResolver } from 'msw'
import { API_URL } from 'lib/constants'
import type { paths } from '../../data/api'
export const mswServer = setupServer(...GlobalAPIMocks)
mswServer.events.on('request:start', ({ request }) => {
console.log('[MSW] Outgoing:', request.method, request.url)
})
// Recursively changes params in an endpoint path segment from {param}
// format to :param format which is expected by Mock Service Worker
type RemapParams<T extends string> = T extends `${infer Before}{${infer Param}}${infer After}`
? `${Before}:${Param}${RemapParams<After>}`
: T
type TrimQueryParams<T extends string> = T extends `${infer Endpoint}?${string}` ? Endpoint : T
// We need to remap all keys from our openapi-typescript generated types
// so that they follow MSW's parameter formatting
type RemapPaths = {
[K in keyof paths as RemapParams<K>]: paths[K]
}
type Endpoints = keyof RemapPaths
type Methods = Exclude<keyof typeof http, 'all'>
// Extract either the 200 or 201 response object
type SuccessResponse<P extends Endpoints, M extends Methods> = RemapPaths[P][M] extends {
responses: { 200: { content: { 'application/json': infer R200 } } }
}
? R200
: RemapPaths[P][M] extends {
responses: { 201: { content: { 'application/json': infer R201 } } }
}
? R201
: never
const isResponseResolver = (val: unknown): val is HttpResponseResolver => typeof val === `function`
export const addAPIMock = <P extends Endpoints | `${Endpoints}?${string}`, M extends Methods>({
method,
path,
response,
}: SuccessResponse<TrimQueryParams<P>, M> extends never
? // Don't require a mocked response when the API doesn't return one
{ method: M; path: P; response?: never }
: {
method: M
path: P
response: SuccessResponse<TrimQueryParams<P>, M> | HttpResponseResolver
}) => {
const fullPath = `${API_URL}${path}`
console.log('[MSW] Adding mock:', method.toUpperCase(), fullPath)
mswServer.use(
http[method](
fullPath,
isResponseResolver(response)
? response
: ({ request }) => {
console.log('[MSW] Handling request:', request.method, request.url, response)
return HttpResponse.json(response ?? null)
}
)
)
}