Update dependency cypress to v10 (#2095)

* Update dependency cypress to v10
* Migrate cypress files

Signed-off-by: Renovate Bot <bot@renovateapp.com>
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
renovate[bot] 2022-06-08 11:19:51 +00:00 committed by GitHub
parent e93607c96e
commit 040e11924f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 57 additions and 45 deletions

View file

@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { testNoteId } from '../support/visit-test-editor'
describe('Delete note', () => {
beforeEach(() => {
cy.visitTestNote()
})
it('correctly deletes a note', () => {
cy.intercept('DELETE', `/api/mock-backend/private/notes/${testNoteId}`, {
statusCode: 204
})
cy.getByCypressId('sidebar.deleteNote.button').click()
cy.getByCypressId('sidebar.deleteNote.modal').should('be.visible')
cy.getByCypressId('sidebar.deleteNote.modal.noteTitle').should('be.visible').text().should('eq', '')
cy.getByCypressId('deletionModal.confirmButton').should('be.visible').click()
cy.getByCypressId('sidebar.deleteNote.modal').should('not.be.exist')
cy.getByCypressId('notification-toast').should('not.exist')
})
it('displays an error notification if something goes wrong', () => {
cy.getByCypressId('sidebar.deleteNote.button').click()
cy.getByCypressId('sidebar.deleteNote.modal').should('be.visible')
cy.getByCypressId('sidebar.deleteNote.modal.noteTitle').should('be.visible').text().should('eq', '')
cy.getByCypressId('deletionModal.confirmButton').should('be.visible').click()
cy.getByCypressId('sidebar.deleteNote.modal').should('not.exist')
cy.getByCypressId('notification-toast').should('be.visible')
})
describe('displays the note title coming from', () => {
const title = 'mock_title'
it('yaml metadata', () => {
cy.setCodemirrorContent(`---\ntitle: ${title}\n---`)
})
it('opengraph', () => {
cy.setCodemirrorContent(`---\nopengraph:\n title: ${title}\n---`)
})
it('just first heading', () => {
cy.setCodemirrorContent(`# ${title}`)
})
afterEach(() => {
cy.getByCypressId('sidebar.deleteNote.button').click()
cy.getByCypressId('sidebar.deleteNote.modal').should('be.visible')
cy.getByCypressId('sidebar.deleteNote.modal.noteTitle').should('be.visible').text().should('eq', title)
})
})
})

View file

@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Diagram codeblock ', () => {
beforeEach(() => {
cy.visitTestNote()
})
/*
TODO: Readd test after fixing https://github.com/hedgedoc/react-client/issues/1709
it('renders markmap', () => {
cy.setCodemirrorContent('```markmap\n- pro\n- contra\n```')
cy.getMarkdownBody().findByCypressId('markmap').children().should('be.visible')
})
*/
it('renders mermaid', () => {
cy.setCodemirrorContent('```mermaid\ngraph TD;\n A-->B;\n```')
cy.getMarkdownBody().findByCypressId('mermaid-frame').children().should('be.visible')
})
})

View file

@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { PAGE_MODE } from '../support/visit'
describe('Document read only page', () => {
it('renders the document mode', () => {
cy.visitTestNote(PAGE_MODE.DOCUMENT_READ_ONLY)
cy.getMarkdownBody().should('exist')
})
})

View file

