import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { render, waitFor, fireEvent, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; // eslint-disable-next-line @nx/enforce-module-boundaries import { server } from '@availity/mock/src/lib/server'; import avMessages from '@availity/message-core'; import { FavoritesProvider } from './Favorites'; import { FavoriteHeart } from './FavoriteHeart'; vi.mock('@availity/message-core'); const domain = () => { if (window.location.origin) { return window.location.origin; } if (window.location.hostname) { return `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : '' }`; } return '*'; }; avMessages.subscribe = vi.fn((event, fn) => { window.addEventListener('message', (event) => { if (!event || !event.data) { // check origin as trusted domain return; } let { data } = event; if (typeof data === 'string') { try { data = JSON.parse(data); } catch { // do nothing } } event = data && data.event; fn(data); }); return () => vi.fn(); }); avMessages.send = vi.fn((payload, target) => { try { const message = typeof payload === 'string' ? payload : JSON.stringify(payload); target?.postMessage(message, domain()); } catch (error) { // eslint-disable-next-line no-console console.warn('AvMessage.send()', error); } }); const queryClient = new QueryClient(); describe('Favorites', () => { beforeAll(() => { // Start the interception. server.listen(); }); afterEach(() => { // Remove any handlers you may have added // in individual tests (runtime handlers). server.resetHandlers(); vi.clearAllMocks(); queryClient.clear(); }); // terminate the server afterAll(() => server.close()); it('should render favorited', async () => { const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-123'); await waitFor(() => expect(heart).toBeChecked()); }); it('should render unfavorited', async () => { const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-789'); await waitFor(() => expect(heart).not.toBeChecked()); }); it('should render disabled', async () => { const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-789'); await waitFor(() => expect(heart).toBeDisabled()); }); it('should show tooltip with add message', async () => { const { container, getByRole } = render( ); const heart = container.querySelector('#av-favorite-heart-789'); act(() => { if (heart) fireEvent.mouseOver(heart); }); expect(heart).toBeDefined(); await waitFor( () => { const tooltip = getByRole('tooltip'); expect(tooltip.textContent).toContain('Add to My Favorites'); }, { timeout: 2000 } ); }); it('should show tooltip with remove message', async () => { const { container, getByRole } = render( ); const heart = container.querySelector('#av-favorite-heart-123'); act(() => { if (heart) fireEvent.mouseOver(heart); }); expect(heart).toBeDefined(); await waitFor( () => { const tooltip = getByRole('tooltip'); expect(tooltip.textContent).toContain('Remove from My Favorites'); }, { timeout: 2000 } ); }); it('should render label with app name', async () => { const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-123'); expect(heart).toBeDefined(); expect(heart).toHaveAttribute('aria-label', 'Favorite App #1'); }); it('should add favorite and send post message with updated favorites', async () => { const user = userEvent.setup(); const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-789'); await waitFor(() => expect(heart).not.toBeChecked()); if (heart) await user.click(heart); await waitFor(() => expect(heart).toBeChecked()); await waitFor(() => { expect(avMessages.send).toHaveBeenCalledTimes(1); expect(avMessages.send).toHaveBeenCalledWith({ event: 'av:favorites:update', favorites: [ { id: '123', pos: 0 }, { id: '456', pos: 1 }, { id: '789', pos: 2 }, ], }); }); }); it('should toggle favorite and send post message with updated favorites on keypress', async () => { const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-123'); await waitFor(() => { expect(heart).toBeChecked(); }); if (heart) await fireEvent.keyDown(heart, { key: 'Enter', code: 'Enter', charCode: 13 }); await waitFor(() => expect(heart).not.toBeChecked()); await waitFor(() => { expect(avMessages.send).toHaveBeenCalledTimes(1); expect(avMessages.send).toHaveBeenCalledWith({ event: 'av:favorites:update', favorites: [{ id: '456', pos: 1 }], }); }); }); it('should remove favorite and send post message with updated favorites', async () => { const user = userEvent.setup(); const { container } = render( ); const heart = container.querySelector('#av-favorite-heart-123'); await waitFor(() => expect(heart).toBeChecked()); if (heart) await user.click(heart); await waitFor(() => expect(heart).not.toBeChecked()); await waitFor(() => { expect(avMessages.send).toHaveBeenCalledTimes(1); expect(avMessages.send).toHaveBeenCalledWith({ event: 'av:favorites:update', favorites: [{ id: '456', pos: 1 }], }); }); }); });