editor.js/test/cypress/tests/onchange.spec.ts
Peter Savchenko 8f156a87ea
feat(ui): the toolbox became vertical (#2014)
* the popover component, vertical toolbox

* toolbox position improved

* popover width improved

* always show the plus button

* search field added

* search input in popover

* trying to create mobile toolbox

* feat(toolbox): popover adapted for mobile devices (#2004)

* FIx mobile popover fixed positioning

* Add mobile popover overlay

* Hide mobile popover on scroll

* Alter toolbox buttons hover

* Fix closing popover on overlay click

* Tests fix

* Fix onchange test

* restore focus after toolbox closing by ESC

* don't move toolbar by block-hover on mobile

Resolves #1972

* popover mobile styles improved

* Cleanup

* Remove scroll event listener

* Lock scroll on mobile

* don't show shortcuts in mobile popover

* Change data attr name

* Remove unused styles

* Remove unused listeners

* disable hover on mobile popover

* Scroll fix

* Lint

* Revert "Scroll fix"

This reverts commit 82deae543e.

* Return back background color for active state of toolbox buttons

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>

* Vertical toolbox fixes (#2017)

* Replace visibility property with display for hiding popover

* Disable arrow right and left keys for popover

* Revert "Replace visibility property with display for hiding popover"

This reverts commit af521cf6f2.

* Hide popover via setting max-height to 0 to fix animation in safari

* Remove redundant condition

* Extend element interface to avoid ts errors

* Do not subscribe to block hovered if mobile

* Add unsubscribing from overlay click event

* Rename isMobile to isMobileScreen

* Cleanup

* fix: popover opening direction (#2022)

* Change popover opening direction based on available space below it

* Update check

* Use cacheable decorator

* Update src/components/flipper.ts

Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com>

* Fixes

* Fix test

* Clear search on popover hide

* Fix popover width

* Fix for tests

* Update todos

* Linter fixes

* rm todo about beforeInsert

because I have no idea what does it mean

* i18n for search labels done

* rm methods for hiding/showing of +

* some code style update

* Update CHANGELOG.md

* make the list items a little bit compact

* fix z-index issue caused by block-appearing animation

also, improve popover padding for two reasons:

- make the popover more consistent with the Table tool popover (in future, it can be done with the same api method)
- make popover looks better

Co-authored-by: Tanya Fomina <fomina.tatianaaa@yandex.ru>
Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com>
2022-04-25 18:28:58 +03:00

327 lines
7.8 KiB
TypeScript

import Header from '@editorjs/header';
import Code from '@editorjs/code';
import Delimiter from '@editorjs/delimiter';
import { BlockMutationType } from '../../../types/events/block/mutation-type';
/**
* @todo Add checks that correct block API object is passed to onChange
* @todo Add cases for native inputs changes
* @todo debug onChange firing on Block Tune toggling (see below)
*/
describe('onChange callback', () => {
/**
* Creates Editor instance
*
* @param blocks - list of blocks to prefill the editor
*/
function createEditor(blocks = null): void {
const config = {
tools: {
header: Header,
code: Code,
},
onChange: (api, event): void => {
console.log('something changed', api, event);
},
data: blocks ? {
blocks,
} : null,
};
cy.spy(config, 'onChange').as('onChange');
cy.createEditor(config).as('editorInstance');
}
/**
* Creates Editor instance with save inside the onChange event.
*
* @param blocks - list of blocks to prefill the editor
*/
function createEditorWithSave(blocks = null): void {
const config = {
tools: {
header: Header,
code: Code,
delimiter: Delimiter,
},
onChange: (api, event): void => {
console.log('something changed', api, event);
api.saver.save();
},
data: blocks ? {
blocks,
} : null,
};
cy.spy(config, 'onChange').as('onChange');
cy.createEditor(config).as('editorInstance');
}
/**
* EditorJS API is passed as the first parameter of the onChange callback
*/
const EditorJSApiMock = Cypress.sinon.match.any;
it('should fire onChange callback with correct index on block insertion above the current (by pressing Enter at the start)', () => {
createEditor();
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click()
.type('{enter}');
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Added,
detail: {
target: {
name: 'paragraph',
},
index: 0,
},
}));
});
it('should fire onChange callback with correct index on block insertion below the current (by pressing enter at the end)', () => {
createEditor();
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click()
.type('some text')
.type('{enter}');
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Added,
detail: {
target: {
name: 'paragraph',
},
index: 1,
},
}));
});
it('should fire onChange callback on typing into block', () => {
createEditor();
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click()
.type('some text');
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Changed,
detail: {
index: 0,
},
}));
});
it('should fire onChange callback on block insertion with save inside onChange', () => {
createEditorWithSave();
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click();
cy.get('[data-cy=editorjs]')
.get('div.ce-toolbar__plus')
.click();
cy.get('[data-cy=editorjs]')
.get('div.ce-popover__item[data-item-name=delimiter]')
.click();
cy.get('@onChange').should('be.calledThrice');
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Removed,
detail: {
index: 0,
target: {
name: 'paragraph',
},
},
}));
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Added,
detail: {
index: 0,
target: {
name: 'delimiter',
},
},
}));
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Added,
detail: {
index: 1,
target: {
name: 'paragraph',
},
},
}));
});
it('should fire onChange callback on block replacement for both of blocks', () => {
createEditor();
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click();
cy.get('[data-cy=editorjs]')
.get('div.ce-toolbar__plus')
.click();
cy.get('[data-cy=editorjs]')
.get('div.ce-popover__item[data-item-name=header]')
.click();
cy.get('@onChange').should('be.calledTwice');
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Removed,
detail: {
index: 0,
target: {
name: 'paragraph',
},
},
}));
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Added,
detail: {
index: 0,
target: {
name: 'header',
},
},
}));
});
it('should fire onChange callback on tune modifying', () => {
createEditor([
{
type: 'header',
data: {
text: 'Header block',
},
},
]);
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click();
cy.get('[data-cy=editorjs]')
.get('span.ce-toolbar__settings-btn')
.click();
cy.get('[data-cy=editorjs]')
.get('span.cdx-settings-button[data-level=4]')
.click()
/**
* For some reason, the first click fires the mutation of removeFakeCursor only, so we need to click again.
* Reproduced only in Cypress.
*
* @todo debug it later
*/
.click();
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Changed,
detail: {
index: 0,
target: {
name: 'header',
},
},
}));
});
it('should fire onChange callback when block is removed', () => {
createEditor();
/**
* The only block does not have Tune menu, so need to create at least 2 blocks to test deleting
*/
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click()
.type('some text');
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click();
cy.get('[data-cy=editorjs]')
.get('span.ce-toolbar__settings-btn')
.click();
cy.get('[data-cy=editorjs]')
.get('div.ce-settings__button--delete')
.click()
.click();
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Removed,
detail: {
index: 0,
},
}));
});
it('should fire onChange callback when block is moved', () => {
createEditor();
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.click()
.type('{enter}');
cy.get('[data-cy=editorjs]')
.get('div.ce-block')
.last()
.click();
cy.get('[data-cy=editorjs]')
.get('span.ce-toolbar__settings-btn')
.click();
cy.get('[data-cy=editorjs]')
.get('div.ce-tune-move-up')
.click();
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Moved,
detail: {
fromIndex: 1,
toIndex: 0,
},
}));
});
it('should fire onChange if something changed inside native input', () => {
createEditor([ {
type: 'code',
data: {
code: '',
},
} ]);
cy.get('[data-cy=editorjs')
.get('textarea')
.type('Some input to the textarea');
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
type: BlockMutationType.Changed,
detail: {
index: 0,
},
}));
});
});