Files
portainer/app/react/components/datatables/groupSortState.test.ts

208 lines
6.9 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { buildGroupSortExtras } from './groupSortState';
describe('buildGroupSortExtras — summary bar scenarios', () => {
it('switching to status sort clears status set via summary bar', () => {
// sort='name', status='error' (set via summary bar) → setSortBy('status')
// → status cleared (entering grouped-by-status mode resets the filter)
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'name', status: 'error' }, setUrlState);
extras.setSortBy('status', false);
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'status',
order: 'asc',
page: 0,
status: null,
});
});
it('switching to a different sort preserves status set via summary bar', () => {
// sort='name', status='error' (set via summary bar) → setSortBy('type')
// → status persists (cross-dimension, type cleared, status untouched)
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'name', status: 'error' }, setUrlState);
extras.setSortBy('type', false);
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'type',
order: 'asc',
page: 0,
type: null,
});
});
});
describe('buildGroupSortExtras — sort bar group scenarios', () => {
it('leaving status sort clears status set via sort bar group', () => {
// sort='status', status='error' (set via sort bar group) → setSortBy('name')
// → status cleared (leaving grouped-by-status mode)
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'status', status: 'error' }, setUrlState);
extras.setSortBy('name', false);
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'name',
order: 'asc',
page: 0,
status: null,
});
});
it('clicking a sort bar group value sets sort and filter together', () => {
// sort='name' → setGroupFilter('status', 'error')
// → sort=status, status=error
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'name' }, setUrlState);
extras.setGroupFilter({ group: 'status', groupValue: 'error' });
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'status',
order: 'asc',
page: 0,
status: 'error',
});
});
it('deselecting a sort bar group value keeps sort, clears filter, changes order', () => {
// sort='status', status='error' (set via sort bar group) → setGroupFilter('status', null)
// → sort stays status, status cleared, order toggles
const setUrlState = vi.fn();
const extras = makeExtras(
{ sort: 'status', status: 'error', order: 'asc' },
setUrlState
);
extras.setGroupFilter({ group: 'status', groupValue: null });
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'status',
order: 'desc',
page: 0,
status: null,
});
});
});
describe('buildGroupSortExtras — cross-dimension AND filter scenarios', () => {
it('status set via summary bar persists when switching to a different sort bar group option', () => {
// sort='name', status='error' (set via summary bar) → setGroupFilter('type', 'stack')
// → sort=type, type=stack, status=error preserved (AND filter)
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'name', status: 'error' }, setUrlState);
extras.setGroupFilter({ group: 'type', groupValue: 'stack' });
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'type',
order: 'asc',
page: 0,
type: 'stack',
});
});
it('status set via summary bar persists through a second sort bar group switch, old group dimension clears', () => {
// sort='type', type='stack', status='error' (set via summary bar, AND filter)
// → setGroupFilter('platform', 'docker')
// → sort=platform, type cleared, status still persists
const setUrlState = vi.fn();
const extras = makeExtrasWithPlatform(
{ sort: 'type', type: 'stack', status: 'error' },
setUrlState
);
extras.setGroupFilter({ group: 'platform', groupValue: 'docker' });
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'platform',
order: 'asc',
page: 0,
platform: 'docker',
type: null,
});
});
it('status set via sort bar group clears when switching to a different sort bar group option', () => {
// sort='status', status='error' (set via sort bar group) → setGroupFilter('type', 'stack')
// → status cleared (was the old sort dimension)
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'status', status: 'error' }, setUrlState);
extras.setGroupFilter({ group: 'type', groupValue: 'stack' });
expect(setUrlState).toHaveBeenCalledWith({
sort: 'type',
order: 'asc',
page: 0,
type: 'stack',
status: null,
groupBy: null,
groupFilter: null,
});
});
});
describe('buildGroupSortExtras — override scenarios', () => {
it('summary bar overrides status set via sort bar group (last write wins)', () => {
// setStatus is handled by the view, not buildGroupSortExtras.
// Verify that groupFilter reflects the current URL status when sort=status.
const extras = makeExtras({ sort: 'status', status: 'healthy' });
expect(extras.groupFilter).toBe('healthy');
});
it('toggling sort direction preserves the active sort bar group filter', () => {
const setUrlState = vi.fn();
const extras = makeExtras({ sort: 'status', status: 'error' }, setUrlState);
extras.setSortBy('status', true);
expect(setUrlState).toHaveBeenCalledWith({
groupBy: null,
groupFilter: null,
sort: 'status',
order: 'desc',
page: 0,
});
});
});
function makeExtras(
urlState: {
sort: string;
status?: string | null;
type?: string | null;
order?: 'desc' | 'asc';
},
setUrlState = vi.fn()
) {
const order = urlState.order || 'asc';
return buildGroupSortExtras({
urlState: { status: null, type: null, order, ...urlState },
setUrlState,
defaultSort: 'name',
sortKeys: ['name', 'status', 'type'] as const,
dimensions: [{ key: 'status' }, { key: 'type' }],
});
}
function makeExtrasWithPlatform(
urlState: {
sort: string;
status?: string | null;
type?: string | null;
platform?: string | null;
order?: 'asc' | 'desc';
},
setUrlState = vi.fn()
) {
const order = urlState.order || 'asc';
return buildGroupSortExtras({
urlState: { status: null, type: null, platform: null, order, ...urlState },
setUrlState,
defaultSort: 'name',
sortKeys: ['name', 'status', 'type', 'platform'] as const,
dimensions: [{ key: 'status' }, { key: 'type' }, { key: 'platform' }],
});
}