chai 5.1.2 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.prettierrc.json +10 -0
  2. package/README.md +1 -1
  3. package/chai.js +892 -542
  4. package/eslint.config.js +15 -0
  5. package/lib/chai/assertion.js +181 -141
  6. package/lib/chai/config.js +0 -2
  7. package/lib/chai/core/assertions.js +760 -538
  8. package/lib/chai/interface/assert.js +437 -260
  9. package/lib/chai/interface/expect.js +11 -7
  10. package/lib/chai/interface/should.js +27 -21
  11. package/lib/chai/utils/addChainableMethod.js +69 -70
  12. package/lib/chai/utils/addLengthGuard.js +18 -5
  13. package/lib/chai/utils/addMethod.js +4 -5
  14. package/lib/chai/utils/addProperty.js +27 -28
  15. package/lib/chai/utils/expectTypes.js +18 -10
  16. package/lib/chai/utils/flag.js +4 -3
  17. package/lib/chai/utils/getMessage.js +18 -12
  18. package/lib/chai/utils/getOperator.js +7 -7
  19. package/lib/chai/utils/getProperties.js +2 -2
  20. package/lib/chai/utils/index.js +8 -2
  21. package/lib/chai/utils/inspect.js +3 -3
  22. package/lib/chai/utils/isNaN.js +1 -20
  23. package/lib/chai/utils/isProxyEnabled.js +4 -2
  24. package/lib/chai/utils/objDisplay.js +7 -6
  25. package/lib/chai/utils/overwriteChainableMethod.js +15 -14
  26. package/lib/chai/utils/overwriteMethod.js +8 -9
  27. package/lib/chai/utils/overwriteProperty.js +38 -39
  28. package/lib/chai/utils/proxify.js +40 -29
  29. package/lib/chai/utils/test.js +2 -2
  30. package/lib/chai/utils/transferFlags.js +9 -4
  31. package/lib/chai/utils/type-detect.js +1 -1
  32. package/lib/chai.js +2 -1
  33. package/package.json +15 -7
  34. package/tsconfig.json +18 -0
  35. package/lib/chai/utils/getEnumerableProperties.js +0 -25
  36. package/register-assert.cjs +0 -3
  37. package/register-expect.cjs +0 -3
  38. package/register-should.cjs +0 -3
@@ -18,7 +18,9 @@ import {config} from '../config.js';
18
18
  * @returns {boolean}
19
19
  */
20
20
  export function isProxyEnabled() {
21
- return config.useProxy &&
21
+ return (
22
+ config.useProxy &&
22
23
  typeof Proxy !== 'undefined' &&
23
- typeof Reflect !== 'undefined';
24
+ typeof Reflect !== 'undefined'
25
+ );
24
26
  }
@@ -21,8 +21,8 @@ import {config} from '../config.js';
21
21
  * @public
22
22
  */