@ -0,0 +1,84 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { branding } from '../support/config'
const title = 'This is a test title'
describe('Document Title', () => {
beforeEach(() => {
cy.visitTestNote()
cy.getByCypressId('view-mode-both').should('exist')
})
describe('title should be yaml metadata title', () => {
it('just yaml metadata title', () => {
cy.setCodemirrorContent(`---\ntitle: ${title}\n---`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('yaml metadata title and opengraph title', () => {
cy.setCodemirrorContent(`---\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.setCodemirrorContent(`---\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.setCodemirrorContent(`---\nopengraph:\n title: ${title}\n---`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('opengraph title and first heading', () => {
cy.setCodemirrorContent(`---\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.setCodemirrorContent(`# ${title}`)
cy.title().should('eq', `${title} - HedgeDoc @ ${branding.name}`)
})
it('just first heading with alt-text instead of image', () => {
cy.setCodemirrorContent(`# ${title} ![abc](https://dummyimage.com/48)`)
cy.title().should('eq', `${title} abc - HedgeDoc @ ${branding.name}`)
})
it('just first heading without link syntax', () => {
cy.setCodemirrorContent(`# ${title} [link](https://hedgedoc.org)`)
cy.title().should('eq', `${title} link - HedgeDoc @ ${branding.name}`)
})
it('markdown syntax removed first', () => {
cy.setCodemirrorContent(`# ${title} 1*2*3 4*5**`)
cy.title().should('eq', `${title} 123 4*5** - HedgeDoc @ ${branding.name}`)
})
it('markdown syntax removed second', () => {
cy.setCodemirrorContent(`# ${title} **1 2*`)
cy.title().should('eq', `${title} *1 2 - HedgeDoc @ ${branding.name}`)
})
it('markdown syntax removed third', () => {
cy.setCodemirrorContent(`# ${title} _asd_`)
cy.title().should('eq', `${title} asd - HedgeDoc @ ${branding.name}`)
})
it('katex code looks right', () => {
cy.setCodemirrorContent(`# $\\alpha$-foo`)
cy.getIframeBody().find('h1').should('contain', 'α')
//TODO: Remove workaround after https://github.com/hedgedoc/react-client/issues/1816 has been fixed.
cy.get('.cm-editor .cm-content').type('{Enter}{Enter}{Enter}{Enter}{Enter}')
cy.title().should('eq', `α-foo - HedgeDoc @ ${branding.name}`)
})
})
})

View file

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { PAGE_MODE } from '../support/visit'
describe('Editor mode from URL parameter is used', () => {
it('mode view', () => {
cy.visitTestNote(PAGE_MODE.EDITOR, 'view')
cy.getByCypressId('editor-pane').should('not.be.visible')
cy.getByCypressId('documentIframe').should('be.visible')
})
it('mode both', () => {
cy.visitTestNote(PAGE_MODE.EDITOR, 'both')
cy.getByCypressId('editor-pane').should('be.visible')
cy.getByCypressId('documentIframe').should('be.visible')
})
it('mode edit', () => {
cy.visitTestNote(PAGE_MODE.EDITOR, 'edit')
cy.getByCypressId('editor-pane').should('be.visible')
cy.getByCypressId('documentIframe').should('not.be.visible')
})
})

View file

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Export', () => {
const testTitle = 'testContent'
const testContent = `---\ntitle: ${testTitle}\n---\nThis is some test content`
beforeEach(() => {
cy.visitTestNote()
cy.setCodemirrorContent(testContent)
})
it('Markdown', () => {
cy.getByCypressId('menu-export').click()
cy.getByCypressId('menu-export-markdown').click()
cy.get('a[download]')
.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'
// 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()
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)
}
}
xhr.send()
})
)
// Now the regular Cypress assertions should work.
.should('equal', testContent)
})
})

View file

@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
const imageUrl = 'http://example.com/non-existing.png'
describe('File upload', () => {
beforeEach(() => {
cy.visitTestNote()
cy.fixture('demo.png').as('demoImage')
})
describe('works', () => {
beforeEach(() => {
cy.intercept(
{
method: 'POST',
url: '/api/mock-backend/private/media'
},
{
statusCode: 201,
body: {
url: imageUrl
}
}
)
})
it('via button', () => {
cy.getByCypressId('editor-pane').should('have.attr', 'data-cypress-editor-ready', 'true')
cy.getByCypressId('editor-toolbar-upload-image-button').should('be.visible')
cy.getByCypressId('editor-toolbar-upload-image-input').selectFile(
{
contents: '@demoImage',
fileName: 'demo.png',
mimeType: 'image/png'
},
{ force: true }
)
cy.get('.cm-line').contains(`![demo.png](${imageUrl})`)
})
it('via paste', () => {
cy.getByCypressId('editor-pane').should('have.attr', 'data-cypress-editor-ready', 'true')
cy.fixture('demo.png').then((image: string) => {
const pasteEvent = {
clipboardData: {
files: [Cypress.Blob.base64StringToBlob(image, 'image/png')],
getData: () => ''
}
}
cy.get('.cm-content').trigger('paste', pasteEvent)
cy.get('.cm-line').contains(`![](${imageUrl})`)
})
})
it('via drag and drop', () => {
cy.getByCypressId('editor-pane').should('have.attr', 'data-cypress-editor-ready', 'true')
cy.get('.cm-content').selectFile(
{
contents: '@demoImage',
fileName: 'demo.png',
mimeType: 'image/png'
},
{ action: 'drag-drop', force: true }
)
cy.get('.cm-line').contains(`![demo.png](${imageUrl})`)
})
})
it('fails', () => {
cy.getByCypressId('editor-pane').should('have.attr', 'data-cypress-editor-ready', 'true')
cy.intercept(
{
method: 'POST',
url: '/api/mock-backend/private/media'
},
{
statusCode: 400
}
)
cy.getByCypressId('editor-toolbar-upload-image-button').should('be.visible')
cy.getByCypressId('editor-toolbar-upload-image-input').selectFile(
{
contents: '@demoImage',
fileName: 'demo.png',
mimeType: 'image/png'
},
{ force: true }
)
cy.get('.cm-line').contains('![upload of demo.png failed]()')
})
it('lets text paste still work', () => {
cy.getByCypressId('editor-pane').should('have.attr', 'data-cypress-editor-ready', 'true')
const testText = 'a long test text'
const pasteEvent: Event = Object.assign(new Event('paste', { bubbles: true, cancelable: true }), {
clipboardData: {
files: [],
getData: () => testText
}
})
cy.get('.cm-content').trigger('paste', pasteEvent)
cy.get('.cm-line').contains(`${testText}`)
})
})

View file

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Help Dialog', () => {
beforeEach(() => {
cy.visitTestNote()
})
it('ToDo-List', () => {
cy.getByCypressId('editor-help-button').click()
cy.get('input[type="checkbox"]').should('exist').should('not.be.checked')
})
})

191
cypress/e2e/history.spec.ts Normal file
View file

@ -0,0 +1,191 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('History', () => {
describe('History Mode', () => {
beforeEach(() => {
cy.visitHistory()
})
it('Cards', () => {
cy.getByCypressId('history-card').should('be.visible')
})
it('Table', () => {
cy.getByCypressId('history-mode-table').click()
cy.getByCypressId('history-table').should('be.visible')
})
})
describe('entry title', () => {
describe('is as given when not empty', () => {
beforeEach(() => {
cy.clearLocalStorage('history')
cy.intercept('GET', '/api/mock-backend/private/me/history', {
body: [
{
identifier: 'cypress',
title: 'Features',
lastVisited: '2020-05-16T22:26:56.547Z',
pinStatus: false,
tags: []
}
]
})
cy.visitHistory()
})
it('in table view', () => {
cy.getByCypressId('history-mode-table').click()
cy.getByCypressId('history-table').should('be.visible')
cy.getByCypressId('history-entry-title').contains('Features')
})
it('in cards view', () => {
cy.getByCypressId('history-entry-title').contains('Features')
})
})
describe('is untitled when not empty', () => {
beforeEach(() => {
cy.clearLocalStorage('history')
cy.intercept('GET', '/api/mock-backend/private/me/history', {
body: [
{
identifier: 'cypress-no-title',
title: '',
lastVisited: '2020-05-16T22:26:56.547Z',
pinStatus: false,
tags: []
}
]
})
cy.visitHistory()
})
it('in table view', () => {
cy.getByCypressId('history-mode-table').click()
cy.getByCypressId('history-table').should('be.visible')
cy.getByCypressId('history-entry-title').contains('Untitled')
})
it('in cards view', () => {
cy.getByCypressId('history-entry-title').contains('Untitled')
})
})
})
describe('Pinning', () => {
beforeEach(() => {
cy.visitHistory()
})
describe('working', () => {
beforeEach(() => {
cy.intercept('PUT', '/api/mock-backend/private/me/history/features', (req) => {
req.reply(200, req.body)
})
})
it('Cards', () => {
cy.getByCypressId('history-card').should('be.visible')
cy.getByCypressId('history-entry-pin-button').first().as('pin-button')
cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'true').click()
cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'false')
})
it('Table', () => {
cy.getByCypressId('history-mode-table').click()
cy.getByCypressId('history-entry-pin-button').first().as('pin-button')
cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'true').click()
cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'false')
})
})
describe('failing', () => {
beforeEach(() => {
cy.intercept('PUT', '/api/mock-backend/private/me/history/features', {
statusCode: 401
})
})
it('Cards', () => {
cy.getByCypressId('history-card').should('be.visible')
cy.getByCypressId('history-entry-pin-button').first().click()
cy.getByCypressId('notification-toast').should('be.visible')
})
it('Table', () => {
cy.getByCypressId('history-mode-table').click()
cy.getByCypressId('history-entry-pin-button').first().click()
cy.getByCypressId('notification-toast').should('be.visible')
})
})
})
describe('Import', () => {
beforeEach(() => {
cy.clearLocalStorage('history')
cy.intercept('GET', '/api/mock-backend/private/me/history', {
body: []
})
cy.visitHistory()
cy.logout()
cy.fixture('history.json').as('history')
cy.fixture('history-2.json').as('history-2')
cy.fixture('invalid-history.txt').as('invalid-history')
})
it('works with valid file', () => {
cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getByCypressId('import-history-file-input').selectFile(
{
contents: '@history',
fileName: 'history.json',
mimeType: 'application/json'
},
{ force: true }
)
cy.getByCypressId('history-entry-title').should('have.length', 1).contains('cy-Test')
})
it('fails on invalid file', () => {
cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getByCypressId('import-history-file-input').selectFile(
{
contents: '@invalid-history',
fileName: 'invalid-history.txt',
mimeType: 'text/plain'
},
{ force: true }
)
cy.getByCypressId('notification-toast').should('be.visible')
})
it('works when selecting two files with the same name', () => {
cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getByCypressId('import-history-file-input').selectFile(
{
contents: '@history',
fileName: 'history.json',
mimeType: 'application/json'
},
{ force: true }
)
cy.getByCypressId('history-entry-title').should('have.length', 1).contains('cy-Test')
cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getByCypressId('import-history-file-input').selectFile(
{
contents: '@history-2',
fileName: 'history.json',
mimeType: 'application/json'
},
{ force: true }
)
cy.getByCypressId('history-entry-title').should('have.length', 2).contains('cy-Test2')
})
})
})

