Skip to content
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
1 change: 1 addition & 0 deletions .github/workflows/visual-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
visual-baseline:
timeout-minutes: 60
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
Expand Down
21 changes: 10 additions & 11 deletions scripts/check-edge-integration-coverage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
/**
* scripts/check-edge-integration-coverage.mjs
*
* Compara Edge Functions implantadas vs. funções cobertas por testes de integração.
* Falha CI se a porcentagem de funções cobertas cair abaixo do threshold (padrão 60%).
* Verifica que cada Edge Function pública tem ao menos um arquivo de
* "client contract test" em tests/edge-functions/integration/ que
* referencia seu nome (via fetch mock).
*
* Critério de cobertura: presença de um arquivo de teste que menciona o nome da função.
* Atenção: esses testes verificam contratos de resposta (status, headers,
* shape), não executam o código real da função. Para cobertura de código real,
* use `supabase functions serve` + testes contra localhost.
*
* Falha CI se a porcentagem de funções com contrato cair abaixo do threshold
* (padrão 60%, ajustável via EDGE_COVERAGE_THRESHOLD).
*/

import { readdirSync, readFileSync, existsSync } from "node:fs";
Expand All @@ -16,17 +22,10 @@ const THRESHOLD = Number(process.env.EDGE_COVERAGE_THRESHOLD) || 60;
const FUNCTIONS_DIR = "supabase/functions";
const TESTS_DIR = "tests/edge-functions/integration";

// Funções a ignorar (utilitários internos sem endpoint HTTP direto)
const IGNORED_FUNCTIONS = new Set([
"_shared",
"_templates",
"_utils",
]);

function listEdgeFunctions() {
if (!existsSync(FUNCTIONS_DIR)) return [];
return readdirSync(FUNCTIONS_DIR, { withFileTypes: true })
.filter((d) => d.isDirectory() && !IGNORED_FUNCTIONS.has(d.name))
.filter((d) => d.isDirectory() && !d.name.startsWith("_"))
.map((d) => d.name);
}

