emotion icon indicating copy to clipboard operation
emotion copied to clipboard

PrettyFormatPluginError: Cannot delete property 'className' of #<Object>

Open Fafruch opened this issue 2 years ago • 4 comments

Current behavior:

Components that have a static defaultProps (with className set to '') cannot be serialized using the @emotion/jest/enzyme-serializer (and probably also with @emotion/jest/serializer as it's using shared logic).

The tests are throwing:

PrettyFormatPluginError: Cannot delete property 'className' of #<Object>
TypeError: Cannot delete property 'className' of #<Object>

      at clean (node_modules/@emotion/jest/dist/create-serializer-3afd473f.cjs.dev.js:506:19)
      at Object.serialize (node_modules/@emotion/jest/dist/create-serializer-3afd473f.cjs.dev.js:537:5)
      at Object.serialize (node_modules/@emotion/jest/dist/create-enzyme-serializer-c92dc591.cjs.dev.js:31:32)
      at printPlugin (node_modules/pretty-format/build/index.js:330:16)
      at printer (node_modules/pretty-format/build/index.js:379:12)
      at node_modules/pretty-format/build/plugins/lib/markup.js:73:13
          at Array.map (<anonymous>)
      at printChildren (node_modules/pretty-format/build/plugins/lib/markup.js:67:6)
      at Object.serialize (node_modules/pretty-format/build/plugins/ReactElement.js:144:35)
      at printPlugin (node_modules/pretty-format/build/index.js:330:16)
      at printer (node_modules/pretty-format/build/index.js:379:12)
      at Object.serialize (node_modules/@emotion/jest/dist/create-serializer-3afd473f.cjs.dev.js:539:22)
      at Object.serialize (node_modules/@emotion/jest/dist/create-enzyme-serializer-c92dc591.cjs.dev.js:31:32)
      at printPlugin (node_modules/pretty-format/build/index.js:330:16)
      at printer (node_modules/pretty-format/build/index.js:379:12)
      at node_modules/pretty-format/build/plugins/lib/markup.js:33:21
          at Array.map (<anonymous>)
      at printProps (node_modules/pretty-format/build/plugins/lib/markup.js:31:6)
      at Object.serialize (node_modules/pretty-format/build/plugins/ReactTestComponent.js:45:36)
      at printPlugin (node_modules/pretty-format/build/index.js:330:16)
      at printer (node_modules/pretty-format/build/index.js:379:12)
      at Object.serialize (node_modules/@emotion/jest/dist/create-serializer-3afd473f.cjs.dev.js:539:22)
      at Object.serialize (node_modules/@emotion/jest/dist/create-enzyme-serializer-c92dc591.cjs.dev.js:31:32)
      at printPlugin (node_modules/pretty-format/build/index.js:330:16)
      at printer (node_modules/pretty-format/build/index.js:379:12)
      at node_modules/@emotion/jest/dist/create-enzyme-serializer-c92dc591.cjs.dev.js:26:18
      at Object.print (node_modules/enzyme-to-json/createSerializer.js:21:14)
      at Object.serialize (node_modules/@emotion/jest/dist/create-enzyme-serializer-c92dc591.cjs.dev.js:24:33)
      at printPlugin (node_modules/pretty-format/build/index.js:330:16)
      at format (node_modules/pretty-format/build/index.js:567:16)
      at __EXTERNAL_MATCHER_TRAP__ (node_modules/expect/build/index.js:386:30)
      at Object.throwingMatcher (node_modules/expect/build/index.js:387:15)
      at Object.<anonymous> ([redacted])

Looks like t's failing on this line: https://github.com/emotion-js/emotion/blob/main/packages/jest/src/create-serializer.js#L174

To reproduce:

Define a component with defaultProps. Use either the syntax:

class SomeComponent extends Component {
  static defaultProps = {
     className: ''
  }
 // ...
}

or

class SomeComponent extends Component {
  // ...
}
SomeComponent.defaultProps = {
  className: '',
}

then prepare a test where this component is used and serialized to a snapshot:

import React from "react";
import { shallow } from "enzyme";
import SomeComponent from "./SomeComponent";

Enzyme.configure({ adapter: new Adapter() });

describe("SomeComponent", () => {
  it("should match snapshot", function () {
    const node = shallow(<SomeComponent />);
    expect(node).toMatchSnapshot();
  });
});

Expected behavior:

Test should run and either fail if snapshots are not matching, or succeed if they are matching.

Actual behavior: The test fails on the serialization process.

Environment information:

  • react version: ^17.0.2
  • @emotion/css version: 11.5.0
  • @emotion/jest version: 11.5.0
  • @emotion/react version: 11.5.0
  • @emotion/styled version: 11.3.0
  • jest version: ^27.5.1
  • ts-jest version: ^27.1.3
  • babel-jest version: ^27.5.1

Jest config:

  {
      preset: 'ts-jest/presets/js-with-babel',
      displayName: 'client',
      automock: false,
      timers: 'legacy',
      testTimeout: 20000,
      testRunner: 'jest-jasmine2',
      verbose: true,
      coveragePathIgnorePatterns: [
         // [redacted]
      ],
      collectCoverageFrom: [
         // [redacted]
      ],
      testPathIgnorePatterns: [
         // [redacted]
      ],
      snapshotSerializers: ['@emotion/jest/enzyme-serializer'],
      testEnvironment: 'jsdom',
      setupFiles: ['<rootDir>/jest-setup.js'],
      globals: {
        window: {},
        document: {},
        'ts-jest': {
          diagnostics: false,
        },
      },
      transformIgnorePatterns: [
          // [redacted]
      ],
      transform: {
        '^.+\\.(ts|tsx)?$': 'ts-jest',
        '^.+\\.(js|jsx)$': 'babel-jest',
      },
    }

Fafruch avatar Feb 17 '22 12:02 Fafruch

I've added such tests locally and they pass: https://github.com/emotion-js/emotion/commit/6f678f894623ab3a7c18074fd7d6a5f59763d037

You'd have to provide a full runnable repro case for me to investigate it any further.

Andarist avatar Feb 17 '22 14:02 Andarist

Hi, I managed to reproduce this consistently with a node passed in a render prop: PR #2959

(I'll try to find the cause and submit a real PR if I find the time :sweat_smile: )

Forgot to mention here that I updated my PR to suggest a fix!

@Andarist - are you able to get this merged?

shannonhochkins avatar Dec 18 '23 01:12 shannonhochkins