import { ApproxStructure, Assertions, FocusTools, Mouse, UiFinder, Waiter } from '@ephox/agar'; import { before, describe, it } from '@ephox/bedrock-client'; import { Fun } from '@ephox/katamari'; import { SelectorFind, SugarBody, SugarDocument } from '@ephox/sugar'; import { assert } from 'chai'; import { WindowManagerImpl } from 'tinymce/core/api/WindowManager'; import * as WindowManager from 'tinymce/themes/silver/ui/dialog/WindowManager'; import * as TestExtras from '../../module/TestExtras'; describe('headless.tinymce.themes.silver.window.WindowManagerAlertTest', () => { const extrasHook = TestExtras.bddSetup(); let windowManager: WindowManagerImpl; before(() => { windowManager = WindowManager.setup(extrasHook.access().extras); }); const pTeardown = async () => { Mouse.clickOn(SugarBody.body(), '.tox-button--icon[aria-label="Close"]'); await Waiter.pTryUntil( 'Waiting for blocker to disappear after clicking close', () => UiFinder.notExists(SugarBody.body(), '.tox-dialog-wrap') ); }; const createAlert = (message: string, callback: () => void) => { windowManager.alert(message, callback); }; const pWaitForDialog = () => Waiter.pTryUntil( 'alert dialog shows', () => UiFinder.exists(SugarBody.body(), '.tox-dialog__body') ); it('Check the basic structure of the alert dialog', async () => { createAlert('The alert dialog loads with the basic structure', Fun.noop); await pWaitForDialog(); const sink = extrasHook.access().getDialogSink(); Assertions.assertStructure('A basic alert dialog should have these components', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('mce-silver-sink') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog-wrap') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog-wrap__backdrop') ] }), s.element('div', { classes: [ arr.has('tox-dialog') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog__header') ], styles: { display: str.is('none') }, children: [ s.element('div', { classes: [ arr.has('tox-dialog__title') ], styles: { display: str.is('none') }, html: str.is('') }), s.element('button', { classes: [ arr.has('tox-button'), arr.has('tox-button--icon'), arr.has('tox-button--naked') ], attrs: { 'aria-label': str.is('Close'), 'data-alloy-tabstop': str.is('true'), 'type': str.is('button') }, html: str.is('') }) ] }), s.element('div', { classes: [ arr.has('tox-dialog__body') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog__body-content') ], children: [ s.element('p', {}) ] }) ] }), s.element('div', { classes: [ arr.has('tox-dialog__footer') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog__footer-start') ], attrs: { role: str.is('presentation') } }), s.element('div', { classes: [ arr.has('tox-dialog__footer-end') ], attrs: { role: str.is('presentation') }, children: [ s.element('button', { html: str.is('OK'), classes: [ arr.has('tox-button') ], attrs: { 'type': str.is('button'), 'data-alloy-tabstop': str.is('true') } }) ] }) ] }) ] }) ] }) ] })), sink ); await pTeardown(); }); it('Should display a HTML error message', async () => { const label = 'should display this message'; createAlert(label, Fun.noop); const dialogBody = SelectorFind.descendant(SugarDocument.getDocument(), '.tox-dialog__body').getOrDie('Cannot find dialog body element'); Assertions.assertStructure('A basic alert dialog should have these components', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('tox-dialog__body') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog__body-content') ], children: [ s.element('p', { html: str.is(label) }) ] }) ] })), dialogBody ); await pTeardown(); }); it('The callback should fire when ok is invoked', async () => { let calls = 0; const testCallback = () => { calls++; }; windowManager.alert('alert', testCallback); assert.equal(calls, 0, 'callback should not have been called yet'); Mouse.clickOn(SugarBody.body(), '.tox-button--icon[aria-label="Close"]'); await Waiter.pTryUntil( 'Waiting for blocker to disappear after clicking close', () => UiFinder.notExists(SugarBody.body(), '.tox-dialog-wrap') ); assert.equal(calls, 1, 'Clicking on close should call the callback fn once'); }); it('Should focus on the ok button initially', async () => { createAlert('initial focus should be on ok button', Fun.noop); FocusTools.sTryOnSelector('When the alert dialog loads, focus should be on the ok button', SugarDocument.getDocument(), 'button:contains(OK)'); await pTeardown(); }); it('Should focus the first button when the dialog is clicked', async () => { createAlert('Click should focus ok button', Fun.noop); await FocusTools.pTryOnSelector('When the alert dialog loads, focus should be on the ok button', SugarDocument.getDocument(), 'button:contains(OK)'); Mouse.trueClickOn(SugarDocument.getDocument(), '.tox-dialog'); await FocusTools.pTryOnSelector('Focus should still be on the ok button', SugarDocument.getDocument(), 'button:contains(OK)'); await pTeardown(); }); it('Check that clicking ok in the dialog makes the dialog go away', () => { createAlert('Showing an alert', Fun.noop); Mouse.clickOn(SugarBody.body(), '.tox-button:contains("OK")'); UiFinder.notExists(SugarBody.body(), '[role="dialog"]'); }); it('TINY-3548: sanitize message', async () => { createAlert('invalid linkvalid link', Fun.noop); const dialogBody = SelectorFind.descendant(SugarDocument.getDocument(), '.tox-dialog__body').getOrDie('Cannot find dialog body element'); Assertions.assertStructure('A basic alert dialog should have these components', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('tox-dialog__body') ], children: [ s.element('div', { classes: [ arr.has('tox-dialog__body-content') ], children: [ s.element('p', { children: [ s.element('a', { exactAttrs: { }, children: [ s.text(str.is('invalid link')) ] }), s.element('a', { exactAttrs: { href: str.is('http://tiny.cloud') }, children: [ s.text(str.is('valid link')) ] }) ] }) ] }) ] })), dialogBody ); await pTeardown(); }); });