View file

@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Iframe capsule', () => {
beforeEach(() => {
cy.visitTestNote()
})
it('shows a clickable click shield instead of the iframe', () => {
cy.setCodemirrorContent('<iframe src="https://example.org"></iframe>')
cy.getMarkdownBody().findByCypressId('iframe-capsule-click-shield').should('exist').click()
cy.getMarkdownBody().find('iframe').should('exist').should('have.attr', 'src', 'https://example.org')
})
})

View file

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Import markdown file', () => {
beforeEach(() => {
cy.visitTestNote()
cy.fixture('import.md').as('import')
})
it('import on blank note', () => {
cy.getByCypressId('menu-import').click()
cy.getByCypressId('menu-import-markdown-button').should('be.visible')
cy.getByCypressId('menu-import-markdown-input').selectFile(
{
contents: '@import',
fileName: 'import.md',
mimeType: 'text/markdown'
},
{ force: true }
)
cy.get('.cm-editor .cm-line:nth-child(1)').should('have.text', '# Some short import test file')
cy.get('.cm-editor .cm-line:nth-child(2)').should('have.text', ':)')
})
it('import on note with content', () => {
cy.setCodemirrorContent('test\nabc')
cy.getByCypressId('menu-import').click()
cy.getByCypressId('menu-import-markdown-button').should('be.visible')
cy.getByCypressId('menu-import-markdown-input').selectFile(
{
contents: '@import',
fileName: 'import.md',
mimeType: 'text/markdown'
},
{ force: true }
)
cy.get('.cm-editor .cm-line:nth-child(1)').should('have.text', 'test')
cy.get('.cm-editor .cm-line:nth-child(2)').should('have.text', 'abc')
cy.get('.cm-editor .cm-line:nth-child(3)').should('have.text', '# Some short import test file')
cy.get('.cm-editor .cm-line:nth-child(4)').should('have.text', ':)')
})
})

60
cypress/e2e/intro.spec.ts Normal file
View file

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/no-unsafe-call */
describe('Intro page', () => {
beforeEach(() => {
cy.intercept('/mock-public/intro.md', 'test content')
cy.visitHome()
})
describe('customizable content', () => {
it('fetches and shows the correct intro page content', () => {
cy.getIntroBody().contains('test content')
})
it("won't show anything if no content was found", () => {
cy.intercept('/mock-public/intro.md', {
statusCode: 404
})
cy.visitHome()
cy.getByCypressId('documentIframe').should('not.exist')
})
})
describe('features button', () => {
it('is hidden when logged in', () => {
cy.getByCypressId('features-button').should('not.exist')
})
it('is visible when logged out', () => {
cy.logout()
cy.getByCypressId('features-button').should('exist')
})
})
describe('sign in button', () => {
it('is hidden when logged in', () => {
cy.getByCypressId('sign-in-button').should('not.exist')
})
it('is visible when logged out', () => {
cy.logout()
cy.getByCypressId('sign-in-button').should('exist')
})
})
describe('version dialog', () => {
it('can be opened and closed', () => {
cy.getByCypressId('version-modal').should('not.exist')
cy.getByCypressId('show-version-modal').click()
cy.getByCypressId('version-modal').should('be.visible')
cy.getByCypressId('version-modal').find('.modal-header .close').click()
cy.getByCypressId('version-modal').should('not.exist')
})
})
})

View file

