2024-03-11 17:02:15 +02:00
|
|
|
import * as React from 'react';
|
2024-03-29 14:40:54 +02:00
|
|
|
import RepositoryApi, { InstallMode } from '@joplin/lib/services/plugins/RepositoryApi';
|
2024-04-03 19:51:09 +02:00
|
|
|
import { afterAllCleanUp, afterEachCleanUp, mockMobilePlatform, setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils';
|
2024-03-11 17:02:15 +02:00
|
|
|
|
|
|
|
import { render, screen, userEvent, waitFor } from '@testing-library/react-native';
|
|
|
|
import '@testing-library/react-native/extend-expect';
|
|
|
|
|
|
|
|
import SearchPlugins from './SearchPlugins';
|
|
|
|
import Setting from '@joplin/lib/models/Setting';
|
|
|
|
import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
|
|
|
import { useMemo } from 'react';
|
|
|
|
import pluginServiceSetup from './testUtils/pluginServiceSetup';
|
|
|
|
import newRepoApi from './testUtils/newRepoApi';
|
|
|
|
|
|
|
|
interface WrapperProps {
|
|
|
|
repoApi: RepositoryApi;
|
|
|
|
repoApiInitialized?: boolean;
|
|
|
|
pluginSettings?: PluginSettings;
|
|
|
|
onUpdatePluginStates?: (states: PluginSettings)=> void;
|
|
|
|
}
|
|
|
|
|
|
|
|
const noOpFunction = ()=>{};
|
|
|
|
|
|
|
|
const SearchWrapper = (props: WrapperProps) => {
|
|
|
|
const serializedPluginSettings = useMemo(() => {
|
|
|
|
return PluginService.instance().serializePluginSettings(props.pluginSettings ?? {});
|
|
|
|
}, [props.pluginSettings]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<SearchPlugins
|
|
|
|
themeId={Setting.THEME_LIGHT}
|
|
|
|
pluginSettings={serializedPluginSettings}
|
|
|
|
repoApiInitialized={props.repoApiInitialized ?? true}
|
|
|
|
repoApi={props.repoApi}
|
|
|
|
onUpdatePluginStates={props.onUpdatePluginStates ?? noOpFunction}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2024-03-29 14:40:54 +02:00
|
|
|
const expectSearchResultCountToBe = async (count: number) => {
|
|
|
|
await waitFor(() => {
|
|
|
|
expect(screen.queryAllByTestId('plugin-card')).toHaveLength(count);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-03-11 17:02:15 +02:00
|
|
|
describe('SearchPlugins', () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
await setupDatabaseAndSynchronizer(0);
|
|
|
|
await switchClient(0);
|
|
|
|
pluginServiceSetup();
|
|
|
|
});
|
2024-03-29 14:40:54 +02:00
|
|
|
afterEach(() => afterEachCleanUp());
|
|
|
|
afterAll(() => afterAllCleanUp());
|
2024-03-11 17:02:15 +02:00
|
|
|
|
|
|
|
it('should find results', async () => {
|
2024-03-29 14:40:54 +02:00
|
|
|
const repoApi = await newRepoApi(InstallMode.Default);
|
2024-03-11 17:02:15 +02:00
|
|
|
render(<SearchWrapper repoApi={repoApi}/>);
|
|
|
|
|
|
|
|
const searchBox = screen.queryByPlaceholderText('Search');
|
|
|
|
expect(searchBox).toBeVisible();
|
|
|
|
|
|
|
|
// No plugin cards should be visible by default
|
|
|
|
expect(screen.queryAllByTestId('plugin-card')).toHaveLength(0);
|
|
|
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
await user.type(searchBox, 'backlinks');
|
|
|
|
|
|
|
|
// Should find one result
|
2024-03-29 14:40:54 +02:00
|
|
|
await expectSearchResultCountToBe(1);
|
2024-03-11 17:02:15 +02:00
|
|
|
|
|
|
|
// Clearing the search input should hide all results
|
|
|
|
await user.clear(searchBox);
|
2024-03-29 14:40:54 +02:00
|
|
|
await expectSearchResultCountToBe(0);
|
|
|
|
|
|
|
|
// Typing a space should show all results
|
|
|
|
await user.type(searchBox, ' ');
|
2024-03-11 17:02:15 +02:00
|
|
|
await waitFor(() => {
|
2024-03-29 14:40:54 +02:00
|
|
|
expect(screen.queryAllByTestId('plugin-card').length).toBeGreaterThan(2);
|
2024-03-11 17:02:15 +02:00
|
|
|
});
|
|
|
|
});
|
2024-03-29 14:40:54 +02:00
|
|
|
|
|
|
|
it('should only show recommended plugin search results on iOS-like environments', async () => {
|
|
|
|
// iOS uses restricted install mode
|
|
|
|
const repoApi = await newRepoApi(InstallMode.Restricted);
|
|
|
|
render(<SearchWrapper repoApi={repoApi}/>);
|
|
|
|
|
|
|
|
const searchBox = screen.queryByPlaceholderText('Search');
|
|
|
|
expect(searchBox).toBeVisible();
|
|
|
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
await user.type(searchBox, 'abc');
|
|
|
|
|
|
|
|
// Should find recommended plugins
|
|
|
|
await expectSearchResultCountToBe(1);
|
|
|
|
|
|
|
|
// Should not find non-recommended plugins
|
|
|
|
await user.clear(searchBox);
|
|
|
|
await user.type(searchBox, 'backlinks');
|
|
|
|
await expectSearchResultCountToBe(0);
|
|
|
|
|
|
|
|
await user.clear(searchBox);
|
|
|
|
await user.type(searchBox, ' ');
|
|
|
|
await expectSearchResultCountToBe(1);
|
|
|
|
expect(screen.getByText(/ABC Sheet Music/i)).toBeTruthy();
|
|
|
|
expect(screen.queryByText(/backlink/i)).toBeNull();
|
|
|
|
});
|
2024-04-03 19:51:09 +02:00
|
|
|
|
|
|
|
it('should mark incompatible plugins as incompatible', async () => {
|
|
|
|
const mock = mockMobilePlatform('android');
|
|
|
|
const repoApi = await newRepoApi(InstallMode.Default);
|
|
|
|
render(<SearchWrapper repoApi={repoApi}/>);
|
|
|
|
|
|
|
|
const searchBox = screen.queryByPlaceholderText('Search');
|
|
|
|
const user = userEvent.setup();
|
|
|
|
await user.type(searchBox, 'abc');
|
|
|
|
|
|
|
|
await expectSearchResultCountToBe(1);
|
|
|
|
expect(screen.queryByText('Incompatible')).toBeNull();
|
|
|
|
|
|
|
|
await user.clear(searchBox);
|
|
|
|
await user.type(searchBox, 'side bar toggle');
|
|
|
|
await expectSearchResultCountToBe(1);
|
|
|
|
expect(await screen.findByText(/Note list and side bar/i)).toBeVisible();
|
|
|
|
expect(await screen.findByText('Incompatible')).toBeVisible();
|
|
|
|
|
|
|
|
mock.reset();
|
|
|
|
});
|
2024-03-11 17:02:15 +02:00
|
|
|
});
|