import React from 'react' import { act, render, screen } from '@testing-library/react' import { hydrateRoot } from 'react-dom/client' import { renderToString } from 'react-dom/server' import { afterEach, describe, expect, it } from 'vitest' import GroupProfileSummary from './GroupProfileSummary' const backendFixture = { group: { id: 1, name: 'Test Group', slug: 'test-group', headline: 'A public collaboration', avatar_url: null, profile_url: '/groups/test-group', }, joined_at: '2026-08-01T12:00:00.000000Z', role: 'member', counts: { credited_artworks: 12, releases: 3, projects: 2, review_actions: 7, }, trusted_indicator: true, summary: 'Contributes across the group releases.', role_labels: ['Coder', 'Designer'], recent_release_titles: ['Release A', 'Release B'], } afterEach(() => { document.body.innerHTML = '' }) describe('GroupProfileSummary backend contract alignment', () => { it('renders the current backend-shaped contribution fixture', () => { render() expect(screen.getByText('Test Group')).toBeTruthy() expect(screen.getByText('member')).toBeTruthy() expect(screen.getByText('Contributes across the group releases.')).toBeTruthy() expect(screen.getByText('Trusted contributor')).toBeTruthy() expect(screen.getByText('Coder')).toBeTruthy() expect(screen.getByText('Designer')).toBeTruthy() expect(screen.getByText('Release A, Release B')).toBeTruthy() expect(screen.getByText('12 artworks')).toBeTruthy() expect(screen.getByText('3 releases')).toBeTruthy() expect(screen.getByText('2 projects')).toBeTruthy() expect(screen.getByText('7 reviews')).toBeTruthy() expect(screen.getByRole('link', { name: /Test Group/ }).getAttribute('href')).toBe('/groups/test-group') }) it('does not render the trusted badge when trusted_indicator is false', () => { render() expect(screen.queryByText('Trusted contributor')).toBeNull() }) it('renders zero counts instead of hiding falsy values', () => { render() expect(screen.getByText('0 artworks')).toBeTruthy() expect(screen.getByText('0 releases')).toBeTruthy() expect(screen.getByText('0 projects')).toBeTruthy() expect(screen.getByText('0 reviews')).toBeTruthy() expect(screen.queryByText('Trusted contributor')).toBeNull() expect(screen.queryByText('Recent releases')).toBeNull() }) it('keeps the empty state unchanged', () => { const { container } = render() expect(container.innerHTML).toBe('') }) it('handles missing optional fields without throwing', () => { render() expect(screen.getByText('Minimal Group')).toBeTruthy() expect(screen.getByText('0 artworks')).toBeTruthy() expect(screen.getByText('0 releases')).toBeTruthy() expect(screen.getByText('0 projects')).toBeTruthy() expect(screen.getByText('0 reviews')).toBeTruthy() }) it('supports the previous frontend-shaped aliases as a compatibility fallback', () => { render() expect(screen.getByText('editor')).toBeTruthy() expect(screen.getByText('Trusted contributor')).toBeTruthy() expect(screen.getByText('4 artworks')).toBeTruthy() }) it('hydrates populated backend data without recoverable errors or markup drift', async () => { const container = document.createElement('div') const serverMarkup = renderToString() container.innerHTML = serverMarkup document.body.appendChild(container) const recoverableErrors = [] const root = hydrateRoot(container, , { onRecoverableError: (error) => recoverableErrors.push(error), }) await act(async () => { await new Promise((resolve) => setTimeout(resolve, 0)) }) expect(container.innerHTML).toBe(serverMarkup) expect(recoverableErrors).toHaveLength(0) expect(container.textContent).toContain('12 artworks') expect(container.textContent).toContain('Release A, Release B') await act(async () => root.unmount()) }) })