@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { languages } from '../fixtures/languages'
describe('Languages', () => {
beforeEach(() => {
cy.visitHome()
})
it('all languages are available', () => {
cy.getByCypressId('language-picker').find('option').as('languages')
cy.get('@languages').should('have.length', 28)
languages.forEach((language) => {
cy.get('@languages').contains(language)
})
})
it('language changes affect the UI', () => {
cy.getByCypressId('language-picker').select('English')
cy.getByCypressId('new-note-button').find('span').contains('New note')
cy.getByCypressId('language-picker').select('Deutsch')
cy.getByCypressId('new-note-button').find('span').contains('Neue Notiz')
})
})

View file

@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Link gets replaced with embedding: ', () => {
beforeEach(() => {
cy.visitTestNote()
})
// TODO Add general testing of one-click-embedding component. The tests below just test a specific use of the component.
it('GitHub Gist', () => {
cy.setCodemirrorContent('https://gist.github.com/schacon/1')
cy.getMarkdownBody().findByCypressId('click-shield-gist').find('.preview-background').parent().click()
cy.getMarkdownBody().findByCypressId('gh-gist').should('be.visible')
})
})

View file

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('markdown formatted links to', () => {
beforeEach(() => {
cy.visitTestNote()
})
it('external domains render as external link', () => {
cy.setCodemirrorContent('[external](https://hedgedoc.org/)')
cy.getMarkdownBody()
.find('a')
.should('have.attr', 'href', 'https://hedgedoc.org/')
.should('have.attr', 'rel', 'noreferer noopener')
.should('have.attr', 'target', '_blank')
})
it('note anchor references render as anchor link', () => {
cy.setCodemirrorContent('[anchor](#anchor)')
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor')
})
it('internal pages render as internal link', () => {
cy.setCodemirrorContent('[internal](other-note)')
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note')
})
it('data URIs do not render', () => {
cy.setCodemirrorContent('[data](data:text/plain,evil)')
cy.getMarkdownBody().find('a').should('not.exist')
})
it('javascript URIs do not render', () => {
cy.setCodemirrorContent('[js](javascript:alert("evil"))')
cy.getMarkdownBody().find('a').should('not.exist')
})
})
describe('HTML anchor element links to', () => {
beforeEach(() => {
cy.visitTestNote()
})
it('external domains render as external link', () => {
cy.setCodemirrorContent('<a href="https://hedgedoc.org/">external</a>')
cy.getMarkdownBody()
.find('a')
.should('have.attr', 'href', 'https://hedgedoc.org/')
.should('have.attr', 'rel', 'noreferer noopener')
.should('have.attr', 'target', '_blank')
})
it('note anchor references render as anchor link', () => {
cy.setCodemirrorContent('<a href="#anchor">anchor</a>')
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor')
})
it('internal pages render as internal link', () => {
cy.setCodemirrorContent('<a href="other-note">internal</a>')
cy.getMarkdownBody().find('a').should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note')
})
it('data URIs do not render', () => {
cy.setCodemirrorContent('<a href="data:text/plain,evil">data</a>')
cy.getMarkdownBody().find('a').should('not.have.attr', 'href')
})
it('javascript URIs do not render', () => {
cy.setCodemirrorContent('<a href="javascript:alert(\'evil\')">js</a>')
cy.getMarkdownBody().find('a').should('not.have.attr', 'href')
})
})

View file

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('The status bar text length info', () => {
const warningTestContent = '0123456789'.repeat(10)
const dangerTestContent = '0123456789'.repeat(20)
const tooMuchTestContent = `${dangerTestContent}a`
beforeEach(() => {
cy.visitTestNote()
})
it('shows the maximal length of the document as number of available characters in the tooltip', () => {
cy.getByCypressId('remainingCharacters').attribute('title').should('contain', ' 200 ')
})
it('color is set to "warning" on <= 100 characters remaining', () => {
cy.setCodemirrorContent(warningTestContent)
cy.getByCypressId('remainingCharacters').should('have.class', 'text-warning')
})
it('color is set to danger on <= 0 characters remaining', () => {
cy.setCodemirrorContent(dangerTestContent)
cy.getByCypressId('remainingCharacters').should('have.class', 'text-danger')
})
it('opens a modal', () => {
cy.setCodemirrorContent(tooMuchTestContent)
cy.getByCypressId('limitReachedModal').should('be.visible')
})
})

110
cypress/e2e/motd.spec.ts Normal file
View file

