diff --git a/cypress/e2e/directediting.spec.js b/cypress/e2e/directediting.spec.js index 9915ad8064d..2fc348a015b 100644 --- a/cypress/e2e/directediting.spec.js +++ b/cypress/e2e/directediting.spec.js @@ -6,10 +6,8 @@ function enterContentAndClose() { cy.intercept({ method: 'POST', url: '**/session/*/close' }).as('closeRequest') cy.intercept({ method: 'POST', url: '**/session/*/push' }).as('push') cy.intercept({ method: 'POST', url: '**/session/*/sync' }).as('sync') - cy.getContent().type('# This is a headline') - cy.getContent().type('{enter}') - cy.getContent().type('Some text') - cy.getContent().type('{enter}') + cy.insertLine('# This is a headline') + cy.insertLine('Some text') cy.getContent().type('{ctrl+s}') cy.wait('@push') cy.wait('@sync') diff --git a/cypress/e2e/nodes/CodeBlock.spec.js b/cypress/e2e/nodes/CodeBlock.spec.js index 1a825932850..05b926d29af 100644 --- a/cypress/e2e/nodes/CodeBlock.spec.js +++ b/cypress/e2e/nodes/CodeBlock.spec.js @@ -104,7 +104,7 @@ describe('Front matter support', function() { cy.isolateTest({ sourceFile: 'codeblock.md' }) cy.openFile('codeblock.md').then(() => { cy.clearContent() - cy.getContent().type('{enter}```javascript{enter}') + cy.insertLine('```javascript') cy.getContent().type('const foo = "bar"{enter}{enter}{enter}') cy.getContent().find('.hljs-keyword').first().contains('const') }) @@ -123,7 +123,7 @@ describe('Front matter support', function() { it('Add an invalid mermaid block', function() { cy.isolateTest() cy.openFile('empty.md').then(() => { - cy.getContent().type('```mermaid{enter}') + cy.insertLine('```mermaid') cy.getContent().find('code').should('exist') cy.getContent().get('.split-view__preview').should('be.visible') // eslint-disable-next-line cypress/no-unnecessary-waiting @@ -138,7 +138,7 @@ describe('Front matter support', function() { it('Add a valid mermaid block', function() { cy.isolateTest() cy.openFile('empty.md').then(() => { - cy.getContent().type('```mermaid{enter}') + cy.insertLine('```mermaid') cy.getContent().find('code').should('exist') cy.getContent().get('.split-view__preview').should('be.visible') // eslint-disable-next-line cypress/no-unnecessary-waiting diff --git a/cypress/e2e/nodes/Links.spec.js b/cypress/e2e/nodes/Links.spec.js index c1b0dfaaeb9..d5fddbc7e90 100644 --- a/cypress/e2e/nodes/Links.spec.js +++ b/cypress/e2e/nodes/Links.spec.js @@ -1,11 +1,11 @@ -import { initUserAndFiles, randUser } from '../../utils/index.js' +import { randUser } from '../../utils/index.js' const user = randUser() const fileName = 'empty.md' describe('test link marks', function() { before(function() { - initUserAndFiles(user) + cy.createUser(user) }) beforeEach(function() { @@ -21,14 +21,17 @@ describe('test link marks', function() { }) describe('link bubble', function() { - it('shows a link preview in the bubble after clicking link', () => { - const link = 'https://nextcloud.com/' - cy.getContent() - .type(`${link}{enter}`) + function clickLink(link, options = {}) { cy.getContent() .find(`a[href*="${link}"]`) - .click() + .click(options) + } + + it('shows a link preview in the bubble after clicking link', () => { + const link = 'https://nextcloud.com/' + cy.insertLine(link) + clickLink(link) cy.get('.link-view-bubble .widget-default', { timeout: 10000 }) .find('.widget-default--name') @@ -38,8 +41,7 @@ describe('test link marks', function() { it('shows a link preview in the bubble after browsing to link', () => { const link = 'https://nextcloud.com/' - cy.getContent() - .type(`${link}{enter}`) + cy.insertLine(link) cy.getContent() .find(`a[href*="${link}"]`) @@ -53,12 +55,9 @@ describe('test link marks', function() { it('closes the link bubble when clicking elsewhere', () => { const link = 'https://nextcloud.com/' - cy.getContent() - .type(`${link}{enter}`) - cy.getContent() - .find(`a[href*="${link}"]`) - cy.getContent() - .type('{upArrow}') + cy.insertLine(link) + clickLink(link) + cy.get('.link-view-bubble .widget-default', { timeout: 10000 }) .find('.widget-default--name') .contains('Nextcloud') @@ -69,32 +68,47 @@ describe('test link marks', function() { .should('not.exist') }) - it('allows to edit a link in the bubble', () => { - cy.getContent() - .type('https://example.org{enter}') - cy.getContent() - .type('{upArrow}{rightArrow}') - + const changeLink = target => { cy.get('.link-view-bubble button[title="Edit link"]') .click() - cy.get('.link-view-bubble input') - .type('{selectAll}https://nextcloud.com') - - cy.get('.link-view-bubble button[title="Save changes"]') - .click() + .type(`{selectAll}${target}{enter}`) + } + it('allows to edit a link in the bubble', () => { + cy.insertLine('https://example.org') + clickLink('https://example.org') + changeLink('https://nextcloud.com') cy.getContent() .find('a[href*="https://nextcloud.com"]') + }) + it('does not link to other protocols', () => { + cy.insertLine('https://example.org') + clickLink('https://example.org') + cy.get('.link-view-bubble .widget-default') + .should('exist') + changeLink('mailto:test@my.example') + cy.getContent() + .find('a[href*="mailto:test@my.example"]') + .should('exist') + cy.get('.link-view-bubble .widget-default') + .should('not.exist') + changeLink('unknown:protocol') + cy.getContent() + .find('a[href*="unknown:protocol"]') + .should('not.exist') + cy.getContent() + .find('a[href*="#"]') + .should('exist') + cy.get('.link-view-bubble .widget-default') + .should('not.exist') }) it('allows to remove a link in the bubble', () => { const link = 'https://nextcloud.com' - cy.getContent() - .type(`${link}{enter}`) - cy.getContent() - .type('{upArrow}{rightArrow}') + cy.insertLine(link) + clickLink(link) cy.get('.link-view-bubble button[title="Remove link"]') .click() @@ -107,17 +121,15 @@ describe('test link marks', function() { it('Ctrl-click on a link opens a new tab', () => { const link = 'https://nextcloud.com/' - cy.getContent() - .type(`${link}{enter}`) + cy.insertLine(link) - cy.getContent() - .find(`a[href*="${link}"]`) - .click({ ctrlKey: true }) + clickLink(link, { ctrlKey: true }) cy.get('@winOpen') .should('have.been.calledOnce') .should('have.been.calledWith', link) }) + }) describe('autolink', function() { @@ -128,8 +140,7 @@ describe('test link marks', function() { const link = `${Cypress.env('baseUrl')}/apps/files/?dir=/&openfile=${id}#relPath=/${fileName}` cy.clearContent() - cy.getContent() - .type(`${link}{enter}`) + cy.insertLine(link) cy.getContent() .find(`a[href*="${Cypress.env('baseUrl')}"]`) @@ -138,16 +149,14 @@ describe('test link marks', function() { it('without protocol', () => { cy.clearContent() - cy.getContent() - .type('google.com{enter}') + cy.insertLine('google.com') cy.getContent() .find('a[href*="google.com"]') .should('not.exist') }) it('with protocol but without space', () => { - cy.getContent() - .type('https://nextcloud.com') + cy.getContent().type('https://nextcloud.com') cy.getContent() .find('a[href*="nextcloud.com"]') diff --git a/cypress/e2e/sections.spec.js b/cypress/e2e/sections.spec.js index bca3b00a5b7..d7457db142f 100644 --- a/cypress/e2e/sections.spec.js +++ b/cypress/e2e/sections.spec.js @@ -45,7 +45,7 @@ describe('Content Sections', () => { it('Anchor ID is updated', () => { cy.visitTestFolder() cy.openFile(fileName, { force: true }) - cy.getContent().type('# Heading 1{enter}') + cy.insertLine('# Heading 1') cy.getContent() .find('h1 > a') .should('have.attr', 'id') @@ -84,8 +84,7 @@ describe('Content Sections', () => { cy.visitTestFolder() cy.openFile(fileName, { force: true }) // Issue #2868 - cy.getContent() - .type('# Heading 1{enter}') + cy.insertLine('# Heading 1') cy.getContent() .find('h1 > a') .should('have.attr', 'id') diff --git a/cypress/e2e/sync.spec.js b/cypress/e2e/sync.spec.js index 11f17f41d06..9be6edf9051 100644 --- a/cypress/e2e/sync.spec.js +++ b/cypress/e2e/sync.spec.js @@ -38,7 +38,7 @@ describe('Sync', () => { cy.openTestFile() cy.wait('@sync', { timeout: 10000 }) cy.getContent().find('h2').should('contain', 'Hello world') - cy.getContent().type('{moveToEnd}* Saving the doc saves the doc state{enter}') + cy.insertLine('{moveToEnd}* Saving the doc saves the doc state') cy.wait('@sync', { timeout: 10000 }) }) @@ -77,7 +77,7 @@ describe('Sync', () => { .should('not.contain', 'Document could not be loaded.') // FIXME: There seems to be a bug where typed words maybe lost if not waiting for the new session cy.wait('@syncAfterRecovery', { timeout: 10000 }) - cy.getContent().type('* more content added after the lost connection{enter}') + cy.insertLine('* more content added after the lost connection') cy.wait('@syncAfterRecovery', { timeout: 10000 }) cy.closeFile() cy.testName() @@ -137,7 +137,7 @@ describe('Sync', () => { .should('not.contain', 'Document could not be loaded.') // FIXME: There seems to be a bug where typed words maybe lost if not waiting for the new session cy.wait('@syncAfterRecovery', { timeout: 10000 }) - cy.getContent().type('* more content added after the lost connection{enter}') + cy.insertLine('* more content added after the lost connection') cy.wait('@syncAfterRecovery', { timeout: 10000 }) cy.closeFile() cy.testName() diff --git a/cypress/e2e/viewer.spec.js b/cypress/e2e/viewer.spec.js index 4a640ae5e7c..b5601a3a7f4 100644 --- a/cypress/e2e/viewer.spec.js +++ b/cypress/e2e/viewer.spec.js @@ -95,8 +95,7 @@ describe('Open test.md in viewer', function() { // This used to break with the focus trap that the viewer modal has cy.openFile('empty.md') - cy.getContent() - .type('- test{enter}') + cy.insertLine('- test') // Cypress does not have native tab key support, though this seems to work // for triggering the key handler of tiptap diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 51a5e216501..9b2b045bc44 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -385,6 +385,11 @@ Cypress.Commands.add('clearContent', () => { cy.getContent() }) +Cypress.Commands.add('insertLine', (line = '') => { + cy.getContent() + .type(`${line}{enter}`) +}) + Cypress.Commands.add('openWorkspace', () => { cy.createDescription() cy.get('#rich-workspace .editor__content').click({ force: true }) diff --git a/src/components/Link/LinkBubbleView.vue b/src/components/Link/LinkBubbleView.vue index 89158031bb8..a41b56c09c4 100644 --- a/src/components/Link/LinkBubbleView.vue +++ b/src/components/Link/LinkBubbleView.vue @@ -69,7 +69,7 @@ - 'files') +const linkTo = href => domHref({ attrs: { href } }) + describe('Preparing href attributes for the DOM', () => { test('leave empty hrefs alone', () => { - expect(domHref({attrs: {href: ''}})).toBe('') + expect(linkTo('')).toBe('') }) test('leave undefined hrefs alone', () => { @@ -27,32 +29,30 @@ describe('Preparing href attributes for the DOM', () => { }) test('full url', () => { - expect(domHref({attrs: {href: 'https://otherdomain.tld'}})) - .toBe('https://otherdomain.tld') + expect(linkTo('https://otherdomain.tld')).toBe('https://otherdomain.tld') }) - test('other protocol', () => { - expect(domHref({attrs: {href: 'mailTo:test@mail.example'}})) - .toBe('mailTo:test@mail.example') + test('other protocols', () => { + expect(linkTo('mailto:name@otherdomain.tld')).toBe('mailto:name@otherdomain.tld') }) test('relative link with fileid (old format from file picker)', () => { - expect(domHref({attrs: {href: 'otherfile?fileId=123'}})) + expect(linkTo('otherfile?fileId=123')) .toBe('http://localhost/f/123') }) test('relative path with ../ (old format from file picker)', () => { - expect(domHref({attrs: {href: '../other/otherfile?fileId=123'}})) + expect(linkTo('../other/otherfile?fileId=123')) .toBe('http://localhost/f/123') }) test('absolute path (old format from file picker)', () => { - expect(domHref({attrs: {href: '/other/otherfile?fileId=123'}})) + expect(linkTo('/other/otherfile?fileId=123')) .toBe('http://localhost/f/123') }) test('absolute path (old format from file picker)', () => { - expect(domHref({attrs: {href: '/otherfile?fileId=123'}})) + expect(linkTo('/otherfile?fileId=123')) .toBe('http://localhost/f/123') }) @@ -134,7 +134,7 @@ describe('Preparing href attributes for the DOM in Collectives app', () => { }) test('relative link with fileid in Collectives', () => { - expect(domHref({attrs: {href: 'otherfile?fileId=123'}})) + expect(linkTo('otherfile?fileId=123')) .toBe('otherfile?fileId=123') }) })