diff --git a/package-lock.json b/package-lock.json
index 0d2c56a99..53708c878 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -96,6 +96,7 @@
"zustand": "^4.5.0"
},
"devDependencies": {
+ "@axe-core/playwright": "^4.11.3",
"@playwright/test": "^1.59.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
@@ -207,6 +208,29 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/@axe-core/playwright": {
+ "version": "4.11.3",
+ "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.11.3.tgz",
+ "integrity": "sha512-h/kfksv4F0cVIDlKpT4700OehdRgpvuVskuQ2nb7/JmtWUXpe9ftHAPtwyXGvVSsa6SJ64A9ER7Zrzc/sIvC4w==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "axe-core": "~4.11.4"
+ },
+ "peerDependencies": {
+ "playwright-core": ">= 1.0.0"
+ }
+ },
+ "node_modules/@axe-core/playwright/node_modules/axe-core": {
+ "version": "4.11.4",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz",
+ "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
diff --git a/src/components/inventory/risk/RiskTooltip.tsx b/src/components/inventory/risk/RiskTooltip.tsx
index 22b6d1b0d..8770872f1 100644
--- a/src/components/inventory/risk/RiskTooltip.tsx
+++ b/src/components/inventory/risk/RiskTooltip.tsx
@@ -1,5 +1,4 @@
import { forwardRef } from 'react';
-import { cn } from '@/lib/utils';
interface RiskChartDataPoint {
fullDate?: string;
@@ -25,36 +24,38 @@ export const RiskTooltip = forwardRef<
-
+
Estoque Atual
- {data.stockClose != null ? data.stockClose.toLocaleString('pt-BR') : '—'}
+ {typeof data.stockClose === 'number' ? data.stockClose.toLocaleString('pt-BR') : '—'}
{(data.depleted || data.restocked) && (
- {data.depleted !== null && data.depleted > 0 && (
+ {typeof data.depleted === 'number' && data.depleted > 0 && (
Saídas
-
-{data.depleted}
+
-{data.depleted}
)}
- {data.restocked !== null && data.restocked > 0 && (
+ {typeof data.restocked === 'number' && data.restocked > 0 && (
Entradas
-
+{data.restocked}
+
+{data.restocked}
)}
)}
{data.restockDetected && (
-
+
-
Reposição Detectada
+
+ Reposição Detectada
+
)}
diff --git a/src/components/products/ProductCategoryBadges.test.tsx b/src/components/products/ProductCategoryBadges.test.tsx
index 0f2c9dbeb..f9c11644f 100644
--- a/src/components/products/ProductCategoryBadges.test.tsx
+++ b/src/components/products/ProductCategoryBadges.test.tsx
@@ -1,10 +1,10 @@
+import type { ComponentProps } from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { ProductCategoryBadges } from './ProductCategoryBadges';
import { BrowserRouter } from 'react-router-dom';
import { TooltipProvider } from '@/components/ui/tooltip';
import { describe, it, expect, vi, beforeEach } from 'vitest';
-
const mockNavigate = vi.fn();
// Mock do hook useCategoryIcons
@@ -25,8 +25,7 @@ vi.mock('react-router-dom', async () => {
};
});
-const defaultProps = {
-
+const defaultProps: ComponentProps
= {
category: { id: 'cat-1', name: 'Squeeze' },
groups: [
{ id: 'cat-2', name: 'Garrafas' },
@@ -47,11 +46,10 @@ const renderComponent = (props = defaultProps) => {
-
+ ,
);
};
-
describe('ProductCategoryBadges', () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -68,7 +66,7 @@ describe('ProductCategoryBadges', () => {
renderComponent();
const mainCategory = screen.getByText('Squeeze').parentElement;
if (mainCategory) fireEvent.click(mainCategory);
-
+
expect(mockNavigate).toHaveBeenCalledWith('/filtros?categories=uuid-123');
});
@@ -76,7 +74,7 @@ describe('ProductCategoryBadges', () => {
renderComponent({ ...defaultProps, categoryUuid: null });
const mainCategory = screen.getByText('Squeeze').parentElement;
if (mainCategory) fireEvent.click(mainCategory);
-
+
expect(mockNavigate).toHaveBeenCalledWith('/filtros?categories=cat-1');
});
@@ -130,10 +128,10 @@ describe('ProductCategoryBadges', () => {
});
it('não deve renderizar nada se não houver categorias', () => {
- const { container } = renderComponent({
- ...defaultProps,
- category: null as any,
- groups: []
+ const { container } = renderComponent({
+ ...defaultProps,
+ category: null as unknown as ComponentProps['category'],
+ groups: [],
});
expect(container.firstChild).toBeNull();
});
diff --git a/src/contexts/ThemeContext.tsx b/src/contexts/ThemeContext.tsx
index c4d2f6787..b0a288933 100644
--- a/src/contexts/ThemeContext.tsx
+++ b/src/contexts/ThemeContext.tsx
@@ -20,6 +20,7 @@ interface ThemeProviderProps {
children: ReactNode;
defaultTheme?: Theme;
storageKey?: string;
+ tooltipStorageKey?: string;
}
export function ThemeProvider({
@@ -117,8 +118,11 @@ export function ThemeProvider({
});
};
- if (typeof document !== 'undefined' && 'startViewTransition' in document) {
- (document as any).startViewTransition(apply);
+ const docWithViewTransition = document as Document & {
+ startViewTransition?: (callback: () => void) => void;
+ };
+ if (typeof document !== 'undefined' && docWithViewTransition.startViewTransition) {
+ docWithViewTransition.startViewTransition(apply);
} else {
apply();
}
@@ -159,8 +163,10 @@ export function useTheme() {
return {
theme: 'light',
actualTheme: 'light',
+ tooltipStyle: 'standard',
setTheme: () => {},
toggleTheme: () => {},
+ setTooltipStyle: () => {},
isFallback: true,
} as ThemeContextType;
}
diff --git a/src/pages/filters/useFiltersPageState.ts b/src/pages/filters/useFiltersPageState.ts
index 7a2ef10c7..0778b7d13 100644
--- a/src/pages/filters/useFiltersPageState.ts
+++ b/src/pages/filters/useFiltersPageState.ts
@@ -487,6 +487,7 @@ export function useFiltersPageState() {
hasCategoryFilter,
categoryFilteredProductIds,
isLoadingCategoryFilter,
+ categoryFilterError,
hasColorFilter,
colorFilteredProductIds,
isLoadingColorFilter,
diff --git a/src/tests/B2BProductDetailFlow.test.tsx b/src/tests/B2BProductDetailFlow.test.tsx
index f24dee75d..cc61a10d4 100644
--- a/src/tests/B2BProductDetailFlow.test.tsx
+++ b/src/tests/B2BProductDetailFlow.test.tsx
@@ -1,4 +1,4 @@
-import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { render, screen, fireEvent } from '@testing-library/react';
import { ProductDetailHero } from '@/pages/products/product-detail/ProductDetailHero';
import { BrowserRouter } from 'react-router-dom';
import { TooltipProvider } from '@/components/ui/tooltip';
@@ -38,7 +38,7 @@ vi.mock('@/hooks/products/useCategoryIcons', () => ({
}));
vi.mock('@/components/products/SingleVariantPicker', () => ({
- SingleVariantPicker: ({ onSelect }: { onSelect: (v: any) => void }) => (
+ SingleVariantPicker: ({ onSelect }: { onSelect: (v: unknown) => void }) => (
@@ -62,20 +62,20 @@ const mockProduct: Product = {
category: { id: 1, name: 'Brindes' },
category_id: 'cat-uuid-1',
supplier: { id: 'supp-1', name: 'Fornecedor A' },
- tags: {
- publicoAlvo: ['Executivos'],
- datasComemorativas: [],
- endomarketing: [],
- ramo: [],
- nicho: []
+ tags: {
+ publicoAlvo: ['Executivos'],
+ datasComemorativas: [],
+ endomarketing: [],
+ ramo: [],
+ nicho: [],
},
priceUpdatedAt: new Date().toISOString(),
leadTimeDays: 5,
-} as any;
+} as unknown as Product;
const queryClient = new QueryClient();
-const renderPDP = (tags = {}) => {
+const renderPDP = () => {
return render(
@@ -92,11 +92,10 @@ const renderPDP = (tags = {}) => {
onOpenPackagingModal={() => {}}
onOpenFutureStock={() => {}}
onOpenSupplierComparison={() => {}}
- tags={tags}
/>
-
+ ,
);
};
@@ -107,47 +106,51 @@ describe('B2B Product Detail Flow Integration', () => {
it('Fluxo 1: Adicionar ao Carrinho (Quick Add)', async () => {
renderPDP();
-
+
const cartButton = screen.getByText('Carrinho');
fireEvent.click(cartButton);
const variantButton = await screen.findByText('Mock Variant');
fireEvent.click(variantButton);
-
+
const confirmAdd = await screen.findByTestId('product-card-add-to-cart');
fireEvent.click(confirmAdd);
- expect(mockAddToActiveCart).toHaveBeenCalledWith(expect.objectContaining({
- product_id: 'prod-123',
- quantity: 50,
- color_name: 'Azul'
- }));
+ expect(mockAddToActiveCart).toHaveBeenCalledWith(
+ expect.objectContaining({
+ product_id: 'prod-123',
+ quantity: 50,
+ color_name: 'Azul',
+ }),
+ );
});
it('Fluxo 2: Navegação por Categorias', () => {
renderPDP();
const categoryBadge = screen.getByText('Brindes');
fireEvent.click(categoryBadge.parentElement!);
-
- expect(mockNavigate).toHaveBeenCalledWith(expect.stringContaining('/filtros?categories=cat-uuid-1'));
+
+ expect(mockNavigate).toHaveBeenCalledWith(
+ expect.stringContaining('/filtros?categories=cat-uuid-1'),
+ );
});
it('Fluxo 3: Abrir Modais de Ação Rápida (Preços)', async () => {
renderPDP();
-
+
const pricesButton = screen.getByText('Preços');
fireEvent.click(pricesButton);
-
+
const title = await screen.findByText(/Tabela de Preços/i);
expect(title).toBeDefined();
});
it('Fluxo 4: Verificação de Tags e Nichos (Indicação)', async () => {
- renderPDP({ 'Público-Alvo': ['Executivos'] });
-
+ renderPDP();
+
const indicationButton = screen.getByText('Indicação');
fireEvent.click(indicationButton);
-
+
const modalTitle = await screen.findByText(/Indicado para/i);
expect(modalTitle).toBeDefined();
});
diff --git a/src/tests/ThemeInitializer.test.tsx b/src/tests/ThemeInitializer.test.tsx
index dec0eb7d6..caf31605e 100644
--- a/src/tests/ThemeInitializer.test.tsx
+++ b/src/tests/ThemeInitializer.test.tsx
@@ -34,8 +34,10 @@ describe('ThemeInitializer', () => {
const mockContext = {
theme: 'light' as const,
actualTheme: 'light' as const,
+ tooltipStyle: 'standard' as const,
setTheme: vi.fn(),
toggleTheme: vi.fn(),
+ setTooltipStyle: vi.fn(),
};
render(
@@ -54,8 +56,10 @@ describe('ThemeInitializer', () => {
value={{
theme: 'light',
actualTheme: 'light',
+ tooltipStyle: 'standard',
setTheme: vi.fn(),
toggleTheme: vi.fn(),
+ setTooltipStyle: vi.fn(),
}}
>
@@ -70,8 +74,10 @@ describe('ThemeInitializer', () => {
value={{
theme: 'dark',
actualTheme: 'dark',
+ tooltipStyle: 'standard',
setTheme: vi.fn(),
toggleTheme: vi.fn(),
+ setTooltipStyle: vi.fn(),
}}
>