@ -0,0 +1,110 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
const MOTD_LOCAL_STORAGE_KEY = 'motd.lastModified'
const MOCK_LAST_MODIFIED = 'mockETag'
const motdMockContent = 'This is the **mock** Motd call'
const motdMockHtml = 'This is the <strong>mock</strong> Motd call'
describe('Motd', () => {
const mockExistingMotd = (useEtag?: boolean, content = motdMockContent) => {
cy.intercept('GET', '/mock-public/motd.md', {
statusCode: 200,
headers: { [useEtag ? 'etag' : 'Last-Modified']: MOCK_LAST_MODIFIED },
body: content
})
cy.intercept('HEAD', '/mock-public/motd.md', {
statusCode: 200,
headers: { [useEtag ? 'etag' : 'Last-Modified']: MOCK_LAST_MODIFIED }
})
}
beforeEach(() => {
localStorage.removeItem(MOTD_LOCAL_STORAGE_KEY)
})
it('shows the correct alert Motd text', () => {
mockExistingMotd()
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
})
it("doesn't allow html in the motd", () => {
mockExistingMotd(false, '<iframe></iframe>')
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('have.html', '<p>&lt;iframe&gt;&lt;/iframe&gt;</p>\n')
})
it('can be dismissed using etag', () => {
mockExistingMotd(true)
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
cy.getByCypressId('motd-dismiss')
.click()
.then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
})
cy.getByCypressId('motd').should('not.exist')
})
it('can be dismissed', () => {
mockExistingMotd()
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
cy.getByCypressId('motd-dismiss')
.click()
.then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
})
cy.getByCypressId('motd').should('not.exist')
})
it("won't show again after dismiss and reload", () => {
mockExistingMotd()
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
cy.getByCypressId('motd-dismiss')
.click()
.then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
})
cy.getByCypressId('motd').should('not.exist')
cy.reload()
cy.get('main').should('exist')
cy.getByCypressId('motd').should('not.exist')
})
it('will show again after reload without dismiss', () => {
mockExistingMotd()
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
cy.reload()
cy.get('main').should('exist')
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
})
it("won't show again after dismiss and page navigation", () => {
mockExistingMotd()
cy.visitHome()
cy.getByCypressId('motd').find('.markdown-body').should('contain.html', motdMockHtml)
cy.getByCypressId('motd-dismiss')
.click()
.then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
})
cy.getByCypressId('motd').should('not.exist')
cy.getByCypressId('navLinkHistory').click()
cy.get('main').should('exist')
cy.getByCypressId('motd').should('not.exist')
})
it("won't show if no file exists", () => {
cy.visitHome()
cy.get('main').should('exist')
cy.getByCypressId('motd').should('not.exist')
})
})

View file

@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('profile page', () => {
beforeEach(() => {
cy.intercept(
{
url: '/api/mock-backend/private/tokens',
method: 'GET'
},
{
body: [
{
label: 'cypress-App',
keyId: 'cypress',
createdAt: '2021-11-21T01:11:12+01:00',
lastUsed: '2021-11-21T01:11:12+01:00',
validUntil: '2023-11-21'
}
]
}
)
cy.intercept(
{
url: '/api/mock-backend/private/tokens',
method: 'POST'
},
{
body: {
label: 'cypress',
keyId: 'cypress2',
secret: 'c-y-p-r-e-s-s',
createdAt: '2021-11-21T01:11:12+01:00',
lastUsed: '2021-11-21T01:11:12+01:00',
validUntil: '2023-11-21'
},
statusCode: 201
}
)
cy.intercept(
{
url: '/api/mock-backend/private/tokens/cypress',
method: 'DELETE'
},
{
body: [],
statusCode: 204
}
)
cy.visit('/profile', { retryOnNetworkFailure: true })
})
describe('access tokens', () => {
it('list existing tokens', () => {
cy.getByCypressId('access-token-label').contains('cypress-App')
})
it('delete token', () => {
cy.getByCypressId('access-token-delete-button').click()
cy.getByCypressId('access-token-modal-delete').as('deletion-modal')
cy.get('@deletion-modal').should('be.visible').find('.modal-footer .btn-danger').click()
cy.get('@deletion-modal').should('not.exist')
})
it('add token', () => {
cy.getByCypressId('access-token-add-button').should('be.disabled')
cy.getByCypressId('access-token-add-input-label').type('cypress')
cy.getByCypressId('access-token-modal-add').should('not.exist')
cy.getByCypressId('access-token-add-button').should('not.be.disabled').click()
cy.getByCypressId('access-token-modal-add')
.should('be.visible')
.find('input[readonly]')
.should('have.value', 'c-y-p-r-e-s-s')
})
})
})

View file

