diff --git a/docs/reference/slate/editor.md b/docs/reference/slate/editor.md index f3a04d068..2abcb93c1 100644 --- a/docs/reference/slate/editor.md +++ b/docs/reference/slate/editor.md @@ -79,6 +79,26 @@ Synchronously flush the current changes to editor, calling `onChange`. > 🤖 In normal operation you never need to use this method! However, it can be helpful for writing tests to be able to keep the entire test synchronous. +### `hasCommand` + +`hasCommand(type: String) => Boolean` + +```js +editor.hasCommand('insertLink') +``` + +Checks if a command by `type` has been registered. + +### `hasQuery` + +`hasQuery(type: String) => Boolean` + +```js +editor.hasQuery('isLinkActive') +``` + +Checks if a query by `type` has been registered. + ### `query` `query(type: String, ...args) => Any` diff --git a/packages/slate-react/package.json b/packages/slate-react/package.json index 8df64dd77..e818a4289 100644 --- a/packages/slate-react/package.json +++ b/packages/slate-react/package.json @@ -39,6 +39,7 @@ "devDependencies": { "immutable": "^3.8.1", "mocha": "^2.5.3", + "react-test-renderer": "^16.6.3", "slate": "^0.44.8", "slate-hyperscript": "^0.11.23", "slate-simulator": "^0.4.67" diff --git a/packages/slate-react/src/components/editor.js b/packages/slate-react/src/components/editor.js index 376a396b8..25fcf0737 100644 --- a/packages/slate-react/src/components/editor.js +++ b/packages/slate-react/src/components/editor.js @@ -243,6 +243,14 @@ class Editor extends React.Component { return this.controller.command(...args) } + hasCommand(...args) { + return this.controller.hasCommand(...args) + } + + hasQuery(...args) { + return this.controller.hasQuery(...args) + } + normalize(...args) { return this.controller.normalize(...args) } diff --git a/packages/slate-react/test/components/editor/has-command/core-command.js b/packages/slate-react/test/components/editor/has-command/core-command.js new file mode 100644 index 000000000..e06349804 --- /dev/null +++ b/packages/slate-react/test/components/editor/has-command/core-command.js @@ -0,0 +1,13 @@ +/** @jsx h */ + +import Plain from 'slate-plain-serializer' + +const defaultValue = Plain.deserialize('') + +export const input = { defaultValue } + +export default function(editor) { + return editor.hasCommand('insertText') +} + +export const output = true diff --git a/packages/slate-react/test/components/editor/has-command/existing-plugin.js b/packages/slate-react/test/components/editor/has-command/existing-plugin.js new file mode 100644 index 000000000..ddae7417b --- /dev/null +++ b/packages/slate-react/test/components/editor/has-command/existing-plugin.js @@ -0,0 +1,21 @@ +/** @jsx h */ + +import Plain from 'slate-plain-serializer' + +const defaultValue = Plain.deserialize('') + +const plugins = [ + { + commands: { + customCommand: () => {}, + }, + }, +] + +export const input = { defaultValue, plugins } + +export default function(editor) { + return editor.hasCommand('customCommand') +} + +export const output = true diff --git a/packages/slate-react/test/components/editor/has-command/missing-plugin.js b/packages/slate-react/test/components/editor/has-command/missing-plugin.js new file mode 100644 index 000000000..9ec7db1c1 --- /dev/null +++ b/packages/slate-react/test/components/editor/has-command/missing-plugin.js @@ -0,0 +1,21 @@ +/** @jsx h */ + +import Plain from 'slate-plain-serializer' + +const defaultValue = Plain.deserialize('') + +const plugins = [ + { + commands: { + customCommand: () => {}, + }, + }, +] + +export const input = { defaultValue, plugins } + +export default function(editor) { + return editor.hasCommand('otherCommand') +} + +export const output = false diff --git a/packages/slate-react/test/components/editor/has-query/core-query.js b/packages/slate-react/test/components/editor/has-query/core-query.js new file mode 100644 index 000000000..704be8a09 --- /dev/null +++ b/packages/slate-react/test/components/editor/has-query/core-query.js @@ -0,0 +1,13 @@ +/** @jsx h */ + +import Plain from 'slate-plain-serializer' + +const defaultValue = Plain.deserialize('') + +export const input = { defaultValue } + +export default function(editor) { + return editor.hasQuery('isVoid') +} + +export const output = true diff --git a/packages/slate-react/test/components/editor/has-query/existing-plugin.js b/packages/slate-react/test/components/editor/has-query/existing-plugin.js new file mode 100644 index 000000000..7e7d57d32 --- /dev/null +++ b/packages/slate-react/test/components/editor/has-query/existing-plugin.js @@ -0,0 +1,21 @@ +/** @jsx h */ + +import Plain from 'slate-plain-serializer' + +const defaultValue = Plain.deserialize('') + +const plugins = [ + { + queries: { + customQuery: () => {}, + }, + }, +] + +export const input = { defaultValue, plugins } + +export default function(editor) { + return editor.hasQuery('customQuery') +} + +export const output = true diff --git a/packages/slate-react/test/components/editor/has-query/missing-plugin.js b/packages/slate-react/test/components/editor/has-query/missing-plugin.js new file mode 100644 index 000000000..74201da9e --- /dev/null +++ b/packages/slate-react/test/components/editor/has-query/missing-plugin.js @@ -0,0 +1,21 @@ +/** @jsx h */ + +import Plain from 'slate-plain-serializer' + +const defaultValue = Plain.deserialize('') + +const plugins = [ + { + queries: { + customQuery: () => {}, + }, + }, +] + +export const input = { defaultValue, plugins } + +export default function(editor) { + return editor.hasQuery('otherQuery') +} + +export const output = false diff --git a/packages/slate-react/test/index.js b/packages/slate-react/test/index.js index 8c4e22013..891d90dfa 100644 --- a/packages/slate-react/test/index.js +++ b/packages/slate-react/test/index.js @@ -2,11 +2,25 @@ import assert from 'assert' import clean from './helpers/clean' import React from 'react' import ReactDOM from 'react-dom/server' +import ShallowRenderer from 'react-test-renderer/shallow' import { Editor } from 'slate-react' import { fixtures } from 'slate-dev-test-utils' import { JSDOM } from 'jsdom' describe('slate-react', () => { + fixtures(__dirname, 'components', ({ module }) => { + const { input, output, default: fn } = module + + const renderer = new ShallowRenderer() + renderer.render(React.createElement(Editor, input, null)) + const editor = renderer.getRenderOutput().props.editor + + const actual = fn(editor) + const expected = output + + assert.equal(actual, expected) + }) + fixtures(__dirname, 'rendering/fixtures', ({ module }) => { const { value, output, props } = module const p = { diff --git a/packages/slate/src/controllers/editor.js b/packages/slate/src/controllers/editor.js index fd1e51171..5732a47bf 100644 --- a/packages/slate/src/controllers/editor.js +++ b/packages/slate/src/controllers/editor.js @@ -158,6 +158,34 @@ class Editor { return controller } + /** + * Checks if a command by `type` has been registered. + * + * @param {String} type + * @return {Boolean} + */ + + hasCommand(type) { + const { controller } = this + const has = type in controller && controller[type].__command + + return has + } + + /** + * Checks if a query by `type` has been registered. + * + * @param {String} type + * @return {Boolean} + */ + + hasQuery(type) { + const { controller } = this + const has = type in controller && controller[type].__query + + return has + } + /** * Normalize all of the nodes in the document from scratch. * diff --git a/packages/slate/test/controllers/editor/has-command/existing-plugin.js b/packages/slate/test/controllers/editor/has-command/existing-plugin.js new file mode 100644 index 000000000..ad7826d47 --- /dev/null +++ b/packages/slate/test/controllers/editor/has-command/existing-plugin.js @@ -0,0 +1,19 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +const plugins = [ + { + commands: { + customCommand: () => {}, + }, + }, +] + +export const input = new Editor({ plugins }) + +export default function(editor) { + return editor.hasCommand('customCommand') +} + +export const output = true diff --git a/packages/slate/test/controllers/editor/has-command/existing-registered.js b/packages/slate/test/controllers/editor/has-command/existing-registered.js new file mode 100644 index 000000000..a69dba5ac --- /dev/null +++ b/packages/slate/test/controllers/editor/has-command/existing-registered.js @@ -0,0 +1,11 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +export const input = new Editor().registerCommand('customCommand') + +export default function(editor) { + return editor.hasCommand('customCommand') +} + +export const output = true diff --git a/packages/slate/test/controllers/editor/has-command/missing-plugin.js b/packages/slate/test/controllers/editor/has-command/missing-plugin.js new file mode 100644 index 000000000..bc9bfebd1 --- /dev/null +++ b/packages/slate/test/controllers/editor/has-command/missing-plugin.js @@ -0,0 +1,19 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +const plugins = [ + { + commands: { + customCommand: () => {}, + }, + }, +] + +export const input = new Editor({ plugins }) + +export default function(editor) { + return editor.hasCommand('otherCommand') +} + +export const output = false diff --git a/packages/slate/test/controllers/editor/has-command/missing-registered.js b/packages/slate/test/controllers/editor/has-command/missing-registered.js new file mode 100644 index 000000000..9b9fc7b67 --- /dev/null +++ b/packages/slate/test/controllers/editor/has-command/missing-registered.js @@ -0,0 +1,11 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +export const input = new Editor().registerCommand('customCommand') + +export default function(editor) { + return editor.hasCommand('otherCommand') +} + +export const output = false diff --git a/packages/slate/test/controllers/editor/has-query/existing-plugin.js b/packages/slate/test/controllers/editor/has-query/existing-plugin.js new file mode 100644 index 000000000..a97a06b4a --- /dev/null +++ b/packages/slate/test/controllers/editor/has-query/existing-plugin.js @@ -0,0 +1,19 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +const plugins = [ + { + queries: { + customQuery: () => {}, + }, + }, +] + +export const input = new Editor({ plugins }) + +export default function(editor) { + return editor.hasQuery('customQuery') +} + +export const output = true diff --git a/packages/slate/test/controllers/editor/has-query/existing-registered.js b/packages/slate/test/controllers/editor/has-query/existing-registered.js new file mode 100644 index 000000000..2affe22d6 --- /dev/null +++ b/packages/slate/test/controllers/editor/has-query/existing-registered.js @@ -0,0 +1,11 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +export const input = new Editor().registerQuery('customQuery') + +export default function(editor) { + return editor.hasQuery('customQuery') +} + +export const output = true diff --git a/packages/slate/test/controllers/editor/has-query/missing-plugin.js b/packages/slate/test/controllers/editor/has-query/missing-plugin.js new file mode 100644 index 000000000..2635fd5f5 --- /dev/null +++ b/packages/slate/test/controllers/editor/has-query/missing-plugin.js @@ -0,0 +1,19 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +const plugins = [ + { + queries: { + customquery: () => {}, + }, + }, +] + +export const input = new Editor({ plugins }) + +export default function(editor) { + return editor.hasQuery('otherquery') +} + +export const output = false diff --git a/packages/slate/test/controllers/editor/has-query/missing-registered.js b/packages/slate/test/controllers/editor/has-query/missing-registered.js new file mode 100644 index 000000000..35f5f50c2 --- /dev/null +++ b/packages/slate/test/controllers/editor/has-query/missing-registered.js @@ -0,0 +1,11 @@ +/** @jsx h */ + +import { Editor } from 'slate' + +export const input = new Editor().registerQuery('customQuery') + +export default function(editor) { + return editor.hasQuery('otherQuery') +} + +export const output = false diff --git a/packages/slate/test/index.js b/packages/slate/test/index.js index c5294c3bf..7fd2fabaa 100644 --- a/packages/slate/test/index.js +++ b/packages/slate/test/index.js @@ -126,6 +126,15 @@ describe('slate', () => { assert.deepEqual(actual, expected) }) + fixtures(__dirname, 'controllers', ({ module }) => { + const { input, output, default: fn } = module + + const actual = fn(input) + const expected = output + + assert.equal(actual, expected) + }) + fixtures(__dirname, 'schema', ({ module }) => { const { input, output, schema } = module const editor = new Editor({ value: input, plugins: [{ schema }] }) diff --git a/yarn.lock b/yarn.lock index 22febf934..343702a9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6217,7 +6217,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.4, prop-types@^15.6.1: +prop-types@^15.5.4, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -6427,6 +6427,10 @@ react-immutable-proptypes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz#023d6f39bb15c97c071e9e60d00d136eac5fa0b4" +react-is@^16.6.3: + version "16.6.3" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0" + react-portal@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.1.5.tgz#6665d4d2a92d47d6f8b07a6529e26fc52d5cccde" @@ -6462,6 +6466,15 @@ react-router@^4.3.1: prop-types "^15.6.1" warning "^4.0.1" +react-test-renderer@^16.6.3: + version "16.6.3" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.6.3.tgz#5f3a1a7d5c3379d46f7052b848b4b72e47c89f38" + dependencies: + object-assign "^4.1.1" + prop-types "^15.6.2" + react-is "^16.6.3" + scheduler "^0.11.2" + react-values@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/react-values/-/react-values-0.3.0.tgz#ae592c368ea50bfa6063029e31430598026f5287" @@ -6986,6 +6999,13 @@ sax@^1.2.1, sax@~1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" +scheduler@^0.11.2: + version "0.11.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.2.tgz#a8db5399d06eba5abac51b705b7151d2319d33d3" + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"