mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
ae9be74719
* feat(settings): redesign server cards with identity line and capability badges Compact two-line server headers (entry name + user@host), HTTPS lock, and a clickable version info tooltip. Navidrome ≥0.62 shows a green AudioMuse inline badge; older Navidrome keeps the manual toggle row. Adds click-pinned tooltips via data-tooltip-click on TooltipPortal. * feat(settings): unify use/active slot and move delete into edit form Merge Active badge and Use button into one rightmost action; Active uses green styling. Reorder actions to edit, test, use/active. Remove the card delete icon — deletion lives in the server edit form footer. * docs: note compact server cards in CHANGELOG and credits (PR #1054) * fix(credits): move PR #1054 server cards line to cucadmuh block Was appended to Psychotoxical's contributions array by mistake; CHANGELOG already credited cucadmuh (gh pr view author).
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import { act, fireEvent, screen } from '@testing-library/react';
|
|
import { renderWithProviders } from '@/test/helpers/renderWithProviders';
|
|
import TooltipPortal from './TooltipPortal';
|
|
|
|
function Fixture() {
|
|
return (
|
|
<>
|
|
<TooltipPortal />
|
|
<button data-tooltip="Play this album">play</button>
|
|
</>
|
|
);
|
|
}
|
|
|
|
describe('TooltipPortal open delay', () => {
|
|
beforeEach(() => vi.useFakeTimers());
|
|
afterEach(() => {
|
|
vi.runOnlyPendingTimers();
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('shows the tooltip only after the 1s open delay', () => {
|
|
renderWithProviders(<Fixture />);
|
|
const btn = screen.getByText('play');
|
|
|
|
fireEvent.mouseOver(btn);
|
|
expect(screen.queryByText('Play this album')).toBeNull();
|
|
|
|
act(() => {
|
|
vi.advanceTimersByTime(999);
|
|
});
|
|
expect(screen.queryByText('Play this album')).toBeNull();
|
|
|
|
act(() => {
|
|
vi.advanceTimersByTime(1);
|
|
});
|
|
expect(screen.getByText('Play this album')).toBeInTheDocument();
|
|
});
|
|
|
|
it('cancels the pending tooltip when the pointer leaves before the delay', () => {
|
|
renderWithProviders(<Fixture />);
|
|
const btn = screen.getByText('play');
|
|
|
|
fireEvent.mouseOver(btn);
|
|
act(() => {
|
|
vi.advanceTimersByTime(500);
|
|
});
|
|
fireEvent.mouseOut(btn, { relatedTarget: document.body });
|
|
act(() => {
|
|
vi.advanceTimersByTime(1000);
|
|
});
|
|
|
|
expect(screen.queryByText('Play this album')).toBeNull();
|
|
});
|
|
|
|
it('hides immediately on mousedown', () => {
|
|
renderWithProviders(<Fixture />);
|
|
const btn = screen.getByText('play');
|
|
|
|
fireEvent.mouseOver(btn);
|
|
act(() => {
|
|
vi.advanceTimersByTime(1000);
|
|
});
|
|
expect(screen.getByText('Play this album')).toBeInTheDocument();
|
|
|
|
fireEvent.mouseDown(btn);
|
|
expect(screen.queryByText('Play this album')).toBeNull();
|
|
});
|
|
|
|
it('shows immediately on click when data-tooltip-click is set', () => {
|
|
renderWithProviders(
|
|
<>
|
|
<TooltipPortal />
|
|
<button data-tooltip="Server version" data-tooltip-click="">info</button>
|
|
</>,
|
|
);
|
|
const btn = screen.getByText('info');
|
|
|
|
fireEvent.click(btn);
|
|
expect(screen.getByText('Server version')).toBeInTheDocument();
|
|
});
|
|
|
|
it('does not hide click-mode tooltips on mousedown', () => {
|
|
renderWithProviders(
|
|
<>
|
|
<TooltipPortal />
|
|
<button data-tooltip="Server version" data-tooltip-click="">info</button>
|
|
</>,
|
|
);
|
|
const btn = screen.getByText('info');
|
|
|
|
fireEvent.click(btn);
|
|
expect(screen.getByText('Server version')).toBeInTheDocument();
|
|
|
|
fireEvent.mouseDown(btn);
|
|
expect(screen.getByText('Server version')).toBeInTheDocument();
|
|
});
|
|
|
|
it('toggles off when the click anchor is clicked again', () => {
|
|
renderWithProviders(
|
|
<>
|
|
<TooltipPortal />
|
|
<button data-tooltip="Server version" data-tooltip-click="">info</button>
|
|
</>,
|
|
);
|
|
const btn = screen.getByText('info');
|
|
|
|
fireEvent.click(btn);
|
|
expect(screen.getByText('Server version')).toBeInTheDocument();
|
|
|
|
fireEvent.click(btn);
|
|
expect(screen.queryByText('Server version')).toBeNull();
|
|
});
|
|
|
|
it('keeps click-opened tooltips visible after mouseout', () => {
|
|
renderWithProviders(
|
|
<>
|
|
<TooltipPortal />
|
|
<button data-tooltip="Server version" data-tooltip-click="">info</button>
|
|
</>,
|
|
);
|
|
const btn = screen.getByText('info');
|
|
|
|
fireEvent.click(btn);
|
|
expect(screen.getByText('Server version')).toBeInTheDocument();
|
|
|
|
fireEvent.mouseOut(btn, { relatedTarget: document.body });
|
|
expect(screen.getByText('Server version')).toBeInTheDocument();
|
|
});
|
|
});
|