mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 21:59:16 +03:00
* 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>
98 lines
3.3 KiB
TypeScript
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`)
|
|
})
|
|
})
|