From 7eeecd87016f174bc5b284352c3e843fdd357e85 Mon Sep 17 00:00:00 2001 From: Nick Sandstrom <32273437+nick4810@users.noreply.github.com> Date: Sat, 2 May 2026 02:05:31 -0700 Subject: [PATCH] Formatting changes --- .../src/components/forms/GroupManager.jsx | 29 +- .../src/components/forms/LiveGroupFilter.jsx | 55 +-- frontend/src/components/forms/Logo.jsx | 28 +- frontend/src/components/forms/M3UProfile.jsx | 25 +- frontend/src/components/forms/M3UProfiles.jsx | 35 +- .../forms/__tests__/ChannelGroup.test.jsx | 4 +- .../forms/__tests__/GroupManager.test.jsx | 216 +++++++++--- .../forms/__tests__/LiveGroupFilter.test.jsx | 316 +++++++++++++----- .../forms/__tests__/LoginForm.test.jsx | 47 ++- .../components/forms/__tests__/Logo.test.jsx | 165 ++++++--- .../components/forms/__tests__/M3U.test.jsx | 106 ++++-- .../forms/__tests__/M3UFilter.test.jsx | 70 +++- .../forms/__tests__/M3UFilters.test.jsx | 31 +- .../forms/__tests__/M3UGroupFilter.test.jsx | 87 +++-- .../forms/__tests__/M3UProfile.test.jsx | 77 ++++- .../forms/__tests__/M3UProfiles.test.jsx | 23 +- frontend/src/utils/forms/ChannelGroupUtils.js | 2 +- frontend/src/utils/forms/M3uFilterUtils.js | 2 +- .../src/utils/forms/M3uGroupFilterUtils.js | 2 +- frontend/src/utils/forms/M3uProfileUtils.js | 2 +- frontend/src/utils/forms/M3uUtils.js | 5 +- .../forms/__tests__/ChannelGroupUtils.test.js | 6 +- .../__tests__/LiveGroupFilterUtils.test.js | 99 ++++-- .../utils/forms/__tests__/LogoUtils.test.js | 71 +++- .../forms/__tests__/M3uFilterUtils.test.js | 71 +++- .../__tests__/M3uGroupFilterUtils.test.js | 201 +++++++++-- .../forms/__tests__/M3uProfileUtils.test.js | 110 ++++-- .../forms/__tests__/M3uProfilesUtils.test.js | 11 +- .../utils/forms/__tests__/M3uUtils.test.js | 27 +- 29 files changed, 1418 insertions(+), 505 deletions(-) diff --git a/frontend/src/components/forms/GroupManager.jsx b/frontend/src/components/forms/GroupManager.jsx index 29c356e0..22694406 100644 --- a/frontend/src/components/forms/GroupManager.jsx +++ b/frontend/src/components/forms/GroupManager.jsx @@ -16,7 +16,18 @@ import { TextInput, useMantineTheme, } from '@mantine/core'; -import { AlertCircle, Check, Database, Filter, SquareMinus, SquarePen, SquarePlus, Trash, Tv, X, } from 'lucide-react'; +import { + AlertCircle, + Check, + Database, + Filter, + SquareMinus, + SquarePen, + SquarePlus, + Trash, + Tv, + X, +} from 'lucide-react'; import useChannelsStore from '../../store/channels'; import useWarningsStore from '../../store/warnings'; import ConfirmationDialog from '../ConfirmationDialog'; @@ -220,7 +231,14 @@ const GroupManager = React.memo(({ isOpen, onClose }) => { } return { filteredGroups: filtered, filterCounts: counts }; - }, [sortedGroups, groupUsage, searchTerm, showChannelGroups, showM3UGroups, showUnusedGroups]); + }, [ + sortedGroups, + groupUsage, + searchTerm, + showChannelGroups, + showM3UGroups, + showUnusedGroups, + ]); const fetchGroupUsage = useCallback(async () => { setLoading(true); @@ -268,10 +286,9 @@ const GroupManager = React.memo(({ isOpen, onClose }) => { } try { - await updateChannelGroup( - channelGroups[editingGroupId], - { name: editName.trim() } - ); + await updateChannelGroup(channelGroups[editingGroupId], { + name: editName.trim(), + }); showNotification({ title: 'Success', diff --git a/frontend/src/components/forms/LiveGroupFilter.jsx b/frontend/src/components/forms/LiveGroupFilter.jsx index 71ab8287..74f19c38 100644 --- a/frontend/src/components/forms/LiveGroupFilter.jsx +++ b/frontend/src/components/forms/LiveGroupFilter.jsx @@ -51,16 +51,20 @@ const OptionWithTooltip = forwardRef( ) ); -const LogoPopover = ({ group, - channelLogos, - logosLoading, - onPopoverChange, - onLogoInputClick, - onFilterChange, - onLogoSelect, +const LogoPopover = ({ + group, + channelLogos, + logosLoading, + onPopoverChange, + onLogoInputClick, + onFilterChange, + onLogoSelect, }) => { const renderLogoList = () => { - const logoOptions = [{ id: '0', name: 'Default' }, ...Object.values(channelLogos)]; + const logoOptions = [ + { id: '0', name: 'Default' }, + ...Object.values(channelLogos), + ]; const filteredLogos = logoOptions.filter((logo) => logo.name.toLowerCase().includes((group.logoFilter || '').toLowerCase()) ); @@ -69,7 +73,9 @@ const LogoPopover = ({ group, return (
- {group.logoFilter ? 'No logos match your filter' : 'No logos available'} + {group.logoFilter + ? 'No logos match your filter' + : 'No logos available'}
); @@ -92,14 +98,14 @@ const LogoPopover = ({ group, padding: '5px', borderRadius: '4px', }} - onClick={() => onLogoSelect(logoItem.id === '0' ? null : logoItem.id)} + onClick={() => + onLogoSelect(logoItem.id === '0' ? null : logoItem.id) + } onMouseEnter={(e) => { - e.currentTarget.style.backgroundColor = - 'rgb(68, 68, 68)'; + e.currentTarget.style.backgroundColor = 'rgb(68, 68, 68)'; }} onMouseLeave={(e) => { - e.currentTarget.style.backgroundColor = - 'transparent'; + e.currentTarget.style.backgroundColor = 'transparent'; }} >
); -} +}; const LiveGroupFilter = ({ playlist, @@ -836,22 +843,30 @@ const LiveGroupFilter = ({ channelLogos={channelLogos} logosLoading={logosLoading} onPopoverChange={(opened) => { - updateGroupState(group.channel_group, () => ({ logoPopoverOpened: opened })); + updateGroupState(group.channel_group, () => ({ + logoPopoverOpened: opened, + })); if (opened) ensureLogosLoaded(); }} onLogoInputClick={() => { setGroupStates((prev) => prev.map((state) => ({ ...state, - logoPopoverOpened: state.channel_group === group.channel_group, + logoPopoverOpened: + state.channel_group === + group.channel_group, })) ); }} onFilterChange={(val) => { - updateGroupState(group.channel_group, () => ({ logoFilter: val })); + updateGroupState(group.channel_group, () => ({ + logoFilter: val, + })); }} onLogoSelect={(logoId) => { - updateCustomProps(group.channel_group, () => ({ custom_logo_id: logoId })); + updateCustomProps(group.channel_group, () => ({ + custom_logo_id: logoId, + })); }} /> diff --git a/frontend/src/components/forms/Logo.jsx b/frontend/src/components/forms/Logo.jsx index ddd92d8b..52d1b0b3 100644 --- a/frontend/src/components/forms/Logo.jsx +++ b/frontend/src/components/forms/Logo.jsx @@ -1,9 +1,25 @@ -import React, {useEffect, useMemo, useState} from 'react'; -import {useForm} from 'react-hook-form'; -import {Box, Button, Center, Divider, Group, Image, Modal, Stack, Text, TextInput,} from '@mantine/core'; -import {Dropzone, DropzoneAccept, DropzoneIdle, DropzoneReject,} from '@mantine/dropzone'; -import {FileImage, Upload, X} from 'lucide-react'; -import {showNotification} from '../../utils/notificationUtils.js'; +import React, { useEffect, useMemo, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { + Box, + Button, + Center, + Divider, + Group, + Image, + Modal, + Stack, + Text, + TextInput, +} from '@mantine/core'; +import { + Dropzone, + DropzoneAccept, + DropzoneIdle, + DropzoneReject, +} from '@mantine/dropzone'; +import { FileImage, Upload, X } from 'lucide-react'; +import { showNotification } from '../../utils/notificationUtils.js'; import { createLogo, getFilenameWithoutExtension, diff --git a/frontend/src/components/forms/M3UProfile.jsx b/frontend/src/components/forms/M3UProfile.jsx index f31deff7..898eca25 100644 --- a/frontend/src/components/forms/M3UProfile.jsx +++ b/frontend/src/components/forms/M3UProfile.jsx @@ -81,21 +81,36 @@ const RegexFormAndView = ({ profile = null, m3u, isOpen, onClose }) => { if (isXC && xcMode === 'simple' && !isDefaultProfile) { const errs = validateXcSimple(newUsername, newPassword); - if (Object.keys(errs).length > 0) { setSimpleErrors(errs); return; } + if (Object.keys(errs).length > 0) { + setSimpleErrors(errs); + return; + } setSimpleErrors({}); values = applyXcSimplePatterns(values, m3u, newUsername, newPassword); } if (isXC && xcMode === 'advanced' && !isDefaultProfile) { - if (!searchPattern.trim()) { setError('search_pattern', { message: 'Search pattern is required' }); return; } - if (!replacePattern.trim()) { setError('replace_pattern', { message: 'Replace pattern is required' }); return; } + if (!searchPattern.trim()) { + setError('search_pattern', { message: 'Search pattern is required' }); + return; + } + if (!replacePattern.trim()) { + setError('replace_pattern', { message: 'Replace pattern is required' }); + return; + } } - const submitValues = buildSubmitValues(values, profile, isDefaultProfile, isXC, xcMode); + const submitValues = buildSubmitValues( + values, + profile, + isDefaultProfile, + isXC, + xcMode + ); if (expDate !== undefined) submitValues.exp_date = expDate; profile?.id - ? await updateM3UProfile(m3u, {...submitValues, id: profile.id}) + ? await updateM3UProfile(m3u, { ...submitValues, id: profile.id }) : await addM3UProfile(m3u, submitValues); reset(); diff --git a/frontend/src/components/forms/M3UProfiles.jsx b/frontend/src/components/forms/M3UProfiles.jsx index 5827ebe4..c48c0ba2 100644 --- a/frontend/src/components/forms/M3UProfiles.jsx +++ b/frontend/src/components/forms/M3UProfiles.jsx @@ -19,7 +19,10 @@ import { useMantineTheme, } from '@mantine/core'; import { Info, SquareMinus, SquarePen } from 'lucide-react'; -import { deleteM3UProfile, updateM3UProfile, } from '../../utils/forms/M3uProfileUtils.js'; +import { + deleteM3UProfile, + updateM3UProfile, +} from '../../utils/forms/M3uProfileUtils.js'; import { getExpirationInfo, isAccountExpired, @@ -291,22 +294,20 @@ const M3UProfiles = ({ playlist = null, isOpen, onClose }) => { withinPortal={true} yOffset="2vh" > - {profilesArray - .sort(profileSortComparator) - .map((item) => { - return ( - showAccountInfo(item)} - onChangeMaxStreams={(value) => modifyMaxStreams(value, item)} - onChangeActive={() => toggleActive(item)} - onClickEdit={() => editProfile(item)} - onClickDelete={() => deleteProfile(item.id)} - /> - ); - })} + {profilesArray.sort(profileSortComparator).map((item) => { + return ( + showAccountInfo(item)} + onChangeMaxStreams={(value) => modifyMaxStreams(value, item)} + onChangeActive={() => toggleActive(item)} + onClickEdit={() => editProfile(item)} + onClickDelete={() => deleteProfile(item.id)} + /> + ); + })} ), Chip: ({ children, checked, onChange }) => ( ), @@ -104,7 +126,9 @@ vi.mock('@mantine/core', async () => ({ onKeyDown={onKeyDown} /> ), - useMantineTheme: () => ({ tailwind: { yellow: ['#fefcbf'], red: ['#f56565'] } }), + useMantineTheme: () => ({ + tailwind: { yellow: ['#fefcbf'], red: ['#f56565'] }, + }), })); // ── Imports after mocks ──────────────────────────────────────────────────────── @@ -193,7 +217,9 @@ describe('GroupManager', () => { }, }); renderGroupManager(); - const names = screen.getAllByText(/Alpha|Zebra/).map((el) => el.textContent); + const names = screen + .getAllByText(/Alpha|Zebra/) + .map((el) => el.textContent); expect(names.indexOf('Alpha')).toBeLessThan(names.indexOf('Zebra')); }); @@ -278,7 +304,9 @@ describe('GroupManager', () => { }); it('calls updateChannelGroup with trimmed name on save', async () => { - vi.mocked(ChannelGroupUtils.updateChannelGroup).mockResolvedValue(undefined); + vi.mocked(ChannelGroupUtils.updateChannelGroup).mockResolvedValue( + undefined + ); setupMocks({ groups: { 1: makeGroup() } }); renderGroupManager(); @@ -296,7 +324,9 @@ describe('GroupManager', () => { }); it('shows success notification after save', async () => { - vi.mocked(ChannelGroupUtils.updateChannelGroup).mockResolvedValue(undefined); + vi.mocked(ChannelGroupUtils.updateChannelGroup).mockResolvedValue( + undefined + ); setupMocks({ groups: { 1: makeGroup() } }); renderGroupManager(); @@ -328,7 +358,9 @@ describe('GroupManager', () => { }); it('shows error notification when updateChannelGroup throws', async () => { - vi.mocked(ChannelGroupUtils.updateChannelGroup).mockRejectedValue(new Error('fail')); + vi.mocked(ChannelGroupUtils.updateChannelGroup).mockRejectedValue( + new Error('fail') + ); setupMocks({ groups: { 1: makeGroup() } }); renderGroupManager(); @@ -371,7 +403,9 @@ describe('GroupManager', () => { fireEvent.click(screen.getByTestId('icon-check').closest('button')); await waitFor(() => { - expect(ChannelGroupUtils.addChannelGroup).toHaveBeenCalledWith({ name: 'New Group' }); + expect(ChannelGroupUtils.addChannelGroup).toHaveBeenCalledWith({ + name: 'New Group', + }); }); }); @@ -408,7 +442,9 @@ describe('GroupManager', () => { }); it('shows error notification when addChannelGroup throws', async () => { - vi.mocked(ChannelGroupUtils.addChannelGroup).mockRejectedValue(new Error('fail')); + vi.mocked(ChannelGroupUtils.addChannelGroup).mockRejectedValue( + new Error('fail') + ); setupMocks(); renderGroupManager(); @@ -435,7 +471,9 @@ describe('GroupManager', () => { fireEvent.click(screen.getByTestId('icon-check').closest('button')); await waitFor(() => { - expect(screen.queryByPlaceholderText(/Enter group name/i)).not.toBeInTheDocument(); + expect( + screen.queryByPlaceholderText(/Enter group name/i) + ).not.toBeInTheDocument(); }); }); @@ -444,10 +482,14 @@ describe('GroupManager', () => { renderGroupManager(); fireEvent.click(screen.getByTestId('icon-square-plus').closest('button')); - expect(screen.getByPlaceholderText(/Enter group name/i)).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(/Enter group name/i) + ).toBeInTheDocument(); fireEvent.click(screen.getByTestId('icon-x').closest('button')); - expect(screen.queryByPlaceholderText(/Enter group name/i)).not.toBeInTheDocument(); + expect( + screen.queryByPlaceholderText(/Enter group name/i) + ).not.toBeInTheDocument(); }); }); @@ -455,36 +497,62 @@ describe('GroupManager', () => { describe('delete group', () => { it('opens confirmation dialog when delete is clicked', async () => { - setupMocks({ groups: { 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false } } }); + setupMocks({ + groups: { + 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false }, + }, + }); renderGroupManager(); - fireEvent.click(screen.getByTestId('icon-square-minus').closest('button')); + fireEvent.click( + screen.getByTestId('icon-square-minus').closest('button') + ); await waitFor(() => { - expect(screen.getByTestId('confirmation-dialog')).toBeInTheDocument(); - expect(screen.getByTestId('confirm-title')).toHaveTextContent('Confirm Group Deletion'); + expect(screen.getByTestId('confirmation-dialog')).toBeInTheDocument(); + expect(screen.getByTestId('confirm-title')).toHaveTextContent( + 'Confirm Group Deletion' + ); }); }); it('calls deleteChannelGroup when confirmed', async () => { - vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockResolvedValue(undefined); - const groupToDelete = { ...makeGroup(), hasChannels: false, hasM3UAccounts: false }; + vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockResolvedValue( + undefined + ); + const groupToDelete = { + ...makeGroup(), + hasChannels: false, + hasM3UAccounts: false, + }; setupMocks({ groups: { 1: groupToDelete } }); renderGroupManager(); - fireEvent.click(screen.getByTestId('icon-square-minus').closest('button')); + fireEvent.click( + screen.getByTestId('icon-square-minus').closest('button') + ); fireEvent.click(screen.getByTestId('confirm-btn')); await waitFor(() => { - expect(ChannelGroupUtils.deleteChannelGroup).toHaveBeenCalledWith(groupToDelete); + expect(ChannelGroupUtils.deleteChannelGroup).toHaveBeenCalledWith( + groupToDelete + ); }); }); it('shows success notification after delete', async () => { - vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockResolvedValue(undefined); - setupMocks({ groups: { 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false } } }); + vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockResolvedValue( + undefined + ); + setupMocks({ + groups: { + 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false }, + }, + }); renderGroupManager(); - fireEvent.click(screen.getByTestId('icon-square-minus').closest('button')); + fireEvent.click( + screen.getByTestId('icon-square-minus').closest('button') + ); fireEvent.click(screen.getByTestId('confirm-btn')); await waitFor(() => { @@ -495,11 +563,19 @@ describe('GroupManager', () => { }); it('shows error notification when deleteChannelGroup throws', async () => { - vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockRejectedValue(new Error('fail')); - setupMocks({ groups: { 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false } } }); + vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockRejectedValue( + new Error('fail') + ); + setupMocks({ + groups: { + 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false }, + }, + }); renderGroupManager(); - fireEvent.click(screen.getByTestId('icon-square-minus').closest('button')); + fireEvent.click( + screen.getByTestId('icon-square-minus').closest('button') + ); fireEvent.click(screen.getByTestId('confirm-btn')); await waitFor(() => { @@ -510,25 +586,43 @@ describe('GroupManager', () => { }); it('closes confirmation dialog on cancel', () => { - setupMocks({ groups: { 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false } } }); + setupMocks({ + groups: { + 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false }, + }, + }); renderGroupManager(); - fireEvent.click(screen.getByTestId('icon-square-minus').closest('button')); + fireEvent.click( + screen.getByTestId('icon-square-minus').closest('button') + ); fireEvent.click(screen.getByTestId('cancel-btn')); - expect(screen.queryByTestId('confirmation-dialog')).not.toBeInTheDocument(); + expect( + screen.queryByTestId('confirmation-dialog') + ).not.toBeInTheDocument(); }); it('closes confirmation dialog after successful delete', async () => { - vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockResolvedValue(undefined); - setupMocks({ groups: { 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false } } }); + vi.mocked(ChannelGroupUtils.deleteChannelGroup).mockResolvedValue( + undefined + ); + setupMocks({ + groups: { + 1: { ...makeGroup(), hasChannels: false, hasM3UAccounts: false }, + }, + }); renderGroupManager(); - fireEvent.click(screen.getByTestId('icon-square-minus').closest('button')); + fireEvent.click( + screen.getByTestId('icon-square-minus').closest('button') + ); fireEvent.click(screen.getByTestId('confirm-btn')); await waitFor(() => { - expect(screen.queryByTestId('confirmation-dialog')).not.toBeInTheDocument(); + expect( + screen.queryByTestId('confirmation-dialog') + ).not.toBeInTheDocument(); }); }); }); @@ -548,7 +642,9 @@ describe('GroupManager', () => { }); it('calls cleanupUnusedChannelGroups directly when warning is suppressed', async () => { - vi.mocked(ChannelGroupUtils.cleanupUnusedChannelGroups).mockResolvedValue(successResponse); + vi.mocked(ChannelGroupUtils.cleanupUnusedChannelGroups).mockResolvedValue( + successResponse + ); setupMocks({ isWarningSuppressed: true }); renderGroupManager(); @@ -557,11 +653,15 @@ describe('GroupManager', () => { await waitFor(() => { expect(ChannelGroupUtils.cleanupUnusedChannelGroups).toHaveBeenCalled(); }); - expect(screen.queryByTestId('confirmation-dialog')).not.toBeInTheDocument(); + expect( + screen.queryByTestId('confirmation-dialog') + ).not.toBeInTheDocument(); }); it('calls cleanupUnusedChannelGroups when cleanup confirmed', async () => { - vi.mocked(ChannelGroupUtils.cleanupUnusedChannelGroups).mockResolvedValue(successResponse); + vi.mocked(ChannelGroupUtils.cleanupUnusedChannelGroups).mockResolvedValue( + successResponse + ); setupMocks({ isWarningSuppressed: false }); renderGroupManager(); @@ -574,7 +674,9 @@ describe('GroupManager', () => { }); it('shows success notification after cleanup', async () => { - vi.mocked(ChannelGroupUtils.cleanupUnusedChannelGroups).mockResolvedValue(successResponse); + vi.mocked(ChannelGroupUtils.cleanupUnusedChannelGroups).mockResolvedValue( + successResponse + ); setupMocks({ isWarningSuppressed: true }); renderGroupManager(); @@ -610,7 +712,9 @@ describe('GroupManager', () => { fireEvent.click(screen.getByText(/cleanup/i)); fireEvent.click(screen.getByTestId('cancel-btn')); - expect(screen.queryByTestId('confirmation-dialog')).not.toBeInTheDocument(); + expect( + screen.queryByTestId('confirmation-dialog') + ).not.toBeInTheDocument(); }); }); @@ -618,8 +722,18 @@ describe('GroupManager', () => { describe('filter chips', () => { const twoGroups = { - 1: makeGroup({ id: 1, name: 'Channel Group', hasChannels: true, hasM3UAccounts: false }), - 2: makeGroup({ id: 2, name: 'M3U Group', hasChannels: false, hasM3UAccounts: true }), + 1: makeGroup({ + id: 1, + name: 'Channel Group', + hasChannels: true, + hasM3UAccounts: false, + }), + 2: makeGroup({ + id: 2, + name: 'M3U Group', + hasChannels: false, + hasM3UAccounts: true, + }), }; it('hides channel groups when Channels chip is unchecked', () => { @@ -647,8 +761,18 @@ describe('GroupManager', () => { it('hides unused groups when Unused chip is unchecked', () => { setupMocks({ groups: { - 1: makeGroup({ id: 1, name: 'Unused Group', hasChannels: false, hasM3UAccounts: false }), - 2: makeGroup({ id: 2, name: 'Used Group', hasChannels: true, hasM3UAccounts: false }), + 1: makeGroup({ + id: 1, + name: 'Unused Group', + hasChannels: false, + hasM3UAccounts: false, + }), + 2: makeGroup({ + id: 2, + name: 'Used Group', + hasChannels: true, + hasM3UAccounts: false, + }), }, }); renderGroupManager(); @@ -684,4 +808,4 @@ describe('GroupManager', () => { expect(screen.queryByTestId('modal')).not.toBeInTheDocument(); }); }); -}); \ No newline at end of file +}); diff --git a/frontend/src/components/forms/__tests__/LiveGroupFilter.test.jsx b/frontend/src/components/forms/__tests__/LiveGroupFilter.test.jsx index 2c9abf47..050310ff 100644 --- a/frontend/src/components/forms/__tests__/LiveGroupFilter.test.jsx +++ b/frontend/src/components/forms/__tests__/LiveGroupFilter.test.jsx @@ -17,7 +17,8 @@ vi.mock('../../../utils/forms/LiveGroupFilterUtils', () => ({ { value: 'stream_profile', label: 'Stream Profile', - description: 'Assign a specific stream profile to all channels in this group during auto sync', + description: + 'Assign a specific stream profile to all channels in this group during auto sync', isActive: (p) => p.stream_profile_id !== undefined, defaults: { stream_profile_id: null }, removeKeys: ['stream_profile_id'], @@ -49,7 +50,9 @@ vi.mock('../Logo', () => ({ })); vi.mock('../../LazyLogo', () => ({ - default: ({ logoId, alt }) => {alt}, + default: ({ logoId, alt }) => ( + {alt} + ), })); vi.mock('react-window', () => ({ @@ -66,7 +69,15 @@ vi.mock('../../../images/logo.png', () => ({ default: 'logo.png' })); // ── Mantine core ─────────────────────────────────────────────────────────────── vi.mock('@mantine/core', async () => ({ - TextInput: ({ label, placeholder, value, onChange, onClick, readOnly, size }) => ( + TextInput: ({ + label, + placeholder, + value, + onChange, + onClick, + readOnly, + size, + }) => ( ({ /> ), Button: ({ children, onClick, disabled, variant, size, leftSection }) => ( - @@ -94,7 +110,9 @@ vi.mock('@mantine/core', async () => ({ data-size={size} /> {label} - {description && {description}} + {description && ( + {description} + )} ), Flex: ({ children, gap }) =>
{children}
, @@ -114,9 +132,15 @@ vi.mock('@mantine/core', async () => ({ ), Stack: ({ children, gap }) =>
{children}
, - Group: ({ children, justify }) =>
{children}
, + Group: ({ children, justify }) => ( +
{children}
+ ), SimpleGrid: ({ children }) =>
{children}
, - Text: ({ children, size, c }) => {children}, + Text: ({ children, size, c }) => ( + + {children} + + ), NumberInput: ({ label, value, onChange, min, step, size }) => ( ({ multiple value={value || []} onChange={(e) => { - const selected = Array.from(e.target.selectedOptions).map((o) => o.value); + const selected = Array.from(e.target.selectedOptions).map( + (o) => o.value + ); onChange(selected); }} data-size={size} @@ -155,10 +181,14 @@ vi.mock('@mantine/core', async () => ({ ), Tooltip: ({ children, label, disabled }) => ( -
{children}
+
+ {children} +
), Popover: ({ children, opened }) => ( -
{children}
+
+ {children} +
), ScrollArea: ({ children, style }) =>
{children}
, Center: ({ children }) =>
{children}
, @@ -177,7 +207,9 @@ vi.mock('@mantine/core', async () => ({ ), PopoverTarget: ({ children }) =>
{children}
, PopoverDropdown: ({ children, onMouseDown }) => ( -
{children}
+
+ {children} +
), })); @@ -195,12 +227,8 @@ import useChannelsStore from '../../../store/channels'; import useStreamProfilesStore from '../../../store/streamProfiles'; import { useChannelLogoSelection } from '../../../hooks/useSmartLogos'; import { - ADVANCED_OPTIONS_CONFIG, - applyAdvancedOptionsChange, getEPGs, getEpgSourceData, - getEpgSourceValue, - getSelectedAdvancedOptions, } from '../../../utils/forms/LiveGroupFilterUtils.js'; // ── Fixtures ─────────────────────────────────────────────────────────────────── @@ -238,11 +266,11 @@ const defaultStreamProfiles = [ ]; const setupStoreMocks = ({ - channelGroups = defaultChannelGroups, - profiles = defaultProfiles, - streamProfiles = defaultStreamProfiles, - fetchStreamProfiles = vi.fn(), - } = {}) => { + channelGroups = defaultChannelGroups, + profiles = defaultProfiles, + streamProfiles = defaultStreamProfiles, + fetchStreamProfiles = vi.fn(), +} = {}) => { vi.mocked(useChannelsStore).mockImplementation((sel) => sel({ channelGroups, profiles }) ); @@ -252,10 +280,10 @@ const setupStoreMocks = ({ }; const setupLogoMock = ({ - logos = { 5: { id: 5, name: 'My Logo', url: '/logos/5.png' } }, - ensureLogosLoaded = vi.fn(), - isLoading = false, - } = {}) => { + logos = { 5: { id: 5, name: 'My Logo', url: '/logos/5.png' } }, + ensureLogosLoaded = vi.fn(), + isLoading = false, +} = {}) => { vi.mocked(useChannelLogoSelection).mockReturnValue({ logos, ensureLogosLoaded, @@ -265,12 +293,12 @@ const setupLogoMock = ({ }; const defaultProps = ({ - groupStates = [], - setGroupStates = vi.fn(), - autoEnableNewGroupsLive = true, - setAutoEnableNewGroupsLive = vi.fn(), - playlist = makePlaylist([]), - } = {}) => ({ + groupStates = [], + setGroupStates = vi.fn(), + autoEnableNewGroupsLive = true, + setAutoEnableNewGroupsLive = vi.fn(), + playlist = makePlaylist([]), +} = {}) => ({ playlist, groupStates, setGroupStates, @@ -300,7 +328,9 @@ describe('LiveGroupFilter', () => { }); it('renders auto-enable checkbox with correct checked state', async () => { - render(); + render( + + ); const checkbox = screen.getByRole('checkbox', { name: /Automatically enable new groups/i, }); @@ -310,7 +340,11 @@ describe('LiveGroupFilter', () => { }); it('renders auto-enable checkbox unchecked when false', () => { - render(); + render( + + ); const checkbox = screen.getByRole('checkbox', { name: /Automatically enable new groups/i, }); @@ -320,7 +354,9 @@ describe('LiveGroupFilter', () => { it('renders filter input', async () => { render(); await waitFor(() => { - expect(screen.getByPlaceholderText('Filter groups...')).toBeInTheDocument(); + expect( + screen.getByPlaceholderText('Filter groups...') + ).toBeInTheDocument(); }); }); @@ -401,7 +437,9 @@ describe('LiveGroupFilter', () => { it('handles getEPGs failure gracefully', async () => { vi.mocked(getEPGs).mockRejectedValue(new Error('Network error')); - expect(() => render()).not.toThrow(); + expect(() => + render() + ).not.toThrow(); }); }); @@ -411,22 +449,25 @@ describe('LiveGroupFilter', () => { it('calls setGroupStates when channelGroups and playlist are set', () => { const setGroupStates = vi.fn(); const playlist = makePlaylist([ - { channel_group: 1, enabled: true, auto_channel_sync: false, auto_sync_channel_start: 1 }, + { + channel_group: 1, + enabled: true, + auto_channel_sync: false, + auto_sync_channel_start: 1, + }, ]); render( - + ); expect(setGroupStates).toHaveBeenCalled(); }); it('skips groups that are not in channelGroups', () => { const setGroupStates = vi.fn(); - const playlist = makePlaylist([ - { channel_group: 999, enabled: true }, - ]); - render(); + const playlist = makePlaylist([{ channel_group: 999, enabled: true }]); + render( + + ); expect(setGroupStates).toHaveBeenCalledWith([]); }); @@ -441,8 +482,11 @@ describe('LiveGroupFilter', () => { custom_properties: JSON.stringify({ foo: 'bar' }), }, ]); - render(); - const [mappedGroups] = setGroupStates.mock.calls[setGroupStates.mock.calls.length - 1]; + render( + + ); + const [mappedGroups] = + setGroupStates.mock.calls[setGroupStates.mock.calls.length - 1]; expect(mappedGroups[0].custom_properties).toEqual({ foo: 'bar' }); }); @@ -452,7 +496,9 @@ describe('LiveGroupFilter', () => { { channel_group: 1, enabled: true, custom_properties: '{invalid}' }, ]); expect(() => - render() + render( + + ) ).not.toThrow(); }); @@ -471,11 +517,16 @@ describe('LiveGroupFilter', () => { const setAutoEnableNewGroupsLive = vi.fn(); render( ); fireEvent.click( - screen.getByRole('checkbox', { name: /Automatically enable new groups/i }) + screen.getByRole('checkbox', { + name: /Automatically enable new groups/i, + }) ); expect(setAutoEnableNewGroupsLive).toHaveBeenCalled(); }); @@ -490,15 +541,19 @@ describe('LiveGroupFilter', () => { const setGroupStates = vi.fn((arg) => { if (typeof arg === 'function') lastUpdater = arg; }); - render(); + render( + + ); fireEvent.click(screen.getByText('Sports')); await waitFor(() => { expect(setGroupStates).toHaveBeenCalled(); const result = lastUpdater(groupStates); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ channel_group: 1, enabled: false }), - ])); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ channel_group: 1, enabled: false }), + ]) + ); }); }); @@ -511,7 +566,9 @@ describe('LiveGroupFilter', () => { const setGroupStates = vi.fn((arg) => { if (typeof arg === 'function') lastUpdater = arg; }); - render(); + render( + + ); const buttons = screen.getAllByRole('button', { name: /Sports/ }); fireEvent.click(buttons[0]); // click Sports await waitFor(() => { @@ -603,7 +660,9 @@ describe('LiveGroupFilter', () => { makeGroupState({ channel_group: 1, name: 'Sports', enabled: false }), makeGroupState({ channel_group: 2, name: 'News', enabled: false }), ]; - render(); + render( + + ); fireEvent.click(screen.getByText('Select Visible')); await waitFor(() => { expect(setGroupStates).toHaveBeenCalled(); @@ -622,7 +681,9 @@ describe('LiveGroupFilter', () => { makeGroupState({ channel_group: 1, name: 'Sports', enabled: true }), makeGroupState({ channel_group: 2, name: 'News', enabled: true }), ]; - render(); + render( + + ); fireEvent.click(screen.getByText('Deselect Visible')); await waitFor(() => { expect(setGroupStates).toHaveBeenCalled(); @@ -641,7 +702,9 @@ describe('LiveGroupFilter', () => { makeGroupState({ channel_group: 1, name: 'Sports', enabled: false }), makeGroupState({ channel_group: 2, name: 'News', enabled: false }), ]; - render(); + render( + + ); fireEvent.change(screen.getByPlaceholderText('Filter groups...'), { target: { value: 'Sports' }, }); @@ -661,13 +724,17 @@ describe('LiveGroupFilter', () => { it('renders Auto Channel Sync checkbox when group is enabled', () => { const groupStates = [makeGroupState({ enabled: true })]; render(); - expect(screen.getByRole('checkbox', { name: /Auto Channel Sync/i })).toBeInTheDocument(); + expect( + screen.getByRole('checkbox', { name: /Auto Channel Sync/i }) + ).toBeInTheDocument(); }); it('Auto Channel Sync checkbox is disabled when group is disabled', () => { const groupStates = [makeGroupState({ enabled: false })]; render(); - expect(screen.getByRole('checkbox', { name: /Auto Channel Sync/i })).toBeDisabled(); + expect( + screen.getByRole('checkbox', { name: /Auto Channel Sync/i }) + ).toBeDisabled(); }); it('toggleAutoSync calls setGroupStates toggling auto_channel_sync', async () => { @@ -675,9 +742,15 @@ describe('LiveGroupFilter', () => { const setGroupStates = vi.fn((arg) => { if (typeof arg === 'function') lastUpdater = arg; }); - const groupStates = [makeGroupState({ enabled: true, auto_channel_sync: false })]; - render(); - fireEvent.click(screen.getByRole('checkbox', { name: /Auto Channel Sync/i })); + const groupStates = [ + makeGroupState({ enabled: true, auto_channel_sync: false }), + ]; + render( + + ); + fireEvent.click( + screen.getByRole('checkbox', { name: /Auto Channel Sync/i }) + ); await waitFor(() => { expect(setGroupStates).toHaveBeenCalled(); const result = lastUpdater(groupStates); @@ -686,15 +759,23 @@ describe('LiveGroupFilter', () => { }); it('shows Start Channel # input when auto_channel_sync is enabled', () => { - const groupStates = [makeGroupState({ enabled: true, auto_channel_sync: true })]; + const groupStates = [ + makeGroupState({ enabled: true, auto_channel_sync: true }), + ]; render(); - expect(screen.getByRole('spinbutton', { name: /Start Channel #/i })).toBeInTheDocument(); + expect( + screen.getByRole('spinbutton', { name: /Start Channel #/i }) + ).toBeInTheDocument(); }); it('hides Start Channel # when auto_channel_sync is false', () => { - const groupStates = [makeGroupState({ enabled: true, auto_channel_sync: false })]; + const groupStates = [ + makeGroupState({ enabled: true, auto_channel_sync: false }), + ]; render(); - expect(screen.queryByRole('spinbutton', { name: /Start Channel #/i })).not.toBeInTheDocument(); + expect( + screen.queryByRole('spinbutton', { name: /Start Channel #/i }) + ).not.toBeInTheDocument(); }); it('updateChannelStart calls setGroupStates with new value', async () => { @@ -702,11 +783,18 @@ describe('LiveGroupFilter', () => { const setGroupStates = vi.fn((arg) => { if (typeof arg === 'function') lastUpdater = arg; }); - const groupStates = [makeGroupState({ enabled: true, auto_channel_sync: true })]; - render(); - fireEvent.change(screen.getByRole('spinbutton', { name: /Start Channel #/i }), { - target: { value: '100' }, - }); + const groupStates = [ + makeGroupState({ enabled: true, auto_channel_sync: true }), + ]; + render( + + ); + fireEvent.change( + screen.getByRole('spinbutton', { name: /Start Channel #/i }), + { + target: { value: '100' }, + } + ); await waitFor(() => { expect(setGroupStates).toHaveBeenCalled(); const result = lastUpdater(groupStates); @@ -719,9 +807,13 @@ describe('LiveGroupFilter', () => { describe('Channel Numbering Mode', () => { it('shows Channel Numbering Mode select when auto_channel_sync enabled', () => { - const groupStates = [makeGroupState({ enabled: true, auto_channel_sync: true })]; + const groupStates = [ + makeGroupState({ enabled: true, auto_channel_sync: true }), + ]; render(); - expect(screen.getByRole('combobox', { name: /Channel Numbering Mode/i })).toBeInTheDocument(); + expect( + screen.getByRole('combobox', { name: /Channel Numbering Mode/i }) + ).toBeInTheDocument(); }); it('shows Fallback Channel # when numbering mode is provider', () => { @@ -747,16 +839,25 @@ describe('LiveGroupFilter', () => { }), ]; render(); - expect(screen.queryByRole('spinbutton', { name: /Start Channel #/i })).not.toBeInTheDocument(); + expect( + screen.queryByRole('spinbutton', { name: /Start Channel #/i }) + ).not.toBeInTheDocument(); }); it('updating Channel Numbering Mode calls setGroupStates', () => { const setGroupStates = vi.fn(); - const groupStates = [makeGroupState({ enabled: true, auto_channel_sync: true })]; - render(); - fireEvent.change(screen.getByRole('combobox', { name: /Channel Numbering Mode/i }), { - target: { value: 'provider' }, - }); + const groupStates = [ + makeGroupState({ enabled: true, auto_channel_sync: true }), + ]; + render( + + ); + fireEvent.change( + screen.getByRole('combobox', { name: /Channel Numbering Mode/i }), + { + target: { value: 'provider' }, + } + ); expect(setGroupStates).toHaveBeenCalled(); }); }); @@ -777,23 +878,35 @@ describe('LiveGroupFilter', () => { {...defaultProps({ groupStates: [makeAutoSyncGroup()] })} /> ); - expect(screen.getByRole('listbox', { name: /Advanced Options/i })).toBeInTheDocument(); + expect( + screen.getByRole('listbox', { name: /Advanced Options/i }) + ).toBeInTheDocument(); }); it('shows Channel Name Find input when name_regex_pattern is set', () => { const groupStates = [ - makeAutoSyncGroup({ name_regex_pattern: '.*', name_replace_pattern: '$1' }), + makeAutoSyncGroup({ + name_regex_pattern: '.*', + name_replace_pattern: '$1', + }), ]; render(); - expect(screen.getByRole('textbox', { name: /Channel Name Find/i })).toBeInTheDocument(); + expect( + screen.getByRole('textbox', { name: /Channel Name Find/i }) + ).toBeInTheDocument(); }); it('shows Channel Name Replace input when name_replace_pattern is set', () => { const groupStates = [ - makeAutoSyncGroup({ name_regex_pattern: '.*', name_replace_pattern: '$1' }), + makeAutoSyncGroup({ + name_regex_pattern: '.*', + name_replace_pattern: '$1', + }), ]; render(); - expect(screen.getByRole('textbox', { name: /Channel Name Replace/i })).toBeInTheDocument(); + expect( + screen.getByRole('textbox', { name: /Channel Name Replace/i }) + ).toBeInTheDocument(); }); it('shows Channel Name Filter input when name_match_regex is set', () => { @@ -807,7 +920,9 @@ describe('LiveGroupFilter', () => { it('shows Channel Profiles multiselect when channel_profile_ids is set', () => { const groupStates = [makeAutoSyncGroup({ channel_profile_ids: [] })]; render(); - expect(screen.getByRole('listbox', { name: /Channel Profiles/i })).toBeInTheDocument(); + expect( + screen.getByRole('listbox', { name: /Channel Profiles/i }) + ).toBeInTheDocument(); }); it('shows Override Channel Group select when group_override is set', () => { @@ -821,7 +936,9 @@ describe('LiveGroupFilter', () => { it('shows Stream Profile select when stream_profile_id is set', () => { const groupStates = [makeAutoSyncGroup({ stream_profile_id: null })]; render(); - expect(screen.getByRole('combobox', { name: /Stream Profile/i })).toBeInTheDocument(); + expect( + screen.getByRole('combobox', { name: /Stream Profile/i }) + ).toBeInTheDocument(); }); it('shows Channel Sort Order select when channel_sort_order is set', () => { @@ -834,22 +951,31 @@ describe('LiveGroupFilter', () => { it('shows Reverse Sort Order checkbox when channel_sort_order is set', () => { const groupStates = [ - makeAutoSyncGroup({ channel_sort_order: '', channel_sort_reverse: false }), + makeAutoSyncGroup({ + channel_sort_order: '', + channel_sort_reverse: false, + }), ]; render(); - expect(screen.getByRole('checkbox', { name: /Reverse Sort Order/i })).toBeInTheDocument(); + expect( + screen.getByRole('checkbox', { name: /Reverse Sort Order/i }) + ).toBeInTheDocument(); }); it('shows EPG Source select when force_dummy_epg is set', () => { const groupStates = [makeAutoSyncGroup({ force_dummy_epg: true })]; render(); - expect(screen.getByRole('combobox', { name: /EPG Source/i })).toBeInTheDocument(); + expect( + screen.getByRole('combobox', { name: /EPG Source/i }) + ).toBeInTheDocument(); }); it('shows EPG Source select when custom_epg_id is set', () => { const groupStates = [makeAutoSyncGroup({ custom_epg_id: 42 })]; render(); - expect(screen.getByRole('combobox', { name: /EPG Source/i })).toBeInTheDocument(); + expect( + screen.getByRole('combobox', { name: /EPG Source/i }) + ).toBeInTheDocument(); }); }); @@ -890,7 +1016,9 @@ describe('LiveGroupFilter', () => { if (typeof arg === 'function') lastUpdater = arg; }); const groupStates = [makeLogoGroup()]; - render(); + render( + + ); fireEvent.click(screen.getByText('Upload or Create Logo')); fireEvent.click(screen.getByTestId('logo-form-success')); expect(setGroupStates).toHaveBeenCalled(); @@ -927,8 +1055,12 @@ describe('LiveGroupFilter', () => { ]; render(); await waitFor(() => { - expect(screen.getByRole('option', { name: /EPG One/i })).toBeInTheDocument(); - expect(screen.getByRole('option', { name: /EPG Two/i })).toBeInTheDocument(); + expect( + screen.getByRole('option', { name: /EPG One/i }) + ).toBeInTheDocument(); + expect( + screen.getByRole('option', { name: /EPG Two/i }) + ).toBeInTheDocument(); }); }); }); @@ -947,4 +1079,4 @@ describe('LiveGroupFilter', () => { expect(buttons[1]).toHaveTextContent('Zebra'); }); }); -}); \ No newline at end of file +}); diff --git a/frontend/src/components/forms/__tests__/LoginForm.test.jsx b/frontend/src/components/forms/__tests__/LoginForm.test.jsx index 585c3f72..7e30f3cd 100644 --- a/frontend/src/components/forms/__tests__/LoginForm.test.jsx +++ b/frontend/src/components/forms/__tests__/LoginForm.test.jsx @@ -44,7 +44,15 @@ vi.mock('../../../assets/logo.png', () => ({ default: 'logo.png' })); vi.mock('@mantine/core', async () => ({ Paper: ({ children }) =>
{children}
, Title: ({ children }) =>

{children}

, - TextInput: ({ label, name, value, onChange, placeholder, type, disabled }) => ( + TextInput: ({ + label, + name, + value, + onChange, + placeholder, + type, + disabled, + }) => ( { + isAuthenticated = false, + loginResult = Promise.resolve(true), + version = '1.0.0', +} = {}) => { const mockLogin = vi.fn().mockReturnValue(loginResult); const mockLogout = vi.fn(); const mockInitData = vi.fn().mockResolvedValue(undefined); @@ -200,7 +208,7 @@ describe('LoginForm', () => { it('renders version info when version is available', () => { setupMocks({ version: '2.3.4' }); renderLoginForm(); - expect(screen.getByText(/2.3.4/i)).toBeInTheDocument(); + expect(screen.getByText(/2.3.4/i)).toBeInTheDocument(); }); it('renders forgot password anchor', () => { @@ -256,12 +264,17 @@ describe('LoginForm', () => { fireEvent.click(getLoginButton()); await waitFor(() => { - expect(mockLogin).toHaveBeenCalledWith({ username: 'admin', password: 'pass123' }); + expect(mockLogin).toHaveBeenCalledWith({ + username: 'admin', + password: 'pass123', + }); }); }); it('calls initData after successful login', async () => { - const { mockInitData } = setupMocks({ loginResult: Promise.resolve(true) }); + const { mockInitData } = setupMocks({ + loginResult: Promise.resolve(true), + }); renderLoginForm(); fireEvent.change(getUsername(), { target: { value: 'admin' } }); @@ -320,7 +333,9 @@ describe('LoginForm', () => { describe('loading state', () => { it('disables the login button while loading', async () => { let resolveLogin; - const loginResult = new Promise((res) => { resolveLogin = res; }); + const loginResult = new Promise((res) => { + resolveLogin = res; + }); setupMocks({ loginResult }); renderLoginForm(); @@ -357,7 +372,9 @@ describe('LoginForm', () => { fireEvent.click(getLoginButton()); await waitFor(() => { - expect(localStorage.getItem('dispatcharr_remembered_username')).toBe('savedUser'); + expect(localStorage.getItem('dispatcharr_remembered_username')).toBe( + 'savedUser' + ); }); }); @@ -370,7 +387,9 @@ describe('LoginForm', () => { fireEvent.click(getLoginButton()); await waitFor(() => { - expect(localStorage.getItem('dispatcharr_remembered_username')).toBeNull(); + expect( + localStorage.getItem('dispatcharr_remembered_username') + ).toBeNull(); }); }); @@ -397,7 +416,9 @@ describe('LoginForm', () => { }); await waitFor(() => { - expect(localStorage.getItem('dispatcharr_saved_password')).not.toBeNull(); + expect( + localStorage.getItem('dispatcharr_saved_password') + ).not.toBeNull(); }); }); @@ -451,4 +472,4 @@ describe('LoginForm', () => { expect(screen.queryByTestId('modal')).not.toBeInTheDocument(); }); }); -}); \ No newline at end of file +}); diff --git a/frontend/src/components/forms/__tests__/Logo.test.jsx b/frontend/src/components/forms/__tests__/Logo.test.jsx index dd3a33ca..9b3b0107 100644 --- a/frontend/src/components/forms/__tests__/Logo.test.jsx +++ b/frontend/src/components/forms/__tests__/Logo.test.jsx @@ -26,8 +26,12 @@ vi.mock('@mantine/dropzone', () => ({ {children} )), - DropzoneAccept: ({ children }) =>
{children}
, - DropzoneReject: ({ children }) =>
{children}
, + DropzoneAccept: ({ children }) => ( +
{children}
+ ), + DropzoneReject: ({ children }) => ( +
{children}
+ ), DropzoneIdle: ({ children }) =>
{children}
, })); @@ -35,7 +39,13 @@ vi.mock('@mantine/dropzone', () => ({ vi.mock('@mantine/core', () => ({ Box: ({ children }) =>
{children}
, Button: ({ children, onClick, type, loading, variant }) => ( - ), @@ -49,17 +59,30 @@ vi.mock('@mantine/core', () => ({ opened ? (
{title}
- + {children}
) : null, Stack: ({ children }) =>
{children}
, Text: ({ children, size, color }) => ( - {children} + + {children} + ), - TextInput: ({ label, placeholder, onChange, onBlur, error, disabled, ...rest }) => ( + TextInput: ({ + label, + placeholder, + onChange, + onBlur, + error, + disabled, + ...rest + }) => (
-