Chai: test array to include an object with a certain key: value

Created on 10 Aug 2017  路  7Comments  路  Source: chaijs/chai

Hello,

As the title says we found our selves in a situation where we need to check if an array contains an element that one of his properties equals to something.

We tried and search for a couple of hours until we desided to raise an issue about it.
We were able to solve the problem like this:

const playersRegs = created.gameLog.filter(e => e.nameType === eventTypes.PlayerReg);
expect(playersRegs).to.have.lengthOf(1);

but we were hoping for something a bit like:

expect(created.gameLog).to.include.something.that.has.property('nameType', eventTypes.PlayerReg);

if we missed anything please let us know and if we didnt please consider adding this functionality ;)

Most helpful comment

@keithamus Is there a solution available through chai now?

All 7 comments

I think the chai-things plugin does this, but unfortunately it doesn't currently support v4 (and might not even support v3.5).

Is the exact array index that contains the the desired property value not known ahead of time? I'd like to learn more about the use case that leads to this kind of test being written, as opposed to something like expect(created.gameLog[43]).to.have.property('nameType', eventTypes.PlayerReg);

On an unrelated note, I'd be careful about having a variable like eventTypes.PlayerReg as the expected property value. If .nameType and .PlayerReg both get renamed during some future refactor, then this test will become broken in such a way that it always passes because undefined === undefined. If replacing eventTypes.PlayerReg in the test with an explicit value isn't feasible, then this concern can be mitigated by having a separate test that asserts eventTypes.PlayerReg is the expected value or type.

Hi meeber,
Thank you for your quick answer and for your note (I'll keep that in mind 馃憤 ).

Is the exact array index that contains the the desired property value not known ahead of time?

The array is events array. We represent each event as an object, and one of the properties this object has is 'nameType'. eventTypes is a constant json that contains all of our events 'nameType'.
The exact index is known ahead of time, but as you said - things can changed during some future refactor. We thought that it will be easier and more comfortable if we could just search for this property in the entire array's objects.

Makes sense. In a case like this one, I can understand accepting decreased precision in exchange for increased maintainability.

A couple of weeks ago I was thinking about the level of effort of making the chai-things plugin compatible with Chai v4. The current stance is we'd wait for #585 to be resolved before fixing chai-things, but that feels like a long ways away to me. Given that the plugin is basically unusable at the moment, I think it might be worth it to fix the plugin directly.

I have the same issue - thanks for the workaround idea @Segev95

Hey @Segev95 thanks for the issue.

We've added this to our Roadmap https://github.com/chaijs/chai/projects/2! We'll be releasing chai 5 soon, but for now I'll close this issue because it is tracked on our roadmap.

@keithamus Is there a solution available through chai now?

This isn't quite what OP was asking for, but in the spirit of contributing workarounds, here's what I came up with:

expect(arr.map((e) => e.id).sort()).to.deep.equal([1, 3, 6, 7]);

This requires you to test the validity of the entire array, but that happened to work for my use case. This could also be factored out into a helper function:

expect(extractProperty(arr, id)).to.deep.equal([1, 3, 6, 7]);

function extractProperty(arr, property) {
    return arr.map((e) => e.property).sort();
}

To be more in line with what OP is asking, I suppose you could also do something like:

expect(arr.map((e) => e['id']).includes( /* ID you're testing for */ )).to.be.true;

Which could be rewritten as:

expect(propertyValueInArray(arr, 'id', /* ID you're testing for */)).to.be.true;

function propertyValueInArray(arr, property, value) {
    return arr.map((e) => e[property]).includes(value);
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

basherr picture basherr  路  4Comments

corybill picture corybill  路  4Comments

zzzgit picture zzzgit  路  3Comments

qbolec picture qbolec  路  5Comments

sverrirs picture sverrirs  路  3Comments