diff --git a/packages/rich-text/src/store/test/actions.js b/packages/rich-text/src/store/test/actions.js new file mode 100644 index 00000000000000..a01c64e18b5419 --- /dev/null +++ b/packages/rich-text/src/store/test/actions.js @@ -0,0 +1,30 @@ +/** + * Internal dependencies + */ +import { addFormatTypes, removeFormatTypes } from '../actions'; + +describe( 'actions', () => { + describe( 'addFormatTypes', () => { + it( 'should cast format types as an array', () => { + const formatTypes = { name: 'core/test-format' }; + const expected = { + type: 'ADD_FORMAT_TYPES', + formatTypes: [ formatTypes ], + }; + + expect( addFormatTypes( formatTypes ) ).toEqual( expected ); + } ); + } ); + + describe( 'removeFormatTypes', () => { + it( 'should cast format types as an array', () => { + const names = 'core/test-format'; + const expected = { + type: 'REMOVE_FORMAT_TYPES', + names: [ names ], + }; + + expect( removeFormatTypes( names ) ).toEqual( expected ); + } ); + } ); +} ); diff --git a/packages/rich-text/src/store/test/selectors.js b/packages/rich-text/src/store/test/selectors.js new file mode 100644 index 00000000000000..c0bc2a19ebcc64 --- /dev/null +++ b/packages/rich-text/src/store/test/selectors.js @@ -0,0 +1,33 @@ +/** + * Internal dependencies + */ +import { getFormatTypes, getFormatType } from '../selectors'; + +describe( 'selectors', () => { + const defaultState = { + formatTypes: { + 'core/test-format': { name: 'core/test-format' }, + 'core/test-format-2': { name: 'core/test-format-2' }, + }, + }; + + describe( 'getFormatTypes', () => { + it( 'should get format types', () => { + const expected = [ + { name: 'core/test-format' }, + { name: 'core/test-format-2' }, + ]; + + expect( getFormatTypes( defaultState ) ).toEqual( expected ); + } ); + } ); + + describe( 'getFormatType', () => { + it( 'should get a format type', () => { + const expected = { name: 'core/test-format' }; + const result = getFormatType( defaultState, 'core/test-format' ); + + expect( result ).toEqual( expected ); + } ); + } ); +} ); diff --git a/packages/rich-text/src/test/get-format-type.js b/packages/rich-text/src/test/get-format-type.js new file mode 100644 index 00000000000000..662b625dafbaac --- /dev/null +++ b/packages/rich-text/src/test/get-format-type.js @@ -0,0 +1,39 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * Internal dependencies + */ +import { getFormatType } from '../get-format-type'; +import { unregisterFormatType } from '../unregister-format-type'; +import { registerFormatType } from '../register-format-type'; +import { getFormatTypes } from '../get-format-types'; + +describe( 'getFormatType', () => { + // Initialize format store. + require( '../store' ); + + afterEach( () => { + getFormatTypes().forEach( ( format ) => { + unregisterFormatType( format.name ); + } ); + } ); + + it( 'should return all format type elements', () => { + const formatType = { + edit: noop, + title: 'format title', + keywords: [ 'one', 'two', 'three' ], + formatTestSetting: 'settingTestValue', + }; + + registerFormatType( 'core/test-format-with-settings', formatType ); + + expect( getFormatType( 'core/test-format-with-settings' ) ).toEqual( { + name: 'core/test-format-with-settings', + ...formatType, + } ); + } ); +} ); diff --git a/packages/rich-text/src/test/get-format-types.js b/packages/rich-text/src/test/get-format-types.js new file mode 100644 index 00000000000000..91cd409df59596 --- /dev/null +++ b/packages/rich-text/src/test/get-format-types.js @@ -0,0 +1,48 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * Internal dependencies + */ +import { getFormatTypes } from '../get-format-types'; +import { unregisterFormatType } from '../unregister-format-type'; +import { registerFormatType } from '../register-format-type'; + +describe( 'getFormatTypes', () => { + // Initialize format store. + require( '../store' ); + + afterEach( () => { + getFormatTypes().forEach( ( format ) => { + unregisterFormatType( format.name ); + } ); + } ); + + it( 'should return an empty array at first', () => { + expect( getFormatTypes() ).toEqual( [] ); + } ); + + it( 'should return all registered formats', () => { + const formatType1 = { edit: noop, title: 'format title' }; + const formatType2 = { + edit: noop, + title: 'format title 2', + keywords: [ 'one', 'two', 'three' ], + formatTestSetting: 'settingTestValue', + }; + registerFormatType( 'core/test-format', formatType1 ); + registerFormatType( 'core/test-format-with-settings', formatType2 ); + expect( getFormatTypes() ).toEqual( [ + { + name: 'core/test-format', + ...formatType1, + }, + { + name: 'core/test-format-with-settings', + ...formatType2, + }, + ] ); + } ); +} ); diff --git a/packages/rich-text/src/test/insert-object.js b/packages/rich-text/src/test/insert-object.js new file mode 100644 index 00000000000000..21cc95687ffbd6 --- /dev/null +++ b/packages/rich-text/src/test/insert-object.js @@ -0,0 +1,38 @@ +/** + * External dependencies + */ +import deepFreeze from 'deep-freeze'; + +/** + * Internal dependencies + */ + +import { insertObject } from '../insert-object'; +import { getSparseArrayLength } from './helpers'; + +describe( 'insert', () => { + const obj = { type: 'obj' }; + const em = { type: 'em' }; + + const OBJECT_REPLACEMENT_CHARACTER = '\ufffc'; + + it( 'should delete and insert', () => { + const record = { + formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ], + text: 'one two three', + start: 6, + end: 6, + }; + const expected = { + formats: [ , , [ { ...obj, object: true } ], [ em ], , , , , , , ], + text: 'on' + OBJECT_REPLACEMENT_CHARACTER + 'o three', + start: 3, + end: 3, + }; + const result = insertObject( deepFreeze( record ), obj, 2, 6 ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 2 ); + } ); +} ); diff --git a/packages/rich-text/src/test/register-format-type.js b/packages/rich-text/src/test/register-format-type.js new file mode 100644 index 00000000000000..74894ff5da7334 --- /dev/null +++ b/packages/rich-text/src/test/register-format-type.js @@ -0,0 +1,123 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * Internal dependencies + */ +import { registerFormatType } from '../register-format-type'; +import { unregisterFormatType } from '../unregister-format-type'; +import { getFormatType } from '../get-format-type'; +import { getFormatTypes } from '../get-format-types'; + +describe( 'registerFormatType', () => { + const defaultFormatSettings = { edit: noop, title: 'format title' }; + + // Initialize format store. + require( '../store' ); + + afterEach( () => { + getFormatTypes().forEach( ( format ) => { + unregisterFormatType( format.name ); + } ); + } ); + + it( 'should reject numbers', () => { + const format = registerFormatType( 42 ); + expect( console ).toHaveErroredWith( 'Format names must be strings.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject format types without a namespace', () => { + const format = registerFormatType( 'doing-it-wrong' ); + expect( console ).toHaveErroredWith( 'Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject format types with too many namespaces', () => { + const format = registerFormatType( 'doing/it/wrong' ); + expect( console ).toHaveErroredWith( 'Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject format types with invalid characters', () => { + const format = registerFormatType( 'still/_doing_it_wrong' ); + expect( console ).toHaveErroredWith( 'Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject format types with uppercase characters', () => { + const format = registerFormatType( 'Core/Bold' ); + expect( console ).toHaveErroredWith( 'Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject format types not starting with a letter', () => { + const format = registerFormatType( 'my-plugin/4-fancy-format' ); + expect( console ).toHaveErroredWith( 'Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should accept valid format names', () => { + const format = registerFormatType( 'my-plugin/fancy-format-4', defaultFormatSettings ); + expect( console ).not.toHaveErrored(); + expect( format ).toEqual( { + name: 'my-plugin/fancy-format-4', + edit: noop, + title: 'format title', + } ); + } ); + + it( 'should prohibit registering the same format twice', () => { + registerFormatType( 'core/test-format', defaultFormatSettings ); + const format = registerFormatType( 'core/test-format', defaultFormatSettings ); + expect( console ).toHaveErroredWith( 'Format "core/test-format" is already registered.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject formats without an edit function', () => { + const format = registerFormatType( 'my-plugin/fancy-format-5' ); + expect( console ).toHaveErroredWith( 'The "edit" property must be specified and must be a valid function.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject formats with an invalid edit function', () => { + const formatType = { edit: 'not-a-function', title: 'format title' }, + format = registerFormatType( 'my-plugin/fancy-format-6', formatType ); + expect( console ).toHaveErroredWith( 'The "edit" property must be specified and must be a valid function.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject formats without title', () => { + const formatType = { edit: noop }, + format = registerFormatType( 'my-plugin/fancy-format-7', formatType ); + expect( console ).toHaveErroredWith( 'The format "my-plugin/fancy-format-7" must have a title.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject formats with empty titles', () => { + const formatType = { edit: noop, title: '' }, + format = registerFormatType( 'my-plugin/fancy-format-8', formatType ); + expect( console ).toHaveErroredWith( 'The format "my-plugin/fancy-format-8" must have a title.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should reject titles which are not strings', () => { + const formatType = { edit: noop, title: 1337 }, + format = registerFormatType( 'my-plugin/fancy-format-9', formatType ); + expect( console ).toHaveErroredWith( 'Format titles must be strings.' ); + expect( format ).toBeUndefined(); + } ); + + it( 'should store a copy of the format type', () => { + const formatType = { edit: noop, title: 'format title' }; + registerFormatType( 'core/test-format-with-settings', formatType ); + formatType.mutated = true; + expect( getFormatType( 'core/test-format-with-settings' ) ).toEqual( { + name: 'core/test-format-with-settings', + edit: noop, + title: 'format title', + } ); + } ); +} ); diff --git a/packages/rich-text/src/test/toggle-format.js b/packages/rich-text/src/test/toggle-format.js new file mode 100644 index 00000000000000..4a890a43bfae58 --- /dev/null +++ b/packages/rich-text/src/test/toggle-format.js @@ -0,0 +1,56 @@ +/** + * External dependencies + */ +import deepFreeze from 'deep-freeze'; + +/** + * Internal dependencies + */ + +import { toggleFormat } from '../toggle-format'; +import { getSparseArrayLength } from './helpers'; + +describe( 'toggleFormat', () => { + const strong = { type: 'strong' }; + const em = { type: 'em' }; + + it( 'should remove format if it exists at start of selection', () => { + const record = { + formats: [ , , , [ strong ], [ em, strong ], [ em ], [ em ], , , , , , , ], + text: 'one two three', + start: 3, + end: 6, + }; + const expected = { + formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ], + text: 'one two three', + start: 3, + end: 6, + }; + const result = toggleFormat( deepFreeze( record ), strong ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 3 ); + } ); + + it( 'should apply format if it doesn\'t exist at start of selection', () => { + const record = { + formats: [ , , , , [ em, strong ], [ em ], [ em ], , , , , , , ], + text: 'one two three', + start: 3, + end: 6, + }; + const expected = { + formats: [ , , , [ strong ], [ em, strong ], [ em, strong ], [ em ], , , , , , , ], + text: 'one two three', + start: 3, + end: 6, + }; + const result = toggleFormat( deepFreeze( record ), strong ); + + expect( result ).toEqual( expected ); + expect( result ).not.toBe( record ); + expect( getSparseArrayLength( result.formats ) ).toBe( 4 ); + } ); +} ); diff --git a/packages/rich-text/src/test/unregister-format-type.js b/packages/rich-text/src/test/unregister-format-type.js new file mode 100644 index 00000000000000..ab0d9a31da319c --- /dev/null +++ b/packages/rich-text/src/test/unregister-format-type.js @@ -0,0 +1,47 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * Internal dependencies + */ +import { unregisterFormatType } from '../unregister-format-type'; +import { registerFormatType } from '../register-format-type'; +import { getFormatTypes } from '../get-format-types'; + +describe( 'unregisterFormatType', () => { + const defaultFormatSettings = { edit: noop, title: 'format title' }; + + // Initialize format store. + require( '../store' ); + + afterEach( () => { + getFormatTypes().forEach( ( format ) => { + unregisterFormatType( format.name ); + } ); + } ); + + it( 'should fail if the format is not registered', () => { + const oldFormat = unregisterFormatType( 'core/test-format' ); + expect( console ).toHaveErroredWith( 'Format core/test-format is not registered.' ); + expect( oldFormat ).toBeUndefined(); + } ); + + it( 'should unregister existing formats', () => { + registerFormatType( 'core/test-format', defaultFormatSettings ); + expect( getFormatTypes() ).toEqual( [ + { + name: 'core/test-format', + ...defaultFormatSettings, + }, + ] ); + const oldFormat = unregisterFormatType( 'core/test-format' ); + expect( console ).not.toHaveErrored(); + expect( oldFormat ).toEqual( { + name: 'core/test-format', + ...defaultFormatSettings, + } ); + expect( getFormatTypes() ).toEqual( [] ); + } ); +} );