Skip to content

Commit a512271

Browse files
committed
Add unregisterBlock and resulting improvements:
- No need for a separate `validateBlockSlug` function - More thorough and more isolated tests
1 parent 0f1ea2a commit a512271

File tree

2 files changed

+81
-28
lines changed

2 files changed

+81
-28
lines changed

modules/blocks/index.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,42 @@ export { default as Editable } from './components/editable';
88
const blocks = {};
99

1010
/**
11-
* Validates a block slug and throws an error if it is invalid.
11+
* Registers a block.
1212
*
13-
* @param {string} slug Block slug
13+
* @param {string} slug Block slug
14+
* @param {Object} settings Block settings
1415
*/
15-
export function validateBlockSlug( slug ) {
16+
export function registerBlock( slug, settings ) {
17+
if ( typeof slug !== 'string' ) {
18+
throw new Error(
19+
'Block slugs must be strings.'
20+
);
21+
}
1622
if ( ! /^[a-z0-9-]+\/[a-z0-9-]+$/.test( slug ) ) {
1723
throw new Error(
1824
'Block slugs must contain a namespace prefix. Example: my-plugin/my-custom-block'
1925
);
2026
}
27+
if ( blocks[ slug ] ) {
28+
throw new Error(
29+
'Block "' + slug + '" is already registered.'
30+
);
31+
}
32+
blocks[ slug ] = Object.assign( { slug }, settings );
2133
}
2234

2335
/**
24-
* Registers a block.
36+
* Unregisters a block.
2537
*
26-
* @param {string} slug Block slug
27-
* @param {Object} settings Block settings
38+
* @param {string} slug Block slug
2839
*/
29-
export function registerBlock( slug, settings ) {
30-
validateBlockSlug( slug );
31-
blocks[ slug ] = Object.assign( { slug }, settings );
40+
export function unregisterBlock( slug, settings ) {
41+
if ( ! blocks[ slug ] ) {
42+
throw new Error(
43+
'Block "' + slug + '" is not registered.'
44+
);
45+
}
46+
delete blocks[ slug ];
3247
}
3348

3449
/**

modules/blocks/test/index.js

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,84 @@ import { expect } from 'chai';
99
import * as blocks from '../';
1010

1111
describe( 'blocks API', () => {
12-
// TODO: We probably want a way to undo this, and split this logic out into
13-
// separate tests (clearing require.cache for example, but this probably
14-
// won't work with webpack)
15-
before( () => {
16-
blocks.registerBlock( 'core/test-block' );
17-
const blockSettings = { settingName: 'settingValue' };
18-
blocks.registerBlock( 'core/test-block-with-settings', blockSettings );
19-
// This is tested later: `registerBlock` should store a copy of its input
20-
blockSettings.mutated = true;
12+
// Reset block state before each test.
13+
beforeEach( () => {
14+
blocks.getBlocks().forEach( block => {
15+
blocks.unregisterBlock( block.slug );
16+
} );
2117
} );
2218

23-
describe( 'validateBlockSlug', () => {
19+
describe( 'registerBlock', () => {
2420
it( 'should reject numbers', () => {
2521
expect(
26-
() => blocks.validateBlockSlug( 999 )
27-
).to.throw( /^Block slugs must contain a namespace prefix/ );
22+
() => blocks.registerBlock( 999 )
23+
).to.throw( 'Block slugs must be strings.' );
2824
} );
2925

3026
it( 'should reject blocks without a namespace', () => {
3127
expect(
32-
() => blocks.validateBlockSlug( 'doing-it-wrong' )
28+
() => blocks.registerBlock( 'doing-it-wrong' )
3329
).to.throw( /^Block slugs must contain a namespace prefix/ );
3430
} );
3531

3632
it( 'should reject blocks with invalid characters', () => {
3733
expect(
38-
() => blocks.validateBlockSlug( 'still/_doing_it_wrong' )
34+
() => blocks.registerBlock( 'still/_doing_it_wrong' )
3935
).to.throw( /^Block slugs must contain a namespace prefix/ );
4036
} );
4137

4238
it( 'should accept valid block names', () => {
4339
expect(
44-
() => blocks.validateBlockSlug( 'my-plugin/fancy-block-4' )
40+
() => blocks.registerBlock( 'my-plugin/fancy-block-4' )
4541
).not.to.throw();
4642
} );
43+
44+
it( 'should prohibit registering the same block twice', () => {
45+
blocks.registerBlock( 'core/test-block' );
46+
expect(
47+
() => blocks.registerBlock( 'core/test-block' )
48+
).to.throw( 'Block "core/test-block" is already registered.' );
49+
} );
50+
51+
it( 'should store a copy of block settings', () => {
52+
const blockSettings = { settingName: 'settingValue' };
53+
blocks.registerBlock( 'core/test-block-with-settings', blockSettings );
54+
blockSettings.mutated = true;
55+
expect( blocks.getBlockSettings( 'core/test-block-with-settings' ) ).to.eql( {
56+
slug: 'core/test-block-with-settings',
57+
settingName: 'settingValue',
58+
} );
59+
} );
4760
} );
4861

49-
// TODO: registerBlock tests
62+
describe( 'unregisterBlock', () => {
63+
it( 'should fail if a block is not registered', () => {
64+
expect(
65+
() => blocks.unregisterBlock( 'core/test-block' )
66+
).to.throw( 'Block "core/test-block" is not registered.' );
67+
} );
68+
69+
it( 'should unregister existing blocks', () => {
70+
blocks.registerBlock( 'core/test-block' );
71+
expect( blocks.getBlocks() ).to.eql( [
72+
{ slug: 'core/test-block' },
73+
] );
74+
blocks.unregisterBlock( 'core/test-block' );
75+
expect( blocks.getBlocks() ).to.eql( [] );
76+
} );
77+
} );
5078

5179
describe( 'getBlockSettings', () => {
5280
it( 'should return { slug } for blocks with no settings', () => {
81+
blocks.registerBlock( 'core/test-block' );
5382
expect( blocks.getBlockSettings( 'core/test-block' ) ).to.eql( {
5483
slug: 'core/test-block',
5584
} );
5685
} );
5786

58-
it( 'should return { slug } for blocks with no settings', () => {
87+
it( 'should return all block settings', () => {
88+
const blockSettings = { settingName: 'settingValue' };
89+
blocks.registerBlock( 'core/test-block-with-settings', blockSettings );
5990
expect( blocks.getBlockSettings( 'core/test-block-with-settings' ) ).to.eql( {
6091
slug: 'core/test-block-with-settings',
6192
settingName: 'settingValue',
@@ -64,10 +95,17 @@ describe( 'blocks API', () => {
6495
} );
6596

6697
describe( 'getBlocks', () => {
98+
it( 'should return an empty array at first', () => {
99+
expect( blocks.getBlocks() ).to.eql( [] );
100+
} );
101+
67102
it( 'should return all registered blocks', () => {
103+
blocks.registerBlock( 'core/test-block' );
104+
const blockSettings = { settingName: 'settingValue' };
105+
blocks.registerBlock( 'core/test-block-with-settings', blockSettings );
68106
expect( blocks.getBlocks() ).to.eql( [
69-
blocks.getBlockSettings( 'core/test-block' ),
70-
blocks.getBlockSettings( 'core/test-block-with-settings' ),
107+
{ slug: 'core/test-block' },
108+
{ slug: 'core/test-block-with-settings', settingName: 'settingValue' },
71109
] );
72110
} );
73111
} );

0 commit comments

Comments
 (0)