文件
mynode/packages/editor/CodeMirror/extensions/wikiLinkAutocompleteExtension.test.ts
chen 301194963b
一些检查失败了
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
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

142 行
5.3 KiB
TypeScript

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

import { EditorSelection } from '@codemirror/state';
import createTestEditor from '../testing/createTestEditor';
import { matchWikiLinkTrigger, createWikiLinkCompletionSource } from './wikiLinkAutocompleteExtension';
describe('wikiLinkAutocompleteExtension', () => {
describe('matchWikiLinkTrigger', () => {
it('matches [[ at the end of line', () => {
const res = matchWikiLinkTrigger('Hello [[');
expect(res).toEqual({ query: '', matchLength: 2, trigger: '[[' });
});
it('matches full-width 【【 for Chinese input method', () => {
const res1 = matchWikiLinkTrigger('引用笔记:【【');
expect(res1).toEqual({ query: '', matchLength: 2, trigger: '[[' });
const res2 = matchWikiLinkTrigger('引用笔记:【【工作周报');
expect(res2).toEqual({ query: '工作周报', matchLength: 6, trigger: '[[' });
});
it('matches full-width @ for Chinese input method', () => {
const res1 = matchWikiLinkTrigger('@');
expect(res1).toEqual({ query: '', matchLength: 1, trigger: '@' });
const res2 = matchWikiLinkTrigger('查看 @今天');
expect(res2).toEqual({ query: '今天', matchLength: 3, trigger: '@' });
});
it('matches [[ with partial query', () => {
const res = matchWikiLinkTrigger('Ref: [[Meeting');
expect(res).toEqual({ query: 'Meeting', matchLength: 9, trigger: '[[' });
});
it('matches @ at start of line', () => {
const res = matchWikiLinkTrigger('@Today');
expect(res).toEqual({ query: 'Today', matchLength: 6, trigger: '@' });
});
it('matches @ after whitespace or open brackets', () => {
const res1 = matchWikiLinkTrigger('Check this @journal');
expect(res1).toEqual({ query: 'journal', matchLength: 8, trigger: '@' });
const res2 = matchWikiLinkTrigger('(see @note');
expect(res2).toEqual({ query: 'note', matchLength: 5, trigger: '@' });
});
it('does NOT match normal email addresses', () => {
expect(matchWikiLinkTrigger('user@domain.com')).toBeNull();
expect(matchWikiLinkTrigger('contact: support@joplinapp.org')).toBeNull();
});
it('returns null when no trigger is present', () => {
expect(matchWikiLinkTrigger('Normal text [1]')).toBeNull();
expect(matchWikiLinkTrigger('Just a single [')).toBeNull();
});
it('returns null across newlines', () => {
expect(matchWikiLinkTrigger('[[\nSecond line')).toBeNull();
expect(matchWikiLinkTrigger('@\nSecond line')).toBeNull();
});
});
describe('createWikiLinkCompletionSource', () => {
it('returns completion options matching searchNotes for @ mention', async () => {
const mockNotes = [
{ id: 'note-today', title: '2026-11-01 星期日', parentTitle: '📅 今日日志' },
{ id: 'note-yesterday', title: '2026-10-31 星期六', parentTitle: '📅 昨日日志' },
];
const mockSearch = jest.fn().mockResolvedValue(mockNotes);
const source = createWikiLinkCompletionSource(mockSearch);
const initialText = 'Today log: @';
const editor = await createTestEditor(initialText, EditorSelection.cursor(initialText.length), []);
const result = await source({
state: editor.state,
pos: initialText.length,
explicit: true,
} as any);
expect(result).not.toBeNull();
expect(result?.from).toBe(initialText.indexOf('@'));
expect(result?.options.length).toBe(2);
expect(result?.options[0].label).toBe('2026-11-01 星期日');
expect(result?.options[0].detail).toBe('📅 今日日志');
});
it('applies replacement with standard Joplin markdown link [Title](:/id)', async () => {
const mockNotes = [
{ id: 'uuid-today', title: '2026-11-01 星期日' },
];
const mockSearch = jest.fn().mockResolvedValue(mockNotes);
const source = createWikiLinkCompletionSource(mockSearch);
const initialText = 'See @2026';
const editor = await createTestEditor(initialText, EditorSelection.cursor(initialText.length), []);
const result = await source({
state: editor.state,
pos: initialText.length,
explicit: true,
} as any);
expect(result).not.toBeNull();
const option = result!.options[0];
// Simulate apply
(option.apply as any)(editor, option, result!.from, initialText.length);
expect(editor.state.doc.toString()).toBe('See [2026-11-01 星期日](:/uuid-today)');
});
it('creates note on demand when selecting __CREATE_ item', async () => {
const mockNotes = [
{ id: '__CREATE_TODAY__', title: '2026-11-01 星期日', parentTitle: '📅 新建今日日志' },
];
const mockSearch = jest.fn().mockResolvedValue(mockNotes);
const mockCreate = jest.fn().mockResolvedValue({ id: 'brand-new-uuid', title: '2026-11-01 星期日' });
const source = createWikiLinkCompletionSource(mockSearch, mockCreate);
const initialText = 'Today: @今天';
const editor = await createTestEditor(initialText, EditorSelection.cursor(initialText.length), []);
const result = await source({
state: editor.state,
pos: initialText.length,
explicit: true,
} as any);
expect(result).not.toBeNull();
const option = result!.options[0];
(option.apply as any)(editor, option, result!.from, initialText.length);
// Wait for async createNote to resolve and dispatch
await new Promise(r => setTimeout(r, 20));
expect(mockCreate).toHaveBeenCalledWith('2026-11-01 星期日');
expect(editor.state.doc.toString()).toBe('Today: [2026-11-01 星期日](:/brand-new-uuid)');
});
});
});