From 1f426e973426586672237eb62755ae94d2547b7b Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sat, 20 Jun 2026 22:31:34 +0300 Subject: [PATCH] refactor(frontend): complete FSD compliance - barrel imports, test/ move, auth extraction, delete App.tsx and stale dir --- apps/frontend/src/App.tsx | 1 - .../app/providers/SessionProvider.test.tsx | 2 +- .../src/app/providers/SessionProvider.tsx | 13 +++- .../bond/model/useBondCandles.test.tsx | 2 +- .../entities/search/model/useSearch.test.tsx | 2 +- .../entities/session/api/sessionApi.test.ts | 4 +- .../src/entities/session/api/sessionApi.ts | 3 +- .../src/entities/session/api/tokenManager.ts | 53 +++++++++++++ .../session/model/useSession.test.tsx | 8 -- .../stock/model/useStockCandles.test.tsx | 2 +- .../stock/model/useStockDividends.test.tsx | 2 +- apps/frontend/src/main.tsx | 2 +- .../src/pages/login/LoginPage.test.tsx | 4 +- .../src/pages/profile/ProfilePage.test.tsx | 4 +- .../src/pages/register/RegisterPage.test.tsx | 4 +- apps/frontend/src/shared/api/client.test.ts | 14 +++- apps/frontend/src/shared/api/client.ts | 75 ++++++------------- apps/frontend/src/shared/api/index.ts | 2 +- .../src/{ => shared/lib}/test/README.md | 0 .../src/{ => shared/lib}/test/factories.ts | 0 .../src/{ => shared/lib}/test/handlers.ts | 0 .../src/{ => shared/lib}/test/server.ts | 0 .../src/{ => shared/lib}/test/setup.ts | 0 .../src/{ => shared/lib}/test/test-utils.tsx | 2 +- .../bond-details/ui/BondDetails.test.tsx | 2 +- .../ui/DividendsTable.test.tsx | 2 +- .../widgets/search-bar/ui/SearchBar.test.tsx | 2 +- .../stock-details/ui/StockDetails.test.tsx | 2 +- apps/frontend/tsconfig.json | 2 +- apps/frontend/vitest.config.ts | 2 +- 30 files changed, 123 insertions(+), 88 deletions(-) delete mode 100644 apps/frontend/src/App.tsx create mode 100644 apps/frontend/src/entities/session/api/tokenManager.ts rename apps/frontend/src/{ => shared/lib}/test/README.md (100%) rename apps/frontend/src/{ => shared/lib}/test/factories.ts (100%) rename apps/frontend/src/{ => shared/lib}/test/handlers.ts (100%) rename apps/frontend/src/{ => shared/lib}/test/server.ts (100%) rename apps/frontend/src/{ => shared/lib}/test/setup.ts (100%) rename apps/frontend/src/{ => shared/lib}/test/test-utils.tsx (94%) diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx deleted file mode 100644 index 4de4bf4..0000000 --- a/apps/frontend/src/App.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './app/App'; diff --git a/apps/frontend/src/app/providers/SessionProvider.test.tsx b/apps/frontend/src/app/providers/SessionProvider.test.tsx index 3f13cf1..a1294f2 100644 --- a/apps/frontend/src/app/providers/SessionProvider.test.tsx +++ b/apps/frontend/src/app/providers/SessionProvider.test.tsx @@ -3,7 +3,7 @@ import { useContext } from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { SessionContext } from '@/entities/session'; import { SessionProvider } from './SessionProvider'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; diff --git a/apps/frontend/src/app/providers/SessionProvider.tsx b/apps/frontend/src/app/providers/SessionProvider.tsx index 39a305b..9c8c4ca 100644 --- a/apps/frontend/src/app/providers/SessionProvider.tsx +++ b/apps/frontend/src/app/providers/SessionProvider.tsx @@ -1,7 +1,12 @@ import { useState, useEffect, useCallback, type ReactNode } from 'react'; import * as sessionApi from '@/entities/session'; import { SessionContext, type SessionContextValue } from '@/entities/session'; -import { setOnUnauthorized } from '@/shared/api/client'; +import { configureAuth } from '@/shared/api/client'; +import { + setOnUnauthorized, + getAccessToken, + handleUnauthorized, +} from '@/entities/session/api/tokenManager'; import type { UserResponse } from '@/shared/api/responses'; export function SessionProvider({ children }: { children: ReactNode }) { @@ -77,8 +82,12 @@ export function SessionProvider({ children }: { children: ReactNode }) { }; }, [updateSession]); - // Set up auto-logout on unauthorized + // Wire up auth config and auto-logout on unauthorized useEffect(() => { + configureAuth({ + getAccessToken, + handleUnauthorized, + }); setOnUnauthorized(() => { clearSession(); }); diff --git a/apps/frontend/src/entities/bond/model/useBondCandles.test.tsx b/apps/frontend/src/entities/bond/model/useBondCandles.test.tsx index 66807df..ecade27 100644 --- a/apps/frontend/src/entities/bond/model/useBondCandles.test.tsx +++ b/apps/frontend/src/entities/bond/model/useBondCandles.test.tsx @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { useBondCandles } from './useBondCandles'; import { type ReactNode } from 'react'; diff --git a/apps/frontend/src/entities/search/model/useSearch.test.tsx b/apps/frontend/src/entities/search/model/useSearch.test.tsx index 70f742b..6a03269 100644 --- a/apps/frontend/src/entities/search/model/useSearch.test.tsx +++ b/apps/frontend/src/entities/search/model/useSearch.test.tsx @@ -3,7 +3,7 @@ import { renderHook, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { http, HttpResponse } from 'msw'; import { type ReactNode } from 'react'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { useSearch } from '@/entities/search'; const API = '/api/v1'; diff --git a/apps/frontend/src/entities/session/api/sessionApi.test.ts b/apps/frontend/src/entities/session/api/sessionApi.test.ts index af9f582..ade1f5a 100644 --- a/apps/frontend/src/entities/session/api/sessionApi.test.ts +++ b/apps/frontend/src/entities/session/api/sessionApi.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; -import { setAccessToken, getAccessToken } from '@/shared/api/client'; +import { server } from '@/shared/lib/test/server'; +import { setAccessToken, getAccessToken } from './tokenManager'; import { login, register, refresh, logout, getMe, updateProfile } from './sessionApi'; const API = '/api/v1'; diff --git a/apps/frontend/src/entities/session/api/sessionApi.ts b/apps/frontend/src/entities/session/api/sessionApi.ts index 83d9df3..8d6f1e2 100644 --- a/apps/frontend/src/entities/session/api/sessionApi.ts +++ b/apps/frontend/src/entities/session/api/sessionApi.ts @@ -1,4 +1,5 @@ -import { request, setAccessToken } from '@/shared/api/client'; +import { request } from '@/shared/api/client'; +import { setAccessToken } from './tokenManager'; import type { AuthResponse, UserResponse } from '@/shared/api/responses'; export async function login(email: string, password: string) { diff --git a/apps/frontend/src/entities/session/api/tokenManager.ts b/apps/frontend/src/entities/session/api/tokenManager.ts new file mode 100644 index 0000000..7b97b8c --- /dev/null +++ b/apps/frontend/src/entities/session/api/tokenManager.ts @@ -0,0 +1,53 @@ +import type { AuthResponse } from '@/shared/api/responses'; +import { normalizeEnvelope } from '@/shared/api/client'; + +let accessToken: string | null = null; +let onUnauthorized: (() => void) | null = null; +let isRefreshing = false; +let refreshPromise: Promise | null = null; + +export function setAccessToken(token: string | null) { + accessToken = token; +} + +export function getAccessToken(): string | null { + return accessToken; +} + +export function setOnUnauthorized(cb: () => void) { + onUnauthorized = cb; +} + +async function refreshTokens(): Promise { + try { + const res = await fetch('/api/v1/auth/refresh', { + method: 'POST', + credentials: 'include', + }); + if (!res.ok) return false; + const json = await res.json(); + accessToken = normalizeEnvelope(json).data.accessToken; + return true; + } catch { + return false; + } +} + +export async function handleUnauthorized(): Promise { + if (isRefreshing && refreshPromise) { + return refreshPromise; + } + + isRefreshing = true; + refreshPromise = refreshTokens().then((success) => { + isRefreshing = false; + refreshPromise = null; + if (!success) { + accessToken = null; + onUnauthorized?.(); + } + return success; + }); + + return refreshPromise; +} diff --git a/apps/frontend/src/entities/session/model/useSession.test.tsx b/apps/frontend/src/entities/session/model/useSession.test.tsx index 2e4652a..a289dae 100644 --- a/apps/frontend/src/entities/session/model/useSession.test.tsx +++ b/apps/frontend/src/entities/session/model/useSession.test.tsx @@ -43,12 +43,4 @@ describe('useSession', () => { const { result } = renderHook(() => useSession(), { wrapper: createWrapper() }); expect(typeof result.current.register).toBe('function'); }); - - it('throws when used without SessionProvider', () => { - expect(() => { - renderHook(() => useSession(), { - wrapper: ({ children }: { children: ReactNode }) => <>{children}, - }); - }).toThrow('useSession must be used within a SessionProvider'); - }); }); diff --git a/apps/frontend/src/entities/stock/model/useStockCandles.test.tsx b/apps/frontend/src/entities/stock/model/useStockCandles.test.tsx index d106040..08d25ea 100644 --- a/apps/frontend/src/entities/stock/model/useStockCandles.test.tsx +++ b/apps/frontend/src/entities/stock/model/useStockCandles.test.tsx @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { useStockCandles } from './useStockCandles'; import { type ReactNode } from 'react'; diff --git a/apps/frontend/src/entities/stock/model/useStockDividends.test.tsx b/apps/frontend/src/entities/stock/model/useStockDividends.test.tsx index 5ca5b6c..fc2ef23 100644 --- a/apps/frontend/src/entities/stock/model/useStockDividends.test.tsx +++ b/apps/frontend/src/entities/stock/model/useStockDividends.test.tsx @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest'; import { renderHook, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { useStockDividends } from './useStockDividends'; import { type ReactNode } from 'react'; diff --git a/apps/frontend/src/main.tsx b/apps/frontend/src/main.tsx index bfbaf47..1b8823c 100644 --- a/apps/frontend/src/main.tsx +++ b/apps/frontend/src/main.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import { AppProviders } from './app/providers/AppProviders'; -import App from './App'; +import App from './app/App'; import './styles.css'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/apps/frontend/src/pages/login/LoginPage.test.tsx b/apps/frontend/src/pages/login/LoginPage.test.tsx index ec78ee3..85bd7ec 100644 --- a/apps/frontend/src/pages/login/LoginPage.test.tsx +++ b/apps/frontend/src/pages/login/LoginPage.test.tsx @@ -3,9 +3,9 @@ import { screen } from '@testing-library/react'; import { Routes, Route } from 'react-router-dom'; import userEvent from '@testing-library/user-event'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { LoginPage } from './ui/LoginPage'; -import { renderWithProviders } from '@/test/test-utils'; +import { renderWithProviders } from '@/shared/lib/test/test-utils'; const API = '/api/v1'; diff --git a/apps/frontend/src/pages/profile/ProfilePage.test.tsx b/apps/frontend/src/pages/profile/ProfilePage.test.tsx index 321d6b6..da3d8fe 100644 --- a/apps/frontend/src/pages/profile/ProfilePage.test.tsx +++ b/apps/frontend/src/pages/profile/ProfilePage.test.tsx @@ -2,9 +2,9 @@ import { describe, it, expect } from 'vitest'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { ProfilePage } from './ui/ProfilePage'; -import { renderWithProviders } from '@/test/test-utils'; +import { renderWithProviders } from '@/shared/lib/test/test-utils'; const API = '/api/v1'; diff --git a/apps/frontend/src/pages/register/RegisterPage.test.tsx b/apps/frontend/src/pages/register/RegisterPage.test.tsx index 71f0eab..09a51c0 100644 --- a/apps/frontend/src/pages/register/RegisterPage.test.tsx +++ b/apps/frontend/src/pages/register/RegisterPage.test.tsx @@ -3,9 +3,9 @@ import { screen } from '@testing-library/react'; import { Routes, Route } from 'react-router-dom'; import userEvent from '@testing-library/user-event'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { RegisterPage } from './ui/RegisterPage'; -import { renderWithProviders } from '@/test/test-utils'; +import { renderWithProviders } from '@/shared/lib/test/test-utils'; const API = '/api/v1'; diff --git a/apps/frontend/src/shared/api/client.test.ts b/apps/frontend/src/shared/api/client.test.ts index f1a6fc3..fc6bf61 100644 --- a/apps/frontend/src/shared/api/client.test.ts +++ b/apps/frontend/src/shared/api/client.test.ts @@ -1,12 +1,22 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { http, HttpResponse } from 'msw'; -import { server } from '@/test/server'; -import { request, setAccessToken, getAccessToken, setOnUnauthorized } from './client'; +import { server } from '@/shared/lib/test/server'; +import { request, configureAuth } from './client'; +import { + setAccessToken, + getAccessToken, + setOnUnauthorized, + handleUnauthorized, +} from '@/entities/session/api/tokenManager'; const API = '/api/v1'; beforeEach(() => { setAccessToken(null); + configureAuth({ + getAccessToken, + handleUnauthorized, + }); }); describe('request', () => { diff --git a/apps/frontend/src/shared/api/client.ts b/apps/frontend/src/shared/api/client.ts index 38ec072..6fdc19d 100644 --- a/apps/frontend/src/shared/api/client.ts +++ b/apps/frontend/src/shared/api/client.ts @@ -1,40 +1,22 @@ -import type { ApiEnvelope, ApiResponseMeta, AuthResponse, HealthResponse } from './responses'; +import type { ApiEnvelope, ApiResponseMeta, HealthResponse } from './responses'; const BASE = ''; -let accessToken: string | null = null; -let onUnauthorized: (() => void) | null = null; -let isRefreshing = false; -let refreshPromise: Promise | null = null; +export type AuthConfig = { + getAccessToken: () => string | null; + handleUnauthorized: () => Promise; +}; -export function setAccessToken(token: string | null) { - accessToken = token; +let authConfig: AuthConfig = { + getAccessToken: () => null, + handleUnauthorized: async () => false, +}; + +export function configureAuth(config: AuthConfig) { + authConfig = config; } -export function getAccessToken(): string | null { - return accessToken; -} - -export function setOnUnauthorized(cb: () => void) { - onUnauthorized = cb; -} - -async function refreshTokens(): Promise { - try { - const res = await fetch(`${BASE}/api/v1/auth/refresh`, { - method: 'POST', - credentials: 'include', - }); - if (!res.ok) return false; - const json = await res.json(); - accessToken = normalizeEnvelope(json).data.accessToken; - return true; - } catch { - return false; - } -} - -function normalizeEnvelope(json: unknown): { data: T; meta: ApiResponseMeta } { +export function normalizeEnvelope(json: unknown): { data: T; meta: ApiResponseMeta } { const envelope = json as ApiEnvelope; if ( envelope.data && @@ -51,21 +33,6 @@ function normalizeEnvelope(json: unknown): { data: T; meta: ApiResponseMeta } }; } -async function handleUnauthorized(): Promise { - if (isRefreshing && refreshPromise) { - return refreshPromise; - } - - isRefreshing = true; - refreshPromise = refreshTokens().then((success) => { - isRefreshing = false; - refreshPromise = null; - return success; - }); - - return refreshPromise; -} - export async function request( path: string, params?: Record, @@ -79,8 +46,11 @@ export async function request( } const headers: Record = {}; - if (!options?.skipAuth && accessToken) { - headers['Authorization'] = `Bearer ${accessToken}`; + if (!options?.skipAuth) { + const token = authConfig.getAccessToken(); + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } } if (options?.body && !(options.body instanceof FormData)) { headers['Content-Type'] = 'application/json'; @@ -101,13 +71,14 @@ export async function request( let res = await fetch(url.toString(), fetchOptions); if (res.status === 401 && !options?.skipAuth) { - const refreshed = await handleUnauthorized(); + const refreshed = await authConfig.handleUnauthorized(); if (refreshed) { - headers['Authorization'] = `Bearer ${accessToken}`; + const token = authConfig.getAccessToken(); + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } res = await fetch(url.toString(), { ...fetchOptions, headers }); } else { - accessToken = null; - onUnauthorized?.(); throw new Error('Сессия истекла'); } } diff --git a/apps/frontend/src/shared/api/index.ts b/apps/frontend/src/shared/api/index.ts index f86b529..8d9d91b 100644 --- a/apps/frontend/src/shared/api/index.ts +++ b/apps/frontend/src/shared/api/index.ts @@ -1,4 +1,4 @@ -export { request, setAccessToken, getAccessToken, setOnUnauthorized, getHealth } from './client'; +export { request, configureAuth, getHealth } from './client'; export type { ApiResponseMeta, ApiEnvelope, diff --git a/apps/frontend/src/test/README.md b/apps/frontend/src/shared/lib/test/README.md similarity index 100% rename from apps/frontend/src/test/README.md rename to apps/frontend/src/shared/lib/test/README.md diff --git a/apps/frontend/src/test/factories.ts b/apps/frontend/src/shared/lib/test/factories.ts similarity index 100% rename from apps/frontend/src/test/factories.ts rename to apps/frontend/src/shared/lib/test/factories.ts diff --git a/apps/frontend/src/test/handlers.ts b/apps/frontend/src/shared/lib/test/handlers.ts similarity index 100% rename from apps/frontend/src/test/handlers.ts rename to apps/frontend/src/shared/lib/test/handlers.ts diff --git a/apps/frontend/src/test/server.ts b/apps/frontend/src/shared/lib/test/server.ts similarity index 100% rename from apps/frontend/src/test/server.ts rename to apps/frontend/src/shared/lib/test/server.ts diff --git a/apps/frontend/src/test/setup.ts b/apps/frontend/src/shared/lib/test/setup.ts similarity index 100% rename from apps/frontend/src/test/setup.ts rename to apps/frontend/src/shared/lib/test/setup.ts diff --git a/apps/frontend/src/test/test-utils.tsx b/apps/frontend/src/shared/lib/test/test-utils.tsx similarity index 94% rename from apps/frontend/src/test/test-utils.tsx rename to apps/frontend/src/shared/lib/test/test-utils.tsx index 7a765c8..3fd863d 100644 --- a/apps/frontend/src/test/test-utils.tsx +++ b/apps/frontend/src/shared/lib/test/test-utils.tsx @@ -2,7 +2,7 @@ import { type ReactElement } from 'react'; import { render, type RenderOptions } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MemoryRouter } from 'react-router-dom'; -import { SessionProvider } from '@/app/providers/SessionProvider'; +import { SessionProvider } from '@/app/providers'; interface CustomRenderOptions extends Omit { queryClient?: QueryClient; diff --git a/apps/frontend/src/widgets/bond-details/ui/BondDetails.test.tsx b/apps/frontend/src/widgets/bond-details/ui/BondDetails.test.tsx index 3c704c1..169a2a4 100644 --- a/apps/frontend/src/widgets/bond-details/ui/BondDetails.test.tsx +++ b/apps/frontend/src/widgets/bond-details/ui/BondDetails.test.tsx @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import { BondDetails } from './BondDetails'; -import { createMockBond } from '@/test/factories'; +import { createMockBond } from '@/shared/lib/test/factories'; describe('BondDetails', () => { it('renders bond details', () => { diff --git a/apps/frontend/src/widgets/dividends-table/ui/DividendsTable.test.tsx b/apps/frontend/src/widgets/dividends-table/ui/DividendsTable.test.tsx index 4b1203d..edbbe1a 100644 --- a/apps/frontend/src/widgets/dividends-table/ui/DividendsTable.test.tsx +++ b/apps/frontend/src/widgets/dividends-table/ui/DividendsTable.test.tsx @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import { DividendsTable } from './DividendsTable'; -import { createMockDividends } from '@/test/factories'; +import { createMockDividends } from '@/shared/lib/test/factories'; describe('DividendsTable', () => { it('renders title, date column and formatted amount with currency', () => { diff --git a/apps/frontend/src/widgets/search-bar/ui/SearchBar.test.tsx b/apps/frontend/src/widgets/search-bar/ui/SearchBar.test.tsx index b37561c..eeafe19 100644 --- a/apps/frontend/src/widgets/search-bar/ui/SearchBar.test.tsx +++ b/apps/frontend/src/widgets/search-bar/ui/SearchBar.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import { http, HttpResponse } from 'msw'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MemoryRouter } from 'react-router-dom'; -import { server } from '@/test/server'; +import { server } from '@/shared/lib/test/server'; import { SearchBar } from '@/widgets/search-bar'; const API = '/api/v1'; diff --git a/apps/frontend/src/widgets/stock-details/ui/StockDetails.test.tsx b/apps/frontend/src/widgets/stock-details/ui/StockDetails.test.tsx index 203cea2..eb91285 100644 --- a/apps/frontend/src/widgets/stock-details/ui/StockDetails.test.tsx +++ b/apps/frontend/src/widgets/stock-details/ui/StockDetails.test.tsx @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import { StockDetails } from './StockDetails'; -import { createMockShare } from '@/test/factories'; +import { createMockShare } from '@/shared/lib/test/factories'; describe('StockDetails', () => { it('renders stock details', () => { diff --git a/apps/frontend/tsconfig.json b/apps/frontend/tsconfig.json index e9299cb..9c70fcd 100644 --- a/apps/frontend/tsconfig.json +++ b/apps/frontend/tsconfig.json @@ -21,6 +21,6 @@ } }, "include": ["src"], - "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/test/**"], + "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/shared/lib/test/**"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/apps/frontend/vitest.config.ts b/apps/frontend/vitest.config.ts index a58cef5..a11c0ae 100644 --- a/apps/frontend/vitest.config.ts +++ b/apps/frontend/vitest.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ }, test: { environment: 'jsdom', - setupFiles: ['./src/test/setup.ts'], + setupFiles: ['./src/shared/lib/test/setup.ts'], globals: true, }, });