1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

Merge branch 'master' into html-to-md

# Conflicts:
#	browser/main/modals/NewNoteModal.js
#	package-lock.json
#	package.json
#	yarn.lock
This commit is contained in:
AWolf81
2019-06-29 23:25:52 +02:00
249 changed files with 234965 additions and 4645 deletions

View File

@@ -3,7 +3,7 @@ import renderer from 'react-test-renderer'
import TagListItem from 'browser/components/TagListItem'
it('TagListItem renders correctly', () => {
const tagListItem = renderer.create(<TagListItem name='Test' handleClickTagListItem={jest.fn()} />)
const tagListItem = renderer.create(<TagListItem name='Test' handleClickTagListItem={jest.fn()} color='#000' />)
expect(tagListItem.toJSON()).toMatchSnapshot()
})

View File

@@ -3,6 +3,7 @@
exports[`TagListItem renders correctly 1`] = `
<div
className="tagList-itemContainer"
onContextMenu={[Function]}
>
<div
className="tagList-itemNarrow"
@@ -11,6 +12,14 @@ exports[`TagListItem renders correctly 1`] = `
className="tagList-item"
onClick={[Function]}
>
<span
className="tagList-item-color"
style={
Object {
"backgroundColor": "#000",
}
}
/>
<span
className="tagList-item-name"
>

View File

