Files
SkinbaseNova/resources/js/components/groups/GroupProfileSummary.test.jsx
T

127 lines
4.8 KiB
React

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(<GroupProfileSummary contributions={[backendFixture]} />)
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(<GroupProfileSummary contributions={[{ ...backendFixture, trusted_indicator: false }]} />)
expect(screen.queryByText('Trusted contributor')).toBeNull()
})
it('renders zero counts instead of hiding falsy values', () => {
render(<GroupProfileSummary contributions={[{
...backendFixture,
trusted_indicator: false,
counts: { credited_artworks: 0, releases: 0, projects: 0, review_actions: 0 },
role_labels: [],
recent_release_titles: [],
}]} />)
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(<GroupProfileSummary contributions={[]} />)
expect(container.innerHTML).toBe('')
})
it('handles missing optional fields without throwing', () => {
render(<GroupProfileSummary contributions={[{ group: { id: 2, name: 'Minimal Group', slug: 'minimal' } }]} />)
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(<GroupProfileSummary contributions={[{
group: { id: 3, name: 'Legacy Group', slug: 'legacy', profile_url: '/groups/legacy' },
role: { label: 'editor' },
trusted: true,
counts: { artworks: 4, releases: 1, projects: 0 },
}]} />)
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(<GroupProfileSummary contributions={[backendFixture]} />)
container.innerHTML = serverMarkup
document.body.appendChild(container)
const recoverableErrors = []
const root = hydrateRoot(container, <GroupProfileSummary contributions={[backendFixture]} />, {
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())
})
})