Add unit tests for TournamentGrid component in Challonge integration

This commit is contained in:
2026-01-29 05:33:27 +00:00
parent e4f99e82f4
commit ece566ea56

View File

@@ -0,0 +1,426 @@
/**
* Tests for TournamentGrid Component
*
* Verifies:
* - Loading state display
* - Error state display
* - Empty state display
* - Tournament list rendering
* - Search input functionality
* - Tournament card details
* - State badges rendering
* - Toggle details button
* - Load more pagination (v2.1)
* - Event emissions
*/
import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import TournamentGrid from '@/components/challonge/TournamentGrid.vue';
describe('TournamentGrid', () => {
const mockTournaments = [
{
id: 'abc123',
name: 'Summer Championship',
state: 'pending',
url: 'summer-championship',
tournament_type: 'single elimination',
participants_count: 16,
started_at: '2024-06-01T10:00:00Z'
},
{
tournament: {
id: 'def456',
name: 'Winter Tournament',
state: 'in_progress',
url: 'winter-tournament',
tournament_type: 'double elimination',
participants_count: 32,
started_at: '2024-12-15T14:00:00Z'
}
},
{
id: 'ghi789',
name: 'Spring League',
state: 'ended',
url: 'spring-league',
tournament_type: 'round robin',
participants_count: 8,
started_at: null
}
];
describe('Loading States', () => {
it('displays loading state', () => {
const wrapper = mount(TournamentGrid, {
props: {
loading: true,
tournaments: null
}
});
expect(wrapper.find('.status.loading').exists()).toBe(true);
expect(wrapper.text()).toContain('Loading tournaments');
});
it('displays error state', () => {
const wrapper = mount(TournamentGrid, {
props: {
loading: false,
error: 'Network error',
tournaments: null
}
});
expect(wrapper.find('.status.error').exists()).toBe(true);
expect(wrapper.text()).toContain('Network error');
});
it('displays empty state', () => {
const wrapper = mount(TournamentGrid, {
props: {
loading: false,
tournaments: []
}
});
expect(wrapper.find('.status.empty').exists()).toBe(true);
expect(wrapper.text()).toContain('No tournaments found');
expect(wrapper.find('a[href="https://challonge.com"]').exists()).toBe(true);
});
});
describe('Tournament List Rendering', () => {
it('renders tournament cards', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments
}
});
const cards = wrapper.findAll('.tournament-card');
expect(cards).toHaveLength(3);
});
it('displays tournament names correctly for both v1 and v2.1 formats', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments
}
});
expect(wrapper.text()).toContain('Summer Championship');
expect(wrapper.text()).toContain('Winter Tournament');
expect(wrapper.text()).toContain('Spring League');
});
it('displays tournament details', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]]
}
});
expect(wrapper.text()).toContain('summer-championship');
expect(wrapper.text()).toContain('single elimination');
expect(wrapper.text()).toContain('16');
});
it('displays state badges with correct classes', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments
}
});
expect(wrapper.find('.tournament-state.pending').exists()).toBe(true);
expect(wrapper.find('.tournament-state.in_progress').exists()).toBe(true);
expect(wrapper.find('.tournament-state.ended').exists()).toBe(true);
});
it('formats and displays started_at dates', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]]
}
});
expect(wrapper.text()).toContain('Started:');
// Date formatting varies by locale, just check that something is displayed
const dateText = wrapper.text();
expect(dateText).toMatch(/Started:.*\d/);
});
it('hides started date when null', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[2]],
filteredTournaments: [mockTournaments[2]]
}
});
const cardText = wrapper.find('.tournament-card').text();
expect(cardText).not.toContain('Started:');
});
});
describe('Search Functionality', () => {
it('renders search input', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments
}
});
expect(wrapper.find('.search-input').exists()).toBe(true);
});
it('displays search query in input', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
searchQuery: 'Summer'
}
});
expect(wrapper.find('.search-input').element.value).toBe('Summer');
});
it('emits update:searchQuery on input', async () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments
}
});
const input = wrapper.find('.search-input');
await input.setValue('Winter');
expect(wrapper.emitted('update:searchQuery')).toBeTruthy();
expect(wrapper.emitted('update:searchQuery')[0]).toEqual(['Winter']);
});
it('shows search info when query is present', () => {
const filtered = [mockTournaments[0]];
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: filtered,
searchQuery: 'Summer'
}
});
expect(wrapper.find('.search-info').exists()).toBe(true);
expect(wrapper.text()).toContain('Showing 1 of 3 tournaments');
});
it('hides search info when query is empty', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
searchQuery: ''
}
});
expect(wrapper.find('.search-info').exists()).toBe(false);
});
});
describe('Tournament Details Toggle', () => {
it('renders details toggle button', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]]
}
});
expect(wrapper.find('.btn-small').exists()).toBe(true);
expect(wrapper.text()).toContain('Load Details');
});
it('emits toggle-details event on button click', async () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]]
}
});
await wrapper.find('.btn-small').trigger('click');
expect(wrapper.emitted('toggle-details')).toBeTruthy();
expect(wrapper.emitted('toggle-details')[0]).toEqual(['abc123']);
});
it('shows active state for expanded tournament', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]],
expandedTournamentId: 'abc123'
}
});
const button = wrapper.find('.btn-small');
expect(button.classes()).toContain('btn-active');
expect(button.text()).toBe('Hide Details');
});
it('shows inactive state for non-expanded tournament', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]],
expandedTournamentId: 'other-id'
}
});
const button = wrapper.find('.btn-small');
expect(button.classes()).not.toContain('btn-active');
expect(button.text()).toBe('Load Details');
});
});
describe('Pagination (v2.1)', () => {
it('displays load more button for v2.1 with hasNextPage', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
apiVersion: 'v2.1',
hasNextPage: true
}
});
expect(wrapper.find('.load-more-section').exists()).toBe(true);
expect(wrapper.find('.btn-secondary').text()).toBe('Load More Tournaments');
});
it('hides load more button when hasNextPage is false', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
apiVersion: 'v2.1',
hasNextPage: false
}
});
expect(wrapper.find('.load-more-section').exists()).toBe(false);
});
it('hides load more button for v1', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
apiVersion: 'v1',
hasNextPage: true
}
});
expect(wrapper.find('.load-more-section').exists()).toBe(false);
});
it('shows loading state on load more button', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
apiVersion: 'v2.1',
hasNextPage: true,
loadingMore: true
}
});
const button = wrapper.find('.btn-secondary');
expect(button.text()).toBe('Loading...');
expect(button.attributes('disabled')).toBeDefined();
});
it('emits load-more event on button click', async () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: mockTournaments,
filteredTournaments: mockTournaments,
apiVersion: 'v2.1',
hasNextPage: true
}
});
await wrapper.find('.btn-secondary').trigger('click');
expect(wrapper.emitted('load-more')).toBeTruthy();
expect(wrapper.emitted('load-more')).toHaveLength(1);
});
});
describe('Slots', () => {
it('provides tournament-details slot', () => {
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [mockTournaments[0]],
filteredTournaments: [mockTournaments[0]],
expandedTournamentId: 'abc123'
},
slots: {
'tournament-details': '<div class="custom-details">Custom Content</div>'
}
});
expect(wrapper.find('.custom-details').exists()).toBe(true);
expect(wrapper.text()).toContain('Custom Content');
});
});
describe('Helper Functions', () => {
it('handles v1 format tournaments (flat structure)', () => {
const v1Tournament = {
id: 'test123',
name: 'Test Tournament',
state: 'pending'
};
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [v1Tournament],
filteredTournaments: [v1Tournament]
}
});
expect(wrapper.text()).toContain('Test Tournament');
expect(wrapper.find('.tournament-state.pending').exists()).toBe(true);
});
it('handles v2.1 format tournaments (nested structure)', () => {
const v2Tournament = {
tournament: {
id: 'test456',
name: 'Test Tournament v2',
state: 'in_progress'
}
};
const wrapper = mount(TournamentGrid, {
props: {
tournaments: [v2Tournament],
filteredTournaments: [v2Tournament]
}
});
expect(wrapper.text()).toContain('Test Tournament v2');
expect(wrapper.find('.tournament-state.in_progress').exists()).toBe(true);
});
});
});