5180 fichiers 38.5 Mo 0 téléchargements 249 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / hooks / navigator / useNavigatorSearch.test.tsx
useNavigatorSearch.test.tsx 8.9 Ko Télécharger le fichier
import { NavigatorSearchEvent, NavigatorSearchResultSet, RoomSettingsSavedEvent } from '@octane/renderer';
import { act, cleanup, renderHook, waitFor } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { mockEventDispatcher } from '../../octane-renderer.mock';
import { useNavigatorUiStore } from './navigatorUiStore';
import { useNavigatorSearch } from './useNavigatorSearch';

const makeSearchEvent = (code: string, data = '') => {
    const result = new (NavigatorSearchResultSet as any)() as any;
    result.code = code;
    result.data = data;
    result.results = [];

    const ev = new (NavigatorSearchEvent as any)() as any;
    ev.getParser = () => ({ result });
    return ev;
};

const INITIAL_UI = {
    isVisible: false,
    isReady: false,
    isCreatorOpen: false,
    isRoomInfoOpen: false,
    isRoomLinkOpen: false,
    isOpenSavesSearches: false,
    isLoading: false,
    needsInit: true,
    needsSearch: false,
    currentTabCode: '',
    currentFilter: ''
};

describe('useNavigatorSearch', () => {
    beforeEach(() => {
        useNavigatorUiStore.setState(INITIAL_UI);
    });

    afterEach(() => {
        cleanup();
        vi.clearAllMocks();
    });

    it('1. with empty tabCode no fetch starts (the request effect is gated)', () => {
        const { result } = renderHook(() => useNavigatorSearch());

        expect(result.current.isFetching).toBe(false);
        expect(result.current.searchResult).toBeNull();
    });

    it('2. after setTab("public"), the hook starts fetching and a matching event resolves it', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
        });

        await waitFor(() => expect(result.current.isFetching).toBe(true));

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });

        await waitFor(() => expect(result.current.searchResult).not.toBeNull());
        expect((result.current.searchResult as any).code).toBe('public');
        expect(result.current.isFetching).toBe(false);
    });

    it('3. after setFilter("cocco"), a new fetch fires and a matching event resolves it', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
        });
        await waitFor(() => expect(result.current.isFetching).toBe(true));
        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(false));

        act(() => {
            useNavigatorUiStore.getState().setFilter('cocco');
        });

        await waitFor(() => expect(result.current.isFetching).toBe(true));

        // A late reply for the filter before is not shown for this one.
        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public', '') as any);
        });
        expect(result.current.isFetching).toBe(true);

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public', 'cocco') as any);
        });

        await waitFor(() => expect(result.current.isFetching).toBe(false));
        expect((result.current.searchResult as any).code).toBe('public');
        expect((result.current.searchResult as any).data).toBe('cocco');
        expect(useNavigatorUiStore.getState().currentFilter).toBe('cocco');
    });

    it('4. after setTab("events"), currentFilter resets to "" and a new fetch fires for events', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
            useNavigatorUiStore.getState().setFilter('some-filter');
        });

        await waitFor(() => expect(result.current.isFetching).toBe(true));
        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public', 'some-filter') as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(false));

        act(() => {
            useNavigatorUiStore.getState().setTab('events');
        });

        expect(useNavigatorUiStore.getState().currentFilter).toBe('');
        expect(useNavigatorUiStore.getState().currentTabCode).toBe('events');

        await waitFor(() => expect(result.current.isFetching).toBe(true));

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('events') as any);
        });

        await waitFor(() => expect(result.current.isFetching).toBe(false));
        expect((result.current.searchResult as any).code).toBe('events');
    });

    it('5. NavigatorSearchEvent with result.code === currentTabCode is accepted and updates data', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
        });

        await waitFor(() => expect(result.current.isFetching).toBe(true));

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });

        await waitFor(() => {
            expect(result.current.searchResult).not.toBeNull();
            expect((result.current.searchResult as any).code).toBe('public');
        });
    });

    it('6. reopening the navigator (show sets needsSearch) refetches the same tab and consumes the flag', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
        });
        await waitFor(() => expect(result.current.isFetching).toBe(true));
        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(false));

        act(() => {
            useNavigatorUiStore.getState().show();
        });

        await waitFor(() => expect(result.current.isFetching).toBe(true));
        expect(useNavigatorUiStore.getState().needsSearch).toBe(false);

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(false));
    });

    it('7. NavigatorSearchEvent with result.code !== currentTabCode is REJECTED — data unchanged', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
        });

        await waitFor(() => expect(result.current.isFetching).toBe(true));

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('wrong_tab') as any);
        });

        expect(result.current.searchResult).toBeNull();

        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });

        await waitFor(() => expect(result.current.searchResult).not.toBeNull());
        expect((result.current.searchResult as any).code).toBe('public');
    });

    it('8. RoomSettingsSaved reloads the own rooms list, as AIR does, and leaves other tabs alone', async () => {
        const { result } = renderHook(() => useNavigatorSearch());

        act(() => {
            useNavigatorUiStore.getState().setTab('public');
        });
        await waitFor(() => expect(result.current.isFetching).toBe(true));
        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('public') as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(false));

        act(() => {
            mockEventDispatcher.dispatchEvent(new (RoomSettingsSavedEvent as any)() as any);
        });
        expect(result.current.isFetching).toBe(false);

        act(() => {
            useNavigatorUiStore.getState().setTab('myworld_view');
        });
        await waitFor(() => expect(result.current.isFetching).toBe(true));
        act(() => {
            mockEventDispatcher.dispatchEvent(makeSearchEvent('myworld_view') as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(false));

        act(() => {
            mockEventDispatcher.dispatchEvent(new (RoomSettingsSavedEvent as any)() as any);
        });
        await waitFor(() => expect(result.current.isFetching).toBe(true));
    });
});

describe('isReplyForSearch', () => {
    it('matches the tab and the filter, with the filter cut where the server cuts it', async () => {
        const { isReplyForSearch } = await import('./useNavigatorSearch');

        expect(isReplyForSearch('public', 'cocco', 'public', 'cocco')).toBe(true);
        expect(isReplyForSearch('public', 'cocc', 'public', 'cocco')).toBe(false);
        expect(isReplyForSearch('events', 'cocco', 'public', 'cocco')).toBe(false);
        expect(isReplyForSearch('public', 'x'.repeat(64), 'public', 'x'.repeat(80))).toBe(true);
    });
});
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser