一些检查失败了
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
77 行
2.8 KiB
TypeScript
77 行
2.8 KiB
TypeScript
import Note from '../../models/Note';
|
|
import { setupDatabaseAndSynchronizer, supportDir, switchClient } from '../../testing/test-utils';
|
|
import { ImportModuleOutputFormat, ImportOptions } from './types';
|
|
import InteropService from './InteropService';
|
|
import Folder from '../../models/Folder';
|
|
import { isRecoverableError } from '../../import-enex';
|
|
|
|
const importFolder = async (path: string, onError: ImportOptions['onError'] = null) => {
|
|
const importOptions: ImportOptions = {
|
|
path: path,
|
|
format: 'enex',
|
|
outputFormat: ImportModuleOutputFormat.Markdown,
|
|
onError,
|
|
};
|
|
|
|
await InteropService.instance().import(importOptions);
|
|
};
|
|
|
|
const importTestFile = async (name: string, onError: ImportOptions['onError'] = null) => {
|
|
const enexSampleBaseDir = `${supportDir}/../enex_to_md`;
|
|
await importFolder(`${enexSampleBaseDir}/${name}`, onError);
|
|
};
|
|
|
|
describe('InteropService_Importer_EnexToMd', () => {
|
|
beforeEach(async () => {
|
|
await setupDatabaseAndSynchronizer(1);
|
|
await switchClient(1);
|
|
});
|
|
|
|
it('should resolve cross-notebook links', async () => {
|
|
await importTestFile('links/');
|
|
|
|
const folders = await Folder.all({ order: [{ by: 'title', dir: 'ASC' }] });
|
|
expect(folders).toMatchObject([
|
|
{ title: 'notebook1', parent_id: '' },
|
|
{ title: 'notebook2', parent_id: '' },
|
|
]);
|
|
|
|
const notes = await Note.all({ order: [{ by: 'title', dir: 'ASC' }] });
|
|
expect(notes).toMatchObject([
|
|
{ title: 'Example note', parent_id: folders[0].id },
|
|
{ title: 'Note 2', parent_id: folders[0].id },
|
|
{ title: 'Test', parent_id: folders[1].id },
|
|
{ title: 'Test note', parent_id: folders[1].id },
|
|
{ title: 'Testing', parent_id: folders[1].id },
|
|
]);
|
|
|
|
// Same-folder link (https:// link)
|
|
expect(notes[1].body).toContain(`[Example note](:/${notes[0].id})`);
|
|
// Cross-folder link (https:// link)
|
|
expect(notes[1].body).toContain(`[Test](:/${notes[2].id})`);
|
|
|
|
// Cross-folder link (https:// link)
|
|
expect(notes[2].body).toContain(`[Example note](:/${notes[0].id})`);
|
|
// Same-folder link (evernote:// link)
|
|
expect(notes[2].body).toContain(`[Test note](:/${notes[3].id})`);
|
|
expect(notes[4].body).toContain(`[Test](:/${notes[2].id})`);
|
|
});
|
|
|
|
it('should import notes even if the file contains unescaped ampersands', async () => {
|
|
const errors: Error[] = [];
|
|
await importTestFile('unescaped_ampersand.enex', error => errors.push(error));
|
|
|
|
const notes = await Note.all({ order: [{ by: 'title', dir: 'ASC' }] });
|
|
expect(notes.map(n => n.title)).toEqual([
|
|
'Note after the bad one',
|
|
'Unescaped ampersand',
|
|
]);
|
|
expect(notes[0].body).toContain('This note must still be imported');
|
|
expect(notes[1].body).toContain('Mobilize & Measure');
|
|
|
|
// Reported, but flagged so it's not presented as a failed import.
|
|
expect(errors.length).toBe(1);
|
|
expect(isRecoverableError(errors[0])).toBe(true);
|
|
});
|
|
});
|