@@ -38,7 +38,7 @@ it('should test that copyAttachment should throw an error if sourcePath dosen\'t
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValue(false)
systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(() => {}, error => {
return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(() => {}, error => {
expect(error).toBe('source file does not exist')
expect(fs.existsSync).toHaveBeenCalledWith('path')
})
@@ -64,7 +64,7 @@ it('should test that copyAttachment works correctly assuming correct working of
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue(dummyUniquePath)
systemUnderTest.copyAttachment(sourcePath, storageKey, noteKey).then(
return systemUnderTest.copyAttachment(sourcePath, storageKey, noteKey).then(
function (newFileName) {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(fs.createReadStream).toHaveBeenCalledWith(sourcePath)
@@ -83,7 +83,7 @@ it('should test that copyAttachment creates a new folder if the attachment folde
const dummyReadStream = {}
dummyReadStream.pipe = jest.fn()
dummyReadStream.on = jest.fn()
dummyReadStream.on = jest.fn((event, callback) => { callback() })
fs.createReadStream = jest.fn(() => dummyReadStream)
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValueOnce(true)
@@ -95,7 +95,7 @@ it('should test that copyAttachment creates a new folder if the attachment folde
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue('dummyPath')
systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(
return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(
function () {
expect(fs.existsSync).toHaveBeenCalledWith(attachmentFolderPath)
expect(fs.mkdirSync).toHaveBeenCalledWith(attachmentFolderPath)
@@ -109,7 +109,7 @@ it('should test that copyAttachment don\'t uses a random file name if not intend
const dummyReadStream = {}
dummyReadStream.pipe = jest.fn()
dummyReadStream.on = jest.fn()
dummyReadStream.on = jest.fn((event, callback) => { callback() })
fs.createReadStream = jest.fn(() => dummyReadStream)
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValueOnce(true)
@@ -120,14 +120,155 @@ it('should test that copyAttachment don\'t uses a random file name if not intend
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue('dummyPath')
systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey', false).then(
return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey', false).then(
function (newFileName) {
expect(newFileName).toBe('path')
})
})
it('should test that copyAttachment with url (with extension, without query)', function () {
const dummyStorage = {path: 'dummyStoragePath'}
const dummyReadStream = {
pipe: jest.fn(),
on: jest.fn((event, callback) => { callback() })
}
fs.createReadStream = jest.fn(() => dummyReadStream)
const dummyWriteStream = {
write: jest.fn((data, callback) => { callback() })
}
fs.createWriteStream = jest.fn(() => dummyWriteStream)
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValueOnce(true)
fs.existsSync.mockReturnValueOnce(false)
fs.mkdirSync = jest.fn()
findStorage.findStorage = jest.fn()
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue('dummyPath')
const sourcePath = {
sourceFilePath: 'http://www.foo.bar/baz/qux.jpg',
type: 'base64',
data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl'
}
return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then(
function (newFileName) {
expect(newFileName).toBe('dummyPath.jpg')
})
})
it('should test that copyAttachment with url (with extension, with query)', function () {
const dummyStorage = {path: 'dummyStoragePath'}
const dummyReadStream = {
pipe: jest.fn(),
on: jest.fn((event, callback) => { callback() })
}
fs.createReadStream = jest.fn(() => dummyReadStream)
const dummyWriteStream = {
write: jest.fn((data, callback) => { callback() })
}
fs.createWriteStream = jest.fn(() => dummyWriteStream)
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValueOnce(true)
fs.existsSync.mockReturnValueOnce(false)
fs.mkdirSync = jest.fn()
findStorage.findStorage = jest.fn()
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue('dummyPath')
const sourcePath = {
sourceFilePath: 'http://www.foo.bar/baz/qux.jpg?h=1080',
type: 'base64',
data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl'
}
return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then(
function (newFileName) {
expect(newFileName).toBe('dummyPath.jpg')
})
})
it('should test that copyAttachment with url (without extension, without query)', function () {
const dummyStorage = {path: 'dummyStoragePath'}
const dummyReadStream = {
pipe: jest.fn(),
on: jest.fn((event, callback) => { callback() })
}
fs.createReadStream = jest.fn(() => dummyReadStream)
const dummyWriteStream = {
write: jest.fn((data, callback) => { callback() })
}
fs.createWriteStream = jest.fn(() => dummyWriteStream)
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValueOnce(true)
fs.existsSync.mockReturnValueOnce(false)
fs.mkdirSync = jest.fn()
findStorage.findStorage = jest.fn()
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue('dummyPath')
const sourcePath = {
sourceFilePath: 'http://www.foo.bar/baz/qux',
type: 'base64',
data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl'
}
return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then(
function (newFileName) {
expect(newFileName).toBe('dummyPath.png')
})
})
it('should test that copyAttachment with url (without extension, with query)', function () {
const dummyStorage = {path: 'dummyStoragePath'}
const dummyReadStream = {
pipe: jest.fn(),
on: jest.fn((event, callback) => { callback() })
}
fs.createReadStream = jest.fn(() => dummyReadStream)
const dummyWriteStream = {
write: jest.fn((data, callback) => { callback() })
}
fs.createWriteStream = jest.fn(() => dummyWriteStream)
fs.existsSync = jest.fn()
fs.existsSync.mockReturnValueOnce(true)
fs.existsSync.mockReturnValueOnce(false)
fs.mkdirSync = jest.fn()
findStorage.findStorage = jest.fn()
findStorage.findStorage.mockReturnValue(dummyStorage)
uniqueSlug.mockReturnValue('dummyPath')
const sourcePath = {
sourceFilePath: 'http://www.foo.bar/baz/qux?h=1080',
type: 'base64',
data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl'
}
return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then(
function (newFileName) {
expect(newFileName).toBe('dummyPath.png')
})
})
it('should replace the all ":storage" path with the actual storage path', function () {
const storageFolder = systemUnderTest.DESTINATION_FOLDER
const noteKey = '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c'
const testInput =
'<html>\n' +
' <head>\n' +
@@ -136,13 +277,62 @@ it('should replace the all ":storage" path with the actual storage path', functi
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' <a href=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' <pre class="fence" data-line="8">\n' +
' <span class="filename"></span>\n' +
' <div class="gallery" data-autoplay="undefined" data-height="undefined">:storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + 'f939b2c3.jpg</div>\n' +
' </pre>\n' +
' </body>\n' +
'</html>'
const storagePath = '<<dummyStoragePath>>'
const expectedOutput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + noteKey + path.sep + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href="file:///' + storagePath + path.sep + storageFolder + path.sep + noteKey + path.sep + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + noteKey + path.sep + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' <pre class="fence" data-line="8">\n' +
' <span class="filename"></span>\n' +
' <div class="gallery" data-autoplay="undefined" data-height="undefined">file:///' + storagePath + path.sep + storageFolder + path.sep + noteKey + path.sep + 'f939b2c3.jpg</div>\n' +
' </pre>\n' +
' </body>\n' +
'</html>'
const actual = systemUnderTest.fixLocalURLS(testInput, storagePath)
expect(actual).toEqual(expectedOutput)
})
it('should replace the ":storage" path with the actual storage path when they have different path separators', function () {
const storageFolder = systemUnderTest.DESTINATION_FOLDER
const noteKey = '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c'
const testInput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.win32.sep) + noteKey + mdurl.encode(path.win32.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.posix.sep) + noteKey + mdurl.encode(path.posix.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' </body>\n' +
'</html>'
@@ -155,13 +345,10 @@ it('should replace the all ":storage" path with the actual storage path', functi
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + noteKey + path.sep + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href="file:///' + storagePath + path.sep + storageFolder + path.sep + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' <a href="file:///' + storagePath + path.sep + storageFolder + path.sep + noteKey + path.sep + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' </body>\n' +
'</html>'
@@ -180,54 +367,51 @@ it('should test that generateAttachmentMarkdown works correct both with previews
expect(actual).toEqual(expected)
})
it('should test that getAttachmentsInContent finds all attachments', function () {
const testInput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
const actual = systemUnderTest.getAttachmentsInContent(testInput)
const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
it('should test that migrateAttachments work when they have different path separators', function () {
sander.existsSync = jest.fn(() => true)
const dummyStoragePath = 'dummyStoragePath'
const imagesPath = path.join(dummyStoragePath, 'images')
const attachmentsPath = path.join(dummyStoragePath, 'attachments')
const noteKey = 'noteKey'
const testInput = '"# Test\n' +
'\n' +
'![Screenshot1](:storage' + path.win32.sep + '0.3b88d0dc.png)\n' +
'![Screenshot2](:storage' + path.posix.sep + '0.2cb8875c.pdf)"'
systemUnderTest.migrateAttachments(testInput, dummyStoragePath, noteKey)
expect(sander.existsSync.mock.calls[0][0]).toBe(imagesPath)
expect(sander.existsSync.mock.calls[1][0]).toBe(path.join(imagesPath, '0.3b88d0dc.png'))
expect(sander.existsSync.mock.calls[2][0]).toBe(path.join(attachmentsPath, '0.3b88d0dc.png'))
expect(sander.existsSync.mock.calls[3][0]).toBe(path.join(imagesPath, '0.2cb8875c.pdf'))
expect(sander.existsSync.mock.calls[4][0]).toBe(path.join(attachmentsPath, '0.2cb8875c.pdf'))
})
it('should test that getAttachmentsInMarkdownContent finds all attachments when they have different path separators', function () {
const testInput = '"# Test\n' +
'\n' +
'![Screenshot1](:storage' + path.win32.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.win32.sep + '0.3b88d0dc.png)\n' +
'![Screenshot2](:storage' + path.posix.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.posix.sep + '2cb8875c.pdf)\n' +
'![Screenshot3](:storage' + path.win32.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.posix.sep + 'bbf49b02.jpg)"'
const actual = systemUnderTest.getAttachmentsInMarkdownContent(testInput)
const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.3b88d0dc.png', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '2cb8875c.pdf', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'bbf49b02.jpg']
expect(actual).toEqual(expect.arrayContaining(expected))
})
it('should test that getAbsolutePathsOfAttachmentsInContent returns all absolute paths', function () {
const dummyStoragePath = 'dummyStoragePath'
const testInput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
const noteKey = '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c'
const testInput = '"# Test\n' +
'\n' +
'![Screenshot1](:storage' + path.win32.sep + noteKey + path.win32.sep + '0.6r4zdgc22xp.png)\n' +
'![Screenshot2](:storage' + path.posix.sep + noteKey + path.posix.sep + '0.q2i4iw0fyx.pdf)\n' +
'![Screenshot3](:storage' + path.win32.sep + noteKey + path.posix.sep + 'd6c5ee92.jpg)"'
const actual = systemUnderTest.getAbsolutePathsOfAttachmentsInContent(testInput, dummyStoragePath)
const expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
const expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + noteKey + path.sep + '0.6r4zdgc22xp.png',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + noteKey + path.sep + '0.q2i4iw0fyx.pdf',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + noteKey + path.sep + 'd6c5ee92.jpg']
expect(actual).toEqual(expect.arrayContaining(expected))
})
@@ -242,13 +426,13 @@ it('should remove the all ":storage" and noteKey references', function () {
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' <img src=":storage' + mdurl.encode(path.win32.sep) + noteKey + mdurl.encode(path.win32.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' <a href=":storage' + mdurl.encode(path.posix.sep) + noteKey + mdurl.encode(path.posix.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' <img src=":storage' + mdurl.encode(path.win32.sep) + noteKey + mdurl.encode(path.posix.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
@@ -274,6 +458,21 @@ it('should remove the all ":storage" and noteKey references', function () {
expect(actual).toEqual(expectedOutput)
})
it('should make sure that "removeStorageAndNoteReferences" works with markdown content as well', function () {
const noteKey = 'noteKey'
const testInput =
'Test input' +
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + noteKey + path.win32.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + noteKey + path.posix.sep + 'pdf.pdf](pdf})'
const expectedOutput =
'Test input' +
'![' + systemUnderTest.DESTINATION_FOLDER + path.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.DESTINATION_FOLDER + path.sep + 'pdf.pdf](pdf})'
const actual = systemUnderTest.removeStorageAndNoteReferences(testInput, noteKey)
expect(actual).toEqual(expectedOutput)
})
it('should delete the correct attachment folder if a note is deleted', function () {
const dummyStorage = {path: 'dummyStoragePath'}
const storageKey = 'storageKey'
@@ -339,6 +538,38 @@ it('should test that deleteAttachmentsNotPresentInNote does not delete reference
expect(fsUnlinkCallArguments.includes(path.join(attachmentFolderPath, dummyFilesInFolder[0]))).toBe(false)
})
it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, storageKey or noteContent was null', function () {
const noteKey = null
const storageKey = null
const markdownContent = ''
findStorage.findStorage = jest.fn()
fs.existsSync = jest.fn()
fs.readdir = jest.fn()
fs.unlink = jest.fn()
systemUnderTest.deleteAttachmentsNotPresentInNote(markdownContent, storageKey, noteKey)
expect(fs.existsSync).not.toHaveBeenCalled()
expect(fs.readdir).not.toHaveBeenCalled()
expect(fs.unlink).not.toHaveBeenCalled()
})
it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, storageKey or noteContent was undefined', function () {
const noteKey = undefined
const storageKey = undefined
const markdownContent = ''
findStorage.findStorage = jest.fn()
fs.existsSync = jest.fn()
fs.readdir = jest.fn()
fs.unlink = jest.fn()
systemUnderTest.deleteAttachmentsNotPresentInNote(markdownContent, storageKey, noteKey)
expect(fs.existsSync).not.toHaveBeenCalled()
expect(fs.readdir).not.toHaveBeenCalled()
expect(fs.unlink).not.toHaveBeenCalled()
})
it('should test that moveAttachments moves attachments only if the source folder existed', function () {
fse.existsSync = jest.fn(() => false)
fse.moveSync = jest.fn()
@@ -384,8 +615,8 @@ it('should test that moveAttachments returns a correct modified content version'
const newNoteKey = 'newNoteKey'
const testInput =
'Test input' +
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNoteKey + path.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNoteKey + path.sep + 'pdf.pdf](pdf})'
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + oldNoteKey + path.win32.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + oldNoteKey + path.posix.sep + 'pdf.pdf](pdf})'
const expectedOutput =
'Test input' +
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + 'image.jpg](imageName}) \n' +
@@ -400,9 +631,11 @@ it('should test that cloneAttachments modifies the content of the new note corre
const newNote = {key: 'newNoteKey', content: 'oldNoteContent', storage: 'storageKey', type: 'MARKDOWN_NOTE'}
const testInput =
'Test input' +
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNote.key + path.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNote.key + path.sep + 'pdf.pdf](pdf})'
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + oldNote.key + path.win32.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + oldNote.key + path.posix.sep + 'pdf.pdf](pdf})'
newNote.content = testInput
findStorage.findStorage = jest.fn()
findStorage.findStorage.mockReturnValue({path: 'dummyStoragePath'})
const expectedOutput =
'Test input' +
@@ -422,8 +655,8 @@ it('should test that cloneAttachments finds all attachments and copies them to t
const newNote = {key: 'newNoteKey', content: 'oldNoteContent', storage: 'storageKeyNewNote', type: 'MARKDOWN_NOTE'}
const testInput =
'Test input' +
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNote.key + path.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNote.key + path.sep + 'pdf.pdf](pdf})'
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + oldNote.key + path.win32.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + oldNote.key + path.posix.sep + 'pdf.pdf](pdf})'
oldNote.content = testInput
newNote.content = testInput
@@ -467,3 +700,288 @@ it('should test that cloneAttachments finds all attachments and copies them to t
expect(findStorage.findStorage).not.toHaveBeenCalled()
expect(sander.copyFileSync).not.toHaveBeenCalled()
})
it('should test that isAttachmentLink works correctly', function () {
expect(systemUnderTest.isAttachmentLink('text')).toBe(false)
expect(systemUnderTest.isAttachmentLink('text [linkText](link)')).toBe(false)
expect(systemUnderTest.isAttachmentLink('text ![linkText](link)')).toBe(false)
expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf)')).toBe(true)
expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf )')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text [ linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf)')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text ![linkText ](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf)')).toBe(true)
expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text [linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text ![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf)')).toBe(true)
expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf )')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text [ linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf)')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text ![linkText ](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf)')).toBe(true)
expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text [linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true)
expect(systemUnderTest.isAttachmentLink('text ![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true)
})
it('should test that handleAttachmentLinkPaste copies the attachments to the new location', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf)'
const storageKey = 'storageKey'
const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf')
sander.exists = jest.fn(() => Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName'))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then(() => {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath)
expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePath, storageKey, newNoteKey)
})
})
it('should test that handleAttachmentLinkPaste copies the attachments to the new location - win32 path', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf)'
const storageKey = 'storageKey'
const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf')
sander.exists = jest.fn(() => Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName'))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then(() => {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath)
expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePath, storageKey, newNoteKey)
})
})
it('should test that handleAttachmentLinkPaste don\'t try to copy the file if it does not exist - win32 path', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf)'
const storageKey = 'storageKey'
const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf')
sander.exists = jest.fn(() => Promise.resolve(false))
systemUnderTest.copyAttachment = jest.fn()
systemUnderTest.generateFileNotFoundMarkdown = jest.fn()
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then(() => {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath)
expect(systemUnderTest.copyAttachment).not.toHaveBeenCalled()
})
})
it('should test that handleAttachmentLinkPaste don\'t try to copy the file if it does not exist -- posix', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf)'
const storageKey = 'storageKey'
const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf')
sander.exists = jest.fn(() => Promise.resolve(false))
systemUnderTest.copyAttachment = jest.fn()
systemUnderTest.generateFileNotFoundMarkdown = jest.fn()
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then(() => {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath)
expect(systemUnderTest.copyAttachment).not.toHaveBeenCalled()
})
})
it('should test that handleAttachmentLinkPaste copies multiple attachments if multiple were pasted', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf) ..' +
'![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'img.jpg)'
const storageKey = 'storageKey'
const expectedSourceFilePathOne = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf')
const expectedSourceFilePathTwo = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'img.jpg')
sander.exists = jest.fn(() => Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName'))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then(() => {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathOne)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathTwo)
expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePathOne, storageKey, newNoteKey)
expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePathTwo, storageKey, newNoteKey)
})
})
it('should test that handleAttachmentLinkPaste returns the correct modified paste text', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const dummyNewFileName = 'dummyNewFileName'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf)'
const expectedText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyNewFileName + ')'
const storageKey = 'storageKey'
sander.exists = jest.fn(() => Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve(dummyNewFileName))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then((returnedPastedText) => {
expect(returnedPastedText).toBe(expectedText)
})
})
it('should test that handleAttachmentLinkPaste returns the correct modified paste text if multiple links are posted', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const dummyNewFileNameOne = 'dummyNewFileName'
const dummyNewFileNameTwo = 'dummyNewFileNameTwo'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf) ' +
'![secondImage](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'img.jpg)'
const expectedText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyNewFileNameOne + ') ' +
'![secondImage](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyNewFileNameTwo + ')'
const storageKey = 'storageKey'
sander.exists = jest.fn(() => Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn()
systemUnderTest.copyAttachment.mockReturnValueOnce(Promise.resolve(dummyNewFileNameOne))
systemUnderTest.copyAttachment.mockReturnValue(Promise.resolve(dummyNewFileNameTwo))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then((returnedPastedText) => {
expect(returnedPastedText).toBe(expectedText)
})
})
it('should test that handleAttachmentLinkPaste calls the copy method correct if multiple links are posted where one file was found and one was not', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf) ..' +
'![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'img.jpg)'
const storageKey = 'storageKey'
const expectedSourceFilePathOne = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf')
const expectedSourceFilePathTwo = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'img.jpg')
sander.exists = jest.fn()
sander.exists.mockReturnValueOnce(Promise.resolve(false))
sander.exists.mockReturnValue(Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName'))
systemUnderTest.generateFileNotFoundMarkdown = jest.fn()
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then(() => {
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathOne)
expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathTwo)
expect(systemUnderTest.copyAttachment).toHaveBeenCalledTimes(1)
expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePathTwo, storageKey, newNoteKey)
})
})
it('should test that handleAttachmentLinkPaste returns the correct modified paste text if the file was not found', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt.png](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf)'
const storageKey = 'storageKey'
const fileNotFoundMD = 'file not found'
const expectedPastText = 'text ' + fileNotFoundMD
systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD)
sander.exists = jest.fn(() => Promise.resolve(false))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then((returnedPastedText) => {
expect(returnedPastedText).toBe(expectedPastText)
})
})
it('should test that handleAttachmentLinkPaste returns the correct modified paste text if multiple files were not found', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf) ' +
'![secondImage](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'img.jpg)'
const storageKey = 'storageKey'
const fileNotFoundMD = 'file not found'
const expectedPastText = 'text ' + fileNotFoundMD + ' ' + fileNotFoundMD
systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD)
sander.exists = jest.fn(() => Promise.resolve(false))
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then((returnedPastedText) => {
expect(returnedPastedText).toBe(expectedPastText)
})
})
it('should test that handleAttachmentLinkPaste returns the correct modified paste text if one file was found and one was not found', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const dummyFoundFileName = 'dummyFileName'
const fileNotFoundMD = 'file not found'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf) .. ' +
'![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'img.jpg)'
const storageKey = 'storageKey'
const expectedPastText = 'text ' + fileNotFoundMD + ' .. ![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyFoundFileName + ')'
sander.exists = jest.fn()
sander.exists.mockReturnValueOnce(Promise.resolve(false))
sander.exists.mockReturnValue(Promise.resolve(true))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve(dummyFoundFileName))
systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD)
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then((returnedPastedText) => {
expect(returnedPastedText).toBe(expectedPastText)
})
})
it('should test that handleAttachmentLinkPaste returns the correct modified paste text if one file was found and one was not found', function () {
const dummyStorage = {path: 'dummyStoragePath'}
findStorage.findStorage = jest.fn(() => dummyStorage)
const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723'
const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723'
const dummyFoundFileName = 'dummyFileName'
const fileNotFoundMD = 'file not found'
const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf) .. ' +
'![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'img.jpg)'
const storageKey = 'storageKey'
const expectedPastText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyFoundFileName + ') .. ' + fileNotFoundMD
sander.exists = jest.fn()
sander.exists.mockReturnValueOnce(Promise.resolve(true))
sander.exists.mockReturnValue(Promise.resolve(false))
systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve(dummyFoundFileName))
systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD)
return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText)
.then((returnedPastedText) => {
expect(returnedPastedText).toBe(expectedPastText)
})
})