@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Quote extra tags', function () {
beforeEach(() => {
cy.visitTestNote()
})
describe('Name quote tag', () => {
it('renders correctly', () => {
cy.setCodemirrorContent('[name=testy mctestface]')
cy.getMarkdownBody().find('.blockquote-extra').should('be.visible').find('.fa-user').should('be.visible')
cy.getMarkdownBody().find('.blockquote-extra').should('be.visible').contains('testy mctestface')
})
})
describe('Time quote tag', () => {
it('renders correctly', () => {
cy.setCodemirrorContent(`[time=always]`)
cy.getMarkdownBody().find('.blockquote-extra').should('be.visible').find('.fa-clock-o').should('be.visible')
cy.getMarkdownBody().find('.blockquote-extra').should('be.visible').contains('always')
})
})
describe('Color quote tag', () => {
it('renders correctly', () => {
cy.setCodemirrorContent(`[color=#b51f08]`)
cy.getMarkdownBody().find('.blockquote-extra').should('be.visible').find('.fa-tag').should('be.visible')
cy.getMarkdownBody().find('.blockquote-extra').should('be.visible').should('have.css', 'color', 'rgb(181, 31, 8)')
})
it("doesn't render in a blockquote and dyes the blockquote border", () => {
cy.setCodemirrorContent(`> [color=#b51f08] HedgeDoc`)
cy.getMarkdownBody().find('.blockquote-extra').should('not.exist')
cy.getMarkdownBody()
.find('blockquote')
.should('be.visible')
.should('have.css', 'border-left-color', 'rgb(181, 31, 8)')
})
})
})

View file

@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Renderer mode', () => {
beforeEach(() => {
cy.visitTestNote()
})
it("should be 'document' without type specified", () => {
cy.getMarkdownBody().should('exist')
})
it("should be 'reveal.js' with type 'slide'", () => {
cy.setCodemirrorContent('---\ntype: slide\n---\n')
cy.getReveal().should('exist')
})
it("should be 'document' with invalid type", () => {
cy.setCodemirrorContent('---\ntype: EinDokument\n---\n')
cy.getMarkdownBody().should('exist')
})
it("should change from 'reveal.js' to 'document' if changed from 'slide' to something else", () => {
cy.setCodemirrorContent('---\ntype: slide\n---\n')
cy.getReveal().should('exist')
cy.setCodemirrorContent('')
cy.getMarkdownBody().should('exist')
})
})

View file

@ -0,0 +1,96 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { AuthProvider } from '../../src/api/config/types'
import { AuthProviderType } from '../../src/api/config/types'
const initLoggedOutTestWithCustomAuthProviders = (cy: Cypress.cy, enabledProviders: AuthProvider[]) => {
cy.loadConfig({
authProviders: enabledProviders
})
cy.visitHome()
cy.logout()
}
describe('When logged-in, ', () => {
it('sign-in button is hidden', () => {
cy.visitHome()
cy.getByCypressId('sign-in-button').should('not.exist')
})
})
describe('When logged-out ', () => {
describe('and no auth-provider is enabled, ', () => {
it('sign-in button is hidden', () => {
initLoggedOutTestWithCustomAuthProviders(cy, [])
cy.getByCypressId('sign-in-button').should('not.exist')
})
})
describe('and an interactive auth-provider is enabled, ', () => {
it('sign-in button points to login route: internal', () => {
initLoggedOutTestWithCustomAuthProviders(cy, [
{
type: AuthProviderType.LOCAL
}
])
cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
})
it('sign-in button points to login route: ldap', () => {
initLoggedOutTestWithCustomAuthProviders(cy, [
{
type: AuthProviderType.LDAP,
identifier: 'cy-ldap',
providerName: 'cy LDAP'
}
])
cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
})
})
describe('and only one one-click auth-provider is enabled, ', () => {
it('sign-in button points to auth-provider', () => {
initLoggedOutTestWithCustomAuthProviders(cy, [
{
type: AuthProviderType.GITHUB
}
])
cy.getByCypressId('sign-in-button')
.should('be.visible')
// The absolute URL is used because it is defined as API base URL absolute.
.should('have.attr', 'href', '/auth/github')
})
})
describe('and multiple one-click auth-providers are enabled, ', () => {
it('sign-in button points to login route', () => {
initLoggedOutTestWithCustomAuthProviders(cy, [
{
type: AuthProviderType.GITHUB
},
{
type: AuthProviderType.GOOGLE
}
])
cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
})
})
describe('and one-click- as well as interactive auth-providers are enabled, ', () => {
it('sign-in button points to login route', () => {
initLoggedOutTestWithCustomAuthProviders(cy, [
{
type: AuthProviderType.GITHUB
},
{
type: AuthProviderType.LOCAL
}
])
cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
})
})
})

View file

@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { PAGE_MODE } from '../support/visit'
describe('Slideshow only page', () => {
it('renders slide show mode', () => {
cy.visitTestNote(PAGE_MODE.PRESENTATION)
cy.getReveal().should('exist')
})
})

