Files
supabase/apps/studio/components/interfaces/Account/NewAccessTokenButton.test.tsx
Drake CostaandJoshen Lim af5e591b84 Refactor NewAccessTokenButton to use shadcn components (#36972)
* 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

* 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

* fix imports

* 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

* Shift test file

* Smol fix

* Nit

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2025-07-23 16:54:31 +08:00

98 lines
3.3 KiB
TypeScript

import { faker } from '@faker-js/faker'
import { screen, waitFor } from '@testing-library/dom'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { render } from 'tests/helpers'
import { addAPIMock } from 'tests/lib/msw'
import NewAccessTokenButton from './NewAccessTokenButton'
describe(`NewAccessTokenButton`, () => {
beforeEach(() => {
addAPIMock({
method: `post`,
path: `/platform/profile/access-tokens`,
response: {
name: faker.lorem.word(),
scope: faker.helpers.arrayElement(['V0', undefined]),
created_at: faker.date.past().toISOString(),
id: faker.number.int(),
token_alias: faker.lorem.words(),
token: faker.lorem.words(),
},
})
})
it(`generates regular tokens`, async () => {
const onCreateToken = vi.fn()
render(<NewAccessTokenButton onCreateToken={onCreateToken} />)
const dialogTrigger = screen.getByRole(`button`, { name: `Generate new token` })
await userEvent.click(dialogTrigger)
const nameInput = screen.getByLabelText(`Name`)
await userEvent.type(nameInput, `test{enter}`)
await waitFor(() => expect(onCreateToken).toHaveBeenCalledTimes(1))
})
it(`generates experimental tokens`, async () => {
const onCreateToken = vi.fn()
render(<NewAccessTokenButton onCreateToken={onCreateToken} />)
const dropdownTrigger = screen.getByTitle(`Choose token scope`)
await userEvent.click(dropdownTrigger)
const experimentalMenuItem = await screen.findByRole(`menuitem`, {
name: `Generate token for experimental API`,
})
await userEvent.click(experimentalMenuItem)
await waitFor(async () => {
await expect(
screen.findByRole(`heading`, { name: `Generate token for experimental API` })
).resolves.toBeInTheDocument()
await expect(screen.findByRole(`alert`)).resolves.toBeInTheDocument()
})
const nameInput = screen.getByLabelText(`Name`)
await userEvent.type(nameInput, `test{enter}`)
await waitFor(() => expect(onCreateToken).toHaveBeenCalledTimes(1))
})
it(`resets the form on close/cancel`, async () => {
render(<NewAccessTokenButton onCreateToken={vi.fn()} />)
// pass 1: open dialog and fill form
const dialogTrigger = screen.getByRole(`button`, { name: `Generate new token` })
await userEvent.click(dialogTrigger)
let nameInput = screen.getByLabelText(`Name`)
await userEvent.type(nameInput, `cancel button test`)
expect(nameInput).toHaveValue(`cancel button test`)
// reset the form by pressing the cancel button
const cancelButton = screen.getByRole(`button`, { name: `Cancel` })
await userEvent.click(cancelButton)
// pass 2: check that the form is reset, then fill it again
await userEvent.click(dialogTrigger)
nameInput = screen.getByLabelText(`Name`)
expect(nameInput).not.toHaveValue(`cancel button test`)
await userEvent.type(nameInput, `close modal test`)
expect(nameInput).toHaveValue(`close modal test`)
// reset the form by closing the dialog
await userEvent.keyboard(`{Escape}`)
// pass 3: check that the form has been rest again
await userEvent.click(dialogTrigger)
nameInput = screen.getByLabelText(`Name`)
expect(nameInput).not.toHaveValue(`close modal test`)
})
})