import Note from '../../models/Note'; import Folder from '../../models/Folder'; import { remove, readFile } from 'fs-extra'; import { createTempDir, setupDatabaseAndSynchronizer, supportDir, switchClient } from '../../testing/test-utils'; import { NoteEntity } from '../database/types'; import { MarkupToHtml } from '@joplin/renderer'; import BaseModel from '../../BaseModel'; import InteropService from './InteropService'; import InteropService_Importer_OneNote from './InteropService_Importer_OneNote'; import { JSDOM } from 'jsdom'; import { ImportModuleOutputFormat } from './types'; // We don't require all developers to have Rust to run the project, so we skip this test if not running in CI const skipIfNotCI = process.env.IS_CONTINUOUS_INTEGRATION ? it : it.skip; describe('InteropService_Importer_OneNote', () => { let tempDir: string; async function importNote(path: string) { const newFolder = await Folder.save({ title: 'folder' }); const service = InteropService.instance(); await service.import({ outputFormat: ImportModuleOutputFormat.Markdown, path, destinationFolder: newFolder, destinationFolderId: newFolder.id, }); const allNotes: NoteEntity[] = await Note.all(); return allNotes; } beforeAll(() => { const jsdom = new JSDOM('
'); InteropService.instance().document = jsdom.window.document; InteropService.instance().xmlSerializer = new jsdom.window.XMLSerializer(); }); beforeEach(async () => { await setupDatabaseAndSynchronizer(1); await switchClient(1); tempDir = await createTempDir(); }); afterEach(async () => { await remove(tempDir); }); skipIfNotCI('should import a simple OneNote notebook', async () => { const notes = await importNote(`${supportDir}/onenote/simple_notebook.zip`); const folders = await Folder.all(); expect(notes.length).toBe(2); const mainNote = notes[0]; expect(folders.length).toBe(3); const parentFolder = folders.find(f => f.id === mainNote.parent_id); expect(parentFolder.title).toBe('Section title'); expect(folders.find(f => f.id === parentFolder.parent_id).title).toBe('Simple notebook'); expect(mainNote.title).toBe('Page title'); expect(mainNote.markup_language).toBe(MarkupToHtml.MARKUP_LANGUAGE_HTML); expect(mainNote.body).toMatchSnapshot(mainNote.title); }); skipIfNotCI('should preserve indentation of subpages in Section page', async () => { const notes = await importNote(`${supportDir}/onenote/subpages.zip`); const sectionPage = notes.find(n => n.title === 'Section'); const menuHtml = sectionPage.body.split('')[0]; const menuLines = menuHtml.split(''); const pageTwo = notes.find(n => n.title === 'Page 2'); expect(menuLines[3].trim()).toBe(`
  • ${pageTwo.title}`); const pageTwoA = notes.find(n => n.title === 'Page 2-a'); expect(menuLines[4].trim()).toBe(`
  • ${pageTwoA.title}`); const pageTwoAA = notes.find(n => n.title === 'Page 2-a-a'); expect(menuLines[5].trim()).toBe(`
  • ${pageTwoAA.title}`); const pageTwoB = notes.find(n => n.title === 'Page 2-b'); expect(menuLines[7].trim()).toBe(`
  • ${pageTwoB.title}`); }); skipIfNotCI('should created subsections', async () => { const notes = await importNote(`${supportDir}/onenote/subsections.zip`); const folders = await Folder.all(); const parentSection = folders.find(f => f.title === 'Group Section 1'); const subSection = folders.find(f => f.title === 'Group Section 1-a'); const subSection1 = folders.find(f => f.title === 'Subsection 1'); const subSection2 = folders.find(f => f.title === 'Subsection 2'); const notesFromParentSection = notes.filter(n => n.parent_id === parentSection.id); expect(parentSection.id).toBe(subSection1.parent_id); expect(parentSection.id).toBe(subSection2.parent_id); expect(parentSection.id).toBe(subSection.parent_id); expect(folders.length).toBe(7); expect(notes.length).toBe(6); expect(notesFromParentSection.length).toBe(2); }); skipIfNotCI('should expect notes to be rendered the same', async () => { let idx = 0; const originalIdGenerator = BaseModel.setIdGenerator(() => String(idx++)); const notes = await importNote(`${supportDir}/onenote/complex_notes.zip`); const folders = await Folder.all(); const parentSection = folders.find(f => f.title === 'Quick Notes'); expect(folders.length).toBe(3); expect(notes.length).toBe(7); expect(notes.filter(n => n.parent_id === parentSection.id).length).toBe(6); for (const note of notes) { expect(note.body).toMatchSnapshot(note.title); } BaseModel.setIdGenerator(originalIdGenerator); }); skipIfNotCI('should render the proper tree for notebook with group sections', async () => { const notes = await importNote(`${supportDir}/onenote/group_sections.zip`); const folders = await Folder.all(); const mainFolder = folders.find(f => f.title === 'Notebook created on OneNote App'); const section = folders.find(f => f.title === 'Section'); const sectionA1 = folders.find(f => f.title === 'Section A1'); const sectionA = folders.find(f => f.title === 'Section A'); const sectionB1 = folders.find(f => f.title === 'Section B1'); const sectionB = folders.find(f => f.title === 'Section B'); const sectionD1 = folders.find(f => f.title === 'Section D1'); const sectionD = folders.find(f => f.title === 'Section D'); expect(section.parent_id).toBe(mainFolder.id); expect(sectionA.parent_id).toBe(mainFolder.id); expect(sectionD.parent_id).toBe(mainFolder.id); expect(sectionA1.parent_id).toBe(sectionA.id); expect(sectionB.parent_id).toBe(sectionA.id); expect(sectionB1.parent_id).toBe(sectionB.id); expect(sectionD1.parent_id).toBe(sectionD.id); expect(notes.filter(n => n.parent_id === sectionA1.id).length).toBe(2); expect(notes.filter(n => n.parent_id === sectionB1.id).length).toBe(2); expect(notes.filter(n => n.parent_id === sectionD1.id).length).toBe(1); }); skipIfNotCI.each([ 'svg_with_text_and_style.html', 'many_svgs.html', ])('should extract svgs', async (filename: string) => { const titleGenerator = () => { let id = 0; return () => { id += 1; return `id${id}`; }; }; const filepath = `${supportDir}/onenote/${filename}`; const content = await readFile(filepath, 'utf-8'); const jsdom = new JSDOM('
    '); InteropService.instance().document = jsdom.window.document; InteropService.instance().xmlSerializer = new jsdom.window.XMLSerializer(); const importer = new InteropService_Importer_OneNote(); await importer.init('asdf', { document: jsdom.window.document, xmlSerializer: new jsdom.window.XMLSerializer(), }); expect(importer.extractSvgs(content, titleGenerator())).toMatchSnapshot(); }); skipIfNotCI('should ignore broken characters at the start of paragraph', async () => { let idx = 0; const originalIdGenerator = BaseModel.setIdGenerator(() => String(idx++)); const notes = await importNote(`${supportDir}/onenote/bug_broken_character.zip`); expect(notes.find(n => n.title === 'Action research - Wikipedia').body).toMatchSnapshot(); BaseModel.setIdGenerator(originalIdGenerator); }); });