WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.4k stars 4.15k forks source link

Block unit tests break when testing a gutenberg block as a unit. #37988

Open whizzzkid opened 2 years ago

whizzzkid commented 2 years ago

Description

After upgrade, we noticed our custom components started breaking. The reason for that was the wrapper API changed and now we need to access the wrapper using useBlockProps and useBlockProp.save. This fixed the component and it started working as expected. But this broke our unit tests with the error:

TypeError: Cannot destructure property 'align' of 'attributes' as it is undefined.

  | 16 |   },
  | 17 | }) {
> | 18 |   const blockProps = useBlockProps.save({
  |    |                                    ^
  | 19 |     className: 'foo',
  | 20 |   });
  | 21 |

at apply (node_modules/@wordpress/block-editor/build/hooks/@wordpress/block-editor/src/hooks/align.js:212:10)

Step-by-step reproduction instructions

Say we create a component, where the save function looks like so:

import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';

import React from 'react';
import classNames from 'classnames';

import './style.scss';

export default function save(props) {
  const {
    attributes: { backgroundColor, numberOfItems },
  } = props;

  const blockProps = useBlockProps.save({
    className: classNames('foo'),
  });

  return (
    <section {...blockProps}>
      <div className="container">
        <div className="row justify-content-center align-items-center">
          <div className="bar">
            <InnerBlocks.Content />
          </div>
        </div>
      </div>
    </section>
  );
}

To test this, we can now render it and test it like so:

import React from 'react';
import { shallow } from 'enzyme';

import Component from '../save';

describe('Component Save', () => {
  let wrapper;
  let ATTR;

  beforeAll(() => {
    ATTR = {
        backgroundColor: 'red-panda'
    };

    wrapper = shallow(<Component attributes={ATTR} />);
  });

  it('applies backgroundColor', () => {
    expect(wrapper.find('.red-panda').exists()).to.equal(true);
  });
});

But this results in the error mentioned above.

Screenshots, screen recording, code snippet

No response

Environment info

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

Yes

whizzzkid commented 2 years ago

RCA: It looks like when testing the components like so, the useBlockProps.save calls getBlockProps here the problem there is:

const { blockType, attributes } = blockPropsProvider;

blockPropsProvider has not been yet populated. so a workaround here is:

Fix:

import React from 'react';
import { shallow } from 'enzyme';
import { getSaveElement } from '@wordpress/blocks';

import Component from '../save';

describe('Component Save', () => {
  let wrapper;
  let ATTR;

  beforeAll(() => {
    ATTR = {
        backgroundColor: 'red-panda'
    };

    getSaveElement({ name: 'component', save: Component }, ATTR);
    wrapper = shallow(<Component attributes={ATTR} />);
  });

  it('applies backgroundColor', () => {
    expect(wrapper.find('.red-panda').exists()).to.equal(true);
  });
});

the fix is to call getSaveElement before calling useBlockProps.save this populates blockPropsProvider which makes it a non-issue.

I'll create a PR shortly to address this.

tyxla commented 1 year ago

Hey @whizzzkid,

We removed enzyme from the repository a few months ago in https://github.com/WordPress/gutenberg/pull/44494.

I wonder if using @testing-library to perform full rendering for the test would help fix many of the problems you're encountering.

Let me know if that makes sense or if you need any help trying it out.

amberjones commented 1 year ago

I am running into this same error while writing snapshot tests with@testing-library and this is the only reference I can find to it!

TypeError: Cannot destructure property 'align' of 'attributes' as it is undefined.

      12 |  */
      13 | export default function Save() {
    > 14 |      const blockProps = useBlockProps.save();
         |                                       ^

I have a similar block structure as @whizzzkid with save as its own component.

export default function Save() {
  const blockProps = useBlockProps.save();
  return (
    <section { ...blockProps }>
      <InnerBlocks.Content />
    </section>
  );
}

I've tried calling getSaveElement in the beforeAll hook like the workaround above, but thats not getting around the error for me.

import {
  render,
} from '@testing-library/react';
import { getSaveElement } from '@wordpress/blocks';
import Save from '../../../blocks/chapter/save';

describe('Save component', () => {
  let el;

  beforeAll(() => {
    const attributes = { value: 'randomvalue' }
    getSaveElement({ name: 'my-block-name', save: Save }, attributes);
    const { baseElement } = render(
      <Save
        {...{
    attributes,
    clientId: 'random-id',
    className: 'wp-block-my-block-name',
    }}
      />
    );
    el = baseElement;
  });

  it('matches snapshot', () => {
    expect( el ).toMatchSnapshot();
  });
)};

Any suggestions? Thanks!

whizzzkid commented 1 year ago

Apologies for the radio silence @tyxla, I got occupied with other things and didn't get time to create that PR.

@amberjones the interim fix was mentioned here: https://github.com/WordPress/gutenberg/issues/37988#issuecomment-1013373975 that worked for us, however did you try passing args to Save like my example?

tyxla commented 1 year ago

Apologies for the radio silence @tyxla, I got occupied with other things and didn't get time to create that PR.

No worries @whizzzkid! No rush, but let me know if you need anything in the meantime.

I've tried calling getSaveElement in the beforeAll hook like the workaround above, but thats not getting around the error for me.

Hey @amberjones,

I've tried creating the save component and adding the test you provided, and the tests passed for me. Perhaps you could try providing a branch or PR in this repository with which we're able to reproduce the failure? I'd be happy to take a look at it and offer help fixing it.

With regards to @whizzzkid's I'd like to note again as I noted earlier, that we recently removed Enzyme and it's recommended to use @testing-library for component tests in the future.