Expand Down
10 changes: 5 additions & 5 deletions src/components/common/PersistentBreadcrumbs.teleport.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ describe('PersistentBreadcrumbs - Teletransporte Logic', () => {

beforeEach(() => {
vi.clearAllMocks();
(useNavigate as any).mockReturnValue(mockNavigate);
(useNavigate as ReturnType<typeof vi.fn>).mockReturnValue(mockNavigate);
});

it('should render the Zap icon (portal) and correct aria-label', () => {
(useLocation as any).mockReturnValue({ pathname: '/produtos' });
(useLocation as ReturnType<typeof vi.fn>).mockReturnValue({ pathname: '/produtos' });
render(
<MemoryRouter>
<PersistentBreadcrumbs showBackButton />
Expand All @@ -53,7 +53,7 @@ describe('PersistentBreadcrumbs - Teletransporte Logic', () => {
});

it('should call navigate(-1) and track analytics when history is long enough', () => {
(useLocation as any).mockReturnValue({ pathname: '/favoritos' });
(useLocation as ReturnType<typeof vi.fn>).mockReturnValue({ pathname: '/favoritos' });

// Simula history.length > 2
Object.defineProperty(window, 'history', {
Expand All @@ -75,7 +75,7 @@ describe('PersistentBreadcrumbs - Teletransporte Logic', () => {
});

it('should fallback to home when history is shallow', () => {
(useLocation as any).mockReturnValue({ pathname: '/produtos' });
(useLocation as ReturnType<typeof vi.fn>).mockReturnValue({ pathname: '/produtos' });

// Simula history.length <= 2 (entrada direta)
Object.defineProperty(window, 'history', {
Expand All @@ -97,7 +97,7 @@ describe('PersistentBreadcrumbs - Teletransporte Logic', () => {
});

it('should not show back button on home page', () => {
(useLocation as any).mockReturnValue({ pathname: '/' });
(useLocation as ReturnType<typeof vi.fn>).mockReturnValue({ pathname: '/' });

render(
<MemoryRouter>
Expand Down
2 changes: 1 addition & 1 deletion src/components/pdf/proposal/ProposalProductTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export function ProposalProductTable({ items, showHeader = true, startIndex = 0
</td>
</tr>
)}
{group.items.map(({ item, globalIdx }, idx) => {
{group.items.map(({ item, globalIdx }, _idx) => {
const persUnitCost =
item.personalizations?.reduce((sum, p) => {
const pTotal = p.total_cost || 0;
Expand Down
1 change: 0 additions & 1 deletion src/hooks/products/useProductAnalytics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useCallback } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { useAuth } from '@/contexts/AuthContext';
import { logger } from '@/lib/logger';

interface TrackViewParams {
productId?: string;
Expand Down
70 changes: 70 additions & 0 deletions tests/__mocks__/frenet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* tests/__mocks__/frenet.ts
*
* Static response fixtures for the Frenet freight API.
* Import and use with vi.mock() or as fetch-mock stubs so tests never
* need live Frenet credentials.
*
* Usage:
* import { frenetQuoteResponse, frenetZipResponse } from '../__mocks__/frenet';
* vi.mock('@/lib/freight/frenet', () => ({ quoteFrete: vi.fn().mockResolvedValue(frenetQuoteResponse) }));
*/
Comment on lines +8 to +11

export const frenetZipResponse = {
ZipCode: '01310-100',
Street: 'Avenida Paulista',
Complement: '',
Neighborhood: 'Bela Vista',
City: 'São Paulo',
State: 'SP',
Error: false,
Message: '',
};

export const frenetQuoteResponse = {
ShippingSevicesArray: [
{
ServiceCode: 'FR',
ServiceDescription: 'Frenet',
Carrier: 'Jadlog',
CarrierCode: 'JD',
ShippingPrice: 18.5,
DeliveryTime: 3,
Error: false,
Msg: '',
},
{
ServiceCode: 'FR',
ServiceDescription: 'Frenet Econômico',
Carrier: 'Jadlog',
CarrierCode: 'JD',
ShippingPrice: 14.0,
DeliveryTime: 7,
Error: false,
Msg: '',
},
],
Error: false,
Msg: '',
};

export const frenetQuoteError = {
ShippingSevicesArray: [],
Error: true,
Msg: 'CEP de destino não atendido.',
};

export const frenetTrackResponse = {
TrackingEvents: [
{
EventType: 'ENTREGUE',
EventDescription: 'Objeto entregue ao destinatário',
EventDate: '2025-01-15',
EventTime: '14:23:00',
City: 'São Paulo',
State: 'SP',
},
],
Error: false,
Msg: '',
};
87 changes: 87 additions & 0 deletions tests/__mocks__/totalexpress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* tests/__mocks__/totalexpress.ts
*
* Static response fixtures for the Total Express freight API.
* Import and use with vi.mock() or as fetch-mock stubs so tests never
* need live Total Express credentials.
*
* Usage:
* import { totalexpressQuoteResponse } from '../__mocks__/totalexpress';
* vi.mock('@/lib/freight/totalexpress', () => ({ calcularFrete: vi.fn().mockResolvedValue(totalexpressQuoteResponse) }));
*/
Comment on lines +8 to +11

export const totalexpressQuoteResponse = {
Success: true,
ErrorMessage: null,
Quotations: [
{
ServiceCode: '40010',
ServiceDescription: 'SEDEX',
Price: 35.9,
DeliveryTime: 2,
Weight: 1.0,
Volume: 0.001,
},
{
ServiceCode: '41106',
ServiceDescription: 'PAC',
Price: 22.5,
DeliveryTime: 8,
Weight: 1.0,
Volume: 0.001,
},
],
};

export const totalexpressQuoteError = {
Success: false,
ErrorMessage: 'CEP de destino não atendido pela Total Express.',
Quotations: [],
};

export const totalexpressTrackResponse = {
Success: true,
ErrorMessage: null,
TrackingCode: 'TE123456789BR',
Events: [
{
Code: 'BDE',
Description: 'Objeto entregue ao destinatário',
Date: '2025-01-15',
Time: '14:23',
Local: 'São Paulo / SP',
},
{
Code: 'OEC',
Description: 'Objeto saiu para entrega ao destinatário',
Date: '2025-01-15',
Time: '08:10',
Local: 'São Paulo / SP',
},
],
};

export const totalexpressDeliveryEstimate = {
Success: true,
ErrorMessage: null,
OriginZipCode: '01310-100',
DestinationZipCode: '20040-020',
EstimatedDays: 3,
CutoffTime: '18:00',
};

export const totalexpressZipValidation = {
Success: true,
ErrorMessage: null,
ZipCode: '01310-100',
Covered: true,
ServiceTypes: ['SEDEX', 'PAC'],
};

export const totalexpressZipNotCovered = {
Success: false,
ErrorMessage: 'CEP não coberto.',
ZipCode: '99999-000',
Covered: false,
ServiceTypes: [],
};
Loading