Improve tests (#944)

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
Tilman Vatteroth 2021-01-11 23:22:11 +01:00 committed by GitHub
parent e0e5f2a7dd
commit 3db6bcf892
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 342 additions and 295 deletions

View file

@ -118,7 +118,7 @@ ij_typescript_import_sort_module_name = true
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = false
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces

View file

@ -8,19 +8,21 @@ describe('Autocompletion', () => {
beforeEach(() => {
cy.visit('/n/test')
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
.should('exist')
cy.get('.CodeMirror')
.click()
.get('textarea')
.as('codeinput')
})
describe('code block', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type('```')
cy.get('@codeinput')
.fill('```')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -32,8 +34,8 @@ describe('Autocompletion', () => {
.should('exist')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type('```')
cy.get('@codeinput')
.fill('```')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -50,11 +52,11 @@ describe('Autocompletion', () => {
describe('container', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type(':::')
cy.get('@codeinput')
.fill(':::')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -66,8 +68,8 @@ describe('Autocompletion', () => {
.should('exist')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type(':::')
cy.get('@codeinput')
.fill(':::')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -85,11 +87,11 @@ describe('Autocompletion', () => {
describe('emoji', () => {
describe('normal emoji', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type(':hedg')
cy.get('@codeinput')
.fill(':hedg')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -99,8 +101,8 @@ describe('Autocompletion', () => {
.should('have.text', '🦔')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type(':hedg')
cy.get('@codeinput')
.fill(':hedg')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -115,11 +117,11 @@ describe('Autocompletion', () => {
describe('fork-awesome-icon', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type(':fa-face')
cy.get('@codeinput')
.fill(':fa-face')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -129,8 +131,8 @@ describe('Autocompletion', () => {
.should('exist')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type(':fa-face')
cy.get('@codeinput')
.fill(':fa-face')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -146,11 +148,11 @@ describe('Autocompletion', () => {
describe('header', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type('#')
cy.get('@codeinput')
.fill('#')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -160,8 +162,8 @@ describe('Autocompletion', () => {
.should('have.text', ' ')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type('#')
cy.get('@codeinput')
.fill('#')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -176,11 +178,11 @@ describe('Autocompletion', () => {
describe('images', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type('!')
cy.get('@codeinput')
.fill('!')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -192,8 +194,8 @@ describe('Autocompletion', () => {
.should('have.attr', 'title', 'title')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type('!')
cy.get('@codeinput')
.fill('!')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -210,11 +212,11 @@ describe('Autocompletion', () => {
describe('links', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type('[')
cy.get('@codeinput')
.fill('[')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -226,8 +228,8 @@ describe('Autocompletion', () => {
.should('have.attr', 'title', 'title')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type('[')
cy.get('@codeinput')
.fill('[')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -244,11 +246,11 @@ describe('Autocompletion', () => {
describe('pdf', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type('{')
cy.get('@codeinput')
.fill('{')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
@ -258,8 +260,8 @@ describe('Autocompletion', () => {
.should('exist')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type('{')
cy.get('@codeinput')
.fill('{')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
@ -274,31 +276,31 @@ describe('Autocompletion', () => {
describe('collapsable blocks', () => {
it('via Enter', () => {
cy.get('.CodeMirror textarea')
.type('<d')
cy.get('@codeinput')
.fill('<d')
cy.get('.CodeMirror-hints')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{enter}')
.should('exist')
cy.get('@codeinput')
.type('{enter}')
cy.get('.CodeMirror-hints')
.should('not.exist')
.should('not.exist')
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', '</details>') // after selecting the hint, the last line of the inserted suggestion is active
.should('have.text', '</details>') // after selecting the hint, the last line of the inserted suggestion is active
cy.get('.markdown-body > details')
.should('exist')
.should('exist')
})
it('via doubleclick', () => {
cy.get('.CodeMirror textarea')
.type('<d')
cy.get('@codeinput')
.fill('<d')
cy.get('.CodeMirror-hints > li')
.first()
.dblclick()
.first()
.dblclick()
cy.get('.CodeMirror-hints')
.should('not.exist')
.should('not.exist')
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', '</details>')
.should('have.text', '</details>')
cy.get('.markdown-body > details')
.should('exist')
.should('exist')
})
})
})

View file

@ -13,22 +13,24 @@ describe('Code', () => {
})
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
cy.get('.CodeMirror')
.click()
.get('textarea')
.as('codeinput')
})
describe('without = doesn\'t show gutter', () => {
it('without wrapLines active', () => {
cy.get('.CodeMirror textarea')
.type('```javascript \nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript \nlet x = 0\n```')
cy.get('.markdown-body > pre > code')
.should('have.class', 'hljs')
})
it('with wrapLines active', () => {
cy.get('.CodeMirror textarea')
.type('```javascript!\nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript!\nlet x = 0\n```')
cy.get('.markdown-body > pre > code')
.should('have.class', 'hljs')
.should('have.class', 'wrapLines')
@ -37,8 +39,8 @@ describe('Code', () => {
describe('with = shows gutter', () => {
it('without wrapLines active', () => {
cy.get('.CodeMirror textarea')
.type('```javascript=\nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript=\nlet x = 0\n```')
cy.get('.markdown-body > pre > code')
.should('have.class', 'hljs')
.should('have.class', 'showGutter')
@ -48,8 +50,8 @@ describe('Code', () => {
})
it('with wrapLines active', () => {
cy.get('.CodeMirror textarea')
.type('```javascript=! \nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript=! \nlet x = 0\n```')
cy.get('.markdown-body > pre > code')
.should('have.class', 'hljs')
.should('have.class', 'showGutter')
@ -62,8 +64,8 @@ describe('Code', () => {
describe('with = shows gutter and number is used as startline', () => {
it('without wrapLines active', () => {
cy.get('.CodeMirror textarea')
.type('```javascript=100\nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript=100\nlet x = 0\n```')
cy.get('.markdown-body > pre > code')
.should('have.class', 'hljs')
.should('have.class', 'showGutter')
@ -73,8 +75,8 @@ describe('Code', () => {
})
it('with wrapLines active', () => {
cy.get('.CodeMirror textarea')
.type('```javascript=100! \nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript=100! \nlet x = 0\n```')
cy.get('.markdown-body > pre > code')
.should('have.class', 'hljs')
.should('have.class', 'showGutter')
@ -86,11 +88,11 @@ describe('Code', () => {
})
it('has a button', () => {
cy.get('.CodeMirror textarea')
.type('```javascript \nlet x = 0\n```')
cy.get('@codeinput')
.fill('```javascript \nlet x = 0\n```')
cy.get('.markdown-body > pre > div > button > i')
.should('have.class', 'fa-files-o')
.click()
cy.get('@copy').should('be.calledWithExactly', 'let x = 0\n');
cy.get('@copy').should('be.calledWithExactly', 'let x = 0\n')
})
})

View file

@ -12,80 +12,94 @@ describe('Document Title', () => {
cy.visit('/n/test')
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
cy.get('.CodeMirror')
.click()
.get('textarea')
.as('codeinput')
})
describe('title should be yaml metadata title', () => {
it('just yaml metadata title', () => {
cy.get('.CodeMirror textarea')
.type(`---\ntitle: ${title}\n---`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`---\ntitle: ${title}\n---`)
cy.title()
.should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('yaml metadata title and opengraph title', () => {
cy.get('.CodeMirror textarea')
.type(`---\ntitle: ${title}\nopengraph:\n title: False title\n{backspace}{backspace}---`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`---\ntitle: ${title}\nopengraph:\n title: False title\n---`)
cy.title()
.should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('yaml metadata title, opengraph title and first heading', () => {
cy.get('.CodeMirror textarea')
.type(`---\ntitle: ${title}\nopengraph:\n title: False title\n{backspace}{backspace}---\n# a first title`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`---\ntitle: ${title}\nopengraph:\n title: False title\n---\n# a first title`)
cy.title()
.should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
})
describe('title should be opengraph title', () => {
it('just opengraph title', () => {
cy.get('.CodeMirror textarea')
.type(`---\nopengraph:\n title: ${title}\n{backspace}{backspace}---`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`---\nopengraph:\n title: ${title}\n---`)
cy.title()
.should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('opengraph title and first heading', () => {
cy.get('.CodeMirror textarea')
.type(`---\nopengraph:\n title: ${title}\n{backspace}{backspace}---\n# a first title`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`---\nopengraph:\n title: ${title}\n---\n# a first title`)
cy.title()
.should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
})
describe('title should be first heading', () => {
it('just first heading', () => {
cy.get('.CodeMirror textarea')
.type(`# ${title}`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`# ${title}`)
cy.title()
.should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('just first heading with alt-text instead of image', () => {
cy.get('.CodeMirror textarea')
.type(`# ${title} ![abc](https://dummyimage.com/48)`)
cy.title().should('eq', `${title} abc - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`# ${title} ![abc](https://dummyimage.com/48)`)
cy.title()
.should('eq', `${title} abc - HedgeDoc @ ${branding.name}`)
})
it('just first heading without link syntax', () => {
cy.get('.CodeMirror textarea')
.type(`# ${title} [link](https://hedgedoc.org)`)
cy.title().should('eq', `${title} link - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`# ${title} [link](https://hedgedoc.org)`)
cy.title()
.should('eq', `${title} link - HedgeDoc @ ${branding.name}`)
})
it('markdown syntax removed first', () => {
cy.get('.CodeMirror textarea')
.type(`# ${title} 1*2*3 4*5**`)
cy.title().should('eq', `${title} 123 4*5** - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`# ${title} 1*2*3 4*5**`)
cy.title()
.should('eq', `${title} 123 4*5** - HedgeDoc @ ${branding.name}`)
})
it('markdown syntax removed second', () => {
cy.get('.CodeMirror textarea')
.type(`# ${title} **1 2*`)
cy.title().should('eq', `${title} *1 2 - HedgeDoc @ ${branding.name}`)
cy.get('@codeinput')
.fill(`# ${title} **1 2*`)
cy.title()
.should('eq', `${title} *1 2 - HedgeDoc @ ${branding.name}`)
})
it('markdown syntax removed third', () => {
cy.get('.CodeMirror textarea')
.type(`# ${title} _asd_`)
cy.title().should('eq', `${title} asd - HedgeDoc @ ${branding.name}`)
cy.get('a')
.get('@codeinput')
.fill(`# ${title} _asd_`)
cy.title()
.should('eq', `${title} asd - HedgeDoc @ ${branding.name}`)
})
})
})

View file

@ -7,18 +7,25 @@
describe('Editor mode from URL parameter is used', () => {
it('mode view', () => {
cy.visit('/n/features?view')
cy.get('.splitter.left').should('have.class', 'd-none')
cy.get('.splitter.right').should('not.have.class', 'd-none')
cy.get('.splitter.left')
.should('have.class', 'd-none')
cy.get('.splitter.right')
.should('not.have.class', 'd-none')
})
it('mode both', () => {
cy.visit('/n/features?both')
cy.get('.splitter.left').should('not.have.class', 'd-none')
cy.get('.splitter.separator').should('exist')
cy.get('.splitter.right').should('not.have.class', 'd-none')
cy.get('.splitter.left')
.should('not.have.class', 'd-none')
cy.get('.splitter.separator')
.should('exist')
cy.get('.splitter.right')
.should('not.have.class', 'd-none')
})
it('mode edit', () => {
cy.visit('/n/features?edit')
cy.get('.splitter.left').should('not.have.class', 'd-none')
cy.get('.splitter.right').should('have.class', 'd-none')
cy.get('.splitter.left')
.should('not.have.class', 'd-none')
cy.get('.splitter.right')
.should('have.class', 'd-none')
})
})

View file

@ -4,19 +4,18 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
const testTitle = 'testContent'
const testContent = `---\ntitle: ${testTitle}\n---\nThis is some test content`
describe('Export', () => {
const testTitle = 'testContent'
const testContent = `---\ntitle: ${testTitle}\n---\nThis is some test content`
beforeEach(() => {
cy.visit('/n/test')
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
cy.get('.CodeMirror textarea')
.type(testContent)
cy.get('.CodeMirror')
.click()
.get('textarea')
.fill(testContent)
})
it('Markdown', () => {
@ -28,27 +27,27 @@ describe('Export', () => {
.then((anchor) => (
new Cypress.Promise((resolve: any, _: any) => {
// Use XHR to get the blob that corresponds to the object URL.
const xhr = new XMLHttpRequest();
xhr.open('GET', anchor.prop('href'), true);
xhr.responseType = 'blob';
const xhr = new XMLHttpRequest()
xhr.open('GET', anchor.prop('href'), true)
xhr.responseType = 'blob'
// Once loaded, use FileReader to get the string back from the blob.
xhr.onload = () => {
if (xhr.status === 200) {
const blob = xhr.response;
const reader = new FileReader();
const blob = xhr.response
const reader = new FileReader()
reader.onload = () => {
// Once we have a string, resolve the promise to let
// the Cypress chain continue, e.g. to assert on the result.
resolve(reader.result);
};
reader.readAsText(blob);
resolve(reader.result)
}
reader.readAsText(blob)
}
};
xhr.send();
}
xhr.send()
})
))
// Now the regular Cypress assertions should work.
.should('equal', testContent);
.should('equal', testContent)
})
})

View file

@ -6,28 +6,30 @@
const imageUrl = 'http://example.com/non-existing.png'
describe('Upload', () => {
describe('File upload', () => {
beforeEach(() => {
cy.visit('/n/test')
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
cy.get('.CodeMirror')
.click()
.get('textarea')
.as('codeinput')
})
it('check that text drag\'n\'drop still works', () => {
it('doesn\'t prevent drag\'n\'drop of plain text', () => {
const dataTransfer = new DataTransfer()
cy.get('.CodeMirror textarea')
.type('line 1\nline 2\nline3')
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
cy.get('@codeinput')
.fill('line 1\nline 2\ndragline')
cy.get('.CodeMirror')
.click()
cy.get('.CodeMirror-line > span')
.last()
.dblclick()
cy.get('.CodeMirror-line > span > .cm-matchhighlight')
.trigger('dragstart', { dataTransfer })
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span span')
.trigger('drop', { dataTransfer })
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span span')
.should('have.text', 'linline3e 1')
.should('have.text', 'lindraglinee 1')
})
describe('upload works', () => {
@ -60,7 +62,7 @@ describe('Upload', () => {
}
cy.get('.CodeMirror-scroll').trigger('paste', pasteEvent)
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', `![](${imageUrl})`)
.should('have.text', `![](${imageUrl})`)
})
})
@ -75,13 +77,13 @@ describe('Upload', () => {
cy.get('.CodeMirror-scroll').trigger('dragenter', dropEvent)
cy.get('.CodeMirror-scroll').trigger('drop', dropEvent)
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', `![](${imageUrl})`)
.should('have.text', `![](${imageUrl})`)
})
})
})
it('upload fails', () => {
cy.get('.CodeMirror textarea')
cy.get('@codeinput')
.type('not empty')
cy.intercept({
method: 'POST',
@ -91,8 +93,10 @@ describe('Upload', () => {
})
cy.get('.fa-upload')
.click()
cy.get('input[type=file]')
.attachFile({ filePath: 'acme.png', mimeType: 'image/png' })
cy.fixture('acme.png').then(() => {
cy.get('input[type=file]')
.attachFile({ filePath: 'acme.png', mimeType: 'image/png' })
})
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
.should('have.text', 'not empty')
})

View file

@ -9,9 +9,6 @@ describe('Import markdown file', () => {
cy.visit('/n/test')
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
})
it('import on blank note', () => {
@ -28,8 +25,11 @@ describe('Import markdown file', () => {
})
it('import on note with content', () => {
cy.get('.CodeMirror textarea')
.type('test\nabc', { force: true })
cy.get('.CodeMirror')
.click()
.get('textarea')
.fill('test\nabc')
cy.get('button#editor-menu-import')
.click()
cy.get('.import-md-file')

View file

@ -4,52 +4,47 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
const tenChars = '0123456789'
describe('The status bar text length info', () => {
const warningTestContent = ('0123456789'.repeat(10))
const dangerTestContent = ('0123456789'.repeat(20))
const tooMuchTestContent = `${dangerTestContent}a`
describe('status-bar text-length info', () => {
beforeEach(() => {
cy.visit('/n/test')
cy.get('.CodeMirror ')
.click()
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
.as('codeinput')
})
it('tooltip shows full remaining on empty text', () => {
cy.get('.status-bar div:nth-child(2) span:nth-child(2)')
it('shows the maximal length of the document as number of available characters in the tooltip', () => {
cy.get('.status-bar [data-cy="remainingCharacters"]')
.attribute('title')
.should('contain', ' 200 ')
})
it('color is warning on <= 100 chars remaining', () => {
cy.get('.CodeMirror textarea')
.fill(tenChars.repeat(10))
cy.get('.status-bar div:nth-child(2) span:nth-child(2)')
it('color is set to "warning" on <= 100 characters remaining', () => {
cy.get('@codeinput')
.fill(warningTestContent)
cy.get('.status-bar [data-cy="remainingCharacters"]')
.should('have.class', 'text-warning')
})
it('color is danger on <= 0 chars remaining', () => {
cy.get('.CodeMirror textarea')
.fill(tenChars.repeat(20))
cy.get('.status-bar div:nth-child(2) span:nth-child(2)')
.should('have.class', 'text-danger')
})
})
describe('show warning if content length > configured max length', () => {
beforeEach(() => {
cy.visit('/n/test')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
.fill(tenChars.repeat(20))
it('color is set to danger on <= 0 characters remaining', () => {
cy.get('@codeinput')
.fill(dangerTestContent)
cy.get('.status-bar [data-cy="remainingCharacters"]')
.should('have.class', 'text-danger')
})
it('show warning alert in renderer and as modal', () => {
cy.get('.CodeMirror textarea')
.type('a')
cy.get('.modal-body.limit-warning')
it('shows a warning and opens a modal', () => {
cy.get('@codeinput')
.fill(tooMuchTestContent)
cy.get('[data-cy="limitReachedModal"]')
.should('be.visible')
cy.get('[data-cy="limitReachedMessage"]')
.should('be.visible')
cy.get('.splitter .alert-danger')
.should('be.visible')
})
})

View file

@ -1,37 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('yaml-metadata: tags', () => {
beforeEach(() => {
cy.visit('/n/features')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
})
it('show deprecation notice on old syntax', () => {
cy.get('.CodeMirror textarea')
.type('---\ntags: a, b, c\n---')
cy.get('.splitter.right .w-100.h-100 .alert.alert-warning')
.should('be.visible')
})
it('show no deprecation notice on yaml-array (1)', () => {
cy.get('.CodeMirror textarea')
.type('---\ntags: [\'a\', \'b\', \'c\']\n---')
cy.get('.splitter.right .w-100.h-100 .alert.alert-warning')
.should('not.exist')
})
it('show no deprecation notice on yaml-array (2)', () => {
cy.get('.CodeMirror textarea')
.type('---\ntags:\n - a\nb\nc\n')
.type('{backspace}{backspace}{backspace}{backspace}')
.type('---')
cy.get('.splitter.right .w-100.h-100 .alert.alert-warning')
.should('not.exist')
})
})

View file

@ -4,23 +4,38 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
const testText = 'textText'
const testLink = 'http://hedgedoc.org'
describe('Toolbar', () => {
const testText = 'textText'
const testLink = 'http://hedgedoc.org'
beforeEach(() => {
cy.visit('/n/test')
cy.get('.btn.active.btn-outline-secondary > i.fa-columns')
.should('exist')
cy.get('.CodeMirror textarea')
.type('{ctrl}a', { force: true })
.type('{backspace}')
cy.viewport(1920, 1080)
cy.get('.CodeMirror')
.click()
.get('textarea')
.as('codeinput')
})
const fillTestText = () => {
cy.get('@codeinput')
.fill(testText)
cy.get('.CodeMirror-line > span')
.should("exist")
.should('have.text', testText)
}
const fillTestLink = () => {
cy.get('@codeinput')
.fill(testLink)
cy.get('.CodeMirror-line > span')
.should("exist")
.should('have.text', testLink)
}
it('bold', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-bold')
.click()
@ -29,8 +44,8 @@ describe('Toolbar', () => {
})
it('italic', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-italic')
.click()
@ -39,8 +54,8 @@ describe('Toolbar', () => {
})
it('underline', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-underline')
.click()
@ -49,8 +64,8 @@ describe('Toolbar', () => {
})
it('strikethrough', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-strikethrough')
.click()
@ -59,8 +74,8 @@ describe('Toolbar', () => {
})
it('subscript', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-subscript')
.click()
@ -69,8 +84,8 @@ describe('Toolbar', () => {
})
it('superscript', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-superscript')
.click()
@ -79,8 +94,7 @@ describe('Toolbar', () => {
})
it('heading', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-header')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -93,8 +107,8 @@ describe('Toolbar', () => {
describe('code', () => {
it('nothing selected empty line', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
.type('{backspace}')
cy.get('.fa-code')
@ -106,8 +120,8 @@ describe('Toolbar', () => {
})
it('nothing selected non line', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
.type('{leftArrow}')
cy.get('.fa-code')
@ -121,8 +135,8 @@ describe('Toolbar', () => {
})
it('line selected', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-code')
.click()
@ -136,8 +150,7 @@ describe('Toolbar', () => {
})
it('quote', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-quote-right')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -149,8 +162,7 @@ describe('Toolbar', () => {
})
it('unordered list', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-list')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -162,8 +174,7 @@ describe('Toolbar', () => {
})
it('ordered list', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-list-ol')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -175,8 +186,7 @@ describe('Toolbar', () => {
})
it('todo list', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-check-square')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -189,8 +199,8 @@ describe('Toolbar', () => {
describe('link', () => {
it('with selection text', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-link')
.click()
@ -199,8 +209,7 @@ describe('Toolbar', () => {
})
it('without selection', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-link')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -208,8 +217,8 @@ describe('Toolbar', () => {
})
it('with selection link', () => {
cy.get('.CodeMirror textarea')
.type(`${testLink}`)
fillTestLink()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-link')
.click()
@ -220,8 +229,8 @@ describe('Toolbar', () => {
describe('image', () => {
it('with selection', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-picture-o')
.click()
@ -230,8 +239,7 @@ describe('Toolbar', () => {
})
it('without selection', () => {
cy.get('.CodeMirror textarea')
.type(`${testText}`)
fillTestText()
cy.get('.fa-picture-o')
.click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span')
@ -239,8 +247,8 @@ describe('Toolbar', () => {
})
it('with selection link', () => {
cy.get('.CodeMirror textarea')
.type(`${testLink}`)
fillTestLink()
cy.get('@codeinput')
.type('{ctrl}a')
cy.get('.fa-picture-o')
.click()
@ -312,9 +320,9 @@ describe('Toolbar', () => {
it('collapsable block', () => {
cy.get('.fa-caret-square-o-down')
.click()
.click()
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span')
.should('have.text', '<details>')
.should('have.text', '<details>')
})
it('comment', () => {

View file

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('YAML Array for deprecated syntax of document tags in frontmatter', () => {
beforeEach(() => {
cy.visit('/n/features')
cy.get('.CodeMirror')
.click()
.get('textarea')
.as('codeinput')
})
it('is shown when using old syntax', () => {
cy.get('@codeinput')
.fill('---\ntags: a, b, c\n---')
cy.get('[data-cy="yamlArrayDeprecationAlert"]')
.should('be.visible')
})
it('isn\'t shown when using inline yaml-array', () => {
cy.get('@codeinput')
.fill('---\ntags: [\'a\', \'b\', \'c\']\n---')
cy.get('[data-cy="yamlArrayDeprecationAlert"]')
.should('not.exist')
})
it('isn\'t shown when using multi line yaml-array', () => {
cy.get('@codeinput')
.fill('---\ntags:\n - a\n - b\n - c\n---')
cy.get('[data-cy="yamlArrayDeprecationAlert"]')
.should('not.exist')
})
})

View file

@ -26,7 +26,7 @@ export const CommonModal: React.FC<CommonModalProps> = ({ show, onHide, titleI18
useTranslation()
return (
<Modal show={show} onHide={onHide} animation={true} dialogClassName={`text-dark ${additionalClasses ?? ''}`} size={size}>
<Modal data-cy={'limitReachedModal'} show={show} onHide={onHide} animation={true} dialogClassName={`text-dark ${additionalClasses ?? ''}`} size={size}>
<Modal.Header closeButton={!!closeButton}>
<Modal.Title>
<ShowIf condition={!!icon}>

View file

@ -6,20 +6,18 @@ SPDX-License-Identifier: AGPL-3.0-only
import { TocAst } from 'markdown-it-toc-done-right'
import React, { RefObject, useRef, useState } from 'react'
import { Alert, Dropdown } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { Dropdown } from 'react-bootstrap'
import { useSelector } from 'react-redux'
import useResizeObserver from 'use-resize-observer'
import links from '../../../links.json'
import { ApplicationState } from '../../../redux'
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
import { TranslatedExternalLink } from '../../common/links/translated-external-link'
import { ShowIf } from '../../common/show-if/show-if'
import { FullMarkdownRenderer } from '../../markdown-renderer/full-markdown-renderer'
import { LineMarkerPosition } from '../../markdown-renderer/types'
import { TableOfContents } from '../table-of-contents/table-of-contents'
import { YAMLMetaData } from '../yaml-metadata/yaml-metadata'
import { useAdaptedLineMarkerCallback } from './use-adapted-line-markers-callback'
import { YamlArrayDeprecationAlert } from './yaml-array-deprecation-alert'
export interface DocumentRenderPaneProps {
extraClasses?: string
@ -58,11 +56,7 @@ export const DocumentRenderPane: React.FC<DocumentRenderPaneProps> = ({
<div className={'col-md'}/>
<div className={'bg-light flex-fill'}>
<ShowIf condition={yamlDeprecatedTags}>
<Alert variant='warning' dir='auto'>
<Trans i18nKey='editor.deprecatedTags' />
<br/>
<TranslatedExternalLink i18nKey={'common.readForMoreInfo'} href={links.faq} className={'text-primary'}/>
</Alert>
<YamlArrayDeprecationAlert/>
</ShowIf>
<div >
<FullMarkdownRenderer

View file

@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React from 'react'
import { Alert } from 'react-bootstrap'
import { Trans } from 'react-i18next';
import { TranslatedExternalLink } from '../../common/links/translated-external-link'
import links from '../../../links.json'
export const YamlArrayDeprecationAlert: React.FC = () => {
return (
<Alert data-cy={'yamlArrayDeprecationAlert'} variant='warning' dir='auto'>
<Trans i18nKey='editor.deprecatedTags' />
<br/>
<TranslatedExternalLink i18nKey={'common.readForMoreInfo'} href={links.faq} className={'text-primary'}/>
</Alert>
);
}

View file

@ -19,8 +19,8 @@ export const MaxLengthWarningModal: React.FC<MaxLengthWarningModalProps> = ({ sh
useTranslation()
return (
<CommonModal show={show} onHide={onHide} titleI18nKey={'editor.error.limitReached.title'} closeButton={true}>
<Modal.Body className={'limit-warning'}>
<CommonModal data-cy={'limitReachedModal'} show={show} onHide={onHide} titleI18nKey={'editor.error.limitReached.title'} closeButton={true}>
<Modal.Body>
<Trans i18nKey={'editor.error.limitReached.description'} values={{ maxLength }} />
<strong className='mt-2 d-block'><Trans i18nKey={'editor.error.limitReached.advice'}/></strong>
</Modal.Body>

View file

@ -67,6 +67,7 @@ export const StatusBar: React.FC<StatusBarInfo> = ({ position, selectedColumns,
<span>{t('editor.statusBar.lines', { lines: linesInDocument })}</span>
&nbsp;&nbsp;
<span
data-cy={'remainingCharacters'}
title={getLengthTooltip}
className={remainingCharacters <= 0 ? 'text-danger' : remainingCharacters <= 100 ? 'text-warning' : ''}
>

View file

@ -62,7 +62,7 @@ export const BasicMarkdownRenderer: React.FC<BasicMarkdownRendererProps & Additi
return (
<div className={`${className || ''} d-flex flex-column align-items-center ${wide ? 'wider' : ''}`}>
<ShowIf condition={content.length > maxLength}>
<Alert variant='danger' dir={'auto'}>
<Alert variant='danger' dir={'auto'} data-cy={'limitReachedMessage'}>
<Trans i18nKey={'editor.error.limitReached.description'} values={{ maxLength }}/>
</Alert>
</ShowIf>

View file

@ -14,7 +14,7 @@ export const DeprecationWarning: React.FC = () => {
useTranslation()
return (
<Alert className={'mt-2'} variant={'warning'}>
<Alert data-cy={'yaml'} className={'mt-2'} variant={'warning'}>
<Trans i18nKey={'renderer.sequence.deprecationWarning'}/>
&nbsp;
<TranslatedExternalLink i18nKey={'common.readForMoreInfo'} className={'text-primary'} href={links.faq}/>

View file

@ -82,7 +82,7 @@ ReactDOM.render(
)
if (isTestMode()) {
console.log("This build runs in test mode")
console.log("This build runs in test mode. This means:\n - No default content in the editor")
}
// If you want your app to work offline and load faster, you can change