2021-11-24 19:14:24 +01:00
|
|
|
import Header from '@editorjs/header';
|
2022-01-13 17:12:08 +01:00
|
|
|
import Code from '@editorjs/code';
|
2022-04-07 11:03:09 +02:00
|
|
|
import Delimiter from '@editorjs/delimiter';
|
2023-05-12 19:50:48 +02:00
|
|
|
import { BlockAddedMutationType } from '../../../types/events/block/BlockAdded';
|
|
|
|
import { BlockChangedMutationType } from '../../../types/events/block/BlockChanged';
|
|
|
|
import { BlockRemovedMutationType } from '../../../types/events/block/BlockRemoved';
|
|
|
|
import { BlockMovedMutationType } from '../../../types/events/block/BlockMoved';
|
2023-08-08 21:17:09 +02:00
|
|
|
import type EditorJS from '../../../types/index';
|
2023-05-12 19:50:48 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* EditorJS API is passed as the first parameter of the onChange callback
|
|
|
|
*/
|
|
|
|
const EditorJSApiMock = Cypress.sinon.match.any;
|
|
|
|
|
2021-05-26 17:59:32 +02:00
|
|
|
/**
|
|
|
|
* @todo Add checks that correct block API object is passed to onChange
|
|
|
|
* @todo Add cases for native inputs changes
|
2021-10-05 19:40:44 +02:00
|
|
|
* @todo debug onChange firing on Block Tune toggling (see below)
|
2021-05-26 17:59:32 +02:00
|
|
|
*/
|
|
|
|
describe('onChange callback', () => {
|
2021-10-05 19:40:44 +02:00
|
|
|
/**
|
|
|
|
* Creates Editor instance
|
|
|
|
*
|
|
|
|
* @param blocks - list of blocks to prefill the editor
|
|
|
|
*/
|
|
|
|
function createEditor(blocks = null): void {
|
|
|
|
const config = {
|
|
|
|
tools: {
|
|
|
|
header: Header,
|
2022-01-13 17:12:08 +01:00
|
|
|
code: Code,
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
|
|
|
onChange: (api, event): void => {
|
2023-05-12 19:50:48 +02:00
|
|
|
console.log('something changed', event);
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
|
|
|
data: blocks ? {
|
|
|
|
blocks,
|
|
|
|
} : null,
|
|
|
|
};
|
|
|
|
|
|
|
|
cy.spy(config, 'onChange').as('onChange');
|
|
|
|
|
|
|
|
cy.createEditor(config).as('editorInstance');
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:03:09 +02:00
|
|
|
/**
|
|
|
|
* 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 => {
|
2023-05-12 19:50:48 +02:00
|
|
|
console.log('something changed', event);
|
2022-04-07 11:03:09 +02:00
|
|
|
api.saver.save();
|
|
|
|
},
|
|
|
|
data: blocks ? {
|
|
|
|
blocks,
|
|
|
|
} : null,
|
|
|
|
};
|
|
|
|
|
|
|
|
cy.spy(config, 'onChange').as('onChange');
|
|
|
|
|
|
|
|
cy.createEditor(config).as('editorInstance');
|
|
|
|
}
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should batch events when several changes happened at once', () => {
|
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The first paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
2021-10-05 19:40:44 +02:00
|
|
|
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
2023-05-12 19:50:48 +02:00
|
|
|
.type('change')
|
2021-10-05 19:40:44 +02:00
|
|
|
.type('{enter}');
|
|
|
|
|
2023-08-19 06:53:42 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithBatchedEvents', [
|
|
|
|
{
|
|
|
|
type: BlockChangedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 1,
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
]);
|
2023-05-12 19:50:48 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should filter out similar events on batching', () => {
|
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The first paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
|
|
|
.type('first change')
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
|
|
.wait(100)
|
|
|
|
.type('second change');
|
|
|
|
|
|
|
|
cy.get('@onChange').should('be.calledOnce');
|
2021-10-05 19:40:44 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
2023-05-12 19:50:48 +02:00
|
|
|
type: BlockChangedMutationType,
|
2021-10-05 19:40:44 +02:00
|
|
|
detail: {
|
|
|
|
target: {
|
2022-01-13 17:12:08 +01:00
|
|
|
name: 'paragraph',
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
|
|
|
index: 0,
|
|
|
|
},
|
|
|
|
}));
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired with correct index on block insertion above the current (by pressing Enter at the start)', () => {
|
2021-10-05 19:40:44 +02:00
|
|
|
createEditor();
|
|
|
|
|
2021-05-26 17:59:32 +02:00
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
|
|
|
.type('{enter}');
|
|
|
|
|
2021-10-05 19:40:44 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
2023-05-12 19:50:48 +02:00
|
|
|
type: BlockAddedMutationType,
|
2021-10-05 19:40:44 +02:00
|
|
|
detail: {
|
|
|
|
target: {
|
2022-01-13 17:12:08 +01:00
|
|
|
name: 'paragraph',
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
2023-05-12 19:50:48 +02:00
|
|
|
index: 0,
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be fired with only single "block-added" event by pressing Enter at the end of a block', () => {
|
|
|
|
createEditor([ {
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'some text',
|
|
|
|
},
|
|
|
|
} ]);
|
|
|
|
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
|
|
|
.type('{enter}');
|
|
|
|
|
|
|
|
cy.get('@onChange').should('be.calledOnce');
|
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be fired with correct index on block insertion after the current (by pressing enter at the end)', () => {
|
|
|
|
createEditor([ {
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'some text',
|
|
|
|
},
|
|
|
|
} ]);
|
|
|
|
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
|
|
|
.type('{enter}');
|
|
|
|
|
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
detail: {
|
2021-10-05 19:40:44 +02:00
|
|
|
index: 1,
|
|
|
|
},
|
|
|
|
}));
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired on typing into block', () => {
|
2021-10-05 19:40:44 +02:00
|
|
|
createEditor();
|
|
|
|
|
2021-05-26 17:59:32 +02:00
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
|
|
|
.type('some text');
|
|
|
|
|
2021-10-05 19:40:44 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
2023-05-12 19:50:48 +02:00
|
|
|
type: BlockChangedMutationType,
|
2021-10-05 19:40:44 +02:00
|
|
|
detail: {
|
2022-01-13 17:12:08 +01:00
|
|
|
index: 0,
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
|
|
|
}));
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired on block insertion with save inside onChange', () => {
|
2022-04-07 11:03:09 +02:00
|
|
|
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]')
|
2023-02-10 19:29:58 +01:00
|
|
|
.get('div.ce-popover-item[data-item-name=delimiter]')
|
2022-04-07 11:03:09 +02:00
|
|
|
.click();
|
|
|
|
|
2023-08-19 06:53:42 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithBatchedEvents', [
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
target: {
|
|
|
|
name: 'paragraph',
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2022-04-07 11:03:09 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
target: {
|
|
|
|
name: 'delimiter',
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2022-04-07 11:03:09 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 1,
|
|
|
|
target: {
|
|
|
|
name: 'paragraph',
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2022-04-07 11:03:09 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
]);
|
2022-04-07 11:03:09 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired on block replacement for both of blocks', () => {
|
2021-10-05 19:40:44 +02:00
|
|
|
createEditor();
|
|
|
|
|
2021-05-26 17:59:32 +02:00
|
|
|
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]')
|
2023-02-10 19:29:58 +01:00
|
|
|
.get('div.ce-popover-item[data-item-name=header]')
|
2021-05-26 17:59:32 +02:00
|
|
|
.click();
|
|
|
|
|
2023-08-19 06:53:42 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithBatchedEvents', [
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
target: {
|
|
|
|
name: 'paragraph',
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
target: {
|
|
|
|
name: 'header',
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2021-10-05 19:40:44 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
]);
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired on tune modifying', () => {
|
2021-10-05 19:40:44 +02:00
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'header',
|
|
|
|
data: {
|
|
|
|
text: 'Header block',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
2021-05-26 17:59:32 +02:00
|
|
|
|
|
|
|
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]')
|
2023-02-19 23:59:10 +01:00
|
|
|
.get('.ce-settings .ce-popover-item:nth-child(4)')
|
2021-05-26 17:59:32 +02:00
|
|
|
.click();
|
|
|
|
|
2021-10-05 19:40:44 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
2023-05-12 19:50:48 +02:00
|
|
|
type: BlockChangedMutationType,
|
2021-10-05 19:40:44 +02:00
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
target: {
|
|
|
|
name: 'header',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}));
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired when block is removed', () => {
|
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'some text',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
2022-04-25 17:28:58 +02:00
|
|
|
|
2021-05-26 17:59:32 +02:00
|
|
|
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]')
|
2022-11-03 18:52:33 +01:00
|
|
|
.get('div[data-item-name=delete]')
|
|
|
|
.click();
|
|
|
|
|
|
|
|
/** Second click for confirmation */
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('div[data-item-name=delete]')
|
2021-05-26 17:59:32 +02:00
|
|
|
.click();
|
|
|
|
|
2023-08-19 06:53:42 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithBatchedEvents', [
|
|
|
|
/**
|
|
|
|
* "block-removed" fired since we have deleted a block
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* "block-added" fired since we have deleted the last block, so the new one is created
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
2023-05-12 19:50:48 +02:00
|
|
|
},
|
2023-08-19 06:53:42 +02:00
|
|
|
},
|
|
|
|
]);
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired when block is moved', () => {
|
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'first block',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'second block',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
2021-05-26 17:59:32 +02:00
|
|
|
|
|
|
|
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]')
|
2022-11-03 18:52:33 +01:00
|
|
|
.get('div[data-item-name=move-up]')
|
2021-05-26 17:59:32 +02:00
|
|
|
.click();
|
|
|
|
|
2021-10-05 19:40:44 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
2023-05-12 19:50:48 +02:00
|
|
|
type: BlockMovedMutationType,
|
2021-10-05 19:40:44 +02:00
|
|
|
detail: {
|
|
|
|
fromIndex: 1,
|
|
|
|
toIndex: 0,
|
|
|
|
},
|
|
|
|
}));
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|
2022-01-13 17:12:08 +01:00
|
|
|
|
2023-05-12 19:50:48 +02:00
|
|
|
it('should be fired if something changed inside native input', () => {
|
2022-01-13 17:12:08 +01:00
|
|
|
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({
|
2023-05-12 19:50:48 +02:00
|
|
|
type: BlockChangedMutationType,
|
2022-01-13 17:12:08 +01:00
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
});
|
2023-05-12 19:50:48 +02:00
|
|
|
|
|
|
|
it('should not be fired on fake cursor adding and removing', () => {
|
|
|
|
createEditor([ {
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'some text',
|
|
|
|
},
|
|
|
|
} ]);
|
|
|
|
|
|
|
|
cy.get('[data-cy=editorjs')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open Block Tunes, add fake cursor
|
|
|
|
*/
|
|
|
|
cy.get('[data-cy=editorjs]')
|
|
|
|
.get('span.ce-toolbar__settings-btn')
|
|
|
|
.click();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close Block Tunes, remove fake cursor
|
|
|
|
*/
|
|
|
|
cy.get('[data-cy=editorjs')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click();
|
|
|
|
|
|
|
|
cy.wait(500).then(() => {
|
|
|
|
cy.get('@onChange').should('have.callCount', 0);
|
|
|
|
});
|
|
|
|
});
|
2023-06-21 19:32:25 +02:00
|
|
|
|
|
|
|
it('should be fired when the whole text inside block is removed', () => {
|
|
|
|
createEditor([ {
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'a',
|
|
|
|
},
|
|
|
|
} ]);
|
|
|
|
|
|
|
|
cy.get('[data-cy=editorjs')
|
|
|
|
.get('div.ce-block')
|
|
|
|
.click()
|
|
|
|
.type('{backspace}');
|
|
|
|
|
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
|
|
|
type: BlockChangedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
});
|
2023-06-22 19:42:14 +02:00
|
|
|
|
|
|
|
it('should not be fired when element with the "data-mutation-free" mark changes some attribute', () => {
|
|
|
|
/**
|
|
|
|
* Mock for tool wrapper which we will mutate in a test
|
|
|
|
*/
|
|
|
|
const toolWrapper = document.createElement('div');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark it as mutation-free
|
|
|
|
*/
|
|
|
|
toolWrapper.dataset.mutationFree = 'true';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mock of tool with data-mutation-free attribute
|
|
|
|
*/
|
|
|
|
class ToolWithMutationFreeAttribute {
|
|
|
|
/**
|
|
|
|
* Simply return mocked element
|
|
|
|
*/
|
|
|
|
public render(): HTMLElement {
|
|
|
|
return toolWrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Saving logic is not necessary for this test
|
|
|
|
*/
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
|
|
public save(): void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
const editorConfig = {
|
|
|
|
tools: {
|
|
|
|
testTool: ToolWithMutationFreeAttribute,
|
|
|
|
},
|
|
|
|
onChange: (api, event): void => {
|
|
|
|
console.log('something changed', event);
|
|
|
|
},
|
|
|
|
data: {
|
|
|
|
blocks: [
|
|
|
|
{
|
|
|
|
type: 'testTool',
|
|
|
|
data: {},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
cy.spy(editorConfig, 'onChange').as('onChange');
|
|
|
|
cy.createEditor(editorConfig).as('editorInstance');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Emulate tool's internal attribute mutation
|
|
|
|
*/
|
|
|
|
cy.wait(100).then(() => {
|
|
|
|
toolWrapper.setAttribute('some-changed-attr', 'some-new-value');
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check that onChange callback was not called
|
|
|
|
*/
|
|
|
|
cy.wait(500).then(() => {
|
|
|
|
cy.get('@onChange').should('have.callCount', 0);
|
|
|
|
});
|
|
|
|
});
|
2023-08-08 21:17:09 +02:00
|
|
|
|
|
|
|
it('should be called on blocks.clear() with removed and added blocks', () => {
|
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The first paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The second paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
cy.get<EditorJS>('@editorInstance')
|
|
|
|
.then(async editor => {
|
|
|
|
cy.wrap(editor.blocks.clear());
|
|
|
|
});
|
|
|
|
|
2023-08-19 06:53:42 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithBatchedEvents', [
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockAddedMutationType,
|
|
|
|
},
|
|
|
|
]);
|
2023-08-08 21:17:09 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should be called on blocks.render() on non-empty editor with removed blocks', () => {
|
|
|
|
createEditor([
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The first paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The second paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
cy.get<EditorJS>('@editorInstance')
|
|
|
|
.then(async editor => {
|
|
|
|
cy.wrap(editor.blocks.render({
|
|
|
|
blocks: [
|
|
|
|
{
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The new paragraph',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
2023-08-19 06:53:42 +02:00
|
|
|
cy.get('@onChange').should('be.calledWithBatchedEvents', [
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: BlockRemovedMutationType,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be called on blocks.update() with "block-changed" event', () => {
|
|
|
|
const block = {
|
|
|
|
id: 'bwnFX5LoX7',
|
|
|
|
type: 'paragraph',
|
|
|
|
data: {
|
|
|
|
text: 'The first block mock.',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const config = {
|
|
|
|
data: {
|
|
|
|
blocks: [
|
|
|
|
block,
|
|
|
|
],
|
|
|
|
},
|
|
|
|
onChange: (api, event): void => {
|
|
|
|
console.log('something changed', event);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
cy.spy(config, 'onChange').as('onChange');
|
|
|
|
|
|
|
|
cy.createEditor(config)
|
|
|
|
.then((editor) => {
|
|
|
|
editor.blocks.update(block.id, {
|
|
|
|
text: 'Updated text',
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.get('@onChange').should('be.calledWithMatch', EditorJSApiMock, Cypress.sinon.match({
|
|
|
|
type: BlockChangedMutationType,
|
|
|
|
detail: {
|
|
|
|
index: 0,
|
|
|
|
target: {
|
|
|
|
id: block.id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
});
|
2023-08-08 21:17:09 +02:00
|
|
|
});
|
2021-05-26 17:59:32 +02:00
|
|
|
});
|