Align group profile summary contract
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
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())
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user