1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-27 10:32:58 +02:00
joplin/packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.test.tsx
2024-08-02 14:51:49 +01:00

175 lines
5.6 KiB
TypeScript

import * as React from 'react';
import { describe, it, beforeEach } from '@jest/globals';
import { render, screen, waitFor } from '@testing-library/react-native';
import '@testing-library/jest-native/extend-expect';
import NoteBodyViewer from './NoteBodyViewer';
import Setting from '@joplin/lib/models/Setting';
import { MenuProvider } from 'react-native-popup-menu';
import { resourceFetcher, setupDatabaseAndSynchronizer, supportDir, switchClient, synchronizerStart } from '@joplin/lib/testing/test-utils';
import { MarkupLanguage } from '@joplin/renderer';
import { HandleMessageCallback, OnMarkForDownloadCallback } from './hooks/useOnMessage';
import Resource from '@joplin/lib/models/Resource';
import shim from '@joplin/lib/shim';
import Note from '@joplin/lib/models/Note';
import { ResourceInfo } from './hooks/useRerenderHandler';
import getWebViewDomById from '../../utils/testing/getWebViewDomById';
interface WrapperProps {
noteBody: string;
highlightedKeywords?: string[];
noteResources?: Record<string, ResourceInfo>;
onJoplinLinkClick?: HandleMessageCallback;
onScroll?: (percent: number)=> void;
onMarkForDownload?: OnMarkForDownloadCallback;
}
const emptyObject = {};
const emptyArray: string[] = [];
const noOpFunction = () => {};
const WrappedNoteViewer: React.FC<WrapperProps> = (
{
noteBody,
highlightedKeywords = emptyArray,
noteResources = emptyObject,
onJoplinLinkClick = noOpFunction,
onScroll = noOpFunction,
onMarkForDownload,
}: WrapperProps,
) => {
return <MenuProvider>
<NoteBodyViewer
themeId={Setting.THEME_LIGHT}
style={emptyObject}
noteBody={noteBody}
noteMarkupLanguage={MarkupLanguage.Markdown}
highlightedKeywords={highlightedKeywords}
noteResources={noteResources}
paddingBottom={0}
initialScroll={0}
noteHash={''}
onJoplinLinkClick={onJoplinLinkClick}
onMarkForDownload={onMarkForDownload}
onScroll={onScroll}
pluginStates={emptyObject}
/>
</MenuProvider>;
};
const getNoteViewerDom = async () => {
return await getWebViewDomById('NoteBodyViewer');
};
describe('NoteBodyViewer', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(0);
await switchClient(0);
});
afterEach(() => {
screen.unmount();
});
it('should render markdown and re-render on change', async () => {
render(<WrappedNoteViewer noteBody='# Test'/>);
const expectHeaderToBe = async (text: string) => {
const noteViewer = await getNoteViewerDom();
await waitFor(async () => {
expect(noteViewer.querySelector('h1').textContent).toBe(text);
});
};
await expectHeaderToBe('Test');
screen.rerender(<WrappedNoteViewer noteBody='# Test 2'/>);
await expectHeaderToBe('Test 2');
screen.rerender(<WrappedNoteViewer noteBody='# Test 3'/>);
await expectHeaderToBe('Test 3');
});
it.each([
{ keywords: ['match'], body: 'A match and another match. Both should be highlighted.', expectedMatchCount: 2 },
{ keywords: ['test'], body: 'No match.', expectedMatchCount: 0 },
{ keywords: ['a', 'b'], body: 'a, a, a, b, b, b', expectedMatchCount: 6 },
])('should highlight search terms (case %#)', async ({ keywords, body, expectedMatchCount }) => {
render(
<WrappedNoteViewer
highlightedKeywords={keywords}
noteBody={body}
/>,
);
let noteViewerDom = await getNoteViewerDom();
await waitFor(() => {
expect(noteViewerDom.querySelectorAll('.highlighted-keyword')).toHaveLength(expectedMatchCount);
});
// Should update highlights when the keywords change
screen.rerender(
<WrappedNoteViewer
highlightedKeywords={[]}
noteBody={body}
/>,
);
noteViewerDom = await getNoteViewerDom();
await waitFor(() => {
expect(noteViewerDom.querySelectorAll('.highlighted-keyword')).toHaveLength(0);
});
});
it('tapping on resource download icons should mark the resources for download', async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
let note1 = await Note.save({ title: 'Note 1', parent_id: '' });
note1 = await shim.attachFileToNote(note1, `${supportDir}/photo.jpg`);
await synchronizerStart();
await switchClient(0);
Setting.setValue('sync.resourceDownloadMode', 'manual');
await synchronizerStart();
const allResources = await Resource.all();
expect(allResources.length).toBe(1);
const localResource = allResources[0];
const localState = await Resource.localState(localResource);
expect(localState.fetch_status).toBe(Resource.FETCH_STATUS_IDLE);
const onMarkForDownload: OnMarkForDownloadCallback = jest.fn(({ resourceId }) => {
return resourceFetcher().markForDownload([resourceId]);
});
render(
<WrappedNoteViewer
noteBody={note1.body}
noteResources={{ [localResource.id]: { localState, item: localResource } }}
onMarkForDownload={onMarkForDownload}
/>,
);
// The resource placeholder should have rendered
const noteViewerDom = await getNoteViewerDom();
let resourcePlaceholder: HTMLElement|null = null;
await waitFor(() => {
const placeholders = noteViewerDom.querySelectorAll<HTMLElement>(`[data-resource-id=${JSON.stringify(localResource.id)}]`);
expect(placeholders).toHaveLength(1);
resourcePlaceholder = placeholders[0];
});
expect([...resourcePlaceholder.classList]).toContain('resource-status-notDownloaded');
// Clicking on the placeholder should download its resource
await waitFor(() => {
resourcePlaceholder.click();
expect(onMarkForDownload).toHaveBeenCalled();
});
await resourceFetcher().waitForAllFinished();
await waitFor(async () => {
expect(await Resource.localState(localResource.id)).toMatchObject({ fetch_status: Resource.FETCH_STATUS_DONE });
});
});
});