diff --git a/src/components/constants.ts b/src/components/constants.ts index adef4760..d6bc16e3 100644 --- a/src/components/constants.ts +++ b/src/components/constants.ts @@ -10,8 +10,44 @@ export const selectionChangeDebounceTimeout = 180; */ export const modificationsObserverBatchTimeout = 400; +/** + * The data-interface attribute name + * Used as a single source of truth for the data-interface attribute + */ +export const DATA_INTERFACE_ATTRIBUTE = 'data-interface'; + +/** + * Value for the data-interface attribute on editor wrapper elements + * Used as a single source of truth for editor identification + */ +export const EDITOR_INTERFACE_VALUE = 'editorjs'; + +/** + * Value for the data-interface attribute on inline toolbar elements + * Used as a single source of truth for inline toolbar identification + */ +export const INLINE_TOOLBAR_INTERFACE_VALUE = 'inline-toolbar'; + +/** + * Value for the data-interface attribute on tooltip elements + * Used as a single source of truth for tooltip identification + */ +export const TOOLTIP_INTERFACE_VALUE = 'tooltip'; + /** * CSS selector for the main editor wrapper element * Used to identify the editor container in the DOM */ export const EDITOR_INTERFACE_SELECTOR = '[data-interface=editorjs]'; + +/** + * CSS selector for tooltip elements + * Used to identify tooltip elements in the DOM + */ +export const TOOLTIP_INTERFACE_SELECTOR = '[data-interface="tooltip"]'; + +/** + * CSS selector for inline toolbar elements + * Used to identify inline toolbar elements in the DOM + */ +export const INLINE_TOOLBAR_INTERFACE_SELECTOR = '[data-interface=inline-toolbar]'; diff --git a/src/components/modules/api/tooltip.ts b/src/components/modules/api/tooltip.ts index 37077d0c..fe4e5e48 100644 --- a/src/components/modules/api/tooltip.ts +++ b/src/components/modules/api/tooltip.ts @@ -1,5 +1,5 @@ import type { Tooltip as ITooltip } from '../../../../types/api'; -import type { TooltipOptions, TooltipContent } from 'codex-tooltip/types'; +import type { TooltipOptions, TooltipContent } from '../../utils/tooltip'; import Module from '../../__module'; import type { ModuleConfig } from '../../../types-internal/module-config'; import * as tooltip from '../../utils/tooltip'; diff --git a/src/components/modules/toolbar/inline.ts b/src/components/modules/toolbar/inline.ts index 4e528dbe..ff10ffaa 100644 --- a/src/components/modules/toolbar/inline.ts +++ b/src/components/modules/toolbar/inline.ts @@ -13,6 +13,7 @@ import type { Popover, PopoverItemHtmlParams, PopoverItemParams, WithChildren } import { PopoverItemType } from '../../utils/popover'; import { PopoverInline } from '../../utils/popover/popover-inline'; import type InlineToolAdapter from 'src/components/tools/inline'; +import { DATA_INTERFACE_ATTRIBUTE, INLINE_TOOLBAR_INTERFACE_VALUE } from '../../constants'; /** * Inline Toolbar elements @@ -159,7 +160,7 @@ export default class InlineToolbar extends Module { ...(this.isRtl ? [ this.Editor.UI.CSS.editorRtlFix ] : []), ]); - this.nodes.wrapper.setAttribute('data-interface', 'inline-toolbar'); + this.nodes.wrapper.setAttribute(DATA_INTERFACE_ATTRIBUTE, INLINE_TOOLBAR_INTERFACE_VALUE); this.nodes.wrapper.setAttribute('data-cy', 'inline-toolbar'); /** diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index d66132ed..b8801615 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -15,7 +15,7 @@ import { mobileScreenBreakpoint } from '../utils'; import styles from '../../styles/main.css?inline'; import { BlockHovered } from '../events/BlockHovered'; -import { selectionChangeDebounceTimeout } from '../constants'; +import { DATA_INTERFACE_ATTRIBUTE, EDITOR_INTERFACE_VALUE, selectionChangeDebounceTimeout } from '../constants'; import { EditorMobileLayoutToggled } from '../events'; /** * HTML Elements used for UI @@ -288,7 +288,7 @@ export default class UI extends Module { this.CSS.editorWrapper, ...(this.isRtl ? [ this.CSS.editorRtlFix ] : []), ]); - this.nodes.wrapper.setAttribute('data-interface', 'editorjs'); + this.nodes.wrapper.setAttribute(DATA_INTERFACE_ATTRIBUTE, EDITOR_INTERFACE_VALUE); this.nodes.redactor = $.make('div', this.CSS.editorZone); /** diff --git a/src/components/utils/tooltip.ts b/src/components/utils/tooltip.ts index 95789bda..990a2022 100644 --- a/src/components/utils/tooltip.ts +++ b/src/components/utils/tooltip.ts @@ -1,71 +1,616 @@ -/* eslint-disable jsdoc/no-undefined-types */ -/** - * Use external module CodeX Tooltip - */ -import CodeXTooltips from 'codex-tooltip'; -import type { TooltipOptions, TooltipContent } from 'codex-tooltip/types'; +import tooltipStyles from '../../styles/tooltip.css?inline'; +import { DATA_INTERFACE_ATTRIBUTE, TOOLTIP_INTERFACE_VALUE } from '../constants'; /** - * Tooltips lib: CodeX Tooltips - * - * @see https://github.com/codex-team/codex.tooltips + * Tooltip supported content */ -let lib: null | CodeXTooltips = null; +export type TooltipContent = HTMLElement | DocumentFragment | Node | string; /** - * If library is needed, but it is not initialized yet, this function will initialize it - * - * For example, if editor was destroyed and then initialized again + * Base options interface for tooltips */ -function prepare(): void { - if (lib) { - return; +export interface TooltipOptions { + /** + * Tooltip placement: top|bottom|left|right + */ + placement?: string; + + /** + * Tooltip top margin + */ + marginTop?: number; + + /** + * Tooltip left margin + */ + marginLeft?: number; + + /** + * Tooltip right margin + */ + marginRight?: number; + + /** + * Tooltip bottom margin + */ + marginBottom?: number; + + /** + * Timout before showing + */ + delay?: number; + + /** + * Timout before hiding + */ + hidingDelay?: number; +} + +const DEFAULT_OFFSET = 10; +const TOOLTIP_ROLE = 'tooltip'; +const ARIA_HIDDEN_ATTRIBUTE = 'aria-hidden'; +const ARIA_HIDDEN_FALSE = 'false'; +const ARIA_HIDDEN_TRUE = 'true'; +const VISIBILITY_PROPERTY = 'visibility'; +const VISIBILITY_VISIBLE = 'visible'; +const VISIBILITY_HIDDEN = 'hidden'; + +type CSSTooltipClasses = { + tooltip: string; + tooltipContent: string; + tooltipShown: string; + placement: { + left: string; + bottom: string; + right: string; + top: string; + }; +}; + +/** + * Tiny any beautiful tooltips module. + * + * Can be showed near passed Element with any specified HTML content + * + * Based on codex-tooltip: https://github.com/codex-team/codex.tooltips + * + * @author CodeX + * @license MIT + */ +class Tooltip { + /** + * Tooltip CSS classes + * + * @returns {object} CSS class names + */ + private get CSS(): CSSTooltipClasses { + return { + tooltip: 'ct', + tooltipContent: 'ct__content', + tooltipShown: 'ct--shown', + placement: { + left: 'ct--left', + bottom: 'ct--bottom', + right: 'ct--right', + top: 'ct--top', + }, + }; } - lib = new CodeXTooltips(); + /** + * Module nodes + */ + private nodes: { + wrapper: HTMLElement | null; + content: HTMLElement | null; + } = { + wrapper: null, + content: null, + }; + + /** + * Appearance state + */ + private showed: boolean = false; + + /** + * Offset above the Tooltip + */ + private offsetTop: number = DEFAULT_OFFSET; + + /** + * Offset at the left from the Tooltip + */ + private offsetLeft: number = DEFAULT_OFFSET; + + /** + * Offset at the right from the Tooltip + */ + private offsetRight: number = DEFAULT_OFFSET; + + /** + * Store timeout before showing to clear it on hide + */ + private showingTimeout: ReturnType | null = null; + + /** + * How many milliseconds need to wait before hiding + */ + private hidingDelay: number = 0; + + /** + * Store timeout before hiding + */ + private hidingTimeout: ReturnType | null = null; + + /** + * MutationObserver for watching tooltip visibility changes + */ + private ariaObserver: MutationObserver | null = null; + + /** + * Static singleton instance + */ + private static instance: Tooltip | null = null; + + /** + * Get singleton instance + */ + public static getInstance(): Tooltip { + if (!Tooltip.instance) { + Tooltip.instance = new Tooltip(); + } + + return Tooltip.instance; + } + + /** + * Module constructor + */ + private constructor() { + this.loadStyles(); + this.prepare(); + + window.addEventListener('scroll', this.handleWindowScroll, { passive: true }); + } + + /** + * Show Tooltip near passed element with specified HTML content + * + * @param {HTMLElement} element - target element to place Tooltip near that + * @param {TooltipContent} content — any HTML Element of String that will be used as content + * @param {TooltipOptions} options — Available options {@link TooltipOptions} + */ + public show(element: HTMLElement, content: TooltipContent, options: TooltipOptions = {}): void { + if (!this.nodes.wrapper) { + this.prepare(); + } + + if (this.hidingTimeout) { + clearTimeout(this.hidingTimeout); + this.hidingTimeout = null; + } + + const basicOptions = { + placement: 'bottom', + marginTop: 0, + marginLeft: 0, + marginRight: 0, + marginBottom: 0, + delay: 70, + hidingDelay: 0, + }; + const showingOptions = Object.assign(basicOptions, options); + + if (showingOptions.hidingDelay) { + this.hidingDelay = showingOptions.hidingDelay; + } + + if (!this.nodes.content) { + return; + } + + this.nodes.content.innerHTML = ''; + + if (typeof content === 'string') { + this.nodes.content.appendChild(document.createTextNode(content)); + } else if (content instanceof Node) { + this.nodes.content.appendChild(content); + } else { + throw Error('[CodeX Tooltip] Wrong type of «content» passed. It should be an instance of Node or String. ' + + 'But ' + typeof content + ' given.'); + } + + if (!this.nodes.wrapper) { + return; + } + + this.nodes.wrapper.classList.remove(...Object.values(this.CSS.placement)); + + switch (showingOptions.placement) { + case 'top': + this.placeTop(element, showingOptions); + break; + + case 'left': + this.placeLeft(element, showingOptions); + break; + + case 'right': + this.placeRight(element, showingOptions); + break; + + case 'bottom': + default: + this.placeBottom(element, showingOptions); + break; + } + + if (showingOptions && showingOptions.delay) { + this.showingTimeout = setTimeout(() => { + if (this.nodes.wrapper) { + this.nodes.wrapper.classList.add(this.CSS.tooltipShown); + this.updateTooltipVisibility(); + } + this.showed = true; + }, showingOptions.delay); + } else { + if (this.nodes.wrapper) { + this.nodes.wrapper.classList.add(this.CSS.tooltipShown); + this.updateTooltipVisibility(); + } + this.showed = true; + } + } + + /** + * Hide toolbox tooltip and clean content + * + * @param {boolean} skipDelay - forces hiding immediately + */ + public hide(skipDelay: boolean = false): void { + if (this.hidingDelay && !skipDelay) { + // debounce + if (this.hidingTimeout) { + clearTimeout(this.hidingTimeout); + } + + this.hidingTimeout = setTimeout(() => { + this.hide(true); + }, this.hidingDelay); + + return; + } + + if (this.nodes.wrapper) { + this.nodes.wrapper.classList.remove(this.CSS.tooltipShown); + this.updateTooltipVisibility(); + } + this.showed = false; + + if (this.showingTimeout) { + clearTimeout(this.showingTimeout); + this.showingTimeout = null; + } + } + + /** + * Mouseover/Mouseleave decorator + * + * @param {HTMLElement} element - target element to place Tooltip near that + * @param {TooltipContent} content — any HTML Element of String that will be used as content + * @param {TooltipOptions} options — Available options {@link TooltipOptions} + */ + public onHover(element: HTMLElement, content: TooltipContent, options: TooltipOptions = {}): void { + element.addEventListener('mouseenter', () => { + this.show(element, content, options); + }); + element.addEventListener('mouseleave', () => { + this.hide(); + }); + } + + /** + * Release DOM and event listeners + */ + public destroy(): void { + this.ariaObserver?.disconnect(); + this.ariaObserver = null; + + if (this.nodes.wrapper) { + this.nodes.wrapper.remove(); + } + + window.removeEventListener('scroll', this.handleWindowScroll); + + Tooltip.instance = null; + } + + /** + * Hide tooltip when page is scrolled + */ + private handleWindowScroll = (): void => { + if (this.showed) { + this.hide(true); + } + }; + + /** + * Module Preparation method + */ + private prepare(): void { + this.nodes.wrapper = this.make('div', this.CSS.tooltip); + this.nodes.wrapper.setAttribute(DATA_INTERFACE_ATTRIBUTE, TOOLTIP_INTERFACE_VALUE); + this.nodes.content = this.make('div', this.CSS.tooltipContent); + + if (this.nodes.wrapper && this.nodes.content) { + this.append(this.nodes.wrapper, this.nodes.content); + this.append(document.body, this.nodes.wrapper); + this.ensureTooltipAttributes(); + } + } + + /** + * Update tooltip visibility based on shown state + */ + private updateTooltipVisibility(): void { + if (!this.nodes.wrapper) { + return; + } + + const isShown = this.nodes.wrapper.classList.contains(this.CSS.tooltipShown); + + this.nodes.wrapper.style.setProperty(VISIBILITY_PROPERTY, isShown ? VISIBILITY_VISIBLE : VISIBILITY_HIDDEN); + this.nodes.wrapper.setAttribute(ARIA_HIDDEN_ATTRIBUTE, isShown ? ARIA_HIDDEN_FALSE : ARIA_HIDDEN_TRUE); + } + + /** + * Watch tooltip visibility changes for accessibility + */ + private watchTooltipVisibility(): void { + if (!this.nodes.wrapper) { + return; + } + + this.ariaObserver?.disconnect(); + + this.updateTooltipVisibility(); + + this.ariaObserver = new MutationObserver(() => { + this.updateTooltipVisibility(); + }); + + this.ariaObserver.observe(this.nodes.wrapper, { + attributes: true, + attributeFilter: [ 'class' ], + }); + } + + /** + * Ensure tooltip has proper accessibility attributes + */ + private ensureTooltipAttributes(): void { + if (!this.nodes.wrapper) { + return; + } + + if (!this.nodes.wrapper.hasAttribute(DATA_INTERFACE_ATTRIBUTE) || this.nodes.wrapper.getAttribute(DATA_INTERFACE_ATTRIBUTE) !== TOOLTIP_INTERFACE_VALUE) { + this.nodes.wrapper.setAttribute(DATA_INTERFACE_ATTRIBUTE, TOOLTIP_INTERFACE_VALUE); + } + + this.nodes.wrapper.setAttribute('role', TOOLTIP_ROLE); + this.watchTooltipVisibility(); + } + + /** + * Append CSS file + */ + private loadStyles(): void { + const id = 'codex-tooltips-style'; + + if (document.getElementById(id)) { + return; + } + + const tag = this.make('style', null, { + textContent: tooltipStyles, + id, + }); + + /** + * Append styles at the top of HEAD tag + */ + this.prepend(document.head, tag); + } + + /** + * Calculates element coords and moves tooltip bottom of the element + * + * @param {HTMLElement} element - target element + * @param {TooltipOptions} showingOptions - placement options + */ + private placeBottom(element: HTMLElement, showingOptions: TooltipOptions): void { + if (!this.nodes.wrapper) { + return; + } + + const elementCoords = element.getBoundingClientRect(); + const left = elementCoords.left + element.clientWidth / 2 - this.nodes.wrapper.offsetWidth / 2; + const top = elementCoords.bottom + window.pageYOffset + this.offsetTop + (showingOptions.marginTop ?? 0); + + this.applyPlacement('bottom', left, top); + } + + /** + * Calculates element coords and moves tooltip top of the element + * + * @param {HTMLElement} element - target element + * @param {TooltipOptions} _showingOptions - placement options (unused for top placement) + */ + private placeTop(element: HTMLElement, _showingOptions: TooltipOptions): void { + if (!this.nodes.wrapper) { + return; + } + + const elementCoords = element.getBoundingClientRect(); + const left = elementCoords.left + element.clientWidth / 2 - this.nodes.wrapper.offsetWidth / 2; + const top = elementCoords.top + window.pageYOffset - this.nodes.wrapper.clientHeight - this.offsetTop; + + this.applyPlacement('top', left, top); + } + + /** + * Calculates element coords and moves tooltip left of the element + * + * @param {HTMLElement} element - target element + * @param {TooltipOptions} showingOptions - placement options + */ + private placeLeft(element: HTMLElement, showingOptions: TooltipOptions): void { + if (!this.nodes.wrapper) { + return; + } + + const elementCoords = element.getBoundingClientRect(); + const left = elementCoords.left - this.nodes.wrapper.offsetWidth - this.offsetLeft - (showingOptions.marginLeft ?? 0); + const top = elementCoords.top + window.pageYOffset + element.clientHeight / 2 - this.nodes.wrapper.offsetHeight / 2; + + this.applyPlacement('left', left, top); + } + + /** + * Calculates element coords and moves tooltip right of the element + * + * @param {HTMLElement} element - target element + * @param {TooltipOptions} showingOptions - placement options + */ + private placeRight(element: HTMLElement, showingOptions: TooltipOptions): void { + if (!this.nodes.wrapper) { + return; + } + + const elementCoords = element.getBoundingClientRect(); + const left = elementCoords.right + this.offsetRight + (showingOptions.marginRight ?? 0); + const top = elementCoords.top + window.pageYOffset + element.clientHeight / 2 - this.nodes.wrapper.offsetHeight / 2; + + this.applyPlacement('right', left, top); + } + + /** + * Set wrapper position + * + * @param {string} place - placement direction + * @param {number} left - left position in pixels + * @param {number} top - top position in pixels + */ + private applyPlacement(place: 'top' | 'bottom' | 'left' | 'right', left: number, top: number): void { + if (!this.nodes.wrapper) { + return; + } + + this.nodes.wrapper.classList.add(this.CSS.placement[place]); + + this.nodes.wrapper.style.left = `${left}px`; + this.nodes.wrapper.style.top = `${top}px`; + } + + /** + * Helper for making Elements with classname and attributes + * + * @param {string} tagName - new Element tag name + * @param {Array|string} classNames - list or name of CSS classname(s) + * @param {object} attributes - any attributes + * @returns {HTMLElement} + */ + private make(tagName: string, classNames: string | string[] | null = null, attributes: Record = {}): HTMLElement { + const el = document.createElement(tagName); + + if (Array.isArray(classNames)) { + el.classList.add(...classNames); + } else if (classNames) { + el.classList.add(classNames); + } + + for (const attrName in attributes) { + if (Object.prototype.hasOwnProperty.call(attributes, attrName)) { + (el as unknown as Record)[attrName] = attributes[attrName]; + } + } + + return el; + } + + /** + * Append one or several elements to the parent + * + * @param {Element|DocumentFragment} parent - where to append + * @param {Element|Element[]} elements - element or elements list + */ + private append(parent: Element | DocumentFragment, elements: Element | Element[] | DocumentFragment): void { + if (Array.isArray(elements)) { + elements.forEach((el) => parent.appendChild(el)); + } else { + parent.appendChild(elements); + } + } + + /** + * Append element or a couple to the beginning of the parent elements + * + * @param {Element} parent - where to append + * @param {Element|Element[]} elements - element or elements list + */ + private prepend(parent: Element, elements: Element | Element[]): void { + if (Array.isArray(elements)) { + const reversed = elements.reverse(); + + reversed.forEach((el) => parent.prepend(el)); + } else { + parent.prepend(elements); + } + } } /** - * Shows tooltip on element with passed HTML content + * Get singleton tooltip instance + */ +const getTooltip = (): Tooltip => { + return Tooltip.getInstance(); +}; + +/** + * Show tooltip near element with specified content * - * @param {HTMLElement} element - any HTML element in DOM - * @param content - tooltip's content - * @param options - showing settings + * @param {HTMLElement} element - target element to place tooltip near + * @param {TooltipContent} content - tooltip content + * @param {TooltipOptions} options - tooltip options */ -export function show(element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void { - prepare(); - - lib?.show(element, content, options); -} +export const show = (element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void => { + getTooltip().show(element, content, options ?? {}); +}; /** - * Hides tooltip + * Hide tooltip * - * @param skipHidingDelay — pass true to immediately hide the tooltip + * @param {boolean} skipHidingDelay - forces hiding immediately */ -export function hide(skipHidingDelay = false): void { - prepare(); - - lib?.hide(skipHidingDelay); -} +export const hide = (skipHidingDelay = false): void => { + getTooltip().hide(skipHidingDelay); +}; /** - * Binds 'mouseenter' and 'mouseleave' events that shows/hides the Tooltip + * Show tooltip on hover (mouseenter/mouseleave) * - * @param {HTMLElement} element - any HTML element in DOM - * @param content - tooltip's content - * @param options - showing settings + * @param {HTMLElement} element - target element to place tooltip near + * @param {TooltipContent} content - tooltip content + * @param {TooltipOptions} options - tooltip options */ -export function onHover(element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void { - prepare(); - - lib?.onHover(element, content, options); -} +export const onHover = (element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void => { + getTooltip().onHover(element, content, options ?? {}); +}; /** - * Release the library + * Destroy tooltip instance and clean up */ -export function destroy(): void { - lib?.destroy(); - lib = null; -} +export const destroy = (): void => { + getTooltip().destroy(); +}; diff --git a/src/styles/tooltip.css b/src/styles/tooltip.css new file mode 100644 index 00000000..69b43e21 --- /dev/null +++ b/src/styles/tooltip.css @@ -0,0 +1,105 @@ +:root { + --ct-color-bg: #1d202b; + --ct-color-font: #cdd1e0; +} + +.ct { + position: absolute; + z-index: 999; + top: 0; + left: 0; + opacity: 0; + user-select: none; + pointer-events: none; + transition: opacity 50ms ease-in, transform 70ms cubic-bezier(0.215, 0.61, 0.355, 1); + will-change: opacity, top, left; + box-shadow: 0 8px 12px 0 rgba(29, 32, 43, 0.17), 0 4px 5px -3px rgba(5, 6, 12, 0.49); + border-radius: 9px; +} + +.ct::before { + content: ''; + inset: 0; + position: absolute; + background-color: var(--ct-color-bg); + z-index: -1; + border-radius: 4px; +} + +@supports (-webkit-mask-box-image: url('')) { + .ct::before { + border-radius: 0; + -webkit-mask-box-image: url('data:image/svg+xml;charset=utf-8,') 48% 41% 37.9% 53.3%; + } +} + +@media (max-width: 768px) { + .ct { + display: none; + } +} + +.ct__content { + padding: 6px 10px; + color: var(--ct-color-font); + font-size: 12px; + text-align: center; + letter-spacing: 0.02em; + line-height: 1em; +} + +.ct::after { + content: ''; + width: 8px; + height: 8px; + position: absolute; + background-color: var(--ct-color-bg); + z-index: -1; +} + +.ct--bottom { + transform: translateY(5px); +} + +.ct--bottom::after { + top: -3px; + left: 50%; + transform: translateX(-50%) rotate(-45deg); +} + +.ct--top { + transform: translateY(-5px); +} + +.ct--top::after { + top: auto; + bottom: -3px; + left: 50%; + transform: translateX(-50%) rotate(-45deg); +} + +.ct--left { + transform: translateX(-5px); +} + +.ct--left::after { + top: 50%; + left: auto; + right: 0; + transform: translate(41.6%, -50%) rotate(-45deg); +} + +.ct--right { + transform: translateX(5px); +} + +.ct--right::after { + top: 50%; + left: 0; + transform: translate(-41.6%, -50%) rotate(-45deg); +} + +.ct--shown { + opacity: 1; + transform: none; +} diff --git a/test/cypress/support/constants.ts b/test/cypress/support/constants.ts deleted file mode 100644 index 52b74414..00000000 --- a/test/cypress/support/constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * CSS selector for the main editor wrapper element - * Used in Cypress tests to query the editor container - */ -export const EDITOR_SELECTOR = '[data-interface=editorjs]'; - diff --git a/test/cypress/support/index.ts b/test/cypress/support/index.ts index 74590b76..8b484ad7 100644 --- a/test/cypress/support/index.ts +++ b/test/cypress/support/index.ts @@ -20,7 +20,7 @@ import './commands'; /** * Test constants */ -export { EDITOR_SELECTOR } from './constants'; +export { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; /** * File with custom assertions diff --git a/test/cypress/tests/api/blocks.cy.ts b/test/cypress/tests/api/blocks.cy.ts index 2a614a64..05c2e365 100644 --- a/test/cypress/tests/api/blocks.cy.ts +++ b/test/cypress/tests/api/blocks.cy.ts @@ -3,7 +3,7 @@ import type { ConversionConfig, ToolboxConfig, ToolConfig, API, BlockAPI } from import type { BlockTuneData } from '../../../../types/block-tunes/block-tune-data'; import ToolMock, { type MockToolData } from '../../fixtures/tools/ToolMock'; import { nanoid } from 'nanoid'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; /** * There will be described test cases of 'blocks.*' API @@ -74,7 +74,7 @@ describe('api.blocks', () => { await editor.blocks.update(idToUpdate, newBlockData); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('[data-cy="block-wrapper"]') .should('have.text', newBlockData.text); }); @@ -213,7 +213,7 @@ describe('api.blocks', () => { expect(error.message).to.be.eq(`Block with id "${idToUpdate}" not found`); }) .finally(() => { - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('[data-cy="block-wrapper"]') .invoke('text') .then(blockText => { @@ -276,7 +276,7 @@ describe('api.blocks', () => { }, ], index)); // paste to the 0 index - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('[data-cy="block-wrapper"]') .each(($el, i) => { switch (i) { diff --git a/test/cypress/tests/api/caret.cy.ts b/test/cypress/tests/api/caret.cy.ts index 6755c536..00fc21af 100644 --- a/test/cypress/tests/api/caret.cy.ts +++ b/test/cypress/tests/api/caret.cy.ts @@ -1,6 +1,6 @@ import { createParagraphMock } from '../../support/utils/createParagraphMock'; import type EditorJS from '../../../../types'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; /** * Test cases for Caret API @@ -27,7 +27,7 @@ describe('Caret API', () => { /** * Blur caret from the block before setting via api */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .click(); }); it('should set caret to a block (and return true) if block index is passed as argument', () => { @@ -47,7 +47,7 @@ describe('Caret API', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .first() .should(($block) => { @@ -76,7 +76,7 @@ describe('Caret API', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .first() .should(($block) => { @@ -110,7 +110,7 @@ describe('Caret API', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .first() .should(($block) => { diff --git a/test/cypress/tests/api/toolbar.cy.ts b/test/cypress/tests/api/toolbar.cy.ts index 89fe5fc3..9fcda420 100644 --- a/test/cypress/tests/api/toolbar.cy.ts +++ b/test/cypress/tests/api/toolbar.cy.ts @@ -2,7 +2,7 @@ * There will be described test cases of 'api.toolbar.*' API */ import type EditorJS from '../../../../types'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('api.toolbar', () => { /** @@ -36,7 +36,7 @@ describe('api.toolbar', () => { describe('*.toggleToolbox()', () => { const isToolboxVisible = (): void => { - cy.get(EDITOR_SELECTOR).find('div.ce-toolbox') + cy.get(EDITOR_INTERFACE_SELECTOR).find('div.ce-toolbox') .then((toolbox) => { if (toolbox.is(':visible')) { assert.isOk(true, 'Toolbox visible'); @@ -47,7 +47,7 @@ describe('api.toolbar', () => { }; const isToolboxNotVisible = (): void => { - cy.get(EDITOR_SELECTOR).find('div.ce-toolbox') + cy.get(EDITOR_INTERFACE_SELECTOR).find('div.ce-toolbox') .then((toolbox) => { if (!toolbox.is(':visible')) { assert.isOk(true, 'Toolbox not visible'); diff --git a/test/cypress/tests/api/tools.cy.ts b/test/cypress/tests/api/tools.cy.ts index 6f7193b0..9a3a6a86 100644 --- a/test/cypress/tests/api/tools.cy.ts +++ b/test/cypress/tests/api/tools.cy.ts @@ -1,7 +1,7 @@ import type { ToolboxConfig, BlockToolData, ToolboxConfigEntry, PasteConfig } from '../../../../types'; import type EditorJS from '../../../../types'; import type { HTMLPasteEvent, TunesMenuConfig } from '../../../../types/tools'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; /* eslint-disable @typescript-eslint/no-empty-function */ @@ -31,19 +31,19 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=testTool]') .should('have.length', 1); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=testTool] .ce-popover-item__icon') .should('contain.html', TestTool.toolbox.icon); }); @@ -76,24 +76,24 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=testTool]') .should('have.length', 2); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=testTool]') .first() .should('contain.text', (TestTool.toolbox as ToolboxConfigEntry[])[0].title); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=testTool]') .last() .should('contain.text', (TestTool.toolbox as ToolboxConfigEntry[])[1].title); @@ -165,19 +165,19 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=testTool]') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .last() .click() @@ -238,26 +238,26 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); // Insert test tool block - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get(`[data-item-name="testTool"]`) .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-name=testBlock]') .type('some text') .click(); // Open block tunes - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -316,26 +316,26 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); // Insert test tool block - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get(`[data-item-name="testTool"]`) .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-name=testBlock]') .type('some text') .click(); // Open block tunes - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -386,31 +386,31 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); // Insert test tool block - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get(`[data-item-name="testTool"]`) .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-name=testBlock]') .type('some text') .click(); // Open block tunes - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); // Expect preconfigured custom html tunes to exist in tunes menu - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover') .should('contain.text', sampleText); }); @@ -468,26 +468,26 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); // Insert test tool block - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get(`[data-item-name="testTool"]`) .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-name=testBlock]') .type('some text') .click(); // Open block tunes - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -537,7 +537,7 @@ describe('Editor Tools Api', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -594,7 +594,7 @@ describe('Editor Tools Api', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -660,7 +660,7 @@ describe('Editor Tools Api', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -746,7 +746,7 @@ describe('Editor Tools Api', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -827,7 +827,7 @@ describe('Editor Tools Api', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -918,7 +918,7 @@ describe('Editor Tools Api', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -1001,7 +1001,7 @@ describe('Editor Tools Api', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ diff --git a/test/cypress/tests/api/tunes.cy.ts b/test/cypress/tests/api/tunes.cy.ts index c96ad83e..6b4e812e 100644 --- a/test/cypress/tests/api/tunes.cy.ts +++ b/test/cypress/tests/api/tunes.cy.ts @@ -1,5 +1,5 @@ import type { TunesMenuConfig } from '../../../../types/tools'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; /* eslint-disable @typescript-eslint/no-empty-function */ @@ -32,12 +32,12 @@ describe('Editor Tunes Api', () => { tunes: [ 'testTune' ], }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .type('some text') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -80,12 +80,12 @@ describe('Editor Tunes Api', () => { tunes: [ 'testTune' ], }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .type('some text') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -121,16 +121,16 @@ describe('Editor Tunes Api', () => { tunes: [ 'testTune' ], }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .type('some text') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover') .should('contain.text', sampleText); }); @@ -173,12 +173,12 @@ describe('Editor Tunes Api', () => { tunes: [ 'testTune' ], }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .type('some text') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -218,23 +218,23 @@ describe('Editor Tunes Api', () => { tunes: [ 'testTune' ], }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .type('some text') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check test tune is inserted at index 0 */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-settings .ce-popover-item') .eq(0) .should('have.attr', 'data-item-name', 'test-tune' ); /** Check default Move Up tune is inserted below the test tune */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-settings .ce-popover-item') .eq(1) .should('have.attr', 'data-item-name', 'move-up' ); diff --git a/test/cypress/tests/block-ids.cy.ts b/test/cypress/tests/block-ids.cy.ts index 7f8dcee7..58b0682b 100644 --- a/test/cypress/tests/block-ids.cy.ts +++ b/test/cypress/tests/block-ids.cy.ts @@ -1,7 +1,7 @@ import Header from '@editorjs/header'; import { nanoid } from 'nanoid'; import type EditorJS from '../../../types/index'; -import { EDITOR_SELECTOR } from '../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; describe('Block ids', () => { @@ -12,7 +12,7 @@ describe('Block ids', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('First block ') @@ -22,15 +22,15 @@ describe('Block ids', () => { .type('Second block ') .type('{enter}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=header]') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .last() .click() @@ -108,7 +108,7 @@ describe('Block ids', () => { blocks, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .first() .click() @@ -152,7 +152,7 @@ describe('Block ids', () => { blocks, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .each(($block, index) => { expect($block.attr('data-id')).to.eq(blocks[index].id); diff --git a/test/cypress/tests/copy-paste.cy.ts b/test/cypress/tests/copy-paste.cy.ts index 69ff5caa..352233d5 100644 --- a/test/cypress/tests/copy-paste.cy.ts +++ b/test/cypress/tests/copy-paste.cy.ts @@ -2,7 +2,7 @@ import Header from '@editorjs/header'; import Image from '@editorjs/simple-image'; import * as _ from '../../../src/components/utils'; import type { BlockTool, BlockToolData, OutputData } from '../../../types'; -import { EDITOR_SELECTOR } from '../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; import $ from '../../../src/components/dom'; import type EditorJS from '../../../types/index'; @@ -12,7 +12,7 @@ describe.skip('Copy pasting from Editor', () => { it('should paste plain text', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .as('block') .click() @@ -27,7 +27,7 @@ describe.skip('Copy pasting from Editor', () => { it('should paste inline html data', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .as('block') .click() @@ -42,7 +42,7 @@ describe.skip('Copy pasting from Editor', () => { it('should paste several blocks if plain text contains new lines', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -50,7 +50,7 @@ describe.skip('Copy pasting from Editor', () => { 'text/plain': 'First block\n\nSecond block', }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .then(blocks => { expect(blocks[0].textContent).to.eq('First block'); @@ -61,7 +61,7 @@ describe.skip('Copy pasting from Editor', () => { it('should paste several blocks if html contains several paragraphs', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -69,7 +69,7 @@ describe.skip('Copy pasting from Editor', () => { 'text/html': '

First block

Second block

', }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .then(blocks => { expect(blocks[0].textContent).to.eq('First block'); @@ -80,7 +80,7 @@ describe.skip('Copy pasting from Editor', () => { it('should paste using custom data type', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -101,7 +101,7 @@ describe.skip('Copy pasting from Editor', () => { ]), }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .then(blocks => { expect(blocks[0].textContent).to.eq('First block'); @@ -116,7 +116,7 @@ describe.skip('Copy pasting from Editor', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -127,11 +127,11 @@ describe.skip('Copy pasting from Editor', () => { /** * Check inserted blocks */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('h2.ce-header') .should('contain', 'First block'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-paragraph') .should('contain', 'Second block'); @@ -165,7 +165,7 @@ describe.skip('Copy pasting from Editor', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .paste({ @@ -173,7 +173,7 @@ describe.skip('Copy pasting from Editor', () => { 'text/plain': 'https://codex.so/public/app/img/external/codex2x.png', }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) // In Edge test are performed slower, so we need to increase timeout to wait until image is loaded on the page .get('img', { timeout: 10000 }) .should('have.attr', 'src', 'https://codex.so/public/app/img/external/codex2x.png'); @@ -246,7 +246,7 @@ describe.skip('Copy pasting from Editor', () => { it('should copy inline fragment', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('Some text{selectall}') @@ -262,12 +262,12 @@ describe.skip('Copy pasting from Editor', () => { it('should copy several blocks', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('First block{enter}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .next() .type('Second block') @@ -302,7 +302,7 @@ describe.skip('Copy pasting from Editor', () => { it('should cut inline fragment', () => { cy.createEditor({}); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('Some text{selectall}') @@ -331,7 +331,7 @@ describe.skip('Copy pasting from Editor', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .last() .click() @@ -360,7 +360,7 @@ describe.skip('Copy pasting from Editor', () => { }); }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .should('not.contain', 'First block') .should('not.contain', 'Second block'); }); @@ -384,7 +384,7 @@ describe.skip('Copy pasting from Editor', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .first() .click() diff --git a/test/cypress/tests/initialization.cy.ts b/test/cypress/tests/initialization.cy.ts index fe865fc0..0b974795 100644 --- a/test/cypress/tests/initialization.cy.ts +++ b/test/cypress/tests/initialization.cy.ts @@ -1,6 +1,6 @@ // eslint-disable-next-line spaced-comment, @typescript-eslint/triple-slash-reference /// -import { EDITOR_SELECTOR } from '../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; describe('Editor basic initialization', () => { describe('Zero-config initialization', () => { @@ -23,7 +23,7 @@ describe('Editor basic initialization', () => { /** * Assert if created instance is visible or not. */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.codex-editor') .should('be.visible'); }); @@ -42,7 +42,7 @@ describe('Editor basic initialization', () => { readOnly: true, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.codex-editor') .get('div.ce-paragraph') .invoke('attr', 'contenteditable') @@ -59,7 +59,7 @@ describe('Editor basic initialization', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('#editor-js-styles') .should('have.attr', 'nonce', 'test-nonce'); }); diff --git a/test/cypress/tests/modules/BlockEvents/ArrowLeft.cy.ts b/test/cypress/tests/modules/BlockEvents/ArrowLeft.cy.ts index 286e419d..1c3f52be 100644 --- a/test/cypress/tests/modules/BlockEvents/ArrowLeft.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/ArrowLeft.cy.ts @@ -1,6 +1,6 @@ import { createEditorWithTextBlocks } from '../../../support/utils/createEditorWithTextBlocks'; import ContentlessToolMock from '../../../fixtures/tools/ContentlessTool'; -import { EDITOR_SELECTOR } from '../../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; describe('Arrow Left', () => { describe('starting whitespaces handling', () => { @@ -10,7 +10,7 @@ describe('Arrow Left', () => { ' 2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() // select second block .click() @@ -30,7 +30,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -44,7 +44,7 @@ describe('Arrow Left', () => { ' 2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() // select second block .click() @@ -63,7 +63,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -78,7 +78,7 @@ describe('Arrow Left', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() // select second block .click() @@ -97,7 +97,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -111,7 +111,7 @@ describe('Arrow Left', () => { ' 2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .click() @@ -131,7 +131,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -146,7 +146,7 @@ describe('Arrow Left', () => { ' 2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .click() @@ -166,7 +166,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -181,7 +181,7 @@ describe('Arrow Left', () => { '  2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .click() @@ -201,7 +201,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -256,7 +256,7 @@ describe('Arrow Left', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .as('thirdBlock') @@ -267,7 +267,7 @@ describe('Arrow Left', () => { /** * We navigated to the Delimiter and it is highlighted */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div[data-cy-type=contentless-tool]') .parents('.ce-block') .as('delimiterBlock') @@ -297,7 +297,7 @@ describe('Arrow Left', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .should(($block) => { diff --git a/test/cypress/tests/modules/BlockEvents/ArrowRight.cy.ts b/test/cypress/tests/modules/BlockEvents/ArrowRight.cy.ts index 4be67729..ba8522bf 100644 --- a/test/cypress/tests/modules/BlockEvents/ArrowRight.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/ArrowRight.cy.ts @@ -1,6 +1,6 @@ import { createEditorWithTextBlocks } from '../../../support/utils/createEditorWithTextBlocks'; import ContentlessToolMock from '../../../fixtures/tools/ContentlessTool'; -import { EDITOR_SELECTOR } from '../../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; describe('Arrow Right', () => { describe('starting whitespaces handling', () => { @@ -10,7 +10,7 @@ describe('Arrow Right', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() // select first block .as('firstBlock') @@ -32,7 +32,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { @@ -48,7 +48,7 @@ describe('Arrow Right', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -68,7 +68,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { @@ -84,7 +84,7 @@ describe('Arrow Right', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -104,7 +104,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { @@ -119,7 +119,7 @@ describe('Arrow Right', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -140,7 +140,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { @@ -156,7 +156,7 @@ describe('Arrow Right', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -177,7 +177,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { @@ -193,7 +193,7 @@ describe('Arrow Right', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -214,7 +214,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { @@ -270,7 +270,7 @@ describe('Arrow Right', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .as('firstBlock') @@ -280,7 +280,7 @@ describe('Arrow Right', () => { /** * We navigated to the Delimiter and it is highlighted */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div[data-cy-type=contentless-tool]') .parents('.ce-block') .as('delimiterBlock') @@ -310,7 +310,7 @@ describe('Arrow Right', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should(($block) => { diff --git a/test/cypress/tests/modules/BlockEvents/Delete.cy.ts b/test/cypress/tests/modules/BlockEvents/Delete.cy.ts index 99c98d5d..40d96ff6 100644 --- a/test/cypress/tests/modules/BlockEvents/Delete.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Delete.cy.ts @@ -1,6 +1,6 @@ import type EditorJS from '../../../../../types/index'; import { createEditorWithTextBlocks } from '../../../support/utils/createEditorWithTextBlocks'; -import { EDITOR_SELECTOR } from '../../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; describe('Delete keydown', () => { describe('ending whitespaces handling', () => { @@ -10,7 +10,7 @@ describe('Delete keydown', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -27,7 +27,7 @@ describe('Delete keydown', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -35,7 +35,7 @@ describe('Delete keydown', () => { .type('{rightArrow}') // set caret after "1"; .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .last() .should('have.text', '1 2'); @@ -46,7 +46,7 @@ describe('Delete keydown', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -54,7 +54,7 @@ describe('Delete keydown', () => { .type('{rightArrow}') // set caret after "1"; .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .last() .should('have.text', '12'); @@ -65,7 +65,7 @@ describe('Delete keydown', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -74,7 +74,7 @@ describe('Delete keydown', () => { .type('{del}') // remove nbsp .type('{del}'); // ignore empty tag and merge - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .last() .should('have.text', '12'); @@ -86,7 +86,7 @@ describe('Delete keydown', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -95,7 +95,7 @@ describe('Delete keydown', () => { .type('{del}') // remove nbsp .type('{del}'); // ignore empty tag and merge - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .last() .should('have.text', '12'); @@ -107,7 +107,7 @@ describe('Delete keydown', () => { '2', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -116,7 +116,7 @@ describe('Delete keydown', () => { .type('{del}') // remove nbsp .type('{del}'); // ignore regular space and merge - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .last() /** @@ -141,14 +141,14 @@ describe('Delete keydown', () => { 'The second block', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() .selectText('The ') .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .first() .should('have.text', 'first block'); @@ -160,14 +160,14 @@ describe('Delete keydown', () => { 'The second block', ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() // caret will be at the end of the block .type('{leftarrow}') // now caret is not at the end .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .first() .should('have.text', 'The first bloc'); // last char is removed @@ -217,14 +217,14 @@ describe('Delete keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('[data-cy=quote-tool]') .find('div[contenteditable]') .first() .click() .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('[data-cy=quote-tool]') .find('div[contenteditable]') .last() @@ -267,7 +267,7 @@ describe('Delete keydown', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -304,7 +304,7 @@ describe('Delete keydown', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -334,7 +334,7 @@ describe('Delete keydown', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -345,7 +345,7 @@ describe('Delete keydown', () => { /** * Toolbox has been closed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-toolbar') .should('not.have.class', 'ce-toolbar--opened'); }); @@ -372,7 +372,7 @@ describe('Delete keydown', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -402,7 +402,7 @@ describe('Delete keydown', () => { } const range = selection.getRangeAt(0); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -414,7 +414,7 @@ describe('Delete keydown', () => { /** * Toolbox has been closed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-toolbar') .should('not.have.class', 'ce-toolbar--opened'); }); @@ -464,12 +464,12 @@ describe('Delete keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('[data-cy=unmergeable-tool]') .as('secondBlock'); @@ -495,12 +495,12 @@ describe('Delete keydown', () => { it('should do nothing', () => { createEditorWithTextBlocks([ 'The only block. Not empty' ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('{del}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .should('have.length', 1) .should('have.text', 'The only block. Not empty'); diff --git a/test/cypress/tests/modules/BlockEvents/Enter.cy.ts b/test/cypress/tests/modules/BlockEvents/Enter.cy.ts index 4e784657..729ae0ec 100644 --- a/test/cypress/tests/modules/BlockEvents/Enter.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Enter.cy.ts @@ -1,4 +1,4 @@ -import { EDITOR_SELECTOR } from '../../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; describe('Enter keydown', () => { it('should split block and remove selected fragment if some text fragment selected', () => { @@ -15,14 +15,14 @@ describe('Enter keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .selectText('with so') .wait(0) .type('{enter}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .then((blocks) => { /** @@ -52,12 +52,12 @@ describe('Enter keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('{enter}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .last() .as('lastBlock'); diff --git a/test/cypress/tests/modules/BlockEvents/Slash.cy.ts b/test/cypress/tests/modules/BlockEvents/Slash.cy.ts index 89349b62..6d9de622 100644 --- a/test/cypress/tests/modules/BlockEvents/Slash.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Slash.cy.ts @@ -1,4 +1,4 @@ -import { EDITOR_SELECTOR } from '../../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; describe('Slash keydown', () => { describe('pressed in empty block', () => { @@ -16,7 +16,7 @@ describe('Slash keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('/'); @@ -24,7 +24,7 @@ describe('Slash keydown', () => { /** * Block content should contain slash */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .invoke('text') .should('eq', '/'); @@ -51,7 +51,7 @@ describe('Slash keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type(`{${key}}/`); @@ -77,7 +77,7 @@ describe('Slash keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('/'); @@ -88,7 +88,7 @@ describe('Slash keydown', () => { /** * Block content should contain slash */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .invoke('text') .should('eq', 'Hello/'); @@ -120,10 +120,10 @@ describe('Slash keydown', () => { // Step 1 // Click on the plus button and select the text option - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-toolbar__plus') .click({ force: true }); cy.get('[data-cy="toolbox"] .ce-popover__container') @@ -165,7 +165,7 @@ describe('CMD+Slash keydown', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('{cmd}/'); diff --git a/test/cypress/tests/modules/InlineToolbar.cy.ts b/test/cypress/tests/modules/InlineToolbar.cy.ts index 1bd3e39c..49e019ea 100644 --- a/test/cypress/tests/modules/InlineToolbar.cy.ts +++ b/test/cypress/tests/modules/InlineToolbar.cy.ts @@ -1,7 +1,7 @@ import Header from '@editorjs/header'; import NestedEditor, { NESTED_EDITOR_ID } from '../../support/utils/nestedEditorInstance'; import type { MenuConfig, ToolConstructable } from '@/types/tools'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('Inline Toolbar', () => { it('should appear aligned with left coord of selection rect', () => { @@ -18,7 +18,7 @@ describe('Inline Toolbar', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('block'); @@ -58,7 +58,7 @@ describe('Inline Toolbar', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .as('blockWrapper') .getLineWrapPositions() @@ -68,7 +68,7 @@ describe('Inline Toolbar', () => { /** * Select last 5 chars of the first line */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectTextByOffset([firstLineWrapIndex - 5, firstLineWrapIndex - 1]); }); @@ -136,11 +136,11 @@ describe('Inline Toolbar', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-header') .selectText('block'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar]') .get('.ce-popover--opened') .as('toolbar') @@ -183,7 +183,7 @@ describe('Inline Toolbar', () => { form.appendChild(editorElement); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('Some text'); @@ -214,19 +214,19 @@ describe('Inline Toolbar', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('Some text'); cy.get('[data-item-name=convert-to]') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar') .find('.ce-popover-item[data-item-name=header]') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-header') .should('have.text', 'Some text'); @@ -242,7 +242,7 @@ describe('Inline Toolbar', () => { throw new Error('No range available'); } - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-header') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; diff --git a/test/cypress/tests/modules/Renderer.cy.ts b/test/cypress/tests/modules/Renderer.cy.ts index decd0447..e1d4d490 100644 --- a/test/cypress/tests/modules/Renderer.cy.ts +++ b/test/cypress/tests/modules/Renderer.cy.ts @@ -1,7 +1,7 @@ import ToolMock, { type MockToolData } from '../../fixtures/tools/ToolMock'; import type EditorJS from '../../../../types/index'; import type { BlockToolConstructorOptions } from '../../../../types'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('Renderer module', () => { it('should not cause onChange firing during initial rendering', () => { @@ -59,11 +59,11 @@ describe('Renderer module', () => { }) .as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .should('have.length', 3); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .each(($el, index) => { /** @@ -125,11 +125,11 @@ describe('Renderer module', () => { }) .as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .should('have.length', 3); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .each(($el, index) => { /** @@ -158,7 +158,7 @@ describe('Renderer module', () => { }) .as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .should('have.length', 1); }); @@ -174,7 +174,7 @@ describe('Renderer module', () => { }); }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .should('have.length', 1); }); diff --git a/test/cypress/tests/modules/Saver.cy.ts b/test/cypress/tests/modules/Saver.cy.ts index f25cdfc1..81e8f30e 100644 --- a/test/cypress/tests/modules/Saver.cy.ts +++ b/test/cypress/tests/modules/Saver.cy.ts @@ -1,6 +1,6 @@ import type EditorJS from '../../../../types/index'; import Header from '@editorjs/header'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('Saver module', () => { describe('save()', () => { @@ -22,7 +22,7 @@ describe('Saver module', () => { */ const extensionNode = document.createElement('extension-node'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block__content') .then((blockContent) => { blockContent.append(extensionNode); @@ -58,18 +58,18 @@ describe('Saver module', () => { }) .as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('span.ce-toolbar__settings-btn') .click(); /** * Change header level */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-settings .ce-popover-item:nth-child(3)') .click(); diff --git a/test/cypress/tests/modules/Ui.cy.ts b/test/cypress/tests/modules/Ui.cy.ts index f1b7fe4d..d7be55d5 100644 --- a/test/cypress/tests/modules/Ui.cy.ts +++ b/test/cypress/tests/modules/Ui.cy.ts @@ -1,6 +1,6 @@ import { createEditorWithTextBlocks } from '../../support/utils/createEditorWithTextBlocks'; import type EditorJS from '../../../../types/index'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('Ui module', () => { describe('documentKeydown', () => { @@ -30,7 +30,7 @@ describe('Ui module', () => { /** * Select two blocks by shift+down */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -76,7 +76,7 @@ describe('Ui module', () => { /** * Select two blocks by shift+down */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .click() @@ -105,7 +105,7 @@ describe('Ui module', () => { ]) .as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .eq(1) .click(); @@ -128,7 +128,7 @@ describe('Ui module', () => { }) .as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .eq(1) .click(); diff --git a/test/cypress/tests/onchange.cy.ts b/test/cypress/tests/onchange.cy.ts index 03ad9a96..1d0dfd2a 100644 --- a/test/cypress/tests/onchange.cy.ts +++ b/test/cypress/tests/onchange.cy.ts @@ -2,7 +2,7 @@ import Header from '@editorjs/header'; import Code from '@editorjs/code'; import ToolMock from '../fixtures/tools/ToolMock'; import Delimiter from '@editorjs/delimiter'; -import { EDITOR_SELECTOR } from '../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; import { BlockAddedMutationType } from '../../../types/events/block/BlockAdded'; import { BlockChangedMutationType } from '../../../types/events/block/BlockChanged'; import { BlockRemovedMutationType } from '../../../types/events/block/BlockRemoved'; @@ -82,7 +82,7 @@ describe('onChange callback', () => { }, ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('change') @@ -114,7 +114,7 @@ describe('onChange callback', () => { }, ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('first change') @@ -137,7 +137,7 @@ describe('onChange callback', () => { it('should be fired with correct index on block insertion above the current (by pressing Enter at the start)', () => { createEditor(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('{enter}'); @@ -161,7 +161,7 @@ describe('onChange callback', () => { }, } ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('{enter}'); @@ -180,7 +180,7 @@ describe('onChange callback', () => { }, } ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('{enter}'); @@ -196,7 +196,7 @@ describe('onChange callback', () => { it('should be fired on typing into block', () => { createEditor(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('some text'); @@ -212,15 +212,15 @@ describe('onChange callback', () => { it('should be fired on block insertion with save inside onChange', () => { createEditorWithSave(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=delimiter]') .click(); @@ -258,15 +258,15 @@ describe('onChange callback', () => { it('should be fired on block replacement for both of blocks', () => { createEditor(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-toolbar__plus') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item[data-item-name=header]') .click(); @@ -302,15 +302,15 @@ describe('onChange callback', () => { }, ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('span.ce-toolbar__settings-btn') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-settings .ce-popover-item:nth-child(4)') .click(); @@ -335,20 +335,20 @@ describe('onChange callback', () => { }, ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('span.ce-toolbar__settings-btn') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name=delete]') .click(); /** Second click for confirmation */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name=delete]') .click(); @@ -390,16 +390,16 @@ describe('onChange callback', () => { }, ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .last() .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('span.ce-toolbar__settings-btn') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name=move-up]') .click(); @@ -420,7 +420,7 @@ describe('onChange callback', () => { }, } ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('textarea') .type('Some input to the textarea'); @@ -440,21 +440,21 @@ describe('onChange callback', () => { }, } ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); /** * Open Block Tunes, add fake cursor */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('span.ce-toolbar__settings-btn') .click(); /** * Close Block Tunes, remove fake cursor */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click(); @@ -471,7 +471,7 @@ describe('onChange callback', () => { }, } ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('div.ce-block') .click() .type('{backspace}'); @@ -673,7 +673,7 @@ describe('onChange callback', () => { /** * Emulate tool's child-element text typing */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=tool-child]') .click() .type('some text'); diff --git a/test/cypress/tests/selection.cy.ts b/test/cypress/tests/selection.cy.ts index 7ce71527..dc6f5358 100644 --- a/test/cypress/tests/selection.cy.ts +++ b/test/cypress/tests/selection.cy.ts @@ -1,5 +1,5 @@ import * as _ from '../../../src/components/utils'; -import { EDITOR_SELECTOR } from '../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; describe('Blocks selection', () => { beforeEach(() => { @@ -13,12 +13,12 @@ describe('Blocks selection', () => { }); it('should remove block selection on click', () => { - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .click() .type('First block{enter}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('div.ce-block') .next() .type('Second block') @@ -28,7 +28,7 @@ describe('Blocks selection', () => { keyCode: _.keyCodes.UP, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .click() .find('div.ce-block') .should('not.have.class', '.ce-block--selected'); diff --git a/test/cypress/tests/ui/BlockTunes.cy.ts b/test/cypress/tests/ui/BlockTunes.cy.ts index 0c5179ec..305c779c 100644 --- a/test/cypress/tests/ui/BlockTunes.cy.ts +++ b/test/cypress/tests/ui/BlockTunes.cy.ts @@ -3,7 +3,7 @@ import Header from '@editorjs/header'; import type { ConversionConfig, ToolboxConfig } from '../../../../types'; import type { MenuConfig } from '../../../../types/tools'; import { ToolWithoutConversionExport } from '../../fixtures/tools/ToolWithoutConversionExport'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('BlockTunes', () => { describe('Keyboard only', () => { @@ -23,7 +23,7 @@ describe('BlockTunes', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('{cmd}/') @@ -53,7 +53,7 @@ describe('BlockTunes', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('{cmd}/') @@ -88,28 +88,28 @@ describe('BlockTunes', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check "Convert to" option is present */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item') .contains('Convert to') .should('exist'); /** Click "Convert to" option*/ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item') .contains('Convert to') .click(); /** Check connected popover with the "Heading" option is present */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested [data-item-name=header]') .should('exist'); }); @@ -130,16 +130,16 @@ describe('BlockTunes', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check "Convert to" option is not present */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item') .contains('Convert to') .should('not.exist'); @@ -163,17 +163,17 @@ describe('BlockTunes', () => { }).as('editorInstance'); cy.get('@editorInstance') - .get(EDITOR_SELECTOR) + .get(EDITOR_INTERFACE_SELECTOR) .find('.ce-block') .click(); cy.get('@editorInstance') - .get(EDITOR_SELECTOR) + .get(EDITOR_INTERFACE_SELECTOR) .find('.ce-toolbar__settings-btn') .click(); cy.get('@editorInstance') - .get(EDITOR_SELECTOR) + .get(EDITOR_INTERFACE_SELECTOR) .find('.ce-popover-item[data-item-name=convert-to]') .should('not.exist'); }); @@ -256,28 +256,28 @@ describe('BlockTunes', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Open "Convert to" menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item') .contains('Convert to') .click(); /** Check TestTool option with SAME data is NOT present */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested [data-item-name=testTool]') .contains('Title 1') .should('not.exist'); /** Check TestTool option with DIFFERENT data IS present */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested [data-item-name=testTool]') .contains('Title 2') .should('exist'); @@ -301,27 +301,27 @@ describe('BlockTunes', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Click "Convert to" option*/ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item') .contains('Convert to') .click(); /** Click "Heading" option */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested [data-item-name=header]') .click(); /** Check the block was converted to the second option */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-header') .should('have.text', 'Some text'); @@ -335,7 +335,7 @@ describe('BlockTunes', () => { throw new Error('Range is undefined'); } - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-header') .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -418,21 +418,21 @@ describe('BlockTunes', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check there are more than 1 tune */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item') .should('have.length.above', 1); /** Check the first tune is tool specific tune */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-item:first-child') .contains('Tune') .should('exist'); diff --git a/test/cypress/tests/ui/DataEmpty.cy.ts b/test/cypress/tests/ui/DataEmpty.cy.ts index 25c88131..7346e294 100644 --- a/test/cypress/tests/ui/DataEmpty.cy.ts +++ b/test/cypress/tests/ui/DataEmpty.cy.ts @@ -1,5 +1,5 @@ import { createEditorWithTextBlocks } from '../../support/utils/createEditorWithTextBlocks'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('inputs [data-empty] mark', () => { it('should be added to inputs of editor on initialization', () => { @@ -8,12 +8,12 @@ describe('inputs [data-empty] mark', () => { '', // empty block ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .first() .should('have.attr', 'data-empty', 'false'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should('have.attr', 'data-empty', 'true'); @@ -25,12 +25,12 @@ describe('inputs [data-empty] mark', () => { '', // empty block ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .type('Some text'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should('have.attr', 'data-empty', 'false'); @@ -42,12 +42,12 @@ describe('inputs [data-empty] mark', () => { 'Some text', // not empty block ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .type('{selectall}{backspace}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should('have.attr', 'data-empty', 'true'); @@ -59,12 +59,12 @@ describe('inputs [data-empty] mark', () => { '', // empty block ]); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .type('{enter}'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .last() .should('have.attr', 'data-empty', 'true'); diff --git a/test/cypress/tests/ui/InlineToolbar.cy.ts b/test/cypress/tests/ui/InlineToolbar.cy.ts index fb87ca5c..3c1db1fd 100644 --- a/test/cypress/tests/ui/InlineToolbar.cy.ts +++ b/test/cypress/tests/ui/InlineToolbar.cy.ts @@ -1,7 +1,7 @@ import Header from '@editorjs/header'; import type { InlineTool, InlineToolConstructorOptions, MenuConfig, ToolConstructable } from '../../../../types/tools'; import { createEditorWithTextBlocks } from '../../support/utils/createEditorWithTextBlocks'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('Inline Toolbar', () => { describe('Separators', () => { @@ -25,18 +25,18 @@ describe('Inline Toolbar', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('block'); /** Check that first item (which is convert-to and has children) has a separator after it */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .first() .should('have.attr', 'data-item-name', 'convert-to'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .eq(1) @@ -92,24 +92,24 @@ describe('Inline Toolbar', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-header') .selectText('block'); /** Check that item with children is surrounded by separators */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .eq(3) .should('have.class', 'ce-popover-item-separator'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .eq(4) .should('have.attr', 'data-item-name', 'test-tool'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .eq(5) @@ -165,18 +165,18 @@ describe('Inline Toolbar', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-header') .selectText('block'); /** Check that item with children is surrounded by separators */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .eq(3) .should('have.class', 'ce-popover-item-separator'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-cy=inline-toolbar] .ce-popover__items') .children() .eq(4) @@ -214,7 +214,7 @@ describe('Inline Toolbar', () => { readOnly: true, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('text'); diff --git a/test/cypress/tests/ui/Placeholders.cy.ts b/test/cypress/tests/ui/Placeholders.cy.ts index f5528e13..22605e2f 100644 --- a/test/cypress/tests/ui/Placeholders.cy.ts +++ b/test/cypress/tests/ui/Placeholders.cy.ts @@ -1,4 +1,4 @@ -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; /** * Text will be passed as a placeholder to the editor @@ -19,7 +19,7 @@ describe('Placeholders', () => { placeholder: PLACEHOLDER_TEXT, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .getPseudoElementContent('::before') .should('eq', PLACEHOLDER_TEXT); @@ -31,7 +31,7 @@ describe('Placeholders', () => { autofocus: true, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .getPseudoElementContent('::before') .should('eq', PLACEHOLDER_TEXT); @@ -42,7 +42,7 @@ describe('Placeholders', () => { placeholder: PLACEHOLDER_TEXT, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .as('firstBlock') @@ -55,7 +55,7 @@ describe('Placeholders', () => { placeholder: PLACEHOLDER_TEXT, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .type('aaa') .type('{selectall}{backspace}') @@ -68,7 +68,7 @@ describe('Placeholders', () => { placeholder: PLACEHOLDER_TEXT, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .as('firstBlock') .getPseudoElementContent('::before') @@ -85,7 +85,7 @@ describe('Placeholders', () => { placeholder: PLACEHOLDER_TEXT, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .as('firstBlock') .getPseudoElementContent('::before') diff --git a/test/cypress/tests/ui/toolbox.cy.ts b/test/cypress/tests/ui/toolbox.cy.ts index dd607e37..360d5a97 100644 --- a/test/cypress/tests/ui/toolbox.cy.ts +++ b/test/cypress/tests/ui/toolbox.cy.ts @@ -1,7 +1,7 @@ import type EditorJS from '../../../../types/index'; import type { ConversionConfig, ToolboxConfig } from '../../../../types/index'; import ToolMock from '../../fixtures/tools/ToolMock'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; describe('Toolbox', () => { describe('Shortcuts', () => { @@ -39,7 +39,7 @@ describe('Toolbox', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('Some text') @@ -68,7 +68,7 @@ describe('Toolbox', () => { throw new Error('Selection range is not available'); } - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find(`.ce-block[data-id=${blocks[0].id}]`) .should(($block) => { expect($block[0].contains(range.startContainer)).to.be.true; @@ -102,7 +102,7 @@ describe('Toolbox', () => { }, }).as('editorInstance'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('Some text') @@ -151,7 +151,7 @@ describe('Toolbox', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('Some text') @@ -203,7 +203,7 @@ describe('Toolbox', () => { }, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .click() .type('Some text') diff --git a/test/cypress/tests/utils/flipper.cy.ts b/test/cypress/tests/utils/flipper.cy.ts index a4358f01..0a5d5a31 100644 --- a/test/cypress/tests/utils/flipper.cy.ts +++ b/test/cypress/tests/utils/flipper.cy.ts @@ -1,5 +1,5 @@ import type { PopoverItemParams } from '../../../../types/index.js'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; /** * Mock of some Block Tool @@ -70,7 +70,7 @@ describe('Flipper', () => { cy.spy(SomePlugin, 'pluginInternalKeydownHandler'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-some-plugin') .as('pluginInput') .focus() @@ -78,7 +78,7 @@ describe('Flipper', () => { .wait(100); // Try to delete the block via keyboard - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-some-plugin') // Open tunes menu .trigger('keydown', { code: 'Slash', @@ -93,7 +93,7 @@ describe('Flipper', () => { cy.get('[data-item-name="delete"]') .should('have.class', 'ce-popover-item--focused'); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-some-plugin') // Click delete .trigger('keydown', { keyCode: ENTER_KEY_CODE }) @@ -118,7 +118,7 @@ describe('Flipper', () => { autofocus: true, }); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-paragraph') .as('paragraph') .selectTextByOffset([0, 10]) diff --git a/test/cypress/tests/utils/popover.cy.ts b/test/cypress/tests/utils/popover.cy.ts index 033d4b15..802e8977 100644 --- a/test/cypress/tests/utils/popover.cy.ts +++ b/test/cypress/tests/utils/popover.cy.ts @@ -2,7 +2,7 @@ import { PopoverDesktop as Popover, PopoverItemType } from '../../../../src/comp import type { PopoverItemParams } from '@/types/utils/popover'; import type { MenuConfig } from '../../../../types/tools'; import type { BlockToolConstructable } from '../../../../types/tools'; -import { EDITOR_SELECTOR } from '../../support/constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; import Header from '@editorjs/header'; /* eslint-disable @typescript-eslint/no-empty-function */ @@ -285,16 +285,16 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check item with custom html content is displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover .ce-popover-item-html') .contains('Tune') .should('be.visible'); @@ -355,11 +355,11 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -368,7 +368,7 @@ describe('Popover', () => { cy.get('body').tab(); /** Check the first custom html item is focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover .ce-popover-item-html .ce-settings__button') .contains('Tune1') .should('have.class', 'ce-popover-item--focused'); @@ -378,7 +378,7 @@ describe('Popover', () => { cy.get('body').tab(); /** Check the second custom html item is focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover .ce-popover-item-html .ce-settings__button') .contains('Tune2') .should('have.class', 'ce-popover-item--focused'); @@ -388,7 +388,7 @@ describe('Popover', () => { cy.get('body').tab(); /** Check that default popover item got focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name=move-up]') .should('have.class', 'ce-popover-item--focused'); }); @@ -438,32 +438,32 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check item with children has arrow icon */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name="test-item"]') .get('.ce-popover-item__icon--chevron-right') .should('be.visible'); /** Click the item */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name="test-item"]') .click(); /** Check nested popover opened */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested .ce-popover__container') .should('be.visible'); /** Check child item displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested .ce-popover__container') .get('[data-item-name="nested-test-item"]') .should('be.visible'); @@ -517,62 +517,62 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check item with children has arrow icon */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name="test-item"]') .get('.ce-popover-item__icon--chevron-right') .should('be.visible'); /** Click the item */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name="test-item"]') .click(); /** Check child item displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="nested-test-item"]') .should('be.visible'); /** Check header displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-header') .should('have.text', 'Tune'); /** Check back button displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('.ce-popover-header__back-button') .should('be.visible'); /** Click back button */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('.ce-popover-header__back-button') .click(); /** Check child item is not displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="nested-test-item"]') .should('not.exist'); /** Check back button is not displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('.ce-popover-header__back-button') .should('not.exist'); /** Check header is not displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover-header') .should('not.exist'); }); @@ -614,16 +614,16 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check item displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="test-item"]') .should('be.visible'); @@ -671,22 +671,22 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); /** Check item displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="test-item"]') .should('be.visible'); /** Check separator displayed */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('.ce-popover-item-separator') .should('be.visible'); @@ -738,11 +738,11 @@ describe('Popover', () => { }); /** Open block tunes menu */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.cdx-block') .click(); - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-toolbar__settings-btn') .click(); @@ -751,13 +751,13 @@ describe('Popover', () => { cy.get('body').tab(); /** Check first item is focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="test-item-1"].ce-popover-item--focused') .should('exist'); /** Check second item is not focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="test-item-2"].ce-popover-item--focused') .should('not.exist'); @@ -767,13 +767,13 @@ describe('Popover', () => { cy.get('body').tab(); /** Check first item is not focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="test-item-1"].ce-popover-item--focused') .should('not.exist'); /** Check second item is focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="test-item-2"].ce-popover-item--focused') .should('exist'); @@ -801,27 +801,27 @@ describe('Popover', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('block'); /** Hover Convert To item which has nested popover */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name=convert-to]') .trigger('mouseover'); /** Check nested popover didn't open */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested .ce-popover__container') .should('not.exist'); /** Click Convert To item which has nested popover */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('[data-item-name=convert-to]') .click(); /** Check nested popover opened */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover--nested .ce-popover__container') .should('exist'); }); @@ -847,17 +847,17 @@ describe('Popover', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('block'); /** Check Inline Popover opened */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover__container') .should('be.visible'); /** Check first item is NOT focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover__container') .get('[data-item-name="convert-to"].ce-popover-item--focused') .should('not.exist'); @@ -866,13 +866,13 @@ describe('Popover', () => { cy.tab(); /** Check first item became focused after tab */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover__container') .get('[data-item-name="convert-to"].ce-popover-item--focused') .should('exist'); /** Check second item is NOT focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover__container') .get('[data-item-name="link"] .ce-popover-item--focused') .should('not.exist'); @@ -881,7 +881,7 @@ describe('Popover', () => { cy.tab(); /** Check second item became focused after tab */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover__container') .get('[data-item-name="link"] .ce-popover-item--focused') .should('exist'); @@ -908,12 +908,12 @@ describe('Popover', () => { }); /** Open Inline Toolbar */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .find('.ce-paragraph') .selectText('block'); /** Check Inline Popover opened */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover__container') .should('be.visible'); @@ -925,12 +925,12 @@ describe('Popover', () => { .type('{enter}'); /** Check Inline Popover opened */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-inline-toolbar .ce-popover--nested .ce-popover__container') .should('be.visible'); /** Check first item is NOT focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="header"].ce-popover-item--focused') .should('not.exist'); @@ -940,7 +940,7 @@ describe('Popover', () => { cy.get('body').tab(); /** Check first item is focused */ - cy.get(EDITOR_SELECTOR) + cy.get(EDITOR_INTERFACE_SELECTOR) .get('.ce-popover__container') .get('[data-item-name="header"].ce-popover-item--focused') .should('exist'); diff --git a/test/playwright/tests/constants.ts b/test/playwright/tests/constants.ts deleted file mode 100644 index 104d9f25..00000000 --- a/test/playwright/tests/constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * CSS selector for the main editor wrapper element - * Used in Playwright tests to query the editor container - */ -export const EDITOR_SELECTOR = '[data-interface=editorjs]'; - diff --git a/test/playwright/tests/i18n.spec.ts b/test/playwright/tests/i18n.spec.ts index c3cce189..3fd2c41e 100644 --- a/test/playwright/tests/i18n.spec.ts +++ b/test/playwright/tests/i18n.spec.ts @@ -4,20 +4,19 @@ import path from 'node:path'; import { pathToFileURL } from 'node:url'; import type { OutputData } from '@/types'; import { ensureEditorBundleBuilt } from './helpers/ensure-build'; -import { EDITOR_SELECTOR } from './constants'; +import { TOOLTIP_INTERFACE_SELECTOR, EDITOR_INTERFACE_SELECTOR, INLINE_TOOLBAR_INTERFACE_SELECTOR } from '../../../src/components/constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../cypress/fixtures/test.html') ).href; const HOLDER_ID = 'editorjs'; -const BLOCK_SELECTOR = `${EDITOR_SELECTOR} div.ce-block`; -const PARAGRAPH_SELECTOR = `${EDITOR_SELECTOR} [data-block-tool="paragraph"]`; -const SETTINGS_BUTTON_SELECTOR = `${EDITOR_SELECTOR} .ce-toolbar__settings-btn`; -const PLUS_BUTTON_SELECTOR = `${EDITOR_SELECTOR} .ce-toolbar__plus`; -const INLINE_TOOLBAR_SELECTOR = `${EDITOR_SELECTOR} [data-interface=inline-toolbar]`; -const POPOVER_SELECTOR = `${EDITOR_SELECTOR} .ce-popover`; -const TOOLTIP_SELECTOR = '.ct'; +const BLOCK_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} div.ce-block`; +const PARAGRAPH_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} [data-block-tool="paragraph"]`; +const SETTINGS_BUTTON_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} .ce-toolbar__settings-btn`; +const PLUS_BUTTON_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} .ce-toolbar__plus`; +const INLINE_TOOLBAR_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} ${INLINE_TOOLBAR_INTERFACE_SELECTOR}`; +const POPOVER_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} .ce-popover`; const LINK_TOOL_SHORTCUT_MODIFIER = process.platform === 'darwin' ? 'Meta' : 'Control'; /** @@ -215,7 +214,7 @@ const selectText = async (locator: Locator, text: string): Promise => { const getTooltipText = async (page: Page, triggerElement: Locator): Promise => { await triggerElement.hover(); - const tooltip = page.locator(TOOLTIP_SELECTOR); + const tooltip = page.locator(TOOLTIP_INTERFACE_SELECTOR); await expect(tooltip).toBeVisible(); diff --git a/test/playwright/tests/inline-tools/bold.spec.ts b/test/playwright/tests/inline-tools/bold.spec.ts index 6827c4ec..d14f36e9 100644 --- a/test/playwright/tests/inline-tools/bold.spec.ts +++ b/test/playwright/tests/inline-tools/bold.spec.ts @@ -5,15 +5,15 @@ import { pathToFileURL } from 'node:url'; import type EditorJS from '@/types'; import type { OutputData } from '@/types'; import { ensureEditorBundleBuilt } from '../helpers/ensure-build'; -import { EDITOR_SELECTOR } from '../constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../../cypress/fixtures/test.html') ).href; const HOLDER_ID = 'editorjs'; -const PARAGRAPH_SELECTOR = `${EDITOR_SELECTOR} [data-block-tool="paragraph"]`; -const INLINE_TOOLBAR_SELECTOR = `${EDITOR_SELECTOR} [data-cy=inline-toolbar]`; +const PARAGRAPH_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} [data-block-tool="paragraph"]`; +const INLINE_TOOLBAR_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} [data-cy=inline-toolbar]`; /** * Reset the editor holder and destroy any existing instance diff --git a/test/playwright/tests/inline-tools/link.spec.ts b/test/playwright/tests/inline-tools/link.spec.ts index 3afdbb79..617e60be 100644 --- a/test/playwright/tests/inline-tools/link.spec.ts +++ b/test/playwright/tests/inline-tools/link.spec.ts @@ -5,6 +5,7 @@ import { pathToFileURL } from 'node:url'; import type EditorJS from '@/types'; import type { OutputData } from '@/types'; import { ensureEditorBundleBuilt } from '../helpers/ensure-build'; +import { INLINE_TOOLBAR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../../cypress/fixtures/test.html') @@ -12,7 +13,7 @@ const TEST_PAGE_URL = pathToFileURL( const HOLDER_ID = 'editorjs'; const PARAGRAPH_SELECTOR = '[data-block-tool="paragraph"]'; -const INLINE_TOOLBAR_SELECTOR = '[data-interface=inline-toolbar]'; +const INLINE_TOOLBAR_SELECTOR = INLINE_TOOLBAR_INTERFACE_SELECTOR; const LINK_BUTTON_SELECTOR = `${INLINE_TOOLBAR_SELECTOR} [data-item-name="link"] button`; const LINK_INPUT_SELECTOR = `input[data-link-tool-input-opened]`; const NOTIFIER_SELECTOR = '.cdx-notifies'; diff --git a/test/playwright/tests/modules/BlockEvents/Backspace.spec.ts b/test/playwright/tests/modules/BlockEvents/Backspace.spec.ts index ea60b0dd..add3c2c5 100644 --- a/test/playwright/tests/modules/BlockEvents/Backspace.spec.ts +++ b/test/playwright/tests/modules/BlockEvents/Backspace.spec.ts @@ -5,14 +5,14 @@ import { pathToFileURL } from 'node:url'; import type EditorJS from '../../../../../types'; import type { OutputData } from '../../../../../types'; import { ensureEditorBundleBuilt } from '../../helpers/ensure-build'; -import { EDITOR_SELECTOR } from '../../constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../../../cypress/fixtures/test.html') ).href; -const BLOCK_SELECTOR = `${EDITOR_SELECTOR} div.ce-block`; -const PARAGRAPH_SELECTOR = `${EDITOR_SELECTOR} [data-block-tool="paragraph"]`; -const TOOLBAR_SELECTOR = `${EDITOR_SELECTOR} .ce-toolbar`; +const BLOCK_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} div.ce-block`; +const PARAGRAPH_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} [data-block-tool="paragraph"]`; +const TOOLBAR_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} .ce-toolbar`; const HOLDER_ID = 'editorjs'; /** @@ -520,7 +520,7 @@ test.describe('Backspace keydown', () => { test('should navigate to previous input when caret is not at first input', async ({ page }) => { await createMultiInputToolEditor(page); - const inputs = page.locator(`${EDITOR_SELECTOR} [data-cy=quote-tool] div[contenteditable]`); + const inputs = page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-cy=quote-tool] div[contenteditable]`); const lastInput = inputs.last(); await lastInput.click(); @@ -641,7 +641,7 @@ test.describe('Backspace keydown', () => { expect(blocks[0].id).toBe('block1'); expect((blocks[0].data as { text: string }).text).toBe('First block headingSecond block paragraph'); - await expectCaretOffset(page.locator(`${EDITOR_SELECTOR} [data-cy=block-wrapper]`).first(), 'First block heading'.length, { normalize: true }); + await expectCaretOffset(page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-cy=block-wrapper]`).first(), 'First block heading'.length, { normalize: true }); await expectToolbarClosed(page); }); @@ -659,7 +659,7 @@ test.describe('Backspace keydown', () => { }, ]); - const targetBlock = page.locator(`${EDITOR_SELECTOR} [data-cy="block-wrapper"][data-id="block2"]`); + const targetBlock = page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-cy="block-wrapper"][data-id="block2"]`); await targetBlock.click(); await targetBlock.press('Home'); @@ -671,7 +671,7 @@ test.describe('Backspace keydown', () => { expect(blocks[0].id).toBe('block1'); expect((blocks[0].data as { text: string }).text).toBe('First block paragraphSecond block heading'); - await expectCaretOffset(page.locator(`${EDITOR_SELECTOR} [data-cy=block-wrapper]`).first(), 'First block paragraph'.length, { normalize: true }); + await expectCaretOffset(page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-cy=block-wrapper]`).first(), 'First block paragraph'.length, { normalize: true }); await expectToolbarClosed(page); }); @@ -687,7 +687,7 @@ test.describe('Backspace keydown', () => { const { blocks } = await saveEditor(page); expect(blocks).toHaveLength(2); - await expectCaretAtEnd(page.locator(`${EDITOR_SELECTOR} [data-cy=unmergeable-tool]`)); + await expectCaretAtEnd(page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-cy=unmergeable-tool]`)); await expectToolbarClosed(page); }); @@ -703,7 +703,7 @@ test.describe('Backspace keydown', () => { const { blocks } = await saveEditor(page); expect(blocks).toHaveLength(2); - await expectCaretAtEnd(page.locator(`${EDITOR_SELECTOR} [data-cy=unmergeable-tool]`)); + await expectCaretAtEnd(page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-cy=unmergeable-tool]`)); await expectToolbarClosed(page); }); diff --git a/test/playwright/tests/modules/BlockEvents/Tab.spec.ts b/test/playwright/tests/modules/BlockEvents/Tab.spec.ts index 70cdc59b..aa729b52 100644 --- a/test/playwright/tests/modules/BlockEvents/Tab.spec.ts +++ b/test/playwright/tests/modules/BlockEvents/Tab.spec.ts @@ -5,13 +5,13 @@ import { pathToFileURL } from 'node:url'; import type EditorJS from '../../../../../types'; import type { OutputData } from '../../../../../types'; import { ensureEditorBundleBuilt } from '../../helpers/ensure-build'; -import { EDITOR_SELECTOR } from '../../constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../../../src/components/constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../../../cypress/fixtures/test.html') ).href; const HOLDER_ID = 'editorjs'; -const PARAGRAPH_SELECTOR = `${EDITOR_SELECTOR} [data-block-tool="paragraph"]`; +const PARAGRAPH_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} [data-block-tool="paragraph"]`; const TOOL_WITH_TWO_INPUTS_SELECTOR = '[data-cy=tool-with-two-inputs] div[contenteditable=true]'; const CONTENTLESS_TOOL_SELECTOR = '[data-cy=contentless-tool]'; const REGULAR_INPUT_SELECTOR = '[data-cy=regular-input]'; diff --git a/test/playwright/tests/sanitisation.spec.ts b/test/playwright/tests/sanitisation.spec.ts index 6b7d7f5a..25c20b66 100644 --- a/test/playwright/tests/sanitisation.spec.ts +++ b/test/playwright/tests/sanitisation.spec.ts @@ -4,14 +4,14 @@ import path from 'node:path'; import { pathToFileURL } from 'node:url'; import type { OutputData } from '@/types'; import { ensureEditorBundleBuilt } from './helpers/ensure-build'; -import { EDITOR_SELECTOR } from './constants'; +import { EDITOR_INTERFACE_SELECTOR } from '../../../src/components/constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../cypress/fixtures/test.html') ).href; const HOLDER_ID = 'editorjs'; -const BLOCK_SELECTOR = `${EDITOR_SELECTOR} div.ce-block`; +const BLOCK_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} div.ce-block`; /** * Reset the editor holder and destroy any existing instance @@ -237,7 +237,7 @@ test.describe('Sanitizing', () => { await selectAllText(block); // Click bold button - const boldButton = page.locator(`${EDITOR_SELECTOR} [data-item-name="bold"]`); + const boldButton = page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-item-name="bold"]`); await boldButton.click(); @@ -288,7 +288,7 @@ test.describe('Sanitizing', () => { }, ]); - const lastParagraph = page.locator(`${EDITOR_SELECTOR} .ce-paragraph`).last(); + const lastParagraph = page.locator(`${EDITOR_INTERFACE_SELECTOR} .ce-paragraph`).last(); await lastParagraph.click(); await page.keyboard.press('Home'); @@ -324,7 +324,7 @@ test.describe('Sanitizing', () => { await selectAllText(block); - const italicButton = page.locator(`${EDITOR_SELECTOR} [data-item-name="italic"]`); + const italicButton = page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-item-name="italic"]`); await italicButton.click(); await block.click(); @@ -359,7 +359,7 @@ test.describe('Sanitizing', () => { await selectAllText(block); - const linkButton = page.locator(`${EDITOR_SELECTOR} [data-item-name="link"]`); + const linkButton = page.locator(`${EDITOR_INTERFACE_SELECTOR} [data-item-name="link"]`); await linkButton.click(); @@ -721,7 +721,7 @@ test.describe('Sanitizing', () => { }, ]); - const lastParagraph = page.locator(`${EDITOR_SELECTOR} .ce-paragraph`).last(); + const lastParagraph = page.locator(`${EDITOR_INTERFACE_SELECTOR} .ce-paragraph`).last(); await lastParagraph.click(); await page.keyboard.press('Home'); @@ -751,7 +751,7 @@ test.describe('Sanitizing', () => { }, ]); - const lastParagraph = page.locator(`${EDITOR_SELECTOR} .ce-paragraph`).last(); + const lastParagraph = page.locator(`${EDITOR_INTERFACE_SELECTOR} .ce-paragraph`).last(); await lastParagraph.click(); await page.keyboard.press('Home'); diff --git a/test/playwright/tests/utils/popover-search.spec.ts b/test/playwright/tests/utils/popover-search.spec.ts index d2d53b22..3d42d5a5 100644 --- a/test/playwright/tests/utils/popover-search.spec.ts +++ b/test/playwright/tests/utils/popover-search.spec.ts @@ -4,18 +4,17 @@ import path from 'node:path'; import { pathToFileURL } from 'node:url'; import type { OutputData } from '@/types'; import { PopoverItemType } from '@/types/utils/popover/popover-item-type'; -import { selectionChangeDebounceTimeout } from '../../../../src/components/constants'; +import { selectionChangeDebounceTimeout, EDITOR_INTERFACE_SELECTOR } from '../../../../src/components/constants'; import { ensureEditorBundleBuilt } from '../helpers/ensure-build'; -import { EDITOR_SELECTOR } from '../constants'; const TEST_PAGE_URL = pathToFileURL( path.resolve(__dirname, '../../../cypress/fixtures/test.html') ).href; const HOLDER_ID = 'editorjs'; -const BLOCK_SELECTOR = `${EDITOR_SELECTOR} .cdx-block`; -const BLOCK_TUNES_SELECTOR = `${EDITOR_SELECTOR} [data-cy=block-tunes]`; -const SETTINGS_BUTTON_SELECTOR = `${EDITOR_SELECTOR} .ce-toolbar__settings-btn`; +const BLOCK_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} .cdx-block`; +const BLOCK_TUNES_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} [data-cy=block-tunes]`; +const SETTINGS_BUTTON_SELECTOR = `${EDITOR_INTERFACE_SELECTOR} .ce-toolbar__settings-btn`; const SEARCH_INPUT_SELECTOR = `${BLOCK_TUNES_SELECTOR} .cdx-search-field__input`; const POPOVER_ITEM_SELECTOR = `${BLOCK_TUNES_SELECTOR} .ce-popover-item`; const NOTHING_FOUND_SELECTOR = `${BLOCK_TUNES_SELECTOR} .ce-popover__nothing-found-message`; diff --git a/test/playwright/tests/utils/tooltip.spec.ts b/test/playwright/tests/utils/tooltip.spec.ts new file mode 100644 index 00000000..a963a693 --- /dev/null +++ b/test/playwright/tests/utils/tooltip.spec.ts @@ -0,0 +1,975 @@ +import { expect, test } from '@playwright/test'; +import type { Locator, Page } from '@playwright/test'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { ensureEditorBundleBuilt } from '../helpers/ensure-build'; +import { TOOLTIP_INTERFACE_SELECTOR } from '../../../../src/components/constants'; + +const TEST_PAGE_URL = pathToFileURL( + path.resolve(__dirname, '../../../cypress/fixtures/test.html') +).href; + +const HOLDER_ID = 'editorjs'; + +/** + * Reset the editor holder and destroy any existing instance + * + * @param page - The Playwright page object + */ +const resetEditor = async (page: Page): Promise => { + await page.evaluate(async ({ holderId }) => { + if (window.editorInstance) { + await window.editorInstance.destroy?.(); + window.editorInstance = undefined; + } + + document.getElementById(holderId)?.remove(); + + const container = document.createElement('div'); + + container.id = holderId; + container.dataset.cy = holderId; + container.style.border = '1px dotted #388AE5'; + + document.body.appendChild(container); + }, { holderId: HOLDER_ID }); +}; + +/** + * Create editor instance + * + * @param page - The Playwright page object + */ +const createEditor = async (page: Page): Promise => { + await page.waitForFunction(() => typeof window.EditorJS === 'function'); + + await page.evaluate(async ({ holderId }) => { + const editor = new window.EditorJS({ + holder: holderId, + }); + + window.editorInstance = editor; + await editor.isReady; + }, { holderId: HOLDER_ID }); +}; + +/** + * Wait for tooltip to appear and verify it's visible + * + * @param page - The Playwright page object + * @returns The tooltip locator + */ +const waitForTooltip = async (page: Page): Promise => { + const tooltip = page.locator(TOOLTIP_INTERFACE_SELECTOR); + + await expect(tooltip).toBeVisible(); + + return tooltip; +}; + +/** + * Wait for tooltip to disappear + * + * @param page - The Playwright page object + */ +const waitForTooltipToHide = async (page: Page): Promise => { + const tooltip = page.locator(TOOLTIP_INTERFACE_SELECTOR); + + await expect(tooltip).toBeHidden(); +}; + +test.beforeAll(() => { + ensureEditorBundleBuilt(); +}); + +test.beforeEach(async ({ page }) => { + await page.goto(TEST_PAGE_URL); + await resetEditor(page); + await createEditor(page); +}); + +test.describe('Tooltip API', () => { + test.describe('show()', () => { + test('should show tooltip with text content', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Test Button'; + element.id = 'test-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Test tooltip text'); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('Test tooltip text'); + }); + + test('should show tooltip with HTML content', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('div'); + + element.textContent = 'Hover me'; + element.id = 'test-element'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + const htmlContent = document.createElement('div'); + + htmlContent.innerHTML = 'Bold tooltip'; + editor.tooltip.show(element, htmlContent); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip.locator('strong')).toContainText('Bold'); + await expect(tooltip).toContainText('tooltip'); + }); + + test('should show tooltip with options', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('span'); + + element.textContent = 'Test'; + element.id = 'test-span'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Tooltip with options', { + placement: 'top', + hidingDelay: 100, + }); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toBeVisible(); + await expect(tooltip).toContainText('Tooltip with options'); + }); + + test('should replace existing tooltip when showing new one', async ({ page }) => { + const testElements = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element1 = document.createElement('button'); + + element1.textContent = 'Button 1'; + element1.id = 'button-1'; + const element2 = document.createElement('button'); + + element2.textContent = 'Button 2'; + element2.id = 'button-2'; + container?.appendChild(element1); + container?.appendChild(element2); + + return { + id1: element1.id, + id2: element2.id, + }; + }, { holderId: HOLDER_ID }); + + // Show first tooltip + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'First tooltip'); + } + }, { elementId: testElements.id1 }); + + let tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('First tooltip'); + + // Show second tooltip - should replace the first + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Second tooltip'); + } + }, { elementId: testElements.id2 }); + + tooltip = await waitForTooltip(page); + await expect(tooltip).toContainText('Second tooltip'); + await expect(tooltip).not.toContainText('First tooltip'); + }); + }); + + test.describe('hide()', () => { + test('should hide visible tooltip', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Test Button'; + element.id = 'test-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // Show tooltip + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Test tooltip'); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('Test tooltip'); + + // Hide tooltip + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + await waitForTooltipToHide(page); + }); + + test('should hide tooltip when hide() is called', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('div'); + + element.textContent = 'Test'; + element.id = 'test-element'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // Show tooltip with hiding delay + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Tooltip with delay', { + hidingDelay: 1000, + }); + } + }, { elementId: testElement.id }); + + const tooltipBeforeHide = await waitForTooltip(page); + + await expect(tooltipBeforeHide).toBeVisible(); + + // Hide tooltip + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + // Should hide + await waitForTooltipToHide(page); + }); + + test('should handle hide() when no tooltip is visible', async ({ page }) => { + // Calling hide() when no tooltip is visible should not throw + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + // Verify no tooltip appears + const tooltip = page.locator(TOOLTIP_INTERFACE_SELECTOR); + + await expect(tooltip).toBeHidden(); + }); + }); + + test.describe('onHover()', () => { + test('should show tooltip on mouseenter', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Hover me'; + element.id = 'hover-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.onHover(element, 'Hover tooltip'); + } + }, { elementId: testElement.id }); + + const button = page.locator(`#${testElement.id}`); + + await button.hover(); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('Hover tooltip'); + }); + + test('should hide tooltip on mouseleave', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('div'); + + element.textContent = 'Hover area'; + element.id = 'hover-area'; + element.style.padding = '20px'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.onHover(element, 'Hover tooltip'); + } + }, { elementId: testElement.id }); + + const hoverArea = page.locator(`#${testElement.id}`); + + await hoverArea.hover(); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toBeVisible(); + + // Move mouse away + await page.mouse.move(0, 0); + + await waitForTooltipToHide(page); + }); + + test('should show tooltip on hover with HTML content', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('span'); + + element.textContent = 'Rich tooltip'; + element.id = 'rich-tooltip'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + const htmlContent = document.createElement('div'); + + htmlContent.innerHTML = 'Italic content'; + editor.tooltip.onHover(element, htmlContent); + } + }, { elementId: testElement.id }); + + const element = page.locator(`#${testElement.id}`); + + await element.hover(); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip.locator('em')).toContainText('Italic'); + await expect(tooltip).toContainText('content'); + }); + + test('should show tooltip on hover with options', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Configured tooltip'; + element.id = 'configured-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.onHover(element, 'Tooltip with config', { + placement: 'bottom', + delay: 200, + }); + } + }, { elementId: testElement.id }); + + const button = page.locator(`#${testElement.id}`); + + await button.hover(); + + // Wait for tooltip to appear (accounting for delay) + const tooltip = page.locator(TOOLTIP_INTERFACE_SELECTOR); + + await expect(tooltip).toBeVisible({ timeout: 500 }); + await expect(tooltip).toContainText('Tooltip with config'); + }); + }); + + test.describe('Integration', () => { + test('should handle multiple show/hide cycles', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Toggle'; + element.id = 'toggle-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // First cycle + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'First'); + } + }, { elementId: testElement.id }); + + const firstTooltip = await waitForTooltip(page); + + await expect(firstTooltip).toContainText('First'); + + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + await waitForTooltipToHide(page); + + // Second cycle + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Second'); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('Second'); + }); + + test('should work with different element types', async ({ page }) => { + const testElements = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const button = document.createElement('button'); + + button.textContent = 'Button'; + button.id = 'test-button'; + const div = document.createElement('div'); + + div.textContent = 'Div'; + div.id = 'test-div'; + const span = document.createElement('span'); + + span.textContent = 'Span'; + span.id = 'test-span'; + container?.appendChild(button); + container?.appendChild(div); + container?.appendChild(span); + + return { + buttonId: button.id, + divId: div.id, + spanId: span.id, + }; + }, { holderId: HOLDER_ID }); + + // Test with button + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Button tooltip'); + } + }, { elementId: testElements.buttonId }); + + let tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('Button tooltip'); + + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + await waitForTooltipToHide(page); + + // Test with div + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Div tooltip'); + } + }, { elementId: testElements.divId }); + + tooltip = await waitForTooltip(page); + await expect(tooltip).toContainText('Div tooltip'); + + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + await waitForTooltipToHide(page); + + // Test with span + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Span tooltip'); + } + }, { elementId: testElements.spanId }); + + tooltip = await waitForTooltip(page); + await expect(tooltip).toContainText('Span tooltip'); + }); + }); + + test.describe('destroy()', () => { + test('should destroy tooltip library and allow reinitialization', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Test'; + element.id = 'test-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // Show tooltip before destroy + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Before destroy'); + } + }, { elementId: testElement.id }); + + await waitForTooltip(page); + + // Destroy editor (which calls tooltip.destroy()) + await page.evaluate(async () => { + if (window.editorInstance) { + await window.editorInstance.destroy(); + window.editorInstance = undefined; + } + }); + + // Recreate editor + await createEditor(page); + + // Recreate test element if the holder was cleared during destroy + await page.evaluate(({ holderId, elementId }) => { + const container = document.getElementById(holderId); + let element = document.getElementById(elementId); + + if (!element && container) { + element = document.createElement('button'); + element.textContent = 'Test'; + element.id = elementId; + container.appendChild(element); + } + }, { holderId: HOLDER_ID, + elementId: testElement.id }); + + // Tooltip should work after reinitialization + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'After recreate'); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('After recreate'); + }); + }); + + test.describe('Edge cases', () => { + test('should handle calling onHover() multiple times on same element', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Hover me'; + element.id = 'hover-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // First onHover binding + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.onHover(element, 'First binding'); + } + }, { elementId: testElement.id }); + + // Second onHover binding (should replace first) + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.onHover(element, 'Second binding'); + } + }, { elementId: testElement.id }); + + const button = page.locator(`#${testElement.id}`); + + await button.hover(); + + const tooltip = await waitForTooltip(page); + + // Should show the second binding + await expect(tooltip).toContainText('Second binding'); + await expect(tooltip).not.toContainText('First binding'); + }); + + test('should handle calling show() multiple times on same element', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('div'); + + element.textContent = 'Test'; + element.id = 'test-element'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // First show + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'First show'); + } + }, { elementId: testElement.id }); + + let tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText('First show'); + + // Second show on same element + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Second show'); + } + }, { elementId: testElement.id }); + + tooltip = await waitForTooltip(page); + + // Should replace with second show + await expect(tooltip).toContainText('Second show'); + await expect(tooltip).not.toContainText('First show'); + }); + + test('should handle empty string content', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Test'; + element.id = 'test-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, ''); + } + }, { elementId: testElement.id }); + + // Tooltip should still appear (even if empty) + const tooltip = page.locator(TOOLTIP_INTERFACE_SELECTOR); + + await expect(tooltip).toBeVisible(); + }); + + test('should handle very long content', async ({ page }) => { + const longText = 'A'.repeat(500); + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('div'); + + element.textContent = 'Test'; + element.id = 'test-element'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId, text }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, text); + } + }, { elementId: testElement.id, + text: longText }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toContainText(longText.substring(0, 100)); + }); + + test('should handle special characters in content', async ({ page }) => { + const specialChars = '<>&"\'`'; + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('span'); + + element.textContent = 'Test'; + element.id = 'test-element'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + await page.evaluate(({ elementId, text }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, text); + } + }, { elementId: testElement.id, + text: specialChars }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toBeVisible(); + }); + + test('should handle interaction between show() and onHover()', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('button'); + + element.textContent = 'Test'; + element.id = 'test-button'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // First bind onHover + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.onHover(element, 'Hover tooltip'); + } + }, { elementId: testElement.id }); + + // Then show programmatically + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Programmatic tooltip'); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + // Should show programmatic tooltip + await expect(tooltip).toContainText('Programmatic tooltip'); + + // Hide it + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + } + }); + + await waitForTooltipToHide(page); + + // Hover should still work + const button = page.locator(`#${testElement.id}`); + + await button.hover(); + + const hoverTooltip = await waitForTooltip(page); + + await expect(hoverTooltip).toContainText('Hover tooltip'); + }); + + test('should handle hide() called multiple times', async ({ page }) => { + const testElement = await page.evaluate(({ holderId }) => { + const container = document.getElementById(holderId); + const element = document.createElement('div'); + + element.textContent = 'Test'; + element.id = 'test-element'; + container?.appendChild(element); + + return { + id: element.id, + }; + }, { holderId: HOLDER_ID }); + + // Show tooltip + await page.evaluate(({ elementId }) => { + const editor = window.editorInstance; + const element = document.getElementById(elementId); + + if (element && editor?.tooltip) { + editor.tooltip.show(element, 'Test'); + } + }, { elementId: testElement.id }); + + const tooltip = await waitForTooltip(page); + + await expect(tooltip).toBeVisible(); + + // Call hide() multiple times + await page.evaluate(() => { + const editor = window.editorInstance; + + if (editor?.tooltip) { + editor.tooltip.hide(); + editor.tooltip.hide(); + editor.tooltip.hide(); + } + }); + + // Should still be hidden (no errors) + await waitForTooltipToHide(page); + }); + }); +}); + diff --git a/types/api/tooltip.d.ts b/types/api/tooltip.d.ts index 6ca7c42a..a6b98bbf 100644 --- a/types/api/tooltip.d.ts +++ b/types/api/tooltip.d.ts @@ -1,7 +1,7 @@ /** * Tooltip API */ -import {TooltipContent, TooltipOptions} from 'codex-tooltip'; +import {TooltipContent, TooltipOptions} from '../../src/components/utils/tooltip'; export interface Tooltip { /** diff --git a/types/index.d.ts b/types/index.d.ts index 66f0eb38..b7fe1f5c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -138,6 +138,7 @@ declare class EditorJS { public styles: Styles; public toolbar: Toolbar; public inlineToolbar: InlineToolbar; + public tooltip: Tooltip; public readOnly: ReadOnly; constructor(configuration?: EditorConfig|string);