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

Integrate chai-subset into chai core #1621

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9415e46
Version 0.1.0
eagleeye Jul 14, 2014
a5ae493
Merge pull request #2 from e-conomic/0.2
eagleeye Aug 1, 2014
8b9d5cd
v0.3.0 Use circular-json for generating error messages. Fixes #1
eagleeye Aug 3, 2014
968c1eb
v0.3.0 Use circular-json for generating error messages. Fixes #1
eagleeye Aug 3, 2014
d8bb923
Merge pull request #4 from RobertHerhold/master
eagleeye Mar 24, 2015
21c9fbd
Merge pull request #5 from e-conomic/v1.0.0
eagleeye Mar 24, 2015
bba9adf
Merge pull request #14 from debitoor/v1.1.0
eagleeye Aug 29, 2015
71b8eaf
Merge pull request #14 from debitoor/v1.1.0
eagleeye Aug 29, 2015
0fe59da
Merge pull request #22 from debitoor/compare-dates
eagleeye Dec 2, 2015
cea5b39
Merge pull request #22 from debitoor/compare-dates
eagleeye Dec 2, 2015
ac3c162
Add browser support (fixes #34) (#37)
hashchange Jul 16, 2016
f1ce897
bug: fix expecting an object to be a date succeeds (#56)
despairblue Dec 26, 2016
baaa129
bug: fix expecting an object to be a date succeeds (#56)
despairblue Dec 26, 2016
8a88033
Introduce strict equality check in compare() (#57)
oleg-codaio Mar 2, 2017
104982a
1.5.0, handle recursive objects
eagleeye Mar 2, 2017
42f9483
Adding a compare function to be used in expected object template (#66)
Sep 5, 2017
95b237d
Adding a compare function to be used in expected object template (#66)
Sep 5, 2017
173273a
move file so it matches existing directory structure
koddsson May 20, 2024
3a6ff42
run prettier and import `expect` from chai
koddsson May 20, 2024
7417cb1
Version 0.1.0
eagleeye Jul 14, 2014
ef41756
Integrate chai-subset into chai
koddsson May 20, 2024
e31b9a6
fix chai-subset tests
koddsson May 20, 2024
c58cbed
add missing right paren
koddsson May 20, 2024
6f7d42a
add jsdoc
koddsson May 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import {Assertion} from '../assertion.js';
import {AssertionError} from 'assertion-error';
import * as _ from '../utils/index.js';
import {config} from '../config.js';

const {flag} = _;

Expand Down Expand Up @@ -3929,5 +3930,73 @@ Assertion.addProperty('finite', function(msg) {
typeof obj === 'number' && isFinite(obj)
, 'expected #{this} to be a finite number'
, 'expected #{this} to not be a finite number'
)
});

/**
* A subset-aware compare function
*
* @param {unknown} expected
* @param {unknown} actual
* @returns {void}
*/
function compareSubset(expected, actual) {
if (expected === actual) {
return true;
}
if (typeof actual !== typeof expected) {
return false;
}
if (typeof expected !== 'object' || expected === null) {
return expected === actual;
}
if (!!expected && !actual) {
return false;
}

if (Array.isArray(expected)) {
if (typeof actual.length !== 'number') {
return false;
}
var aa = Array.prototype.slice.call(actual);
return expected.every(function (exp) {
return aa.some(function (act) {
return compareSubset(exp, act);
});
});
}

if (expected instanceof Date) {
if (actual instanceof Date) {
return expected.getTime() === actual.getTime();
} else {
return false;
}
}

return Object.keys(expected).every(function (key) {
var eo = expected[key];
var ao = actual[key];
if (typeof eo === 'object' && eo !== null && ao !== null) {
return compareSubset(eo, ao);
}
if (typeof eo === 'function') {
return eo(ao);
}
return ao === eo;
});
}

Assertion.addMethod('containSubset', function (expected) {
const actual = _.flag(this, 'object');
const showDiff = config.showDiff;

this.assert(
compareSubset(expected, actual),
'expected #{act} to contain subset #{exp}',
'expected #{act} to not contain subset #{exp}',
expected,
actual,
showDiff
);
});
4 changes: 4 additions & 0 deletions lib/chai/interface/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -2985,6 +2985,10 @@ assert.isNotEmpty = function(val, msg) {
new Assertion(val, msg, assert.isNotEmpty, true).to.not.be.empty;
};

assert.containSubset = function (val, exp, msg) {
new Assertion(val, msg).to.be.containSubset(exp);
};

/**
* Aliases.
*
Expand Down
205 changes: 205 additions & 0 deletions test/subset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import { assert, expect } from "../index.js";

describe("plain object", function () {
var testedObject = {
a: "b",
c: "d",
};

it("should pass for smaller object", function () {
expect(testedObject).to.containSubset({
a: "b",
});
});

it("should pass for same object", function () {
expect(testedObject).to.containSubset({
a: "b",
c: "d",
});
});

it("should pass for similar, but not the same object", function () {
expect(testedObject).to.not.containSubset({
a: "notB",
c: "d",
});
});
});

describe("complex object", function () {
var testedObject = {
a: "b",
c: "d",
e: {
foo: "bar",
baz: {
qux: "quux",
},
},
};

it("should pass for smaller object", function () {
expect(testedObject).to.containSubset({
a: "b",
e: {
foo: "bar",
},
});
});

it("should pass for smaller object", function () {
expect(testedObject).to.containSubset({
e: {
foo: "bar",
baz: {
qux: "quux",
},
},
});
});

it("should pass for same object", function () {
expect(testedObject).to.containSubset({
a: "b",
c: "d",
e: {
foo: "bar",
baz: {
qux: "quux",
},
},
});
});

it("should pass for similar, but not the same object", function () {
expect(testedObject).to.not.containSubset({
e: {
foo: "bar",
baz: {
qux: "notAQuux",
},
},
});
});

it("should fail if comparing when comparing objects to dates", function () {
expect(testedObject).to.not.containSubset({
e: new Date(),
});
});
});

describe("circular objects", function () {
var object = {};

before(function () {
object.arr = [object, object];
object.arr.push(object.arr);
object.obj = object;
});

it("should contain subdocument", function () {
expect(object).to.containSubset({
arr: [{ arr: [] }, { arr: [] }, [{ arr: [] }, { arr: [] }]],
});
});

it("should not contain similar object", function () {
expect(object).to.not.containSubset({
arr: [
{ arr: ["just random field"] },
{ arr: [] },
[{ arr: [] }, { arr: [] }],
],
});
});
});

describe("object with compare function", function () {
it("should pass when function returns true", function () {
expect({ a: 5 }).to.containSubset({ a: (a) => a });
});

it("should fail when function returns false", function () {
expect({ a: 5 }).to.not.containSubset({ a: (a) => !a });
});

it("should pass for function with no arguments", function () {
expect({ a: 5 }).to.containSubset({ a: () => true });
});
});

describe("comparison of non objects", function () {
it("should fail if actual subset is null", function () {
expect(null).to.not.containSubset({ a: 1 });
});

it("should fail if expected subset is not a object", function () {
expect({ a: 1 }).to.not.containSubset(null);
});

it("should not fail for same non-object (string) variables", function () {
expect("string").to.containSubset("string");
});
});

describe("assert style of test", function () {
it("should find subset", function () {
assert.containSubset({ a: 1, b: 2 }, { a: 1 });
});
});

describe("comparison of dates", function () {
it("should pass for the same date", function () {
expect(new Date("2015-11-30")).to.containSubset(new Date("2015-11-30"));
});

it("should pass for the same date if nested", function () {
expect({ a: new Date("2015-11-30") }).to.containSubset({
a: new Date("2015-11-30"),
});
});

it("should fail for a different date", function () {
expect(new Date("2015-11-30")).to.not.containSubset(new Date("2012-02-22"));
});

it("should fail for a different date if nested", function () {
expect({ a: new Date("2015-11-30") }).to.not.containSubset({
a: new Date("2012-02-22"),
});
});

it("should fail for invalid expected date", function () {
expect(new Date("2015-11-30")).to.not.containSubset(
new Date("not valid date"),
);
});

it("should fail for invalid actual date", function () {
expect(new Date("not valid actual date")).to.not.containSubset(
new Date("not valid expected date"),
);
});
});

describe("cyclic objects", () => {
it("should pass", () => {
const child = {};
const parent = {
children: [child],
};
child.parent = parent;

const myObject = {
a: 1,
b: "two",
c: parent,
};
expect(myObject).to.containSubset({
a: 1,
c: parent,
});
});
});