From 72a7c4d1cf38b563637ce7a8d6d7b47eee18137b Mon Sep 17 00:00:00 2001 From: SONIA Date: Fri, 26 Jun 2026 19:45:07 +0000 Subject: [PATCH] test: add snapshot/regression tests for verify page (closes #594) --- .../__snapshots__/verify-page.test.tsx.snap | 528 ++++++++++++++++++ .../__tests__/components/verify-page.test.tsx | 106 ++++ 2 files changed, 634 insertions(+) create mode 100644 apps/web/src/__tests__/components/__snapshots__/verify-page.test.tsx.snap create mode 100644 apps/web/src/__tests__/components/verify-page.test.tsx diff --git a/apps/web/src/__tests__/components/__snapshots__/verify-page.test.tsx.snap b/apps/web/src/__tests__/components/__snapshots__/verify-page.test.tsx.snap new file mode 100644 index 0000000..7a9d310 --- /dev/null +++ b/apps/web/src/__tests__/components/__snapshots__/verify-page.test.tsx.snap @@ -0,0 +1,528 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`VerifyPage snapshots > renders error state 1`] = ` +
+
+
+
+
+
+ + + +
+
+
+ Error: Not found +
+ +
+
+`; + +exports[`VerifyPage snapshots > renders idle state 1`] = ` +
+
+
+
+
+
+ + + +
+
+
+
+
+`; + +exports[`VerifyPage snapshots > renders success result 1`] = ` +
+
+
+
+
+
+ + + +
+
+
+ Certificate verified successfully. +
+
+
+
+
+
+

+ Certificate +

+
+
+
+ ID +
+
+ cert-abc-123 +
+
+
+
+ Energy +
+
+ 12.5 kWh +
+
+
+
+ Issued +
+
+ 1/15/2024, 10:00:00 AM +
+
+
+
+ Status +
+
+ Active +
+
+
+
+
+
+
+

+ On-chain proof +

+
+
+
+ Anchor tx +
+
+ + anchor-tx-hash-abc + +
+
+
+
+ Mint tx +
+
+ + mint-tx-hash-def + +
+
+
+
+
+
+
+

+ Meter proof +

+
+
+
+ Meter ID +
+
+ meter-xyz-456 +
+
+
+
+ Reading hash +
+
+ abcdef1234567890… +
+
+
+
+ Signature +
+
+ sig1234567890abc… +
+
+
+
+ kWh +
+
+ 12.5 +
+
+
+
+ Timestamp +
+
+ 1/15/2024, 9:55:00 AM +
+
+
+
+ Ed25519 verified +
+
+ ✓ Valid +
+
+
+
+
+
+
+
+`; diff --git a/apps/web/src/__tests__/components/verify-page.test.tsx b/apps/web/src/__tests__/components/verify-page.test.tsx new file mode 100644 index 0000000..4566961 --- /dev/null +++ b/apps/web/src/__tests__/components/verify-page.test.tsx @@ -0,0 +1,106 @@ +/** + * Snapshot/regression tests for the verify page + * Issue #594 — catch unintended visual regressions across all states + * + * To update snapshots after intentional changes: + * pnpm test -- --update-snapshots + */ + +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { render, screen, waitFor, fireEvent, act } from '@testing-library/react' +import VerifyPage from '@/app/verify/page' + +vi.mock('lucide-react', () => ({ + Shield: (props: Record) => , + Search: (props: Record) => , + CheckCircle: (props: Record) => , + XCircle: (props: Record) => , + ExternalLink: (props: Record) => , +})) + +vi.mock('@/components/skeleton', () => ({ + SectionSkeleton: ({ rows }: { rows?: number }) => ( +
+ ), +})) + +const mockChainOfCustody = { + certificate: { + id: 'cert-abc-123', + kwh: 12.5, + issued_at: '2024-01-15T10:00:00.000Z', + retired: false, + retired_at: null, + retired_by: null, + }, + on_chain: { + anchor_tx: 'anchor-tx-hash-abc', + anchor_explorer: 'https://stellar.expert/anchor-tx-hash-abc', + mint_tx: 'mint-tx-hash-def', + mint_explorer: 'https://stellar.expert/mint-tx-hash-def', + }, + meter_proof: { + meter_id: 'meter-xyz-456', + reading_hash: 'abcdef1234567890abcdef1234567890', + signature_hex: 'sig1234567890abcdef1234567890abc', + kwh: 12.5, + timestamp: '2024-01-15T09:55:00.000Z', + verified: true, + }, +} + +beforeEach(() => { + vi.restoreAllMocks() +}) + +describe('VerifyPage snapshots', () => { + it('renders idle state', () => { + const { container } = render() + expect(container).toMatchSnapshot() + }) + + it('renders search form with correct accessibility attributes', () => { + render() + const input = screen.getByRole('searchbox') + expect(input.getAttribute('aria-label')).toBe('Certificate ID, reading hash, or transaction hash') + expect(input.getAttribute('aria-required')).toBe('true') + + const button = screen.getByRole('button', { name: /verify certificate/i }) + expect(button.getAttribute('aria-label')).toBe('Verify certificate') + expect(button.getAttribute('aria-busy')).toBe('false') + }) + + it('renders error state', async () => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ + ok: false, + json: async () => ({ error: 'Not found' }), + })) + + const { container } = render() + const input = screen.getByRole('searchbox') + const button = screen.getByRole('button', { name: /verify certificate/i }) + + fireEvent.change(input, { target: { value: 'bad-id' } }) + await act(async () => { fireEvent.click(button) }) + + await waitFor(() => screen.getByRole('alert')) + expect(container).toMatchSnapshot() + }) + + it('renders success result', async () => { + vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ + ok: true, + json: async () => mockChainOfCustody, + })) + + const { container } = render() + const input = screen.getByRole('searchbox') + const button = screen.getByRole('button', { name: /verify certificate/i }) + + fireEvent.change(input, { target: { value: 'cert-abc-123' } }) + await act(async () => { fireEvent.click(button) }) + + await waitFor(() => screen.getByRole('status')) + expect(container).toMatchSnapshot() + }) +})