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

to.have.attr passes when actual is undefined #11

Merged
merged 3 commits into from
Jan 28, 2016

Conversation

marcodejongh
Copy link
Contributor

The following assertion passes:

            it('Reproduction path', () => {
                const wrapper = shallow(<div />);
                expect(undefined).to.have.attr('key', 'somekey');
            });

It also passes on to.have.prop

@ayrton
Copy link
Contributor

ayrton commented Jan 21, 2016

This certainly feels like unexpected results, both assertions actually pass:

expect(undefined).to.have.attr('key', 'somekey');
expect(undefined).to.not.have.attr('key', 'somekey');

@marcodejongh
Copy link
Contributor Author

Yes this is a particulary nasty bug, I've found that I had a lot of cases passing even tho they should fail.
Because I passed in wrapper.children().get(1) instead of wrapper.children().at(1).
The assertion only seems to work correctly if you expect on a enzyme wrapper

@ljharb
Copy link
Member

ljharb commented Jan 21, 2016

At the very least, an enzyme expectation should always fail if the "actual" is not a non-array non-function object.

This was referenced Jan 21, 2016
@marcodejongh marcodejongh changed the title to.have.attr passes when given a undefined object to.have.attr passes when actual is undefined Jan 21, 2016
@marcodejongh
Copy link
Contributor Author

Ok to summarise: the proposed fix will be to have all the chai-enzyme assertions throw an error if the "actual" is not a enzyme warpper

@vesln
Copy link
Contributor

vesln commented Jan 21, 2016

yeah... that's a bit problematic. the thing is... we use overwrite* in order to play nice with other chai.js plugins that may have the same syntax (such as chai-jquery for example).

to me this seems more or less like a chai.js issue, rather than chai-enzyme. @keithamus do you have any thoughts on this?

@vesln vesln added the bug label Jan 21, 2016
@vesln
Copy link
Contributor

vesln commented Jan 21, 2016

/cc @logicalparadox

@keithamus
Copy link
Contributor

Hey @vesln thanks for bringing me in on this.

TL;DR: This will be "fixed" in version 4.0.0 of chai, but you shouldn't use overwriteMethod unless the method actually exists. (Which, I know, is a pain).


This is kind of a chai bug, and kind of a bug with this lib. For context read chaijs/chai#467, but it boils down to:

  1. Calling overwriteMethod gives you the super method
  2. If you're overwriting a method that doesn't exist then super is an empty function (which coincidentally means its a passing assertion).
  3. attr doesn't exist in chai core, so if you're just using this plugin then you get an empty function as super
  4. It looks as though your lib calls super when the wrap function presumably rejects the assertion object based on some criteria which I assume undefined is part of.

So whats happening:

  1. expect(undefined).to.have.attr('key', 'value') is called
  2. wrap() (your lib internals) rejects undefined as something it can assert on
  3. Your lib calls super with the object
  4. Chai doesn't have a super, so just calls an empty function
  5. Assertion "passes"

The "fix" for this is in Chai 4.x.x branch - it makes the default behaviour of super throw if there is no underlying method. Having said that, this could be fixed on your side by discontinuing use of overwriteMethod unless you absolutely know that the underlying method exists. overwriteMethod, IMO, is for edge cases - not the common case. If you'd like to get involved with how chai intends to fix this long term, take a look at chaijs/chai#585

@vesln
Copy link
Contributor

vesln commented Jan 21, 2016

@keithamus thanks a ton!

in this case, @marcodejongh, i'd suggest to change the overwrite* methods where possible (eg. won't be doable for contain) and throw if the passed objects are not an enzyme wrapper

@keithamus
Copy link
Contributor

You can check to see if a method exists by looking at chai.Assertion.prototype.*. This will let you programatically determine whether you should use overwriteMethod or addMethod. Of course, it depends largely on the plugins you've loaded as to whether you call overwrite or add.

@marcodejongh marcodejongh self-assigned this Jan 21, 2016
@@ -11,6 +11,16 @@ class Fixture extends React.Component {
const it = createTest(<Fixture />)

describe('#attr', () => {
it('fails when actual is not a enzymeWrapper', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it('fails when the actual is not an enzyme wrapper'), () => {})

@ayrton
Copy link
Contributor

ayrton commented Jan 22, 2016

Looking good @marcodejongh 🙌, let's wait for @vesln and @andreasklinger to chime in before merging.

marcodejongh added a commit that referenced this pull request Jan 28, 2016
to.have.attr passes when actual is undefined
@marcodejongh marcodejongh merged commit 40f3fd5 into enzymejs:master Jan 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants