diff --git a/.eslintrc.js b/.eslintrc.js index 098e8035..9b73986c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -19,8 +19,35 @@ module.exports = { sourceType: 'module', project: './tsconfig.json', }, - plugins: ['react', '@typescript-eslint'], - rules: {}, + plugins: ['react', '@typescript-eslint', 'regex'], + rules: { + 'regex/required': [ + 'error', + [ + { + regex: 'describe.+from.+vitest', + message: 'Import `describe` explicitly.', + files: { + inspect: '\\.(test|spec)\\.tsx?$', + }, + }, + { + regex: 'it.+from.+vitest', + message: 'Import `it` explicitly.', + files: { + inspect: '\\.(test|spec)\\.tsx?$', + }, + }, + { + regex: 'expect.+from.+vitest', + message: 'Import `expect` explicitly.', + files: { + inspect: '\\.(test|spec)\\.tsx?$', + }, + }, + ], + ], + }, settings: { react: { version: 'detect', diff --git a/__mocks__/react-list.tsx b/__mocks__/react-list.tsx index 6f87615f..375046d2 100644 --- a/__mocks__/react-list.tsx +++ b/__mocks__/react-list.tsx @@ -1,5 +1,5 @@ import React, { forwardRef } from 'react'; -import { vi } from 'vitest'; +import { vi, beforeEach } from 'vitest'; declare module 'react-list' { const __listRef: { diff --git a/global-setup.ts b/global-setup.ts index 3f1a3a6a..2b2f1044 100644 --- a/global-setup.ts +++ b/global-setup.ts @@ -18,11 +18,6 @@ module.exports = async () => { process.env.TZ = 'America/Chicago'; }; -// vi.mock('react', async () => ({ -// ...(await vi.importActual('react')), -// useLayoutEffect: (await vi.importActual('react')).useEffect, -// })); - vi.mock('@mui/x-date-pickers'); global.scrollTo = vi.fn() as any; diff --git a/package.json b/package.json index 273283a9..17704a71 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-regex": "^1.10.0", "eslint-plugin-testing-library": "^5.6.0", "jsdom": "^20.0.0", "prettier": "2.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92cb3fcb..e5c60f6c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,7 @@ specifiers: eslint-plugin-prettier: ^4.2.1 eslint-plugin-react: ^7.30.1 eslint-plugin-react-hooks: ^4.6.0 + eslint-plugin-regex: ^1.10.0 eslint-plugin-testing-library: ^5.6.0 highlight.run: ^4.3.3 humanize-duration: ^3.27.2 @@ -115,6 +116,7 @@ devDependencies: eslint-plugin-prettier: 4.2.1_uiqy6o6b4zgzqppreuvv3slrjm eslint-plugin-react: 7.30.1_eslint@8.21.0 eslint-plugin-react-hooks: 4.6.0_eslint@8.21.0 + eslint-plugin-regex: 1.10.0_eslint@8.21.0 eslint-plugin-testing-library: 5.6.0_qugx7qdu5zevzvxaiqyxfiwquq jsdom: 20.0.0 prettier: 2.4.1 @@ -2436,6 +2438,15 @@ packages: string.prototype.matchall: 4.0.7 dev: true + /eslint-plugin-regex/1.10.0_eslint@8.21.0: + resolution: {integrity: sha512-C8/qYKkkbIb0epxKzaz4aw7oVAOmm19fJpR/moUrUToq/vc4xW4sEKMlTQqH6EtNGpvLjYsbbZRlWNWwQGeTSA==} + engines: {node: '>=6.0.0'} + peerDependencies: + eslint: '>=4.0.0' + dependencies: + eslint: 8.21.0 + dev: true + /eslint-plugin-testing-library/5.6.0_qugx7qdu5zevzvxaiqyxfiwquq: resolution: {integrity: sha512-y63TRzPhGCMNsnUwMGJU1MFWc/3GvYw+nzobp9QiyNTTKsgAt5RKAOT1I34+XqVBpX1lC8bScoOjCkP7iRv0Mw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} diff --git a/src/App.spec.tsx b/src/App.spec.tsx index 8a0e4fa1..34bc6289 100644 --- a/src/App.spec.tsx +++ b/src/App.spec.tsx @@ -13,7 +13,7 @@ import { MemoryRouter } from 'react-router-dom'; import { __listRef } from 'react-list'; import { waitFor, screen } from '@testing-library/react'; import { addTask } from './lib/api'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, describe, it, expect, beforeEach } from 'vitest'; import getQueryClient from './lib/getQueryClient'; import { QueryClient } from 'react-query'; import loadControlledPromise from './lib/test/loadControlledPromise'; diff --git a/src/components/molecules/FilterButton.spec.tsx b/src/components/molecules/FilterButton.spec.tsx index 2f86d06f..dec5b12e 100644 --- a/src/components/molecules/FilterButton.spec.tsx +++ b/src/components/molecules/FilterButton.spec.tsx @@ -4,6 +4,7 @@ import React from 'react'; import userEvent from '@testing-library/user-event'; import { renderWithQueryProvider } from '../../lib/test/helpers'; import { setCookie } from '../../lib/setCookie'; +import { expect, it, describe } from 'vitest'; describe('FilterButton', () => { it('uses local storage', async () => { diff --git a/src/components/molecules/Task.spec.tsx b/src/components/molecules/Task.spec.tsx index 9c231b37..1dd87b20 100644 --- a/src/components/molecules/Task.spec.tsx +++ b/src/components/molecules/Task.spec.tsx @@ -13,7 +13,7 @@ import { waitFor } from '@testing-library/dom'; import browser from '../../lib/Browser'; import { editTask } from '../../lib/api/editTask'; import { screen } from '@testing-library/react'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, expect, it, describe, beforeEach } from 'vitest'; import { queryTaskCheckbox } from '../../lib/test/queries'; vi.mock('../../lib/api/updateTask'); diff --git a/src/components/organisms/ApiSettings.spec.tsx b/src/components/organisms/ApiSettings.spec.tsx index 55659007..eb45ee5f 100644 --- a/src/components/organisms/ApiSettings.spec.tsx +++ b/src/components/organisms/ApiSettings.spec.tsx @@ -4,7 +4,7 @@ import { screen } from '@testing-library/react'; import React from 'react'; import ApiSettings from './ApiSettings'; import { apiFetch } from '../../lib/api'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, expect, it, describe } from 'vitest'; vi.mock('../../lib/api/getMe'); vi.mock('../../lib/api/updateMe'); diff --git a/src/components/organisms/BeeminderSettings.spec.tsx b/src/components/organisms/BeeminderSettings.spec.tsx index 03509de3..90b653a5 100644 --- a/src/components/organisms/BeeminderSettings.spec.tsx +++ b/src/components/organisms/BeeminderSettings.spec.tsx @@ -9,7 +9,7 @@ import { withMutedReactQueryLogger, } from '../../lib/test/helpers'; import userEvent from '@testing-library/user-event'; -import { vi } from 'vitest'; +import { vi, expect, it, describe, beforeEach } from 'vitest'; import { updateMe } from '../../lib/api'; import { getMe } from '../../lib/api'; diff --git a/src/components/organisms/DueForm.spec.tsx b/src/components/organisms/DueForm.spec.tsx index 4829cbd0..24b69afb 100644 --- a/src/components/organisms/DueForm.spec.tsx +++ b/src/components/organisms/DueForm.spec.tsx @@ -4,7 +4,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import React from 'react'; import TaskForm, { TaskFormProps } from './TaskForm'; import userEvent from '@testing-library/user-event'; -import { vi } from 'vitest'; +import { vi, describe, it, expect } from 'vitest'; vi.mock('@mui/x-date-pickers'); diff --git a/src/components/organisms/GeneralSettings.spec.tsx b/src/components/organisms/GeneralSettings.spec.tsx index 567c3a3b..a3f712ff 100644 --- a/src/components/organisms/GeneralSettings.spec.tsx +++ b/src/components/organisms/GeneralSettings.spec.tsx @@ -3,7 +3,7 @@ import React from 'react'; import GeneralSettings from './GeneralSettings'; import userEvent from '@testing-library/user-event'; import { screen } from '@testing-library/react'; -import { vi } from 'vitest'; +import { vi, expect, it, describe } from 'vitest'; vi.mock('../../lib/api/getMe'); vi.mock('../../lib/api/updateMe'); @@ -16,6 +16,6 @@ describe('general settings', () => { userEvent.click(screen.getByText('Save')); - await screen.findByRole('progressbar'); + expect(await screen.findByRole('progressbar')).toBeInTheDocument(); }); }); diff --git a/src/components/organisms/Login.spec.tsx b/src/components/organisms/Login.spec.tsx index 9db65350..57690be1 100644 --- a/src/components/organisms/Login.spec.tsx +++ b/src/components/organisms/Login.spec.tsx @@ -5,7 +5,7 @@ import { renderWithQueryProvider } from '../../lib/test/helpers'; import Login from './Login'; import React from 'react'; import userEvent from '@testing-library/user-event'; -import { vi } from 'vitest'; +import { vi, expect, it, describe, beforeEach } from 'vitest'; import { screen } from '@testing-library/react'; vi.mock('../../lib/LegacyApi'); diff --git a/src/components/organisms/NavBar.spec.tsx b/src/components/organisms/NavBar.spec.tsx index 08c2f45a..2e8a3307 100644 --- a/src/components/organisms/NavBar.spec.tsx +++ b/src/components/organisms/NavBar.spec.tsx @@ -4,7 +4,7 @@ import { useSession } from '../../lib/api/useSession'; import userEvent from '@testing-library/user-event'; import { screen, waitFor } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, expect, it, describe } from 'vitest'; import { renderWithQueryProvider } from '../../lib/test/helpers'; vi.mock('../../lib/api/useSession'); diff --git a/src/components/organisms/PasswordSettings.spec.tsx b/src/components/organisms/PasswordSettings.spec.tsx index bb6a637f..db28c042 100644 --- a/src/components/organisms/PasswordSettings.spec.tsx +++ b/src/components/organisms/PasswordSettings.spec.tsx @@ -3,7 +3,7 @@ import { renderWithQueryProvider } from '../../lib/test/helpers'; import PasswordSettings from './PasswordSettings'; import userEvent from '@testing-library/user-event'; import { screen } from '@testing-library/react'; -import { vi } from 'vitest'; +import { vi, expect, it, describe } from 'vitest'; vi.mock('../../lib/api/updatePassword'); @@ -17,7 +17,9 @@ describe('password settings', () => { userEvent.click(await screen.findByText('Save')); - await screen.findByText("Passwords don't match"); + expect( + await screen.findByText("Passwords don't match") + ).toBeInTheDocument(); }); it('indicates loading state', async () => { diff --git a/src/components/organisms/PaymentSettings.spec.tsx b/src/components/organisms/PaymentSettings.spec.tsx index 44463b98..3902592c 100644 --- a/src/components/organisms/PaymentSettings.spec.tsx +++ b/src/components/organisms/PaymentSettings.spec.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import { waitFor, screen } from '@testing-library/react'; import PaymentSettings from './PaymentSettings'; import { useCheckoutSession } from '../../lib/api'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, expect, it, describe } from 'vitest'; vi.mock('../../lib/api/getMe'); vi.mock('../../lib/api/updateMe'); diff --git a/src/components/organisms/TaskForm.spec.tsx b/src/components/organisms/TaskForm.spec.tsx index 7cfdbfd9..a64243c1 100644 --- a/src/components/organisms/TaskForm.spec.tsx +++ b/src/components/organisms/TaskForm.spec.tsx @@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event'; import { TaskFormProps } from './TaskForm'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { vi } from 'vitest'; +import { vi, expect, it, describe } from 'vitest'; vi.mock('../../lib/Browser'); vi.mock('@mui/x-date-pickers'); diff --git a/src/components/organisms/TaskForm.tsx b/src/components/organisms/TaskForm.tsx index c5d3ae69..f000ef50 100644 --- a/src/components/organisms/TaskForm.tsx +++ b/src/components/organisms/TaskForm.tsx @@ -48,7 +48,7 @@ const TaskForm = (props: TaskFormProps): JSX.Element => { } = props; const [recurrenceEnabled, setRecurrenceEnabled] = useState(false); const [interval, setInterval] = useState(1); - console.log(due); + return ( diff --git a/src/components/pages/Account.spec.tsx b/src/components/pages/Account.spec.tsx index 3c2245ff..4cfbc095 100644 --- a/src/components/pages/Account.spec.tsx +++ b/src/components/pages/Account.spec.tsx @@ -8,7 +8,7 @@ import { renderWithQueryProvider, } from '../../lib/test/helpers'; import userEvent from '@testing-library/user-event'; -import { vi } from 'vitest'; +import { vi, expect, it, describe, beforeEach } from 'vitest'; import { useGetApiToken } from '../../lib/api'; import { getCheckoutSession } from '../../lib/api/getCheckoutSession'; diff --git a/src/components/pages/RecurringTasks.spec.tsx b/src/components/pages/RecurringTasks.spec.tsx index af6c7e71..66c29ab1 100644 --- a/src/components/pages/RecurringTasks.spec.tsx +++ b/src/components/pages/RecurringTasks.spec.tsx @@ -5,7 +5,7 @@ import RecurringTasks from './RecurringTasks'; import getRecurringTasks from '../../lib/api/getRecurringTasks'; import updateRecurringTask from '../../lib/api/updateRecurringTask'; import { loadMe, renderWithQueryProvider } from '../../lib/test/helpers'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, describe, it, expect, beforeEach } from 'vitest'; vi.mock('../../lib/api/getRecurringTasks'); vi.mock('../../lib/api/getMe'); diff --git a/src/components/pages/Register.spec.tsx b/src/components/pages/Register.spec.tsx index 9a551871..ae3c4ef1 100644 --- a/src/components/pages/Register.spec.tsx +++ b/src/components/pages/Register.spec.tsx @@ -8,7 +8,7 @@ import Register from './Register'; import { waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { getTimezones } from '../../lib/api'; -import { vi } from 'vitest'; +import { vi, expect, it, describe, beforeEach } from 'vitest'; import register from '../../lib/api/register'; vi.mock('../../lib/api/getCheckoutSession'); diff --git a/src/components/pages/Tasks.spec.tsx b/src/components/pages/Tasks.spec.tsx index 3eb230cb..49f7ad0f 100644 --- a/src/components/pages/Tasks.spec.tsx +++ b/src/components/pages/Tasks.spec.tsx @@ -15,7 +15,7 @@ import { getUnloadMessage } from '../../lib/getUnloadMessage'; import browser from '../../lib/Browser'; import { __listRef } from '../../../__mocks__/react-list'; import { editTask } from '../../lib/api/editTask'; -import { vi, Mock } from 'vitest'; +import { vi, Mock, describe, it, expect, beforeEach } from 'vitest'; import loadControlledPromise from '../../lib/test/loadControlledPromise'; import { findTaskCheckbox } from '../../lib/test/queries'; diff --git a/src/lib/LegacyApi.spec.tsx b/src/lib/LegacyApi.spec.tsx index 2795f6d4..37c92885 100644 --- a/src/lib/LegacyApi.spec.tsx +++ b/src/lib/LegacyApi.spec.tsx @@ -1,5 +1,6 @@ import { login } from './LegacyApi'; import { waitFor } from '@testing-library/react'; +import { expect, it, describe } from 'vitest'; describe('LegacyApi', () => { it('stores session token on successful login', async () => { diff --git a/src/lib/api/apiFetch.spec.ts b/src/lib/api/apiFetch.spec.ts index 5e733ab2..a328937b 100644 --- a/src/lib/api/apiFetch.spec.ts +++ b/src/lib/api/apiFetch.spec.ts @@ -1,4 +1,5 @@ import { apiFetch } from './apiFetch'; +import { expect, it, describe } from 'vitest'; describe('apiFetch', () => { it('uses localStorage token', async () => { diff --git a/src/lib/api/updateMe.spec.ts b/src/lib/api/updateMe.spec.ts index 6bf100d7..1160289d 100644 --- a/src/lib/api/updateMe.spec.ts +++ b/src/lib/api/updateMe.spec.ts @@ -1,7 +1,7 @@ import { updateMe } from './updateMe'; import { apiFetch } from './apiFetch'; import _ from 'lodash'; -import { vi } from 'vitest'; +import { vi, expect, it, describe, beforeEach } from 'vitest'; vi.mock('./apiFetch'); diff --git a/src/lib/api/useSession.spec.tsx b/src/lib/api/useSession.spec.tsx index 38eecbbf..97f1db9a 100644 --- a/src/lib/api/useSession.spec.tsx +++ b/src/lib/api/useSession.spec.tsx @@ -1,5 +1,6 @@ import { logout, useSession } from './useSession'; import { act, renderHook } from '@testing-library/react'; +import { expect, it, describe } from 'vitest'; describe('useSession', () => { it('should return the session', () => { diff --git a/src/lib/getUnloadMessage.spec.tsx b/src/lib/getUnloadMessage.spec.tsx index 1c854619..2fc0677a 100644 --- a/src/lib/getUnloadMessage.spec.tsx +++ b/src/lib/getUnloadMessage.spec.tsx @@ -2,7 +2,7 @@ import { getUnloadMessage } from './getUnloadMessage'; import React from 'react'; import { useUpdateTask } from './api/useUpdateTask'; import { renderWithQueryProvider, resolveWithDelay } from './test/helpers'; -import { vi } from 'vitest'; +import { vi, expect, it, describe } from 'vitest'; import { updateTask } from './api'; vi.mock('./api/updateTask'); diff --git a/src/lib/sortTasks.spec.ts b/src/lib/sortTasks.spec.ts index fc452821..df0ec65e 100644 --- a/src/lib/sortTasks.spec.ts +++ b/src/lib/sortTasks.spec.ts @@ -1,5 +1,6 @@ import { makeTask } from './test/helpers'; import { sortTasks } from './sortTasks'; +import { expect, it, describe } from 'vitest'; describe('sortTasks', () => { it('has secondary sort by stakes', () => { diff --git a/src/lib/test/helpers.tsx b/src/lib/test/helpers.tsx index 1b6049f0..615b2b29 100644 --- a/src/lib/test/helpers.tsx +++ b/src/lib/test/helpers.tsx @@ -13,7 +13,7 @@ import { import { waitFor } from '@testing-library/dom'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { vi, Mock, SpyInstance } from 'vitest'; +import { vi, Mock, SpyInstance, expect } from 'vitest'; import { getMe, updateMe } from '../api'; import { createTheme, ThemeProvider } from '@mui/material/styles'; diff --git a/src/lib/useDifferenceToNow.spec.ts b/src/lib/useDifferenceToNow.spec.ts index 9204f420..510320cf 100644 --- a/src/lib/useDifferenceToNow.spec.ts +++ b/src/lib/useDifferenceToNow.spec.ts @@ -1,5 +1,6 @@ import useDifferenceToNow from './useDifferenceToNow'; import { loadNowTime, makeTask } from './test/helpers'; +import { expect, it, describe } from 'vitest'; describe('useDifferenceToNow', () => { it('handles future due', () => { diff --git a/src/lib/useIsDue.spec.ts b/src/lib/useIsDue.spec.ts index cc7063d5..d699c783 100644 --- a/src/lib/useIsDue.spec.ts +++ b/src/lib/useIsDue.spec.ts @@ -1,5 +1,6 @@ import useIsDue from './useIsDue'; import { loadNowTime, makeTask } from './test/helpers'; +import { expect, it, describe } from 'vitest'; describe('useIsDue', () => { it('returns is due', () => { diff --git a/src/vitest.spec.ts b/src/vitest.spec.ts index 7d5ec90a..13566647 100644 --- a/src/vitest.spec.ts +++ b/src/vitest.spec.ts @@ -1,4 +1,4 @@ -import { describe, it } from 'vitest'; +import { describe, it, expect } from 'vitest'; describe('vitest', () => { it('test 1', () => { diff --git a/tsconfig.json b/tsconfig.json index ac3426fe..c6680f10 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "types": ["vitest/globals", "@testing-library/jest-dom"], + "types": ["@testing-library/jest-dom"], "allowUnreachableCode": true }, "include": ["src", "vite.config.ts", "global-setup.ts", "__mocks__"], diff --git a/vite.config.ts b/vite.config.ts index b3f9e643..a11ab9f3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,4 @@ /// -/// import { defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react'; import { visualizer } from 'rollup-plugin-visualizer'; @@ -7,11 +6,9 @@ import { visualizer } from 'rollup-plugin-visualizer'; export default defineConfig({ plugins: [react(), visualizer()], test: { - globals: true, environment: 'jsdom', setupFiles: ['./global-setup.ts'], mockReset: true, - include: ['./src/**/*.spec.{ts,tsx}'], reporters: 'dot', }, });