mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
175 lines
5.6 KiB
TypeScript
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 });
|
|
});
|
|
});
|
|
});
|