View file

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Task lists ', () => {
beforeEach(() => {
cy.visitTestNote()
})
describe('render with checkboxes ', () => {
it('when unchecked', () => {
cy.setCodemirrorContent('- [ ] abc\n\n* [ ] abc\n\n+ [ ] abc\n\n1. [ ] abc\n\n10. [ ] abc\n\n5) [ ] abc')
cy.getMarkdownBody().find('input[type=checkbox]').should('have.length', 6)
})
it('when checked lowercase', () => {
cy.setCodemirrorContent('- [x] abc\n\n* [x] abc\n\n+ [x] abc\n\n1. [x] abc\n\n10. [x] abc\n\n5) [x] abc')
cy.getMarkdownBody().find('input[type=checkbox]').should('have.length', 6)
})
it('when checked uppercase', () => {
cy.setCodemirrorContent('- [X] abc\n\n* [X] abc\n\n+ [X] abc\n\n1. [X] abc\n\n10. [X] abc\n\n5) [X] abc')
cy.getMarkdownBody().find('input[type=checkbox]').should('have.length', 6)
})
})
it('do not render as checkboxes when invalid', () => {
cy.setCodemirrorContent('- [Y] abc\n\n* [ ] abc\n\n+ [-] abc\n\n1. [.] abc\n\n10. [] abc\n\n5) [-] abc')
cy.getMarkdownBody().find('input[type=checkbox]').should('have.length', 0)
})
describe('are clickable and change the markdown source ', () => {
it('from unchecked to checked', () => {
cy.setCodemirrorContent('- [ ] abc')
cy.getMarkdownBody()
.find('input[type=checkbox]')
.each((box) => {
box.click()
})
cy.get('.cm-editor .cm-line').first().should('contain.text', '[x]').should('not.contain.text', '[ ]')
})
it('from checked (lowercase) to unchecked', () => {
cy.setCodemirrorContent('- [x] abc')
cy.getMarkdownBody()
.find('input[type=checkbox]')
.each((box) => {
box.click()
})
cy.get('.cm-editor .cm-line').should('exist').should('contain.text', '[ ]').should('not.contain.text', '[x]')
})
it('from checked (uppercase) to unchecked', () => {
cy.setCodemirrorContent('- [X] abc')
cy.getMarkdownBody()
.find('input[type=checkbox]')
.each((box) => {
box.click()
})
cy.get('.cm-editor .cm-line').should('exist').should('contain.text', '[ ]').should('not.contain.text', '[X]')
})
})
})

View file

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
describe('Test word count with', () => {
beforeEach(() => {
cy.visitTestNote()
})
it('empty note', () => {
cy.setCodemirrorContent('')
cy.wait(500)
cy.getByCypressId('sidebar-btn-document-info').click()
cy.getByCypressId('document-info-modal').should('be.visible')
cy.getByCypressId('document-info-word-count').should('have.text', '0')
})
it('simple words', () => {
cy.setCodemirrorContent('five words should be enough')
cy.wait(500)
cy.getByCypressId('sidebar-btn-document-info').click()
cy.getByCypressId('document-info-modal').should('be.visible')
cy.getByCypressId('document-info-word-count').should('have.text', '5')
})
it('excluded codeblocks', () => {
cy.setCodemirrorContent('```\nthis is should be ignored\n```\n\ntwo `words`')
cy.wait(500)
cy.getByCypressId('sidebar-btn-document-info').click()
cy.getByCypressId('document-info-modal').should('be.visible')
cy.getByCypressId('document-info-word-count').should('have.text', '2')
})
it('excluded images', () => {
cy.setCodemirrorContent('![ignored alt text](https://dummyimage.com/48) not ignored text')
cy.wait(500)
cy.getByCypressId('sidebar-btn-document-info').click()
cy.getByCypressId('document-info-modal').should('be.visible')
cy.getByCypressId('document-info-word-count').should('have.text', '3')
})
})

View file

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2022 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.visitTestNote()
})
it('is shown when using old syntax', () => {
cy.setCodemirrorContent('---\ntags: a, b, c\n---')
cy.getIframeBody().findByCypressId('yamlArrayDeprecationAlert').should('be.visible')
})
it("isn't shown when using inline yaml-array", () => {
cy.setCodemirrorContent("---\ntags: ['a', 'b', 'c']\n---")
cy.getIframeBody().findByCypressId('yamlArrayDeprecationAlert').should('not.exist')
})
it("isn't shown when using multi line yaml-array", () => {
cy.setCodemirrorContent('---\ntags:\n - a\n - b\n - c\n---')
cy.getIframeBody().findByCypressId('yamlArrayDeprecationAlert').should('not.exist')
})
})