一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
100 行
3.3 KiB
TypeScript
100 行
3.3 KiB
TypeScript
import { EditorSelection } from '@codemirror/state';
|
|
import createTestEditor from '../testing/createTestEditor';
|
|
import { getSearchQuery, openSearchPanel, SearchQuery, setSearchQuery } from '@codemirror/search';
|
|
import { EditorView } from '@codemirror/view';
|
|
import searchExtension from './searchExtension';
|
|
import createEditorSettings from '../../testing/createEditorSettings';
|
|
import { Second } from '@joplin/utils/time';
|
|
|
|
const setSearchText = (text: string, view: EditorView) => {
|
|
const oldQuery = getSearchQuery(view.state);
|
|
const query = new SearchQuery({
|
|
search: text,
|
|
caseSensitive: oldQuery.caseSensitive,
|
|
regexp: oldQuery.regexp,
|
|
replace: oldQuery.replace,
|
|
});
|
|
view.dispatch({
|
|
effects: [
|
|
setSearchQuery.of(query),
|
|
],
|
|
});
|
|
};
|
|
|
|
const setSearchTextAndWait = async (text: string, view: EditorView) => {
|
|
setSearchText(text, view);
|
|
await jest.advanceTimersByTimeAsync(Second);
|
|
};
|
|
|
|
const createEditor = async (initialText: string, cursorPosition: number) => {
|
|
const view = await createTestEditor(initialText, EditorSelection.cursor(cursorPosition), [], [
|
|
searchExtension(()=>{}, createEditorSettings(1)),
|
|
]);
|
|
openSearchPanel(view);
|
|
|
|
return view;
|
|
};
|
|
|
|
const getSelectionFrom = (view: EditorView) => {
|
|
return view.state.selection.main.from;
|
|
};
|
|
|
|
describe('searchExtension', () => {
|
|
beforeEach(() => {
|
|
jest.useFakeTimers();
|
|
});
|
|
|
|
test('should auto-scroll to a match when the search changes', async () => {
|
|
const view = await createEditor('Line 1\n\nLine 3\nLine 4', 0);
|
|
const docText = view.state.doc.toString();
|
|
|
|
await setSearchTextAndWait('Line 3', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Line 3'));
|
|
|
|
await setSearchTextAndWait('Line 4', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Line 4'));
|
|
});
|
|
|
|
test('should advance to the next match on change', async () => {
|
|
const view = await createEditor('Match\nMatch2\nMatch23', 0);
|
|
const docText = view.state.doc.toString();
|
|
|
|
await setSearchTextAndWait('Match', view);
|
|
expect(getSelectionFrom(view)).toBe(0);
|
|
|
|
await setSearchTextAndWait('Match2', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Match2'));
|
|
|
|
await setSearchTextAndWait('Match23', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Match23'));
|
|
});
|
|
|
|
test('should preserve auto-match start position until selection is manually changed', async () => {
|
|
const view = await createEditor('Match1\nMatch2\nMatch23', 0);
|
|
const docText = view.state.doc.toString();
|
|
|
|
await setSearchTextAndWait('Match2', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Match2'));
|
|
|
|
await setSearchTextAndWait('Match', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Match'));
|
|
|
|
await setSearchTextAndWait('Match23', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Match23'));
|
|
|
|
// Manually setting the selection should change the match start location
|
|
view.dispatch({
|
|
selection: EditorSelection.single('Match1\n'.length),
|
|
});
|
|
await setSearchTextAndWait('Match2', view);
|
|
expect(getSelectionFrom(view)).toBe(docText.indexOf('Match2'));
|
|
});
|
|
|
|
test('search should wrap to the top when not found after the cursor', async () => {
|
|
const view = await createEditor('Before\nOther\nOther 2', 5);
|
|
|
|
await setSearchTextAndWait('Before', view);
|
|
expect(getSelectionFrom(view)).toBe(0);
|
|
});
|
|
});
|