@instructure/canvas-rce
Version:
A component wrapping Canvas's usage of Tinymce
320 lines (278 loc) • 9.81 kB
JavaScript
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {Selector, ClientFunction} from 'testcafe'
fixture`RCEWrapper`.page`./testcafe.html`
const tinyIframe = Selector('#textarea_ifr')
const textArea = Selector('.RceHtmlEditor')
const rceContainer = Selector('.tox-tinymce')
const toggleButton = Selector('button').withText('</>')
const linksButton = Selector('[role="button"][aria-label="Links"] .tox-split-button__chevron')
const externalLinksMenuItem = Selector('[role^="menuitem"][title="External Links"]')
const courseLinksMenuItem = Selector('[role^="menuitem"][title="Course Links"]')
const editLinkMenuItem = Selector('[role^="menuitem"][title="Edit Link"]')
const removeLinkMenuItem = Selector('[role^="menuitem"][title="Remove Link"]')
const linkDialog = Selector('[data-testid="RCELinkOptionsDialog"]')
const linkTray = Selector('[data-testid="RCELinkOptionsTray"]')
const selectword = Selector('#selectword')
const linksTraySelector = '[role="dialog"][aria-label="Course Links"]'
const rceBody = Selector('#tinymce')
const linksPanelSelector = Selector('[data-testid="instructure_links-LinksPanel"]')
function named(name) {
return Selector(`[name="${name}"]`)
}
function specificValue(value) {
return Selector(`[value="${value}"]`)
}
test.skip('edits in the textarea are reflected in the editor', async t => {
// const myText = ClientFunction(() => document.querySelector('#tinymce').innerText)
await t
.click(toggleButton)
.typeText(textArea, 'this is new content')
.click(toggleButton)
.switchToIframe(tinyIframe)
await t.expect(rceBody.withExactText('this is new content').visible).ok().switchToMainWindow()
await t
.click(toggleButton)
.pressKey('end')
.typeText(textArea, 'this is more content')
.click(toggleButton)
.switchToIframe(tinyIframe)
.expect(Selector('body').find('p').withExactText('this is new content').visible)
.ok()
.expect(Selector('body').find('p').withExactText('this is more content').visible)
.ok()
.switchToMainWindow()
})
test.skip('shows the create links menu', async t => {
await t
.click(toggleButton)
.typeText(textArea, '<div>this is <span id="selectword">selected</span> text</div>')
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t
.switchToIframe(tinyIframe)
.selectEditableContent(selectword, selectword)
.switchToMainWindow()
.click(linksButton)
.expect(externalLinksMenuItem.visible)
.ok()
.expect(courseLinksMenuItem.visible)
.ok()
})
test.skip('shows the edit links menu', async t => {
await t
.click(toggleButton)
.typeText(
textArea,
'<div>this is <a href="http://example.com"><span id="selectword">selected</span></a> text</div>'
)
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t
.switchToIframe(tinyIframe)
.selectEditableContent(selectword, selectword)
.switchToMainWindow()
.click(linksButton)
.expect(editLinkMenuItem.visible)
.ok()
.expect(removeLinkMenuItem.visible)
.ok()
})
test.skip('can create an external link', async t => {
await t
.click(toggleButton)
.typeText(textArea, '<div>this is <span id="selectword">selected</span> text</div>')
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t
.switchToIframe(tinyIframe)
.selectEditableContent(selectword, selectword)
.switchToMainWindow()
.click(linksButton)
.click(externalLinksMenuItem)
.expect(linkDialog.visible)
.ok()
.expect(named('linklink').visible)
.ok()
await t
.typeText(named('linklink'), 'https://instructure.com')
.click(Selector('button').withText('Done'))
.switchToIframe(tinyIframe)
.expect(
Selector('a')
.withAttribute('href', 'https://instructure.com')
.withAttribute('target', '_blank').exists
)
.ok()
})
test.skip('can edit an external link', async t => {
await t
.click(toggleButton)
.typeText(
textArea,
'<div>this is <a href="http://example.com"><span id="selectword">selected</span></a> text</div>'
)
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t
.switchToIframe(tinyIframe)
.selectEditableContent(selectword, selectword)
.switchToMainWindow()
// the link is selected, the toolbar button should be enabled
// await t.expect(linksButton.hasClass('tox-tbtn--enabled')).ok()
await t.click(linksButton).click(editLinkMenuItem).expect(linkTray.visible).ok()
await t.expect(specificValue('http://example.com').exists).ok()
await t.expect(specificValue('selected').exists).ok()
})
test.skip('expands selection to edit external link', async t => {
await t
.click(toggleButton)
.typeText(
textArea,
'<div>this is <a href="http://example.com"><span id="selectword">selected</span></a> text</div>'
)
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t.switchToIframe(tinyIframe).click(selectword, {caretPos: 1}).switchToMainWindow()
await t.click(linksButton).click(editLinkMenuItem).expect(linkTray.visible).ok()
await t.expect(specificValue('http://example.com').exists).ok()
await t.expect(specificValue('selected').exists).ok()
})
test.skip('can remove a link', async t => {
await t
.click(toggleButton)
.typeText(
textArea,
'<div>this is <a href="http://example.com"><span id="selectword">selected</span></a> text</div>'
)
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t
.switchToIframe(tinyIframe)
.selectEditableContent(selectword, selectword)
.switchToMainWindow()
.click(linksButton)
.click(removeLinkMenuItem)
await t.switchToIframe(tinyIframe).expect(Selector('a').exists).notOk()
})
// fails at the React.lazy call to load the tray's panel
test.skip('focus returns on dismissing tray', async t => {
const tinymceSelection = ClientFunction(() => tinymce.get('textarea').selection.getContent()) // the textarea id is from testcafe.html
const focusedId = ClientFunction(() => document.activeElement.id)
const focusedTag = ClientFunction(() => document.activeElement.tagName)
const ltSelector = Selector(linksTraySelector)
await t
.click(toggleButton)
.typeText(textArea, '<div>this is <span id="selectword">selected</span> text</div>')
.click(toggleButton)
.expect(rceContainer.visible)
.ok()
await t
.switchToIframe(tinyIframe)
.selectEditableContent(selectword, selectword)
.switchToMainWindow()
.click(linksButton)
.click(courseLinksMenuItem)
await linksPanelSelector()
await t
.expect(ltSelector.visible)
.ok()
.click(Selector(`${linksTraySelector} button`).withText('Close'))
.expect(ltSelector.exist)
.notOk()
await t
.expect(tinymceSelection())
.eql('selected')
.expect(focusedId())
.eql('textarea_ifr')
.switchToIframe(tinyIframe)
.expect(focusedTag())
.eql('BODY')
})
test.skip('show the kb shortcut modal various ways', async t => {
const kbshortcutbutton = Selector('button[data-testid="ShowOnFocusButton__button"]')
const sbKbshortcutbutton = Selector('button[title="View keyboard shortcuts"]')
const shortcutmodal = Selector('[data-testid="RCE_KeyboardShortcutModal"]')
const focusKBSCBtn = ClientFunction(() => kbshortcutbutton().focus(), {
dependencies: {kbshortcutbutton},
})
const focusSBKBSCBtn = ClientFunction(() => sbKbshortcutbutton().focus(), {
dependencies: {sbKbshortcutbutton},
})
await t.expect(kbshortcutbutton.exists).ok()
await focusKBSCBtn()
// open keyboard shortcut modal from the show-on-focus button
// close with escape
await t
.expect(kbshortcutbutton.visible)
.ok()
.click(kbshortcutbutton)
.expect(shortcutmodal.visible)
.ok()
.pressKey('esc')
.expect(shortcutmodal.exists)
.notOk()
// open modal using alt+0
// close with the close button
// await t
// .switchToIframe(tinyIframe)
// .click(Selector('body'))
// .pressKey('alt+0')
// .expect(shortcutmodal.visible)
// .ok()
// .click(Selector('button').withText('Close'))
// .expect(shortcutmodal.exists)
// .notOk()
// open modal from button in status bar
// debugger;
// close with the close button
await focusSBKBSCBtn()
await t
.expect(sbKbshortcutbutton.exists)
.ok()
.click(sbKbshortcutbutton)
.expect(shortcutmodal.visible)
.ok()
.click(Selector('button').withText('Close'))
.expect(shortcutmodal.exists)
.notOk()
})
// test.skip('can bring up the images dialog', async t => {
// await t
// .switchToMainWindow()
// .click(imagesButton())
// .click(uploadImageMenuItem())
// .expect(uploadImageDialog().visible)
// .ok()
// await t
// .typeText(named('linklink'), 'https://instructure.com')
// .click(Selector('button').withText('Done'))
// .switchToIframe(tinyIframe)
// .expect(
// Selector('a')
// .withAttribute('href', 'https://instructure.com')
// .withAttribute('target', '_blank').exists
// )
// .ok()
// })