enzymejs / chai-enzyme

Chai.js assertions and convenience functions for testing React Components with enzyme
MIT License
787 stars 72 forks source link

Assertion for shallow rendering `equals` #22

Open roadhump opened 8 years ago

roadhump commented 8 years ago

It would be nice to have assertion to check node against node, equals from shallow rendering of enzyme (probably equalsJSX, same to https://github.com/algolia/expect-jsx)

Now

expect(shallow(<Component />).find('SubComponent').equals(<SubComponent foo="bar" />)).to.be.true

Would like to have

expect(shallow(<Component />).find('SubComponent')).to.be.equalsJSX(<SubComponent foo="bar" />)
ljharb commented 8 years ago

I'd think .to.equal(<blah>) would be nicer than to.be.equalsJSX tho

vesln commented 8 years ago

+1 for .to.equal

ayrton commented 8 years ago

For future reference there's chai-equal-jsx.

Anahkiasen commented 8 years ago

@ayrton chai-equals-jsx doesn't accept an enzyme wrapper though, only JSX, or is there a way to get the JSX from the enzyme wrapper?

keithamus commented 8 years ago

i would like to encourage the use of shadowing built in chai assertions - I think this is the direction we'd like to see plugins go in - rather than pre/suffixing. So +1 for .to.equal.

ljharb commented 8 years ago

imo it's a very bad idea to shadow chai assertions. That will require that this project stays tightly in sync with major version updates of chai itself.

It's best to create new method names - it will make support, documentation, googling, and simple reading comprehension to be much more straightforward.

keithamus commented 8 years ago

imo it's a very bad idea to shadow chai assertions. That will require that this project stays tightly in sync with major version updates of chai itself

Why do you think this @ljharb? Since very early versions of chai, it has encouraged the ability to transparently shadow methods with overwriteMethod and the plans for upcoming major versions will only improve the behaviour around this.

vesln commented 8 years ago

I agree with @keithamus, we (chai.js team) have always encouraged it and pretty much the core goal of the next major chai.js release is to make this behavior more robust.

re staying in sync with chai.js - i think that would be the ideal scenario, but it's not necessarily a must do. we can always introduce aliases where it makes sense. imo introducing api breaking changes for this project is a huge no-no unless absolutely necessary.

CzBuCHi commented 7 years ago

i had same issue and this is my solution for it:

const ReactElementToString = require('react-element-to-string');
chai.use(function(_chai, utils) {
    var Assertion = _chai.Assertion;
    utils.addMethod(_chai.Assertion.prototype, 'equalJsx', function (expected) {
        // TODO: check that this._obj is ShallowWrapper instance 
        // i dont know how to get ShallowWrapper type here... (im using typescript)
        // new Assertion(this._obj).to.be.instanceof(ShallowWrapper);
        const actualString = ReactElementToString(this._obj.instance().render());
        const expectedString = ReactElementToString(expected);
        expect(actualString).to.be.equal(expectedString);
    });
});

usage:

// components
function Foo({ name, value }) { return <div className="Foo"><Bar name={name} value={value} /></div>; }
function Bar({ name, value }) { return <div className="Bar"><Baz name={name} value={value} /></div>; }
function Baz({ name, value }) { return <div className="Baz">{name} - {value}</div>; }

// and inside describe-it:
const actual = shallow(<Foo name="Foo" value="Bar" />);
const expected = <div className="Foo"><Bar name="Foo" value="Foo" /></div>;
expect(actual).to.equalJsx(expected);

and nice error message:

-<div className="Foo">
-  <Bar name="Bar" value="Bar" />
+<div className="Foo2">
+  <Bar name="Foo" value="Foo" />
</div>

changed code in package react-element-to-string - props wasnt sorted (not nesseseary - props order is irelevant but if changed tests would fail...)

file: index.js

-26: return Object.keys(element.props || {}).map(function(prop) {
+26: var keys = Object.keys(element.props || {});
+27: keys.sort();
+28: return keys.map(function(prop) {

cheers

edit: sorry for thread necromancy :)