Skip to content

Commit

Permalink
Merge pull request #2665 from nextcloud/feature/drop-menu-bubble
Browse files Browse the repository at this point in the history
Replace MenuBubble with a menu bar entry for links
  • Loading branch information
mejo- authored Oct 24, 2022
2 parents 9c57129 + 3e1ffbd commit 691cbe4
Show file tree
Hide file tree
Showing 31 changed files with 442 additions and 374 deletions.
3 changes: 3 additions & 0 deletions cypress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ cy.getContent()
| `getContent` | Get editor content | |
| `clearContent` | Clear the editor content | |
| `getMenu` | Get editor menu bar | |
| `getMenuEntry` | Same as `getActionEntry` but also searches the overflow menu | `name` |
| `getSubmenuEntry` | Open parent menu and then return sub menu entry | `parent`, `name` |
| `getActionEntry` | Get menu entry | `name` |
| `getActionSubEntry` | Get submenu entry (after menu clicked) | `name` |
| `openWorkspace` | Open workspace and return Editor content | |
100 changes: 89 additions & 11 deletions cypress/e2e/links.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ describe('test link marks', function() {
.then($el => {
const id = $el.data('id')

const link = `${Cypress.env('baseUrl')}/file-name?fileId=${id} `
cy.getContent()
.type('{enter}')
.type(link)
const link = `${Cypress.env('baseUrl')}/file-name?fileId=${id}`
cy.clearContent()
.type(`${link}{enter}`)

cy.getContent()
.find(`a[href*="${Cypress.env('baseUrl')}"]`)
Expand All @@ -67,16 +66,16 @@ describe('test link marks', function() {
})
})

it('whithout protocol', () => {
cy.getContent()
it('without protocol', () => {
cy.clearContent()
.type('google.com{enter}')

cy.getContent()
.find('a[href*="google.com"]')
.should('not.exist')
.then(() => cy.getContent()
.find('a[href*="google.com"]')
.should('not.exist')
)
})

it('whithout space', () => {
it('with protocol but without space', () => {
cy.getContent()
.type('https://nextcloud.com')

Expand All @@ -85,4 +84,83 @@ describe('test link marks', function() {
.should('not.exist')
})
})

describe('link menu', function() {
beforeEach(() => cy.clearContent())
const text = 'some text'

describe('link to website', function() {
const url = 'https://nextcloud.com/'
// Helper to reduce duplicated code, checking inserting with and without selected text
const checkLinkWebsite = (url, text) => {
cy.getSubmenuEntry('insert-link', 'insert-link-website').click()
cy.getActionSubEntry('insert-link-input').find('input[type="text"]').type(`${url}{enter}`)
cy.getContent()
.get(`a[href*="${url}"]`)
.should('have.text', text) // ensure correct text used
.click({ force: true })

cy.get('@winOpen')
.should('have.been.calledOnce')
.should('have.been.calledWith', url)
}

beforeEach(cy.clearContent)
it('Link website without selection', () => {
cy.getFile(fileName)
.then($el => {
checkLinkWebsite(url, url)
})
})

it('Link website with selection', () => {
cy.getFile(fileName)
.then($el => {
cy.getContent().type(`${text}{selectAll}`)
checkLinkWebsite(url, text)
})
})
})

describe('link to local file', function() {
// Helper to reduce duplicated code, checking inserting with and without selected text
const checkLinkFile = (filename, text) => {
cy.getSubmenuEntry('insert-link', 'insert-link-file').click()
cy.get('.oc-dialog').find(`tr[data-entryname="${filename}"]`).click()
cy.get('.oc-dialog').find('.oc-dialog-buttonrow > button').click()

return cy.getContent()
.find(`a[href*="${encodeURIComponent(filename)}"]`)
.should('have.text', text === undefined ? filename : text)
.click({ force: true })
}

beforeEach(() => cy.clearContent())

it('without text', () => {
cy.getFile(fileName)
.then($el => {
checkLinkFile(fileName)
cy.get('.modal-title').should('include.text', fileName)
})
})
it('with selected text', () => {
cy.getFile(fileName)
.then($el => {
cy.getContent().type(`${text}{selectAll}`)
checkLinkFile(fileName, text)
cy.get('.modal-title').should('include.text', fileName)
})
})
it('link to directory', () => {
cy.createFolder(`${window.__currentDirectory}/dummy folder`)
cy.getFile(fileName).then($el => {
cy.getContent().type(`${text}{selectAll}`)
checkLinkFile('dummy folder', text)
cy.get('@winOpen')
.should('have.been.calledOnce')
})
})
})
})
})
12 changes: 7 additions & 5 deletions cypress/e2e/sections.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ describe('Content Sections', () => {
// Create link to top heading
cy.clearContent()
.type('{selectAll}{backspace}move top\n{selectAll}')
.get('.menububble button[data-text-bubble-action="add-link"]')
.click({ force: true })
.then(() => {
cy.get('.menububble .menububble__input')
.type('{shift}')
.type('#top{enter}', { force: true })
cy.getSubmenuEntry('insert-link', 'insert-link-website')
.click()
.then(() => {
cy.getActionSubEntry('insert-link-input')
.find('input[type="text"]')
.type('#top{enter}')
})
})
// Insert content above link
cy.getContent()
Expand Down
72 changes: 14 additions & 58 deletions cypress/e2e/workspace.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,63 +63,36 @@ describe('Workspace', function() {
['underline', 'u'],
['strikethrough', 's'],
].forEach(([button, tag]) => {
menuButton(button)
cy.getMenuEntry(button)
.click({ force: true })
.should('have.class', 'is-active')
cy.getContent()
.find(`${tag}`)
.should('contain', 'Format me')
menuButton(button)
cy.getMenuEntry(button)
.click({ force: true })
.should('not.have.class', 'is-active')
})
})

it('links via menububble', function() {
cy.openWorkspace()
.type('Nextcloud')
.type('{selectall}')
menuBubbleButton('add-link').click()
cy.get('.menububble input').type('https://nextcloud.com{enter}')
cy.getContent()
.find('a')
.should('contain', 'Nextcloud')
.should('be.visible')
cy.getContent()
.find('a').invoke('attr', 'href')
.should('include', 'https://nextcloud.com')
cy.window().then((win) => {
cy.stub(win, 'open').as('windowOpen')
})
cy.getContent()
.find('a').click()
cy.get('@windowOpen').should('be.calledWith', 'https://nextcloud.com/')
cy.getContent().type('{selectall}')
menuBubbleButton('add-link').click()
cy.get('.menububble input').type('/team{enter}')
cy.getContent()
.find('a').click()
cy.get('@windowOpen').should('be.calledWith', 'https://nextcloud.com/team')
})

it('creates headings via submenu', function() {
cy.openWorkspace()
.type('Heading')
.type('{selectall}')
;['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach((heading) => {
const actionName = `headings-${heading}`

getSubmenuItem('headings', actionName).click()
cy.getSubmenuEntry('headings', actionName).click()

cy.getContent()
.find(`${heading}`)
.should('contain', 'Heading')

getSubmenuItem('headings', actionName)
cy.getSubmenuEntry('headings', actionName)
.should('have.class', 'is-active')
.click()

menuButton('headings').should('not.have.class', 'is-active')
cy.getMenuEntry('headings').should('not.have.class', 'is-active')
})
})

Expand All @@ -132,14 +105,14 @@ describe('Workspace', function() {
['ordered-list', 'ol'],
['task-list', 'ul[data-type="taskList"]'],
].forEach(([button, tag]) => {
menuButton(button)
cy.getMenuEntry(button)
.click({ force: true })
.should('have.class', 'is-active')

cy.getContent()
.find(`${tag}`).should('contain', 'List me')

menuButton(button)
cy.getMenuEntry(button)
.click({ force: true })
.should('not.have.class', 'is-active')
})
Expand All @@ -157,7 +130,7 @@ describe('Workspace', function() {
cy.openWorkspace()
.type('# Let\'s smile together{enter}## ')

menuButton('emoji-picker')
cy.getMenuEntry('emoji-picker')
.click()

cy.get('#emoji-mart-list button[aria-label="😀, grinning"]')
Expand Down Expand Up @@ -187,7 +160,7 @@ describe('Workspace', function() {
const actionName = `callout-${type}`

// enable callout
getSubmenuItem('callouts', actionName)
cy.getSubmenuEntry('callouts', actionName)
.click()
.then(() => {
// check content
Expand All @@ -196,7 +169,7 @@ describe('Workspace', function() {
.should('contain', 'Callout')

// disable
return getSubmenuItem('callouts', actionName)
return cy.getSubmenuEntry('callouts', actionName)
.should('have.class', 'is-active')
.click()
})
Expand All @@ -209,13 +182,13 @@ describe('Workspace', function() {
let last = first

// enable callout
getSubmenuItem('callouts', `callout-${first}`)
cy.getSubmenuEntry('callouts', `callout-${first}`)
.click()

cy.wrap(rest)
.each(type => {
const actionName = `callout-${type}`
return getSubmenuItem('callouts', actionName)
return cy.getSubmenuEntry('callouts', actionName)
.click()
.then(() => cy.getContent().find(`.callout.callout--${type}`))
.should('contain', 'Callout')
Expand All @@ -224,10 +197,10 @@ describe('Workspace', function() {
})
})
.then(() => {
getSubmenuItem('callouts', `callout-${last}`)
cy.getSubmenuEntry('callouts', `callout-${last}`)
.click()

menuButton('callouts')
cy.getMenuEntry('callouts')
.should('not.have.class', 'is-active')
})
})
Expand Down Expand Up @@ -287,23 +260,6 @@ describe('Workspace', function() {
})
})

const menuButton = (name) => {
return cy.getActionEntry(name)
}

const submenuButton = (name) => {
return cy.get('.v-popper__wrapper .open').getActionEntry(name)
}

const menuBubbleButton = (name) => {
return cy.get('[data-text-el="menu-bubble"]').find(`[data-text-bubble-action="${name}"]`)
}

const getSubmenuItem = (parent, item) => {
menuButton(parent).click()
return submenuButton(item)
}

const openSidebar = filename => {
cy.get(`.files-fileList tr[data-file="${filename}"]`)
.should('contain', filename)
Expand Down
27 changes: 26 additions & 1 deletion cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ Cypress.Commands.add('isolateTest', ({ sourceFile = 'text.md', targetFile = null
cy.createFolder(folderName)
cy.uploadFile(sourceFile, 'text/markdown', `${encodeURIComponent(folderName)}/${targetFile}`)

window.__currentDirectory = folderName
return cy.visit(`apps/files?dir=/${encodeURIComponent(folderName)}`, { onBeforeLoad })
.then(() => ({ folderName, fileName: targetFile }))
})
Expand Down Expand Up @@ -294,11 +295,32 @@ Cypress.Commands.add('getMenu', { prevSubject: 'optional' }, (subject) => {
.find('[data-text-el="menubar"]')
})

// Get menu entry even if moved into overflow menu
Cypress.Commands.add('getMenuEntry', (name) => {
cy.getMenu().then(($body) => {
if ($body.find(`[data-text-action-entry="${name}"]`).length) {
return cy.getActionEntry(name)
}
return cy.getSubmenuEntry('remain', name)
})
})

Cypress.Commands.add('getSubmenuEntry', { prevSubject: 'optional' }, (subject, parent, name) => {
return (subject ? cy.wrap(subject) : cy.getMenu())
.getActionEntry(parent)
.click()
.then(() => cy.getActionSubEntry(name))
})

Cypress.Commands.add('getActionEntry', { prevSubject: 'optional' }, (subject, name) => {
return (subject ? cy.wrap(subject) : cy.getMenu())
.find(`[data-text-action-entry="${name}"]`)
})

Cypress.Commands.add('getActionSubEntry', (name) => {
return cy.get('.action-item__popper .open').getActionEntry(name)
})

Cypress.Commands.add('getContent', { prevSubject: 'optional' }, (subject) => {
return (subject ? cy.wrap(subject) : cy.getEditor())
.find('.ProseMirror')
Expand All @@ -315,7 +337,10 @@ Cypress.Commands.add('getTOC', () => {
Cypress.Commands.add('clearContent', () => {
return cy.getContent()
.scrollIntoView()
.type('{selectAll}{backspace}', { force: true })
.then(() => cy.getContent()
.type('{selectAll}{backspace}')
)
.then(() => cy.getContent())
})

Cypress.Commands.add('openWorkspace', () => {
Expand Down
2 changes: 0 additions & 2 deletions js/editor-rich.js

This file was deleted.

1 change: 0 additions & 1 deletion js/editor-rich.js.map

This file was deleted.

4 changes: 2 additions & 2 deletions js/editor.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/editor.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/files-modal.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 691cbe4

Please sign in to comment.