23
23
  export function objDisplay(obj) {
24
- var str = inspect(obj)
25
- , type = Object.prototype.toString.call(obj);
24
+ let str = inspect(obj),
25
+ type = Object.prototype.toString.call(obj);
26
26
 
27
27
  if (config.truncateThreshold && str.length >= config.truncateThreshold) {
28
28
  if (type === '[object Function]') {
@@ -32,10 +32,11 @@ export function objDisplay(obj) {
32
32
  } else if (type === '[object Array]') {
33
33
  return '[ Array(' + obj.length + ') ]';
34
34
  } else if (type === '[object Object]') {
35
- var keys = Object.keys(obj)
36
- , kstr = keys.length > 2
37
- ? keys.splice(0, 2).join(', ') + ', ...'
38
- : keys.join(', ');
35
+ let keys = Object.keys(obj),
36
+ kstr =
37
+ keys.length > 2
38
+ ? keys.splice(0, 2).join(', ') + ', ...'
39
+ : keys.join(', ');
39
40
  return '{ Object (' + kstr + ') }';
40
41
  } else {
41
42
  return str;
@@ -40,28 +40,29 @@ import {transferFlags} from './transferFlags.js';
40
40
  * @public
41
41
  */
42
42
  export function overwriteChainableMethod(ctx, name, method, chainingBehavior) {
43
- var chainableBehavior = ctx.__methods[name];
43
+ let chainableBehavior = ctx.__methods[name];
44
44
 
45
- var _chainingBehavior = chainableBehavior.chainingBehavior;
46
- chainableBehavior.chainingBehavior = function overwritingChainableMethodGetter() {
47
- var result = chainingBehavior(_chainingBehavior).call(this);
48
- if (result !== undefined) {
49
- return result;
50
- }
45
+ let _chainingBehavior = chainableBehavior.chainingBehavior;
46
+ chainableBehavior.chainingBehavior =
47
+ function overwritingChainableMethodGetter() {
48
+ let result = chainingBehavior(_chainingBehavior).call(this);
49
+ if (result !== undefined) {
50
+ return result;
51
+ }
51
52
 
52
- var newAssertion = new Assertion();
53
- transferFlags(this, newAssertion);
54
- return newAssertion;
55
- };
53
+ let newAssertion = new Assertion();
54
+ transferFlags(this, newAssertion);
55
+ return newAssertion;
56
+ };
56
57
 
57
- var _method = chainableBehavior.method;
58
+ let _method = chainableBehavior.method;
58
59
  chainableBehavior.method = function overwritingChainableMethodWrapper() {
59
- var result = method(_method).apply(this, arguments);
60
+ let result = method(_method).apply(this, arguments);
60
61
  if (result !== undefined) {
61
62
  return result;
62
63
  }
63
64
 
64
- var newAssertion = new Assertion();
65
+ let newAssertion = new Assertion();
65
66
  transferFlags(this, newAssertion);
66
67
  return newAssertion;
67
68
  };
@@ -44,15 +44,14 @@ import {transferFlags} from './transferFlags.js';
44
44
  * @public
45
45
  */
46
46
  export function overwriteMethod(ctx, name, method) {
47
- var _method = ctx[name]
48
- , _super = function () {
47
+ let _method = ctx[name],
48
+ _super = function () {
49
49
  throw new Error(name + ' is not a function');
50
50
  };
51
51
 
52
- if (_method && 'function' === typeof _method)
53
- _super = _method;
52
+ if (_method && 'function' === typeof _method) _super = _method;
54
53
 
55
- var overwritingMethodWrapper = function () {
54
+ let overwritingMethodWrapper = function () {
56
55
  // Setting the `ssfi` flag to `overwritingMethodWrapper` causes this
57
56
  // function to be the starting point for removing implementation frames from
58
57
  // the stack trace of a failed assertion.
@@ -72,19 +71,19 @@ export function overwriteMethod(ctx, name, method) {
72
71
  // Setting the `lockSsfi` flag to `true` prevents the overwritten assertion
73
72
  // from changing the `ssfi` flag. By this point, the `ssfi` flag is already
74
73
  // set to the correct starting point for this assertion.
75
- var origLockSsfi = flag(this, 'lockSsfi');
74
+ let origLockSsfi = flag(this, 'lockSsfi');
76
75
  flag(this, 'lockSsfi', true);
77
- var result = method(_super).apply(this, arguments);
76
+ let result = method(_super).apply(this, arguments);
78
77
  flag(this, 'lockSsfi', origLockSsfi);
79
78
 
80
79
  if (result !== undefined) {
81
80
  return result;
82
81
  }
83
82
 
84
- var newAssertion = new Assertion();
83
+ let newAssertion = new Assertion();
85
84
  transferFlags(this, newAssertion);
86
85
  return newAssertion;
87
- }
86
+ };
88
87
 
89
88
  addLengthGuard(overwritingMethodWrapper, name, false);
90
89
  ctx[name] = proxify(overwritingMethodWrapper, name);
@@ -42,49 +42,48 @@ import {transferFlags} from './transferFlags.js';
42
42
  * @public
43
43
  */
44
44
  export function overwriteProperty(ctx, name, getter) {
45
- var _get = Object.getOwnPropertyDescriptor(ctx, name)
46
- , _super = function () {};
45
+ let _get = Object.getOwnPropertyDescriptor(ctx, name),
46
+ _super = function () {};
47
47
 
48
- if (_get && 'function' === typeof _get.get)
49
- _super = _get.get
48
+ if (_get && 'function' === typeof _get.get) _super = _get.get;
50
49
 
51
- Object.defineProperty(ctx, name,
52
- { get: function overwritingPropertyGetter() {
53
- // Setting the `ssfi` flag to `overwritingPropertyGetter` causes this
54
- // function to be the starting point for removing implementation frames
55
- // from the stack trace of a failed assertion.
56
- //
57
- // However, we only want to use this function as the starting point if
58
- // the `lockSsfi` flag isn't set and proxy protection is disabled.
59
- //
60
- // If the `lockSsfi` flag is set, then either this assertion has been
61
- // overwritten by another assertion, or this assertion is being invoked
62
- // from inside of another assertion. In the first case, the `ssfi` flag
63
- // has already been set by the overwriting assertion. In the second
64
- // case, the `ssfi` flag has already been set by the outer assertion.
65
- //
66
- // If proxy protection is enabled, then the `ssfi` flag has already been
67
- // set by the proxy getter.
68
- if (!isProxyEnabled() && !flag(this, 'lockSsfi')) {
69
- flag(this, 'ssfi', overwritingPropertyGetter);
70
- }
71
-
72
- // Setting the `lockSsfi` flag to `true` prevents the overwritten
73
- // assertion from changing the `ssfi` flag. By this point, the `ssfi`
74
- // flag is already set to the correct starting point for this assertion.
75
- var origLockSsfi = flag(this, 'lockSsfi');
76
- flag(this, 'lockSsfi', true);
77
- var result = getter(_super).call(this);
78
- flag(this, 'lockSsfi', origLockSsfi);
50
+ Object.defineProperty(ctx, name, {
51
+ get: function overwritingPropertyGetter() {
52
+ // Setting the `ssfi` flag to `overwritingPropertyGetter` causes this
53
+ // function to be the starting point for removing implementation frames
54
+ // from the stack trace of a failed assertion.
55
+ //
56
+ // However, we only want to use this function as the starting point if
57
+ // the `lockSsfi` flag isn't set and proxy protection is disabled.
58
+ //
59
+ // If the `lockSsfi` flag is set, then either this assertion has been
60
+ // overwritten by another assertion, or this assertion is being invoked
61
+ // from inside of another assertion. In the first case, the `ssfi` flag
62
+ // has already been set by the overwriting assertion. In the second
63
+ // case, the `ssfi` flag has already been set by the outer assertion.
64
+ //
65
+ // If proxy protection is enabled, then the `ssfi` flag has already been
66
+ // set by the proxy getter.
67
+ if (!isProxyEnabled() && !flag(this, 'lockSsfi')) {
68
+ flag(this, 'ssfi', overwritingPropertyGetter);
69
+ }
79
70
 
80
- if (result !== undefined) {
81
- return result;
82
- }
71
+ // Setting the `lockSsfi` flag to `true` prevents the overwritten
72
+ // assertion from changing the `ssfi` flag. By this point, the `ssfi`
73
+ // flag is already set to the correct starting point for this assertion.
74
+ let origLockSsfi = flag(this, 'lockSsfi');
75
+ flag(this, 'lockSsfi', true);
76
+ let result = getter(_super).call(this);
77
+ flag(this, 'lockSsfi', origLockSsfi);
83
78
 
84
- var newAssertion = new Assertion();
85
- transferFlags(this, newAssertion);
86
- return newAssertion;
79
+ if (result !== undefined) {
80
+ return result;
87
81
  }
88
- , configurable: true
82
+
83
+ let newAssertion = new Assertion();
84
+ transferFlags(this, newAssertion);
85
+ return newAssertion;
86
+ },
87
+ configurable: true
89
88
  });
90
89
  }
@@ -9,6 +9,7 @@ import {isProxyEnabled} from './isProxyEnabled.js';
9
9
  * MIT Licensed
10
10
  */
11
11
 
12
+ /** @type {PropertyKey[]} */
12
13
  const builtins = ['__flags', '__methods', '_obj', 'assert'];
13
14
 
14
15
  /**
@@ -24,13 +25,13 @@ const builtins = ['__flags', '__methods', '_obj', 'assert'];
24
25
  * If proxies are unsupported or disabled via the user's Chai config, then
25
26
  * return object without modification.
26
27
  *
27
- * @param {object} obj
28
- * @param {string} nonChainableMethodName
29
- * @returns {unknown}
30
28
  * @namespace Utils
31
- * @name proxify
29
+ * @template {object} T
30
+ * @param {T} obj
31
+ * @param {string} [nonChainableMethodName]
32
+ * @returns {T}
32
33
  */
33
- export function proxify(obj ,nonChainableMethodName) {
34
+ export function proxify(obj, nonChainableMethodName) {
34
35
  if (!isProxyEnabled()) return obj;
35
36
 
36
37
  return new Proxy(obj, {
@@ -39,31 +40,37 @@ export function proxify(obj ,nonChainableMethodName) {
39
40
  // such as `Symbol.toStringTag`.
40
41
  // The values for which an error should be thrown can be configured using
41
42
  // the `config.proxyExcludedKeys` setting.
42
- if (typeof property === 'string' &&
43
- config.proxyExcludedKeys.indexOf(property) === -1 &&
44
- !Reflect.has(target, property)) {
43
+ if (
44
+ typeof property === 'string' &&
45
+ config.proxyExcludedKeys.indexOf(property) === -1 &&
46
+ !Reflect.has(target, property)
47
+ ) {
45
48
  // Special message for invalid property access of non-chainable methods.
46
49
  if (nonChainableMethodName) {
47
- throw Error('Invalid Chai property: ' + nonChainableMethodName + '.' +
48
- property + '. See docs for proper usage of "' +
49
- nonChainableMethodName + '".');
50
+ throw Error(
51
+ 'Invalid Chai property: ' +
52
+ nonChainableMethodName +
53
+ '.' +
54
+ property +
55
+ '. See docs for proper usage of "' +
56
+ nonChainableMethodName +
57
+ '".'
58
+ );
50
59
  }
51
60
 
52
61
  // If the property is reasonably close to an existing Chai property,
53
62
  // suggest that property to the user. Only suggest properties with a
54
63
  // distance less than 4.
55
- var suggestion = null;
56
- var suggestionDistance = 4;
57
- getProperties(target).forEach(function(prop) {
64
+ let suggestion = null;
65
+ let suggestionDistance = 4;
66
+ getProperties(target).forEach(function (prop) {
58
67
  if (
68
+ // we actually mean to check `Object.prototype` here
69
+ // eslint-disable-next-line no-prototype-builtins
59
70
  !Object.prototype.hasOwnProperty(prop) &&
60
71
  builtins.indexOf(prop) === -1
61
72
  ) {
62
- var dist = stringDistanceCapped(
63
- property,
64
- prop,
65
- suggestionDistance
66
- );
73
+ let dist = stringDistanceCapped(property, prop, suggestionDistance);
67
74
  if (dist < suggestionDistance) {
68
75
  suggestion = prop;
69
76
  suggestionDistance = dist;
@@ -72,8 +79,13 @@ export function proxify(obj ,nonChainableMethodName) {
72
79
  });
73
80
 
74
81
  if (suggestion !== null) {
75
- throw Error('Invalid Chai property: ' + property +
76
- '. Did you mean "' + suggestion + '"?');
82
+ throw Error(
83
+ 'Invalid Chai property: ' +
84
+ property +
85
+ '. Did you mean "' +
86
+ suggestion +
87
+ '"?'
88
+ );
77
89
  } else {
78
90
  throw Error('Invalid Chai property: ' + property);
79
91
  }
@@ -115,21 +127,21 @@ function stringDistanceCapped(strA, strB, cap) {
115
127
  return cap;
116
128
  }
117
129
 
118
- var memo = [];
130
+ let memo = [];
119
131
  // `memo` is a two-dimensional array containing distances.
120
132
  // memo[i][j] is the distance between strA.slice(0, i) and
121
133
  // strB.slice(0, j).
122
- for (var i = 0; i <= strA.length; i++) {
134
+ for (let i = 0; i <= strA.length; i++) {
123
135
  memo[i] = Array(strB.length + 1).fill(0);
124
136
  memo[i][0] = i;
125
137
  }
126
- for (var j = 0; j < strB.length; j++) {
138
+ for (let j = 0; j < strB.length; j++) {
127
139
  memo[0][j] = j;
128
140
  }
129
141
 
130
- for (var i = 1; i <= strA.length; i++) {
131
- var ch = strA.charCodeAt(i - 1);
132
- for (var j = 1; j <= strB.length; j++) {
142
+ for (let i = 1; i <= strA.length; i++) {
143
+ let ch = strA.charCodeAt(i - 1);
144
+ for (let j = 1; j <= strB.length; j++) {
133
145
  if (Math.abs(i - j) >= cap) {
134
146
  memo[i][j] = cap;
135
147
  continue;
@@ -137,8 +149,7 @@ function stringDistanceCapped(strA, strB, cap) {
137
149
  memo[i][j] = Math.min(
138
150
  memo[i - 1][j] + 1,
139
151
  memo[i][j - 1] + 1,
140
- memo[i - 1][j - 1] +
141
- (ch === strB.charCodeAt(j - 1) ? 0 : 1)
152
+ memo[i - 1][j - 1] + (ch === strB.charCodeAt(j - 1) ? 0 : 1)
142
153
  );
143
154
  }
144
155
  }
@@ -18,7 +18,7 @@ import {flag} from './flag.js';
18
18
  * @name test
19
19
  */
20
20
  export function test(obj, args) {
21
- var negate = flag(obj, 'negate')
22
- , expr = args[0];
21
+ let negate = flag(obj, 'negate'),
22
+ expr = args[0];
23
23
  return negate ? !expr : expr;
24
24
  }
@@ -26,7 +26,7 @@
26
26
  * @private
27
27
  */
28
28
  export function transferFlags(assertion, object, includeAll) {
29
- var flags = assertion.__flags || (assertion.__flags = Object.create(null));
29
+ let flags = assertion.__flags || (assertion.__flags = Object.create(null));
30
30
 
31
31
  if (!object.__flags) {
32
32
  object.__flags = Object.create(null);
@@ -34,9 +34,14 @@ export function transferFlags(assertion, object, includeAll) {
34
34
 
35
35
  includeAll = arguments.length === 3 ? includeAll : true;
36
36
 
37
- for (var flag in flags) {
38
- if (includeAll ||
39
- (flag !== 'object' && flag !== 'ssfi' && flag !== 'lockSsfi' && flag != 'message')) {
37
+ for (let flag in flags) {
38
+ if (
39
+ includeAll ||
40
+ (flag !== 'object' &&
41
+ flag !== 'ssfi' &&
42
+ flag !== 'lockSsfi' &&
43
+ flag != 'message')
44
+ ) {
40
45
  object.__flags[flag] = flags[flag];
41
46
  }
42
47
  }
@@ -6,7 +6,7 @@ export function type(obj) {
6
6
  if (typeof obj === 'undefined') {
7
7
  return 'undefined';
8
8
  }
9
-
9
+
10
10
  if (obj === null) {
11
11
  return 'null';
12
12
  }
package/lib/chai.js CHANGED
@@ -29,6 +29,7 @@ export {AssertionError};
29
29
  */
30
30
  export function use(fn) {
31
31
  const exports = {
32
+ use,
32
33
  AssertionError,
33
34
  util,
34
35
  config,
@@ -44,7 +45,7 @@ export function use(fn) {
44
45
  }
45
46
 
46
47
  return exports;
47
- };
48
+ }
48
49
 
49
50
  // Utility Functions
50
51
  export {util};
package/package.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "Veselin Todorov <hi@vesln.com>",
19
19
  "John Firebaugh <john.firebaugh@gmail.com>"
20
20
  ],
21
- "version": "5.1.2",
21
+ "version": "5.2.1",
22
22
  "repository": {
23
23
  "type": "git",
24
24
  "url": "https://github.com/chaijs/chai"
@@ -31,15 +31,19 @@
31
31
  "prebuild": "npm run clean",
32
32
  "build": "npm run build:esm",
33
33
  "build:esm": "esbuild --bundle --format=esm --keep-names --outfile=chai.js index.js",
34
+ "format": "prettier --write lib",
34
35
  "pretest": "npm run lint && npm run build",
35
36
  "test": "npm run test-node && npm run test-chrome",
36
- "test-node": "mocha --require ./test/bootstrap/index.js --reporter dot test/*.js",
37
+ "test-node": "c8 --99 --check-coverage mocha --require ./test/bootstrap/index.js test/*.js",
37
38
  "test-chrome": "web-test-runner --playwright",
38
- "lint": "eslint lib/",
39
- "clean": "rm -f chai.js coverage"
39
+ "lint": "npm run lint:js && npm run lint:format",
40
+ "lint:js": "eslint lib/",
41
+ "lint:format": "prettier --check lib",
42
+ "lint:types": "tsc",
43
+ "clean": "rm -rf chai.js coverage/"
40
44
  },
41
45
  "engines": {
42
- "node": ">=12"
46
+ "node": ">=18"
43
47
  },
44
48
  "dependencies": {
45
49
  "assertion-error": "^2.0.1",
@@ -49,13 +53,17 @@
49
53
  "pathval": "^2.0.0"
50
54
  },
51
55
  "devDependencies": {
56
+ "@eslint/js": "^9.17.0",
52
57
  "@rollup/plugin-commonjs": "^25.0.7",
53
58
  "@web/dev-server-rollup": "^0.6.1",
54
59
  "@web/test-runner": "^0.18.0",
55
60
  "@web/test-runner-playwright": "^0.11.0",
56
- "esbuild": "^0.19.10",
61
+ "c8": "^10.1.3",
62
+ "esbuild": "^0.25.0",
57
63
  "eslint": "^8.56.0",
58
64
  "eslint-plugin-jsdoc": "^48.0.4",
59
- "mocha": "^10.2.0"
65
+ "mocha": "^10.2.0",
66
+ "prettier": "^3.4.2",
67
+ "typescript": "~5.7.3"
60
68
  }
61
69
  }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "nodenext",
5
+ "moduleResolution": "nodenext",
6
+ "types": [],
7
+ "checkJs": true,
8
+ "noEmit": true,
9
+ "isolatedModules": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "strict": true,
12
+ "noUnusedLocals": true,
13
+ "noUnusedParameters": true
14
+ },
15
+ "include": [
16
+ "lib/**/*.js"
17
+ ]
18
+ }
@@ -1,25 +0,0 @@
1
- /*!
2
- * Chai - getEnumerableProperties utility
3
- * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
4
- * MIT Licensed
5
- */
6
-
7
- /**
8
- * ### .getEnumerableProperties(object)
9
- *
10
- * This allows the retrieval of enumerable property names of an object,
11
- * inherited or not.
12
- *
13
- * @param {object} object
14
- * @returns {Array}
15
- * @namespace Utils
16
- * @name getEnumerableProperties
17
- * @public
18
- */
19
- module.exports = function getEnumerableProperties(object) {
20
- var result = [];
21
- for (var name in object) {
22
- result.push(name);
23
- }
24
- return result;
25
- };
@@ -1,3 +0,0 @@
1
- const {assert} = require('./chai.cjs');
2
-
3
- globalThis.assert = assert;
@@ -1,3 +0,0 @@
1
- const {expect} = require('./chai.cjs');
2
-
3
- globalThis.expect = expect;
@@ -1,3 +0,0 @@
1
- const {should} = require('./chai.cjs');
2
-
3
- globalThis.should = should();