mirror of https://github.com/artf/grapesjs.git
nocodeframeworkdrag-and-dropsite-buildersite-generatortemplate-builderui-builderweb-builderweb-builder-frameworkwebsite-builderno-codepage-builder
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
8.1 KiB
265 lines
8.1 KiB
import type { Editor } from '../../../src';
|
|
import EditorModel from '../../../src/editor/model/Editor';
|
|
import type Commands from '../../../src/commands';
|
|
import type { Command, CommandFunction, CommandOptions } from '../../../src/commands/view/CommandAbstract';
|
|
|
|
describe('Commands', () => {
|
|
describe('Main', () => {
|
|
let em: EditorModel;
|
|
let obj: Commands;
|
|
let commSimple: Command;
|
|
let commRunOnly: Command;
|
|
let commFunc: CommandFunction;
|
|
let commName = 'commandTest';
|
|
let commResultRun = 'Run executed';
|
|
let commResultStop = 'Stop executed';
|
|
|
|
beforeEach(() => {
|
|
commSimple = {
|
|
run: () => commResultRun,
|
|
stop: () => commResultStop,
|
|
};
|
|
commRunOnly = {
|
|
run: () => commResultRun,
|
|
};
|
|
commFunc = () => commResultRun;
|
|
em = new EditorModel();
|
|
em.set('Editor', em);
|
|
obj = em.Commands;
|
|
});
|
|
|
|
afterEach(() => {
|
|
em.destroy();
|
|
});
|
|
|
|
test('No commands inside', () => {
|
|
expect(obj.get('test')).toBeUndefined();
|
|
});
|
|
|
|
test('Push new command', () => {
|
|
const comm = { test: 'test' };
|
|
const len = Object.keys(obj.getAll()).length;
|
|
obj.add('test', comm);
|
|
expect(obj.has('test')).toBe(true);
|
|
expect(Object.keys(obj.getAll()).length).toBe(len + 1);
|
|
expect((obj.get('test') as any).test).toEqual('test');
|
|
});
|
|
|
|
test('Remove command', () => {
|
|
obj.add('test', commSimple);
|
|
|
|
obj.remove('test');
|
|
|
|
expect(obj.has('test')).toBe(false);
|
|
expect(obj.getAll().test).toBeUndefined();
|
|
});
|
|
|
|
test('Remove active command and clean up active state', () => {
|
|
const stop = jest.fn(() => commResultStop);
|
|
obj.add(commName, {
|
|
run: () => commResultRun,
|
|
stop,
|
|
});
|
|
obj.run(commName);
|
|
|
|
obj.remove(commName);
|
|
|
|
expect(stop).toHaveBeenCalledTimes(1);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
expect(obj.has(commName)).toBe(false);
|
|
});
|
|
|
|
test('Default commands after loadDefaultCommands', () => {
|
|
expect(obj.get('select-comp')).not.toBeUndefined();
|
|
});
|
|
|
|
test('Select component command cancels pending debounced callbacks on teardown', () => {
|
|
const command = obj.get('select-comp') as any;
|
|
const cancelOnContainerChange = jest.fn();
|
|
const cancelOnSelect = jest.fn();
|
|
const cancelUpdateAttached = jest.fn();
|
|
const cancelToolbar = jest.fn();
|
|
command.toggleSelectComponent = jest.fn();
|
|
command.onContainerChange = { cancel: cancelOnContainerChange };
|
|
command.onSelect = { cancel: cancelOnSelect };
|
|
command.updateAttached = { cancel: cancelUpdateAttached };
|
|
command._upToolbar = { cancel: cancelToolbar };
|
|
|
|
command.stopSelectComponent();
|
|
|
|
expect(command.toggleSelectComponent).toHaveBeenCalledWith();
|
|
expect(cancelOnContainerChange).toHaveBeenCalledTimes(1);
|
|
expect(cancelOnSelect).toHaveBeenCalledTimes(1);
|
|
expect(cancelUpdateAttached).toHaveBeenCalledTimes(1);
|
|
expect(cancelToolbar).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('Commands module should not have toLoad property', () => {
|
|
// @ts-ignore
|
|
expect(obj.toLoad).toBeUndefined();
|
|
});
|
|
|
|
test('Run simple command and check if the state is tracked', () => {
|
|
// Add the command
|
|
obj.add(commName, commSimple);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
|
|
// Start the command
|
|
let result = obj.run(commName);
|
|
expect(result).toBe(commResultRun);
|
|
expect(obj.isActive(commName)).toBe(true);
|
|
expect(Object.keys(obj.getActive()).length).toBe(1);
|
|
|
|
// Stop the command
|
|
result = obj.stop(commName);
|
|
expect(result).toBe(commResultStop);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
expect(Object.keys(obj.getActive()).length).toBe(0);
|
|
});
|
|
|
|
test('Run command only with run method, ensure is not tracked', () => {
|
|
// Add the command
|
|
obj.add(commName, commRunOnly);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
|
|
// Start the command
|
|
let result = obj.run(commName);
|
|
expect(result).toBe(commResultRun);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
expect(Object.keys(obj.getActive()).length).toBe(0);
|
|
});
|
|
|
|
test('Run function command, ensure is not tracked', () => {
|
|
// Add the command
|
|
obj.add(commName, commFunc);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
|
|
// Start the command
|
|
let result = obj.run(commName);
|
|
expect(result).toBe(commResultRun);
|
|
expect(obj.isActive(commName)).toBe(false);
|
|
expect(Object.keys(obj.getActive()).length).toBe(0);
|
|
});
|
|
|
|
test('Run command and check if none, custom, and default options are passed', () => {
|
|
const customOptions = { customValue: 'customValue' };
|
|
const defaultOptions = { defaultValue: 'defaultValue' };
|
|
|
|
// Create a function that returns the options
|
|
const runFn = (_editor: any, _sender: any, options: any) => options;
|
|
|
|
// Add the command
|
|
obj.add(commName, { run: runFn });
|
|
|
|
// Run the command without custom options
|
|
let result = obj.run(commName);
|
|
expect(result).toEqual({});
|
|
|
|
// Run the command with custom options
|
|
result = obj.run(commName, customOptions);
|
|
expect(result).toEqual(customOptions);
|
|
|
|
// Set default options for the command
|
|
obj.config.defaultOptions = {
|
|
[commName]: {
|
|
run: (options: CommandOptions) => ({ ...options, ...defaultOptions }),
|
|
},
|
|
};
|
|
|
|
// Run the command with default options
|
|
result = obj.run(commName, customOptions);
|
|
expect(result).toEqual({ ...customOptions, ...defaultOptions });
|
|
});
|
|
});
|
|
});
|
|
|
|
interface MyCommandOptions {
|
|
value: number;
|
|
}
|
|
|
|
interface MyCommandResult {
|
|
done: boolean;
|
|
}
|
|
|
|
interface MyCommandStopOptions {
|
|
reason: string;
|
|
}
|
|
|
|
declare module '../../../src' {
|
|
interface CommandRegistryRun {
|
|
'my:command': (options: MyCommandOptions) => MyCommandResult;
|
|
'my:stateless': () => number;
|
|
}
|
|
|
|
interface CommandRegistryStop {
|
|
'my:command': (options: MyCommandStopOptions) => void;
|
|
}
|
|
}
|
|
|
|
const assertCommandTypes = () => {
|
|
const typedEditor = {} as Editor;
|
|
|
|
const fullscreenResult: void = typedEditor.runCommand('core:fullscreen');
|
|
typedEditor.runCommand('fullscreen', { target: document.body });
|
|
// @ts-expect-error Fullscreen target must be an element or selector string
|
|
typedEditor.runCommand('core:fullscreen', { target: 1 });
|
|
|
|
const customResult: MyCommandResult = typedEditor.runCommand('my:command', { value: 1 });
|
|
customResult.done;
|
|
typedEditor.stopCommand('my:command', { reason: 'done' });
|
|
// @ts-expect-error Missing required run options
|
|
typedEditor.runCommand('my:command');
|
|
// @ts-expect-error Stop options do not match the registry
|
|
typedEditor.stopCommand('my:command', { value: 1 });
|
|
|
|
const statelessResult: number = typedEditor.runCommand('my:stateless');
|
|
statelessResult.toFixed();
|
|
// @ts-expect-error Stateless commands should not accept options
|
|
typedEditor.runCommand('my:stateless', {});
|
|
|
|
typedEditor.Commands.add('my:command', {
|
|
run(_editor, _sender, options) {
|
|
options.value.toFixed();
|
|
return { done: true };
|
|
},
|
|
stop(_editor, _sender, options) {
|
|
options.reason.toUpperCase();
|
|
},
|
|
});
|
|
|
|
typedEditor.Commands.add('my:command', (_editor, _sender, options) => {
|
|
options.value.toFixed();
|
|
return { done: true };
|
|
});
|
|
|
|
typedEditor.Commands.add('my:stateless', () => 1);
|
|
|
|
typedEditor.Commands.add('my:command', {
|
|
run(_editor, _sender, options) {
|
|
// @ts-expect-error The command run options should come from the registry
|
|
options.reason.toUpperCase();
|
|
return { done: true };
|
|
},
|
|
});
|
|
|
|
typedEditor.Commands.config.defaultOptions = {
|
|
'my:command': {
|
|
run(options) {
|
|
return { ...options, value: options.value + 1 };
|
|
},
|
|
stop(options) {
|
|
return { ...options, reason: options.reason.toUpperCase() };
|
|
},
|
|
},
|
|
'core:fullscreen': {
|
|
run(options) {
|
|
return { ...options, target: options?.target ?? '.app' };
|
|
},
|
|
},
|
|
};
|
|
typedEditor.Commands.config.defaultOptions['my:command']?.run?.({ value: 1 });
|
|
|
|
return fullscreenResult;
|
|
};
|
|
|
|
void assertCommandTypes;
|
|
|