Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add vitest plugin #30

Merged
merged 9 commits into from
Aug 16, 2024
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
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
env: {
browser: true,
es2021: true,
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ jobs:
- name: Install dependencies
run: yarn install

- name: Install playwright dependencies
run: yarn exec playwright install chromium --with-deps

- name: Run tests
run: |
yarn test:ci
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ junit

# production
/build
.vite-inspect

# misc
.DS_Store
Expand All @@ -30,7 +31,7 @@ yarn-error.log*

# storybook
*-storybook.log

storybook-static

# Yarn berry
/**/.yarn/*
Expand All @@ -39,4 +40,4 @@ yarn-error.log*
!/**/.yarn/plugins
!/**/.yarn/sdks
!/**/.yarn/versions
/**/.pnp.*
/**/.pnp.*
1 change: 1 addition & 0 deletions .storybook/decorators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { GlobalStyle } from '../src/styles/GlobalStyle'
import { darkTheme, lightTheme } from '../src/styles/theme'

initialize({
quiet: true,
onUnhandledRequest: ({ url, method }) => {
const pathname = new URL(url).pathname
if (pathname.startsWith('/.netlify/functions')) {
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"eslint.alwaysShowStatus": true,
"eslint.validate": ["javascript", "typescript"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"workbench.colorCustomizations": {
"activityBar.background": "#156b68",
Expand Down
34 changes: 21 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "course-app",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"@reduxjs/toolkit": "^2.2.3",
"axios": "^1.6.8",
Expand All @@ -22,7 +23,7 @@
"start": "vite",
"build": "tsc && vite build",
"serve": "vite preview",
"test": "vitest run",
"test": "vitest",
"test:coverage": "vitest run --coverage",
"test:ci": "vitest run",
"storybook": "storybook dev -p 6006",
Expand Down Expand Up @@ -56,19 +57,23 @@
},
"devDependencies": {
"@babel/core": "^7.14.6",
"@chromatic-com/storybook": "^1.6.1",
"@chromatic-com/storybook": "1.6.2--canary.df0b83c.0",
"@ladle/react": "^4.0.3",
"@storybook/addon-a11y": "^8.2.1",
"@storybook/addon-a11y": "^8.3.0-alpha.6",
"@storybook/addon-coverage": "^1.0.4",
"@storybook/addon-designs": "^8.0.3",
"@storybook/addon-essentials": "^8.2.1",
"@storybook/addon-interactions": "^8.2.1",
"@storybook/addon-themes": "^8.2.1",
"@storybook/blocks": "^8.2.1",
"@storybook/react": "^8.2.1",
"@storybook/react-vite": "^8.2.1",
"@storybook/test": "^8.2.1",
"@storybook/addon-essentials": "^8.3.0-alpha.6",
"@storybook/addon-interactions": "^8.3.0-alpha.6",
"@storybook/addon-themes": "^8.3.0-alpha.6",
"@storybook/blocks": "^8.3.0-alpha.6",
"@storybook/experimental-addon-vitest": "^8.3.0-alpha.6",
"@storybook/experimental-vitest-plugin": "^0.0.4",
"@storybook/manager-api": "^8.3.0-alpha.6",
"@storybook/react": "^8.3.0-alpha.6",
"@storybook/react-vite": "^8.3.0-alpha.6",
"@storybook/test": "^8.3.0-alpha.6",
"@storybook/test-runner": "^0.19.0",
"@storybook/theming": "^8.3.0-alpha.6",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
Expand All @@ -83,6 +88,8 @@
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^7.8.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/browser": "^2.0.5",
"@vitest/coverage-istanbul": "^2.0.5",
"babel-loader": "8.1.0",
"babel-plugin-istanbul": "^6.1.1",
"babel-plugin-open-source": "^1.3.3",
Expand All @@ -98,21 +105,22 @@
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-storybook": "^0.8.0",
"happy-dom": "^14.12.3",
"husky": ">=6",
"istanbul": "^0.4.5",
"jest-junit": "^16.0.0",
"jsdom": "^24.0.0",
"lint-staged": ">=10",
"msw": "^2.2.2",
"msw-storybook-addon": "^2.0.2",
"playwright": "^1.46.0",
"prettier": "^3.2.5",
"react-is": "^18.3.1",
"react-test-renderer": "^18.3.1",
"storybook": "^8.2.1",
"storybook": "^8.3.0-alpha.6",
"vite": "^4.0.0",
"vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^2.0.2",
"vitest": "^2.0.5",
"vitest-axe": "^0.1.0",
"vitest-canvas-mock": "^0.3.3",
"wait-on": "^7.2.0"
Expand Down
2 changes: 1 addition & 1 deletion public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* - Please do NOT serve this file on production.
*/

const PACKAGE_VERSION = '2.3.1'
const PACKAGE_VERSION = '2.3.4'
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
Expand Down
2 changes: 1 addition & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface BaseApi {

export const BASE_URL = 'https://mealdrop.netlify.app/.netlify/functions/restaurants'

const isMockedEnvironment = !!import.meta.env.STORYBOOK || import.meta.env.NODE_ENV === 'test'
const isMockedEnvironment = !!import.meta.env.STORYBOOK || import.meta.env.NODE_ENV === 'test' || (globalThis as any).__vitest_browser__

const apiCache = new Map()

Expand Down
5 changes: 5 additions & 0 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { StoryObj, Meta } from '@storybook/react'
import { expect } from '@storybook/test'

import { Button } from './Button'

Expand All @@ -25,6 +26,10 @@ export const Disabled: Story = {
args: {
disabled: true,
},
play: async ({ canvas }) => {
const button = await canvas.findByRole('button')
await expect(button).toBeDisabled()
}
}

export const Clear: Story = {
Expand Down
6 changes: 3 additions & 3 deletions src/components/Button/Button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ import * as stories from './Button.stories'

const { Default, Disabled } = composeStories(stories)
test('renders button with custom children', async () => {
await Default.play()
await Default.run()
expect(screen.getByText(/Button/i)).toBeInTheDocument()
// @ts-ignore TODO fix Property 'toHaveNoViolations' does not exist on type 'Assertion<AxeResults>
expect(await axe(document.body.firstChild)).toHaveNoViolations()
})

test('onclick handler is called', async () => {
const onClickSpy = vi.fn()
await Default.play({ args: { ...Default.args, onClick: onClickSpy } })
await Default.run({ args: { ...Default.args, onClick: onClickSpy } })
const buttonElement = screen.getByRole('button')
buttonElement.click()
expect(onClickSpy).toHaveBeenCalled()
})

test('onclick handler is not called when disabled', async () => {
const onClickSpy = vi.fn()
await Disabled.play({ args: { ...Disabled.args, onClick: onClickSpy } })
await Disabled.run({ args: { ...Disabled.args, onClick: onClickSpy } })
screen.getByRole('button').click()
expect(onClickSpy).not.toHaveBeenCalled()
})
Expand Down
10 changes: 5 additions & 5 deletions src/components/RestaurantCard/RestaurantCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@ const { Default, Loading, New, Closed } = composeStories(stories)

describe('RestaurantCard', () => {
test('should render correctly', async () => {
await Default.play()
await Default.run()

expect(screen.getByText('Burger Kingdom')).toBeInTheDocument()
})

test('should provide a loading skeleton', async () => {
await Loading.play()
await Loading.run()
expect(screen.getByTestId('loading')).toBeInTheDocument()
})

test('should show a "new" tag', async () => {
await New.play()
await New.run()
expect(screen.getByText('new')).toBeInTheDocument()
})

test('should not trigger onclick when restaurant is closed', async () => {
const onClickSpy = vi.fn()
await Closed.play({ args: { ...Closed.args, onClick: onClickSpy } })
await Closed.run({ args: { ...Closed.args, onClick: onClickSpy } })

// display closed message
expect(screen.getByText('This restaurant is closed.')).toBeInTheDocument()
Expand All @@ -46,7 +46,7 @@ const testCases = Object.values(composeStories(stories)).map((Story) => [

// Go through all test cases to batch test accessibility
test.each(testCases)('%s story should be accessible', async (_storyName, Story) => {
await (Story as any).play()
await (Story as any).run()
// @ts-ignore TODO fix Property 'toHaveNoViolations' does not exist on type 'Assertion<AxeResults>
expect(await axe(document.body.firstChild)).toHaveNoViolations()
})
4 changes: 4 additions & 0 deletions src/components/forms/Input.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { Meta, StoryObj } from '@storybook/react'

import { Input } from './Input'
import { fn } from '@storybook/test'

const meta = {
title: 'Components/Form/Input',
component: Input,
args: {
onChange: fn(),
},
parameters: {
design: {
type: 'figma',
Expand Down
23 changes: 12 additions & 11 deletions src/pages/RestaurantDetailPage/RestaurantDetailPage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,19 @@ export const Success = {
],
},
},
}
play: async ({ canvas }) => {
const item = await canvas.findByText(/Burger Kingdom/i)
await expect(item).toBeInTheDocument()
},
} satisfies Story

export const WithModalOpen: Story = {
...Success,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
const item = await canvas.findByText(/Cheeseburger/i)
play: async (context) => {
await Success.play(context)
const item = await context.canvas.findByText(/Cheeseburger/i)
await userEvent.click(item)
await expect(canvas.getByTestId('modal')).toBeInTheDocument()
await expect(context.canvas.getByTestId('modal')).toBeInTheDocument()
},
}

Expand All @@ -83,8 +87,7 @@ export const Loading: Story = {
],
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
play: async ({ canvas }) => {
const item = await canvas.findByText(/Looking for some food.../i)
await expect(item).toBeInTheDocument()
},
Expand All @@ -104,8 +107,7 @@ export const NotFound: Story = {
},
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
play: async ({ canvas }) => {
const item = await canvas.findByText(/We can't find this page/i)
await expect(item).toBeInTheDocument()
},
Expand All @@ -125,8 +127,7 @@ export const Error: Story = {
],
},
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement)
play: async ({ canvas, step }) => {
await step('Name of step', async () => {
const item = await canvas.findByText(/Something went wrong!/i)
await expect(item).toBeInTheDocument()
Expand Down
10 changes: 5 additions & 5 deletions src/pages/RestaurantDetailPage/RestaurantDetailPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { Success, Loading, Error, NotFound, WithModalOpen } = composeStories(stor

describe('RestaurantDetailPage', () => {
test('Should add an item to cart', async () => {
await Success.play()
await Success.run()

const foodItem = await screen.findByText(/Cheeseburger/i)
userEvent.click(foodItem)
Expand All @@ -20,19 +20,19 @@ describe('RestaurantDetailPage', () => {
expect(foodQuantity.textContent).toEqual('1')
})
test('Should display an error screen', async () => {
await Error.play()
await Error.run()
await waitFor(() => expect(screen.getByText('Something went wrong!')).toBeInTheDocument())
})
test('Should display a loading screen', async () => {
await Loading.play()
await Loading.run()
await waitFor(() => expect(screen.getByText('Looking for some food...')).toBeInTheDocument())
})
test('Should display a 404 screen', async () => {
await NotFound.play()
await NotFound.run()
await waitFor(() => expect(screen.getByText("We can't find this page")).toBeInTheDocument())
})
test('Should execute story tests', async () => {
await WithModalOpen.play()
await WithModalOpen.run()
})
})

Expand Down
28 changes: 0 additions & 28 deletions src/setupTests.ts

This file was deleted.

11 changes: 11 additions & 0 deletions storybook.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if(!globalThis.__vitest_browser__) {
await import('vitest-canvas-mock')
const { getComputedStyle } = window
window.getComputedStyle = (elt) => getComputedStyle(elt)
window.scrollTo = () => {}
}

import { setProjectAnnotations } from '@storybook/react'
import storybookAnnotations from './.storybook/preview'

setProjectAnnotations([storybookAnnotations])
1 change: 0 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export default defineConfig({
outDir: 'build',
},
server: {
open: true,
port: 3000,
},
})
Loading
Loading