View File

@@ -0,0 +1,35 @@
const test = require('ava')
const copyFile = require('browser/main/lib/dataApi/copyFile')
const path = require('path')
const fs = require('fs')
const testFile = 'test.txt'
const srcFolder = path.join(__dirname, '🤔')
const srcPath = path.join(srcFolder, testFile)
const dstFolder = path.join(__dirname, '😇')
const dstPath = path.join(dstFolder, testFile)
test.before((t) => {
if (!fs.existsSync(srcFolder)) fs.mkdirSync(srcFolder)
fs.writeFileSync(srcPath, 'test')
})
test('`copyFile` should handle encoded URI on src path', (t) => {
return copyFile(encodeURI(srcPath), dstPath)
.then(() => {
t.true(true)
})
.catch(() => {
t.true(false)
})
})
test.after((t) => {
fs.unlinkSync(srcPath)
fs.unlinkSync(dstPath)
fs.rmdirSync(srcFolder)
fs.rmdirSync(dstFolder)
})

View File

@@ -25,13 +25,16 @@ test.serial('Create a note', (t) => {
const storageKey = t.context.storage.cache.key
const folderKey = t.context.storage.json.folders[0].key
const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
const input1 = {
type: 'SNIPPET_NOTE',
description: faker.lorem.lines(),
snippets: [{
name: faker.system.fileName(),
mode: 'text',
content: faker.lorem.lines()
content: faker.lorem.lines(),
linesHighlighted: randLinesHighlightedArray
}],
tags: faker.lorem.words().split(' '),
folder: folderKey
@@ -42,7 +45,8 @@ test.serial('Create a note', (t) => {
type: 'MARKDOWN_NOTE',
content: faker.lorem.lines(),
tags: faker.lorem.words().split(' '),
folder: folderKey
folder: folderKey,
linesHighlighted: randLinesHighlightedArray
}
input2.title = input2.content.split('\n').shift()
@@ -59,6 +63,7 @@ test.serial('Create a note', (t) => {
t.is(storageKey, data1.storage)
const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
t.is(input1.title, data1.title)
t.is(input1.title, jsonData1.title)
t.is(input1.description, data1.description)
@@ -71,6 +76,8 @@ test.serial('Create a note', (t) => {
t.is(input1.snippets[0].content, jsonData1.snippets[0].content)
t.is(input1.snippets[0].name, data1.snippets[0].name)
t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
t.deepEqual(input1.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted)
t.deepEqual(input1.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted)
t.is(storageKey, data2.storage)
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
@@ -80,6 +87,8 @@ test.serial('Create a note', (t) => {
t.is(input2.content, jsonData2.content)
t.is(input2.tags.length, data2.tags.length)
t.is(input2.tags.length, jsonData2.tags.length)
t.deepEqual(input2.linesHighlighted, data2.linesHighlighted)
t.deepEqual(input2.linesHighlighted, jsonData2.linesHighlighted)
})
})

View File

@@ -12,7 +12,7 @@ const TestDummy = require('../fixtures/TestDummy')
const sander = require('sander')
const os = require('os')
const CSON = require('@rokt33r/season')
const faker = require('faker')
// const faker = require('faker')
const storagePath = path.join(os.tmpdir(), 'test/create-note-from-url')
@@ -42,10 +42,10 @@ test.serial('Create a note from URL', (t) => {
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
// <<<<<< fix me - input2 & data not defined
t.is(input2.content, data2.content)
/* t.is(input2.content, data2.content)
t.is(input2.content, jsonData2.content)
t.is(input2.tags.length, data2.tags.length)
t.is(input2.tags.length, jsonData2.tags.length)
t.is(input2.tags.length, jsonData2.tags.length) */
})
})

View File

@@ -0,0 +1,35 @@
const test = require('ava')
const createSnippet = require('browser/main/lib/dataApi/createSnippet')
const sander = require('sander')
const os = require('os')
const path = require('path')
const snippetFilePath = path.join(os.tmpdir(), 'test', 'create-snippet')
const snippetFile = path.join(snippetFilePath, 'snippets.json')
test.beforeEach((t) => {
sander.writeFileSync(snippetFile, '[]')
})
test.serial('Create a snippet', (t) => {
return Promise.resolve()
.then(function doTest () {
return Promise.all([
createSnippet(snippetFile)
])
})
.then(function assert (data) {
data = data[0]
const snippets = JSON.parse(sander.readFileSync(snippetFile))
const snippet = snippets.find(currentSnippet => currentSnippet.id === data.id)
t.not(snippet, undefined)
t.is(snippet.name, data.name)
t.deepEqual(snippet.prefix, data.prefix)
t.is(snippet.content, data.content)
t.deepEqual(snippet.linesHighlighted, data.linesHighlighted)
})
})
test.after.always(() => {
sander.rimrafSync(snippetFilePath)
})

View File

@@ -0,0 +1,37 @@
const test = require('ava')
const deleteSnippet = require('browser/main/lib/dataApi/deleteSnippet')
const sander = require('sander')
const os = require('os')
const path = require('path')
const crypto = require('crypto')
const snippetFilePath = path.join(os.tmpdir(), 'test', 'delete-snippet')
const snippetFile = path.join(snippetFilePath, 'snippets.json')
const newSnippet = {
id: crypto.randomBytes(16).toString('hex'),
name: 'Unnamed snippet',
prefix: [],
content: ''
}
test.beforeEach((t) => {
sander.writeFileSync(snippetFile, JSON.stringify([newSnippet]))
})
test.serial('Delete a snippet', (t) => {
return Promise.resolve()
.then(function doTest () {
return Promise.all([
deleteSnippet(newSnippet, snippetFile)
])
})
.then(function assert (data) {
data = data[0]
const snippets = JSON.parse(sander.readFileSync(snippetFile))
t.is(snippets.length, 0)
})
})
test.after.always(() => {
sander.rimrafSync(snippetFilePath)
})

View File

@@ -0,0 +1,52 @@
const test = require('ava')
const exportStorage = require('browser/main/lib/dataApi/exportStorage')
global.document = require('jsdom').jsdom('<body></body>')
global.window = document.defaultView
global.navigator = window.navigator
const Storage = require('dom-storage')
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
const path = require('path')
const TestDummy = require('../fixtures/TestDummy')
const os = require('os')
const fs = require('fs')
const sander = require('sander')
test.beforeEach(t => {
t.context.storageDir = path.join(os.tmpdir(), 'test/export-storage')
t.context.storage = TestDummy.dummyStorage(t.context.storageDir)
t.context.exportDir = path.join(os.tmpdir(), 'test/export-storage-output')
try { fs.mkdirSync(t.context.exportDir) } catch (e) {}
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
})
test.serial('Export a storage', t => {
const storageKey = t.context.storage.cache.key
const folders = t.context.storage.json.folders
const notes = t.context.storage.notes
const exportDir = t.context.exportDir
const folderKeyToName = folders.reduce(
(acc, folder) => {
acc[folder.key] = folder.name
return acc
}, {})
return exportStorage(storageKey, 'md', exportDir)
.then(() => {
notes.forEach(note => {
const noteDir = path.join(exportDir, folderKeyToName[note.folder], `${note.title}.md`)
if (note.type === 'MARKDOWN_NOTE') {
t.true(fs.existsSync(noteDir))
t.is(fs.readFileSync(noteDir, 'utf8'), note.content)
} else if (note.type === 'SNIPPET_NOTE') {
t.false(fs.existsSync(noteDir))
}
})
})
})
test.afterEach.always(t => {
localStorage.clear()
sander.rimrafSync(t.context.storageDir)
sander.rimrafSync(t.context.exportDir)
})

View File

@@ -0,0 +1,38 @@
const test = require('ava')
const toggleStorage = require('browser/main/lib/dataApi/toggleStorage')
global.document = require('jsdom').jsdom('<body></body>')
global.window = document.defaultView
global.navigator = window.navigator
const Storage = require('dom-storage')
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
const path = require('path')
const _ = require('lodash')
const TestDummy = require('../fixtures/TestDummy')
const sander = require('sander')
const os = require('os')
const storagePath = path.join(os.tmpdir(), 'test/toggle-storage')
test.beforeEach((t) => {
t.context.storage = TestDummy.dummyStorage(storagePath)
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
})
test.serial('Toggle a storage location', (t) => {
const storageKey = t.context.storage.cache.key
return Promise.resolve()
.then(function doTest () {
return toggleStorage(storageKey, true)
})
.then(function assert (data) {
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
t.true(_.find(cachedStorageList, {key: storageKey}).isOpen === true)
})
})
test.after(function after () {
localStorage.clear()
sander.rimrafSync(storagePath)
})

View File

@@ -26,13 +26,17 @@ test.serial('Update a note', (t) => {
const storageKey = t.context.storage.cache.key
const folderKey = t.context.storage.json.folders[0].key
const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
const randLinesHighlightedArray2 = new Array(15).fill().map(() => Math.round(Math.random() * 15))
const input1 = {
type: 'SNIPPET_NOTE',
description: faker.lorem.lines(),
snippets: [{
name: faker.system.fileName(),
mode: 'text',
content: faker.lorem.lines()
content: faker.lorem.lines(),
linesHighlighted: randLinesHighlightedArray
}],
tags: faker.lorem.words().split(' '),
folder: folderKey
@@ -43,7 +47,8 @@ test.serial('Update a note', (t) => {
type: 'MARKDOWN_NOTE',
content: faker.lorem.lines(),
tags: faker.lorem.words().split(' '),
folder: folderKey
folder: folderKey,
linesHighlighted: randLinesHighlightedArray
}
input2.title = input2.content.split('\n').shift()
@@ -53,7 +58,8 @@ test.serial('Update a note', (t) => {
snippets: [{
name: faker.system.fileName(),
mode: 'text',
content: faker.lorem.lines()
content: faker.lorem.lines(),
linesHighlighted: randLinesHighlightedArray2
}],
tags: faker.lorem.words().split(' ')
}
@@ -62,7 +68,8 @@ test.serial('Update a note', (t) => {
const input4 = {
type: 'MARKDOWN_NOTE',
content: faker.lorem.lines(),
tags: faker.lorem.words().split(' ')
tags: faker.lorem.words().split(' '),
linesHighlighted: randLinesHighlightedArray2
}
input4.title = input4.content.split('\n').shift()
@@ -99,6 +106,8 @@ test.serial('Update a note', (t) => {
t.is(input3.snippets[0].content, jsonData1.snippets[0].content)
t.is(input3.snippets[0].name, data1.snippets[0].name)
t.is(input3.snippets[0].name, jsonData1.snippets[0].name)
t.deepEqual(input3.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted)
t.deepEqual(input3.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted)
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
t.is(input4.title, data2.title)
@@ -107,6 +116,8 @@ test.serial('Update a note', (t) => {
t.is(input4.content, jsonData2.content)
t.is(input4.tags.length, data2.tags.length)
t.is(input4.tags.length, jsonData2.tags.length)
t.deepEqual(input4.linesHighlighted, data2.linesHighlighted)
t.deepEqual(input4.linesHighlighted, jsonData2.linesHighlighted)
})
})

View File

@@ -0,0 +1,47 @@
const test = require('ava')
const updateSnippet = require('browser/main/lib/dataApi/updateSnippet')
const sander = require('sander')
const os = require('os')
const path = require('path')
const crypto = require('crypto')
const snippetFilePath = path.join(os.tmpdir(), 'test', 'update-snippet')
const snippetFile = path.join(snippetFilePath, 'snippets.json')
const oldSnippet = {
id: crypto.randomBytes(16).toString('hex'),
name: 'Initial snippet',
prefix: [],
content: ''
}
const newSnippet = {
id: oldSnippet.id,
name: 'new name',
prefix: ['prefix'],
content: 'new content'
}
test.beforeEach((t) => {
sander.writeFileSync(snippetFile, JSON.stringify([oldSnippet]))
})
test.serial('Update a snippet', (t) => {
return Promise.resolve()
.then(function doTest () {
return Promise.all([
updateSnippet(newSnippet, snippetFile)
])
})
.then(function assert () {
const snippets = JSON.parse(sander.readFileSync(snippetFile))
const snippet = snippets.find(currentSnippet => currentSnippet.id === newSnippet.id)
t.not(snippet, undefined)
t.is(snippet.name, newSnippet.name)
t.deepEqual(snippet.prefix, newSnippet.prefix)
t.is(snippet.content, newSnippet.content)
})
})
test.after.always(() => {
sander.rimrafSync(snippetFilePath)
})

View File

@@ -50,11 +50,70 @@ const smartQuotes = 'This is a "QUOTE".'
const breaks = 'This is the first line.\nThis is the second line.'
const abbrevations = `
## abbr
The HTML specification
is maintained by the W3C.
*[HTML]: Hyper Text Markup Language
*[W3C]: World Wide Web Consortium
`
const subTexts = `
## sub
H~2~0
`
const supTexts = `
## sup
29^th^
`
const deflists = `
## definition list
### list 1
Term 1
~ Definition 1
Term 2
~ Definition 2a
~ Definition 2b
Term 3
~
### list 2
Term 1
: Definition 1
Term 2 with *inline markup*
: Definition 2
{ some code, part of Definition 2 }
Third paragraph of definition 2.
`
const shortcuts = '<kbd>Ctrl</kbd>\n\n[[Ctrl]]'
export default {
basic,
codeblock,
katex,
checkboxes,
smartQuotes,
breaks
breaks,
abbrevations,
subTexts,
supTexts,
deflists,
shortcuts
}

View File

@@ -1,5 +1,23 @@
import browserEnv from 'browser-env'
browserEnv(['window', 'document'])
browserEnv(['window', 'document', 'navigator'])
// for CodeMirror mockup
document.body.createTextRange = function () {
return {
setEnd: function () {},
setStart: function () {},
getBoundingClientRect: function () {
return {right: 0}
},
getClientRects: function () {
return {
length: 0,
left: 0,
right: 0
}
}
}
}
window.localStorage = {
// polyfill

View File

@@ -0,0 +1,126 @@
let menuBuilderParameter
jest.mock('electron', () => {
return {remote: {require: jest.fn(() => { return {Menu: {buildFromTemplate: jest.fn((param) => { menuBuilderParameter = param })}} })}}
})
const spellcheck = require('browser/lib/spellcheck')
const buildEditorContextMenu = require('browser/lib/contextMenuBuilder')
beforeEach(() => {
menuBuilderParameter = null
})
it('should make sure that no context menu is build if the passed editor instance was null', function () {
const event = {
pageX: 12,
pageY: 12
}
buildEditorContextMenu(null, event)
expect(menuBuilderParameter).toEqual(null)
})
it('should make sure that word suggestions are only requested if the word contained a typo', function () {
spellcheck.getSpellingSuggestion = jest.fn()
const editor = jest.fn()
editor.coordsChar = jest.fn()
editor.findWordAt = jest.fn(() => { return {anchor: {}, head: {}} })
editor.getRange = jest.fn()
editor.findMarks = jest.fn(() => [])
const event = {
pageX: 12,
pageY: 12
}
const expectedMenuParameter = [ { role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'selectall' } ]
buildEditorContextMenu(editor, event)
expect(menuBuilderParameter).toEqual(expectedMenuParameter)
expect(spellcheck.getSpellingSuggestion).not.toHaveBeenCalled()
})
it('should make sure that word suggestions are only requested if the word contained a typo and no other mark', function () {
spellcheck.getSpellingSuggestion = jest.fn()
spellcheck.getCSSClassName = jest.fn(() => 'dummyErrorClassName')
const editor = jest.fn()
editor.coordsChar = jest.fn()
editor.findWordAt = jest.fn(() => { return {anchor: {}, head: {}} })
editor.getRange = jest.fn()
const dummyMarks = [
{className: 'someStupidClassName'}
]
editor.findMarks = jest.fn(() => dummyMarks)
const event = {
pageX: 12,
pageY: 12
}
const expectedMenuParameter = [ { role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'selectall' } ]
buildEditorContextMenu(editor, event)
expect(menuBuilderParameter).toEqual(expectedMenuParameter)
expect(spellcheck.getSpellingSuggestion).not.toHaveBeenCalled()
})
it('should make sure that word suggestions calls the right editor functions', function () {
spellcheck.getSpellingSuggestion = jest.fn()
spellcheck.getCSSClassName = jest.fn(() => 'dummyErrorClassName')
const dummyCursor = {dummy: 'dummy'}
const dummyRange = {anchor: {test: 'test'}, head: {test2: 'test2'}}
const editor = jest.fn()
editor.coordsChar = jest.fn(() => dummyCursor)
editor.findWordAt = jest.fn(() => dummyRange)
editor.getRange = jest.fn()
const dummyMarks = [
{className: 'someStupidClassName'}
]
editor.findMarks = jest.fn(() => dummyMarks)
const event = {
pageX: 12,
pageY: 21
}
const expectedCoordsCharCall = {left: event.pageX, top: event.pageY}
buildEditorContextMenu(editor, event)
expect(editor.coordsChar).toHaveBeenCalledWith(expectedCoordsCharCall)
expect(editor.findWordAt).toHaveBeenCalledWith(dummyCursor)
expect(editor.getRange).toHaveBeenCalledWith(dummyRange.anchor, dummyRange.head)
})
it('should make sure that word suggestions creates a correct menu if there was an error', function () {
const suggestions = ['test1', 'test2', 'Pustekuchen']
const errorClassName = 'errorCSS'
const wordToCorrect = 'pustekuchen'
const dummyMarks = [
{className: errorClassName}
]
spellcheck.getSpellingSuggestion = jest.fn(() => suggestions)
spellcheck.getCSSClassName = jest.fn(() => errorClassName)
const editor = jest.fn()
editor.coordsChar = jest.fn()
editor.findWordAt = jest.fn(() => { return {anchor: {}, head: {}} })
editor.getRange = jest.fn(() => wordToCorrect)
editor.findMarks = jest.fn(() => [])
editor.findMarks = jest.fn(() => dummyMarks)
const event = {
pageX: 12,
pageY: 12
}
buildEditorContextMenu(editor, event)
expect(menuBuilderParameter[0].label).toEqual(suggestions[0])
expect(menuBuilderParameter[0].click).not.toBeNull()
expect(menuBuilderParameter[1].label).toEqual(suggestions[1])
expect(menuBuilderParameter[1].click).not.toBeNull()
expect(menuBuilderParameter[2].label).toEqual(suggestions[2])
expect(menuBuilderParameter[2].click).not.toBeNull()
expect(menuBuilderParameter[3].type).toEqual('separator')
expect(menuBuilderParameter[4].role).toEqual('cut')
expect(menuBuilderParameter[5].role).toEqual('copy')
expect(menuBuilderParameter[6].role).toEqual('paste')
expect(menuBuilderParameter[7].role).toEqual('selectall')
expect(spellcheck.getSpellingSuggestion).toHaveBeenCalledWith(wordToCorrect)
})

View File

@@ -0,0 +1,73 @@
const { escapeHtmlCharacters } = require('browser/lib/utils')
const test = require('ava')
test('escapeHtmlCharacters should return the original string if nothing needed to escape', t => {
const input = 'Nothing to be escaped'
const expected = 'Nothing to be escaped'
const actual = escapeHtmlCharacters(input)
t.is(actual, expected)
})
test('escapeHtmlCharacters should skip code block if that option is enabled', t => {
const input = ` <no escape>
<escapeMe>`
const expected = ` <no escape>
&lt;escapeMe&gt;`
const actual = escapeHtmlCharacters(input, { detectCodeBlock: true })
t.is(actual, expected)
})
test('escapeHtmlCharacters should NOT skip character not in code block but start with 4 spaces', t => {
const input = '4 spaces &'
const expected = '4 spaces &amp;'
const actual = escapeHtmlCharacters(input, { detectCodeBlock: true })
t.is(actual, expected)
})
test('escapeHtmlCharacters should NOT skip code block if that option is NOT enabled', t => {
const input = ` <no escape>
<escapeMe>`
const expected = ` &lt;no escape&gt;
&lt;escapeMe&gt;`
const actual = escapeHtmlCharacters(input)
t.is(actual, expected)
})
test("escapeHtmlCharacters should NOT escape & character if it's a part of an escaped character", t => {
const input = 'Do not escape &amp; or &quot; but do escape &'
const expected = 'Do not escape &amp; or &quot; but do escape &amp;'
const actual = escapeHtmlCharacters(input)
t.is(actual, expected)
})
test('escapeHtmlCharacters should skip char if in code block', t => {
const input = `
\`\`\`
<dontescapeme>
\`\`\`
das<das>dasd
dasdasdasd
\`\`\`
<dontescapeme>
\`\`\`
`
const expected = `
\`\`\`
<dontescapeme>
\`\`\`
das&lt;das&gt;dasd
dasdasdasd
\`\`\`
<dontescapeme>
\`\`\`
`
const actual = escapeHtmlCharacters(input, { detectCodeBlock: true })
t.is(actual, expected)
})
test('escapeHtmlCharacters should return the correct result', t => {
const input = '& < > " \''
const expected = '&amp; &lt; &gt; &quot; &#39;'
const actual = escapeHtmlCharacters(input)
t.is(actual, expected)
})

View File

@@ -14,12 +14,53 @@ test('findNoteTitle#find should return a correct title (string)', t => {
['hoge\n====\nfuga', 'hoge'],
['====', '===='],
['```\n# hoge\n```', '```'],
['hoge', 'hoge']
['hoge', 'hoge'],
['---\nlayout: test\n---\n # hoge', '# hoge']
]
testCases.forEach(testCase => {
const [input, expected] = testCase
t.is(findNoteTitle(input), expected, `Test for find() input: ${input} expected: ${expected}`)
t.is(findNoteTitle(input, false), expected, `Test for find() input: ${input} expected: ${expected}`)
})
})
test('findNoteTitle#find should ignore front matter when enableFrontMatterTitle=false', t => {
// [input, expected]
const testCases = [
['---\nlayout: test\ntitle: hoge hoge hoge \n---\n# fuga', '# fuga'],
['---\ntitle:hoge\n---\n# fuga', '# fuga'],
['title: fuga\n# hoge', '# hoge']
]
testCases.forEach(testCase => {
const [input, expected] = testCase
t.is(findNoteTitle(input, false), expected, `Test for find() input: ${input} expected: ${expected}`)
})
})
test('findNoteTitle#find should respect front matter when enableFrontMatterTitle=true', t => {
// [input, expected]
const testCases = [
['---\nlayout: test\ntitle: hoge hoge hoge \n---\n# fuga', 'hoge hoge hoge'],
['---\ntitle:hoge\n---\n# fuga', 'hoge'],
['title: fuga\n# hoge', '# hoge']
]
testCases.forEach(testCase => {
const [input, expected] = testCase
t.is(findNoteTitle(input, true), expected, `Test for find() input: ${input} expected: ${expected}`)
})
})
test('findNoteTitle#find should respect frontMatterTitleField when provided', t => {
// [input, expected]
const testCases = [
['---\ntitle: hoge\n---\n# fuga', '# fuga'],
['---\ncustom: hoge\n---\n# fuga', 'hoge']
]
testCases.forEach(testCase => {
const [input, expected] = testCase
t.is(findNoteTitle(input, true, 'custom'), expected, `Test for find() input: ${input} expected: ${expected}`)
})
})

View File

@@ -12,11 +12,30 @@ test('getTodoStatus should return a correct hash object', t => {
['- [ ] a\n- [x] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n+ [X] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n+ [testx] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ [xtest] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ foo[x]bar a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ foo[x] bar a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ foo [x]bar a\n', { total: 1, completed: 0 }]
['+ [ ] a\n+ foo [x]bar a\n', { total: 1, completed: 0 }],
['* [ ] `- [ ] a`\n', { total: 1, completed: 0 }],
['+ [ ] `- [ ] a`\n', { total: 1, completed: 0 }],
['- [ ] `- [ ] a`\n', { total: 1, completed: 0 }],
['- [ ] `- [x] a`\n', { total: 1, completed: 0 }],
['- [ ] `- [X] a`\n', { total: 1, completed: 0 }],
['- [x] `- [ ] a`\n', { total: 1, completed: 1 }],
['- [X] `- [ ] a`\n', { total: 1, completed: 1 }],
['- [x] `- [x] a`\n', { total: 1, completed: 1 }],
['- [X] `- [X] a`\n', { total: 1, completed: 1 }],
[' \t - [X] `- [X] a`\n', { total: 1, completed: 1 }],
[' \t - [X] `- [X] a`\n \t - [ ] `- [X] a`\n', { total: 2, completed: 1 }],
['> - [ ] a\n', { total: 1, completed: 0 }],
['> - [ ] a\n- [x] a\n', { total: 2, completed: 1 }],
['> + [ ] a\n+ foo [x]bar a\n', { total: 1, completed: 0 }],
['> - [X] `- [X] a`\n', { total: 1, completed: 1 }],
['> \t - [X] `- [X] a`\n', { total: 1, completed: 1 }],
['> > - [ ] a\n', { total: 1, completed: 0 }],
['> > > - [ ] a\n- [x] a\n', { total: 2, completed: 1 }]
]
testCases.forEach(testCase => {

View File

@@ -43,3 +43,28 @@ test('Markdown.render() should render line breaks correctly', t => {
const renderedNonBreaks = newmd.render(markdownFixtures.breaks)
t.snapshot(renderedNonBreaks)
})
test('Markdown.render() should renders abbrevations correctly', t => {
const rendered = md.render(markdownFixtures.abbrevations)
t.snapshot(rendered)
})
test('Markdown.render() should renders sub correctly', t => {
const rendered = md.render(markdownFixtures.subTexts)
t.snapshot(rendered)
})
test('Markdown.render() should renders sup correctly', t => {
const rendered = md.render(markdownFixtures.supTexts)
t.snapshot(rendered)
})
test('Markdown.render() should renders definition lists correctly', t => {
const rendered = md.render(markdownFixtures.deflists)
t.snapshot(rendered)
})
test('Markdown.render() should render shortcuts correctly', t => {
const rendered = md.render(markdownFixtures.shortcuts)
t.snapshot(rendered)
})

View File

@@ -36,7 +36,8 @@ test(t => {
['`MY_TITLE`', 'MY_TITLE'],
['MY_TITLE', 'MY_TITLE'],
// I have no idea for it...
['```test', '`test']
['```test', '`test'],
['# C# Features', 'C# Features']
]
testCases.forEach(testCase => {

View File

@@ -0,0 +1,668 @@
/**
* @fileoverview Unit test for browser/lib/markdown-toc-generator
*/
import CodeMirror from 'codemirror'
require('codemirror/addon/search/searchcursor.js')
const test = require('ava')
const markdownToc = require('browser/lib/markdown-toc-generator')
const EOL = require('os').EOL
test(t => {
/**
* Contains array of test cases in format :
* [
* test title
* input markdown,
* expected toc
* ]
* @type {*[]}
*/
const testCases = [
[
'***************************** empty note',
`
`,
`
<!-- toc -->
<!-- tocstop -->
`
],
[
'***************************** single level',
`
# one
`,
`
<!-- toc -->
- [one](#one)
<!-- tocstop -->
`
],
[
'***************************** two levels',
`
# one
# two
`,
`
<!-- toc -->
- [one](#one)
- [two](#two)
<!-- tocstop -->
`
],
[
'***************************** 3 levels with children',
`
# one
## one one
# two
## two two
# three
## three three
`,
`
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
- [three](#three)
* [three three](#three-three)
<!-- tocstop -->
`
],
[
'***************************** 3 levels, 3rd with 6 sub-levels',
`
# one
## one one
# two
## two two
# three
## three three
### three three three
#### three three three three
##### three three three three three
###### three three three three three three
`,
`
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
- [three](#three)
* [three three](#three-three)
+ [three three three](#three-three-three)
- [three three three three](#three-three-three-three)
* [three three three three three](#three-three-three-three-three)
+ [three three three three three three](#three-three-three-three-three-three)
<!-- tocstop -->
`
],
[
'***************************** multilevel with texts in between',
`
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
# three
this is a level three three text
this is a level three three text
## three three
this is a text
this is a text
### three three three
this is a text
this is a text
### three three three 2
this is a text
this is a text
#### three three three three
this is a text
this is a text
#### three three three three 2
this is a text
this is a text
##### three three three three three
this is a text
this is a text
##### three three three three three 2
this is a text
this is a text
###### three three three three three three
this is a text
this is a text
this is a text
`,
`
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
- [three](#three)
* [three three](#three-three)
+ [three three three](#three-three-three)
+ [three three three 2](#three-three-three-2)
- [three three three three](#three-three-three-three)
- [three three three three 2](#three-three-three-three-2)
* [three three three three three](#three-three-three-three-three)
* [three three three three three 2](#three-three-three-three-three-2)
+ [three three three three three three](#three-three-three-three-three-three)
<!-- tocstop -->
`
],
[
'***************************** outdated TOC',
`
<!-- toc -->
- [one](#one)
* [one one](#one-one)
<!-- tocstop -->
# one modified
## one one
`,
`
<!-- toc -->
- [one modified](#one-modified)
* [one one](#one-one)
<!-- tocstop -->
`
],
[
'***************************** properly generated case sensitive TOC',
`
# onE
## oNe one
`,
`
<!-- toc -->
- [onE](#onE)
* [oNe one](#oNe-one)
<!-- tocstop -->
`
],
[
'***************************** position of TOC is stable (do not use elements above toc marker)',
`
# title
this is a text
<!-- toc -->
- [onE](#onE)
* [oNe one](#oNe-one)
<!-- tocstop -->
# onE
## oNe one
`,
`
<!-- toc -->
- [onE](#onE)
* [oNe one](#oNe-one)
<!-- tocstop -->
`
],
[
'***************************** properly handle generation of not completed TOC',
`
# hoge
##
`,
`
<!-- toc -->
- [hoge](#hoge)
<!-- tocstop -->
`
]
]
testCases.forEach(testCase => {
const title = testCase[0]
const inputMd = testCase[1].trim()
const expectedToc = testCase[2].trim()
const generatedToc = markdownToc.generate(inputMd)
t.is(generatedToc, expectedToc, `generate test : ${title} , generated : ${EOL}${generatedToc}, expected : ${EOL}${expectedToc}`)
})
})
test(t => {
/**
* Contains array of test cases in format :
* [
* title
* cursor
* inputMd
* expectedMd
* ]
* @type {*[]}
*/
const testCases = [
[
`***************************** Empty note, cursor at the top`,
{line: 0, ch: 0},
``,
`
<!-- toc -->
<!-- tocstop -->
`
],
[
`***************************** Two level note,TOC at the beginning `,
{line: 0, ch: 0},
`
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`
],
[
`***************************** Two level note, cursor just after 'header text' `,
{line: 1, ch: 12},
`
# header
header text
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
# header
header text
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`
],
[
`***************************** Two level note, cursor at empty line under 'header text' `,
{line: 2, ch: 0},
`
# header
header text
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
# header
header text
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`
],
[
`***************************** Two level note, cursor just before 'text' word`,
{line: 1, ch: 8},
`
# header
header text
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
# header
header
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
text
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`
],
[
`***************************** Already generated TOC without header file, regenerate TOC in place, no changes`,
{line: 13, ch: 0},
`
# header
header text
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
# header
header text
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`
],
[
`***************************** Already generated TOC, needs updating in place`,
{line: 0, ch: 0},
`
# header
header text
<!-- toc -->
- [one](#one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# This is the one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
# header
header text
<!-- toc -->
- [This is the one](#This-is-the-one)
* [one one](#one-one)
- [two](#two)
* [two two](#two-two)
<!-- tocstop -->
# This is the one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`
],
[
`***************************** Document with cursor at the last line, expecting empty TOC `,
{line: 13, ch: 30},
`
# header
header text
# This is the one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
`,
`
# header
header text
# This is the one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
<!-- toc -->
<!-- tocstop -->
`
],
[
`***************************** Empty, not actual TOC , should be supplemented with two new points beneath`,
{line: 0, ch: 0},
`
# header
header text
# This is the one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
<!-- toc -->
<!-- tocstop -->
# new point included in toc
## new subpoint
`,
`
# header
header text
# This is the one
this is a level one text
this is a level one text
## one one
# two
this is a level two text
this is a level two text
## two two
this is a level two two text
this is a level two two text
<!-- toc -->
- [new point included in toc](#new-point-included-in-toc)
* [new subpoint](#new-subpoint)
<!-- tocstop -->
# new point included in toc
## new subpoint
`
]
]
testCases.forEach(testCase => {
const title = testCase[0]
const cursor = testCase[1]
const inputMd = testCase[2].trim()
const expectedMd = testCase[3].trim()
const editor = CodeMirror()
editor.setValue(inputMd)
editor.setCursor(cursor)
markdownToc.generateInEditor(editor)
t.is(expectedMd, editor.getValue(), `generateInEditor test : ${title} , generated : ${EOL}${editor.getValue()}, expected : ${EOL}${expectedMd}`)
})
})

View File

@@ -0,0 +1,16 @@
/**
* @fileoverview Unit test for browser/lib/normalizeEditorFontFamily
*/
import test from 'ava'
import normalizeEditorFontFamily from '../../browser/lib/normalizeEditorFontFamily'
import consts from '../../browser/lib/consts'
const defaultEditorFontFamily = consts.DEFAULT_EDITOR_FONT_FAMILY
test('normalizeEditorFontFamily() should return default font family (string[])', t => {
t.is(normalizeEditorFontFamily(), defaultEditorFontFamily.join(', '))
})
test('normalizeEditorFontFamily(["hoge", "huga"]) should return default font family connected with arg.', t => {
const arg = 'font1, font2'
t.is(normalizeEditorFontFamily(arg), `${arg}, ${defaultEditorFontFamily.join(', ')}`)
})

View File

@@ -5,7 +5,7 @@ const { parse } = require('browser/lib/RcParser')
// Unit test
test('RcParser should return a json object', t => {
const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 }
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': { 'default': 'UPDATED_AT' }, 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
// [input, expected]
const validTestCases = [

58
tests/lib/slugify-test.js Normal file
View File

@@ -0,0 +1,58 @@
import test from 'ava'
import slugify from 'browser/lib/slugify'
test('alphabet and digit', t => {
const upperAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const lowerAlphabet = 'abcdefghijklmnopqrstuvwxyz'
const digit = '0123456789'
const testCase = upperAlphabet + lowerAlphabet + digit
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === testCase)
})
test('should delete unavailable symbols', t => {
const availableSymbols = '_-'
const testCase = availableSymbols + '][!\'#$%&()*+,./:;<=>?@\\^{|}~`'
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === availableSymbols)
})
test('should convert from white spaces between words to hyphens', t => {
const testCase = 'This is one'
const expectedString = 'This-is-one'
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === expectedString)
})
test('should remove leading white spaces', t => {
const testCase = ' This is one'
const expectedString = 'This-is-one'
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === expectedString)
})
test('should remove trailing white spaces', t => {
const testCase = 'This is one '
const expectedString = 'This-is-one'
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === expectedString)
})
test('2-byte charactor support', t => {
const testCase = '菠萝芒果テストÀžƁƵ'
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === testCase)
})
test('emoji', t => {
const testCase = '🌸'
const decodeSlug = decodeURI(slugify(testCase))
t.true(decodeSlug === testCase)
})

View File

@@ -18,11 +18,28 @@ Generated by [AVA](https://ava.li).
This is the second line.</p>␊
`
## Markdown.render() should render shortcuts correctly
> Snapshot 1
`<p data-line="0"><kbd>Ctrl</kbd></p>␊
<p data-line="2"><kbd>Ctrl</kbd></p>␊
`
## Markdown.render() should renders KaTeX correctly
> Snapshot 1
`<span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>c</mi><mo>=</mo><mi>p</mi><mi>m</mi><mi>s</mi><mi>q</mi><mi>r</mi><mi>t</mi><mrow><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup></mrow></mrow><annotation encoding="application/x-tex">c = pmsqrt{a^2 + b^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.8641079999999999em;"></span><span class="strut bottom" style="height:1.0585479999999998em;vertical-align:-0.19444em;"></span><span class="base"><span class="mord mathit">c</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mord rule" style="margin-right:0.2777777777777778em;"></span><span class="mord mathit">p</span><span class="mord mathit">m</span><span class="mord mathit">s</span><span class="mord mathit" style="margin-right:0.03588em;">q</span><span class="mord mathit" style="margin-right:0.02778em;">r</span><span class="mord mathit">t</span><span class="mord"><span class="mord"><span class="mord mathit">a</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mord rule" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mord rule" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathit">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></span>␊
`<span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>c</mi><mo>=</mo><mi>p</mi><mi>m</mi><mi>s</mi><mi>q</mi><mi>r</mi><mi>t</mi><mrow><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup></mrow></mrow><annotation encoding="application/x-tex">c = pmsqrt{a^2 + b^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">c</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.0585479999999998em;vertical-align:-0.19444em;"></span><span class="mord mathdefault">p</span><span class="mord mathdefault">m</span><span class="mord mathdefault">s</span><span class="mord mathdefault" style="margin-right:0.03588em;">q</span><span class="mord mathdefault" style="margin-right:0.02778em;">r</span><span class="mord mathdefault">t</span><span class="mord"><span class="mord"><span class="mord mathdefault">a</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathdefault">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></span>␊
`
## Markdown.render() should renders abbrevations correctly
> Snapshot 1
`<h2 id="abbr" data-line="1">abbr</h2>␊
<p data-line="3">The <abbr title="Hyper Text Markup Language">HTML</abbr> specification<br />␊
is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>.</p>␊
`
## Markdown.render() should renders checkboxes
@@ -30,8 +47,8 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
`<ul>␊
<li class="taskListItem"><input type="checkbox" id="checkbox-2" /> Unchecked</li>␊
<li class="taskListItem"><input type="checkbox" checked id="checkbox-3" /> Checked</li>␊
<li class="taskListItem" data-line="1"><input type="checkbox" id="checkbox-2" /> Unchecked</li>␊
<li class="taskListItem checked" data-line="2"><input type="checkbox" checked id="checkbox-3" /> Checked</li>␊
</ul>␊
`
@@ -39,44 +56,94 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
`<pre class="code CodeMirror"><span class="filename">filename.js</span><span class="lineNumber CodeMirror-gutters"><span class="CodeMirror-linenumber">2</span></span><code class="js">var project = 'boostnote';
`<pre class="code CodeMirror" data-line="1">
<span class="filename">filename.js</span>␊
<span class="lineNumber CodeMirror-gutters"><span class="CodeMirror-linenumber">2</span></span>␊
<code class="js">var project = 'boostnote';␊
</code>␊
</pre>`
## Markdown.render() should renders definition lists correctly
> Snapshot 1
`<h2 id="definition-list" data-line="1">definition list</h2>␊
<h3 id="list-1" data-line="3">list 1</h3>␊
<dl>␊
<dt data-line="5">Term 1</dt>␊
<dd data-line="6">Definition 1</dd>␊
<dt data-line="8">Term 2</dt>␊
<dd data-line="9">Definition 2a</dd>␊
<dd data-line="10">Definition 2b</dd>␊
</dl>␊
<p data-line="12">Term 3<br />␊
~</p>␊
<h3 id="list-2" data-line="16">list 2</h3>␊
<dl>␊
<dt data-line="18">Term 1</dt>␊
<dd data-line="20">␊
<p data-line="20">Definition 1</p>␊
</dd>␊
<dt data-line="22">Term 2 with <em>inline markup</em></dt>␊
<dd data-line="24">␊
<p data-line="24">Definition 2</p>␊
<pre><code> { some code, part of Definition 2 }␊
</code></pre>␊
<p data-line="28">Third paragraph of definition 2.</p>␊
</dd>␊
</dl>␊
`
## Markdown.render() should renders markdown correctly
> Snapshot 1
`<h1 data-line="1" id="Welcome-to-Boostnote">Welcome to Boostnote!</h1>␊
<h2 data-line="2" id="Click-here-to-edit-markdown-%F0%9F%91%8B">Click here to edit markdown 👋</h2>␊
`<h1 id="Welcome-to-Boostnote" data-line="1">Welcome to Boostnote!</h1>␊
<h2 id="Click-here-to-edit-markdown" data-line="2">Click here to edit markdown 👋</h2>␊
<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>␊
<h2 data-line="6" id="Docs-%F0%9F%93%9D">Docs 📝</h2>␊
<h2 id="Docs" data-line="6">Docs 📝</h2>␊
<ul>␊
<li><a href="https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe">Boostnote | Boost your happiness, productivity and creativity.</a></li>␊
<li><a href="https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup">Cloud Syncing &amp; Backups</a></li>␊
<li><a href="https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps">How to sync your data across Desktop and Mobile apps</a></li>␊
<li><a href="https://github.com/BoostIO/Boostnote/wiki/Evernote">Convert data from <strong>Evernote</strong> to Boostnote.</a></li>␊
<li><a href="https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts">Keyboard Shortcuts</a></li>␊
<li><a href="https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode">Keymaps in Editor mode</a></li>␊
<li><a href="https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting">How to set syntax highlight in Snippet note</a></li>␊
<li data-line="7"><a href="https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe">Boostnote | Boost your happiness, productivity and creativity.</a></li>␊
<li data-line="8"><a href="https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup">Cloud Syncing &amp; Backups</a></li>␊
<li data-line="9"><a href="https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps">How to sync your data across Desktop and Mobile apps</a></li>␊
<li data-line="10"><a href="https://github.com/BoostIO/Boostnote/wiki/Evernote">Convert data from <strong>Evernote</strong> to Boostnote.</a></li>␊
<li data-line="11"><a href="https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts">Keyboard Shortcuts</a></li>␊
<li data-line="12"><a href="https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode">Keymaps in Editor mode</a></li>␊
<li data-line="13"><a href="https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting">How to set syntax highlight in Snippet note</a></li>␊
</ul>␊
<hr />␊
<h2 data-line="17" id="Article-Archive-%F0%9F%93%9A">Article Archive 📚</h2>␊
<h2 id="Article-Archive" data-line="17">Article Archive 📚</h2>␊
<ul>␊
<li><a href="http://bit.ly/2mOJPu7">Reddit English</a></li>␊
<li><a href="https://www.reddit.com/r/boostnote_es/">Reddit Spanish</a></li>␊
<li><a href="https://www.reddit.com/r/boostnote_cn/">Reddit Chinese</a></li>␊
<li><a href="https://www.reddit.com/r/boostnote_jp/">Reddit Japanese</a></li>␊
<li data-line="18"><a href="http://bit.ly/2mOJPu7">Reddit English</a></li>␊
<li data-line="19"><a href="https://www.reddit.com/r/boostnote_es/">Reddit Spanish</a></li>␊
<li data-line="20"><a href="https://www.reddit.com/r/boostnote_cn/">Reddit Chinese</a></li>␊
<li data-line="21"><a href="https://www.reddit.com/r/boostnote_jp/">Reddit Japanese</a></li>␊
</ul>␊
<hr />␊
<h2 data-line="25" id="Community-%F0%9F%8D%BB">Community 🍻</h2>␊
<h2 id="Community" data-line="25">Community 🍻</h2>␊
<ul>␊
<li><a href="http://bit.ly/2AWWzkD">GitHub</a></li>␊
<li><a href="http://bit.ly/2z8BUJZ">Twitter</a></li>␊
<li><a href="http://bit.ly/2jcca8t">Facebook Group</a></li>␊
<li data-line="26"><a href="http://bit.ly/2AWWzkD">GitHub</a></li>␊
<li data-line="27"><a href="http://bit.ly/2z8BUJZ">Twitter</a></li>␊
<li data-line="28"><a href="http://bit.ly/2jcca8t">Facebook Group</a></li>␊
</ul>␊
`
## Markdown.render() should renders sub correctly
> Snapshot 1
`<h2 id="sub" data-line="1">sub</h2>␊
<p data-line="3">H<sub>2</sub>0</p>␊
`
## Markdown.render() should renders sup correctly
> Snapshot 1
`<h2 id="sup" data-line="1">sup</h2>␊
<p data-line="3">29<sup>th</sup></p>␊
`
## Markdown.render() should text with quotes correctly
> Snapshot 1

View File

@@ -0,0 +1,330 @@
const Typo = require('typo-js')
const CodeMirror = require('codemirror')
jest.mock('typo-js')
const systemUnderTest = require('browser/lib/spellcheck')
beforeEach(() => {
// Clear all instances and calls to constructor and all methods:
Typo.mockClear()
})
it('should test that checkWord does not marks words that do not contain a typo', function () {
const testWord = 'testWord'
const editor = jest.fn()
editor.getRange = jest.fn(() => testWord)
editor.markText = jest.fn()
const range = {anchor: {line: 1, ch: 0}, head: {line: 1, ch: 10}}
const mockDictionary = jest.fn()
mockDictionary.check = jest.fn(() => true)
systemUnderTest.setDictionaryForTestsOnly(mockDictionary)
systemUnderTest.checkWord(editor, range)
expect(editor.getRange).toHaveBeenCalledWith(range.anchor, range.head)
expect(mockDictionary.check).toHaveBeenCalledWith(testWord)
expect(editor.markText).not.toHaveBeenCalled()
})
it('should test that checkWord should marks words that contain a typo', function () {
const testWord = 'testWord'
const editor = jest.fn()
editor.getRange = jest.fn(() => testWord)
editor.markText = jest.fn()
const range = {anchor: {line: 1, ch: 0}, head: {line: 1, ch: 10}}
const mockDictionary = jest.fn()
mockDictionary.check = jest.fn(() => false)
systemUnderTest.setDictionaryForTestsOnly(mockDictionary)
systemUnderTest.checkWord(editor, range)
expect(editor.getRange).toHaveBeenCalledWith(range.anchor, range.head)
expect(mockDictionary.check).toHaveBeenCalledWith(testWord)
expect(editor.markText).toHaveBeenCalledWith(range.anchor, range.head, {'className': systemUnderTest.CSS_ERROR_CLASS})
})
it('should test that setLanguage clears all marks', function () {
const dummyMarks = [
{clear: jest.fn()},
{clear: jest.fn()},
{clear: jest.fn()}
]
const editor = jest.fn()
editor.getAllMarks = jest.fn(() => dummyMarks)
systemUnderTest.setLanguage(editor, systemUnderTest.SPELLCHECK_DISABLED)
expect(editor.getAllMarks).toHaveBeenCalled()
for (const dummyMark of dummyMarks) {
expect(dummyMark.clear).toHaveBeenCalled()
}
})
it('should test that setLanguage with DISABLED as a lang argument should not load any dictionary and not check the whole document', function () {
const editor = jest.fn()
editor.getAllMarks = jest.fn(() => [])
const checkWholeDocumentSpy = jest.spyOn(systemUnderTest, 'checkWholeDocument').mockImplementation()
systemUnderTest.setLanguage(editor, systemUnderTest.SPELLCHECK_DISABLED)
expect(Typo).not.toHaveBeenCalled()
expect(checkWholeDocumentSpy).not.toHaveBeenCalled()
checkWholeDocumentSpy.mockRestore()
})
it('should test that setLanguage loads the correct dictionary', function () {
const editor = jest.fn()
editor.getAllMarks = jest.fn(() => [])
const lang = 'de_DE'
const checkWholeDocumentSpy = jest.spyOn(systemUnderTest, 'checkWholeDocument').mockImplementation()
expect(Typo).not.toHaveBeenCalled()
systemUnderTest.setLanguage(editor, lang)
expect(Typo).toHaveBeenCalledWith(lang, false, false, expect.anything())
expect(Typo.mock.calls[0][3].dictionaryPath).toEqual(systemUnderTest.DICTIONARY_PATH)
expect(Typo.mock.calls[0][3].asyncLoad).toBe(true)
checkWholeDocumentSpy.mockRestore()
})
it('should test that checkMultiLineRange performs checks for each word in the stated range', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {line: 2, ch: 4}
const rangeTo = {line: 3, ch: 36}
systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(11)
expect(dic.check.mock.calls[0][0]).toEqual('lacus')
expect(dic.check.mock.calls[1][0]).toEqual('elit')
expect(dic.check.mock.calls[2][0]).toEqual('sollicitudin')
expect(dic.check.mock.calls[3][0]).toEqual('vestibulum')
expect(dic.check.mock.calls[4][0]).toEqual('Phasellus')
expect(dic.check.mock.calls[5][0]).toEqual('blandit')
expect(dic.check.mock.calls[6][0]).toEqual('laoreet')
expect(dic.check.mock.calls[7][0]).toEqual('odio')
expect(dic.check.mock.calls[8][0]).toEqual('tristique')
expect(dic.check.mock.calls[9][0]).toEqual('risus')
expect(dic.check.mock.calls[10][0]).toEqual('tristique')
})
it('should test that checkMultiLineRange works correct even when the range is inverted (from is the later position and to the lower)', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {line: 3, ch: 36}
const rangeTo = {line: 2, ch: 4}
systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(11)
expect(dic.check.mock.calls[0][0]).toEqual('lacus')
expect(dic.check.mock.calls[1][0]).toEqual('elit')
expect(dic.check.mock.calls[2][0]).toEqual('sollicitudin')
expect(dic.check.mock.calls[3][0]).toEqual('vestibulum')
expect(dic.check.mock.calls[4][0]).toEqual('Phasellus')
expect(dic.check.mock.calls[5][0]).toEqual('blandit')
expect(dic.check.mock.calls[6][0]).toEqual('laoreet')
expect(dic.check.mock.calls[7][0]).toEqual('odio')
expect(dic.check.mock.calls[8][0]).toEqual('tristique')
expect(dic.check.mock.calls[9][0]).toEqual('risus')
expect(dic.check.mock.calls[10][0]).toEqual('tristique')
})
it('should test that checkMultiLineRange works for single line', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {line: 5, ch: 14}
const rangeTo = {line: 5, ch: 39}
systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(3)
expect(dic.check.mock.calls[0][0]).toEqual('volutpat')
expect(dic.check.mock.calls[1][0]).toEqual('quis')
expect(dic.check.mock.calls[2][0]).toEqual('ullamcorper')
})
it('should test that checkMultiLineRange works for single word', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {line: 7, ch: 6}
const rangeTo = {line: 7, ch: 6}
systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(1)
expect(dic.check.mock.calls[0][0]).toEqual('molestie')
})
it('should make sure that liveSpellcheck don\'t work if the spellcheck is not enabled', function () {
const checkMultiLineRangeSpy = jest.spyOn(systemUnderTest, 'checkMultiLineRange').mockImplementation()
const editor = jest.fn()
editor.findMarks = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(null)
systemUnderTest.checkChangeRange(editor, {}, {})
expect(checkMultiLineRangeSpy).not.toHaveBeenCalled()
expect(editor.findMarks).not.toHaveBeenCalled()
checkMultiLineRangeSpy.mockRestore()
})
it('should make sure that liveSpellcheck works for a range of changes', function () {
const editor = jest.fn()
const marks = [{clear: jest.fn()}, {clear: jest.fn()}]
editor.findMarks = jest.fn(() => marks)
const checkMultiLineRangeSpy = jest.spyOn(systemUnderTest, 'checkMultiLineRange').mockImplementation()
const inputChangeRange = {from: {line: 0, ch: 2}, to: {line: 1, ch: 1}}
const inputChangeRangeTo = {from: {line: 0, ch: 2}, to: {line: 1, ch: 2}}
systemUnderTest.setDictionaryForTestsOnly({})
systemUnderTest.checkChangeRange(editor, inputChangeRange, inputChangeRangeTo)
expect(checkMultiLineRangeSpy).toHaveBeenCalledWith(editor, {line: 0, ch: 1}, {line: 1, ch: 3})
expect(editor.findMarks).toHaveBeenCalledWith({line: 0, ch: 1}, {line: 1, ch: 3})
expect(marks[0].clear).toHaveBeenCalled()
expect(marks[1].clear).toHaveBeenCalled()
checkMultiLineRangeSpy.mockRestore()
})
it('should make sure that liveSpellcheck works if ranges are inverted', function () {
const editor = jest.fn()
const marks = [{clear: jest.fn()}, {clear: jest.fn()}]
editor.findMarks = jest.fn(() => marks)
const checkMultiLineRangeSpy = jest.spyOn(systemUnderTest, 'checkMultiLineRange').mockImplementation()
const inputChangeRange = {from: {line: 0, ch: 2}, to: {line: 1, ch: 2}}
const inputChangeRangeTo = {from: {line: 0, ch: 2}, to: {line: 1, ch: 1}}
systemUnderTest.setDictionaryForTestsOnly({})
systemUnderTest.checkChangeRange(editor, inputChangeRange, inputChangeRangeTo)
expect(checkMultiLineRangeSpy).toHaveBeenCalledWith(editor, {line: 0, ch: 1}, {line: 1, ch: 3})
expect(editor.findMarks).toHaveBeenCalledWith({line: 0, ch: 1}, {line: 1, ch: 3})
expect(marks[0].clear).toHaveBeenCalled()
expect(marks[1].clear).toHaveBeenCalled()
checkMultiLineRangeSpy.mockRestore()
})
it('should make sure that liveSpellcheck works for a single word with change at the beginning', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {from: {line: 7, ch: 6}, to: {line: 7, ch: 6}}
const rangeTo = {from: {line: 7, ch: 6}, to: {line: 7, ch: 6}}
systemUnderTest.checkChangeRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(1)
expect(dic.check.mock.calls[0][0]).toEqual('molestie')
})
it('should make sure that liveSpellcheck works for a single word with change in the middle', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {from: {line: 7, ch: 9}, to: {line: 7, ch: 9}}
const rangeTo = {from: {line: 7, ch: 9}, to: {line: 7, ch: 9}}
systemUnderTest.checkChangeRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(1)
expect(dic.check.mock.calls[0][0]).toEqual('molestie')
})
it('should make sure that liveSpellcheck works for a single word with change at the end', function () {
const dic = jest.fn()
dic.check = jest.fn()
systemUnderTest.setDictionaryForTestsOnly(dic)
document.body.createTextRange = jest.fn(() => document.createElement('textArea'))
const editor = new CodeMirror(jest.fn())
editor.setValue(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' +
'\n' +
'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' +
'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' +
'\n' +
'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' +
'\n' +
'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ')
const rangeFrom = {from: {line: 7, ch: 14}, to: {line: 7, ch: 14}}
const rangeTo = {from: {line: 7, ch: 14}, to: {line: 7, ch: 14}}
systemUnderTest.checkChangeRange(editor, rangeFrom, rangeTo)
expect(dic.check).toHaveBeenCalledTimes(1)
expect(dic.check.mock.calls[0][0]).toEqual('molestie')
})

15
tests/lib/utils.test.js Normal file
View File

@@ -0,0 +1,15 @@
import { isMarkdownTitleURL } from '../../browser/lib/utils'
describe('isMarkdownTitleURL', () => {
it('returns true for valid Markdown title with url', () => {
expect(isMarkdownTitleURL('# https://validurl.com')).toBe(true)
expect(isMarkdownTitleURL('## https://validurl.com')).toBe(true)
expect(isMarkdownTitleURL('###### https://validurl.com')).toBe(true)
})
it('returns true for invalid Markdown title with url', () => {
expect(isMarkdownTitleURL('1 https://validurl.com')).toBe(false)
expect(isMarkdownTitleURL('24 https://validurl.com')).toBe(false)
expect(isMarkdownTitleURL('####### https://validurl.com')).toBe(false)
})
})