Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
whizzzkid opened this issue Jan 14, 2022 · 5 comments
Open

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

whizzzkid opened this issue Jan 14, 2022 · 5 comments
Labels
Needs Technical Feedback Needs testing from a developer perspective. [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Bug An existing feature does not function as intended

Comments

@whizzzkid
Copy link

whizzzkid commented Jan 14, 2022

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

  • Wordpres: 5.8.3
  • Node: 14-LTS
  • Packages
"@wordpress/block-editor": "^8.0.12",
"@wordpress/block-library": "^6.0.17",
"@wordpress/blocks": "^11.1.5",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.3",

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
Copy link
Author

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.

@karmatosed karmatosed added the Needs Technical Feedback Needs testing from a developer perspective. label Jan 14, 2022
@gziolo gziolo added the [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. label Jan 16, 2022
@tyxla
Copy link
Member

tyxla commented Dec 12, 2022

Hey @whizzzkid,

We removed enzyme from the repository a few months ago in #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
Copy link

amberjones commented Jan 6, 2023

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
Copy link
Author

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: #37988 (comment) that worked for us, however did you try passing args to Save like my example?

@tyxla
Copy link
Member

tyxla commented Jan 6, 2023

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.

@jordesign jordesign added the [Type] Bug An existing feature does not function as intended label Sep 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Technical Feedback Needs testing from a developer perspective. [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

No branches or pull requests

6 participants