Showing preview only (869K chars total). Download the full file or copy to clipboard to get everything.
Repository: chaijs/chai
Branch: main
Commit: e87eefa9873f
Files: 75
Total size: 836.6 KB
Directory structure:
gitextract_qa5zm9sp/
├── .github/
│ ├── FUNDING.yml
│ ├── renovate.json
│ └── workflows/
│ ├── browsers.yml
│ ├── node.js.yml
│ └── npm-publish.yml
├── .gitignore
├── .mailmap
├── .prettierrc.json
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── History.md
├── LICENSE
├── README.md
├── ReleaseNotes.md
├── eslint.config.js
├── lib/
│ ├── chai/
│ │ ├── assertion.js
│ │ ├── config.js
│ │ ├── core/
│ │ │ └── assertions.js
│ │ ├── interface/
│ │ │ ├── assert.js
│ │ │ ├── expect.js
│ │ │ └── should.js
│ │ └── utils/
│ │ ├── addChainableMethod.js
│ │ ├── addLengthGuard.js
│ │ ├── addMethod.js
│ │ ├── addProperty.js
│ │ ├── compareByInspect.js
│ │ ├── events.js
│ │ ├── expectTypes.js
│ │ ├── flag.js
│ │ ├── getActual.js
│ │ ├── getMessage.js
│ │ ├── getOperator.js
│ │ ├── getOwnEnumerableProperties.js
│ │ ├── getOwnEnumerablePropertySymbols.js
│ │ ├── getProperties.js
│ │ ├── index.js
│ │ ├── inspect.js
│ │ ├── isNaN.js
│ │ ├── isProxyEnabled.js
│ │ ├── objDisplay.js
│ │ ├── overwriteChainableMethod.js
│ │ ├── overwriteMethod.js
│ │ ├── overwriteProperty.js
│ │ ├── proxify.js
│ │ ├── test.js
│ │ ├── transferFlags.js
│ │ └── type-detect.js
│ └── chai.js
├── package.json
├── register-assert.js
├── register-expect.js
├── register-should.js
├── test/
│ ├── assert.js
│ ├── auth/
│ │ └── .gitkeep
│ ├── bootstrap/
│ │ └── index.js
│ ├── configuration.js
│ ├── display/
│ │ ├── errors.js
│ │ └── message.js
│ ├── expect.js
│ ├── globalErr.js
│ ├── globalShould.js
│ ├── plugins.js
│ ├── should.js
│ ├── subset.js
│ ├── type-detect/
│ │ ├── deno-test.ts
│ │ ├── dom.js
│ │ ├── index.js
│ │ ├── new-ecmascript-types.js
│ │ ├── node.js
│ │ └── tostringtag-extras.js
│ ├── utilities.js
│ └── virtual-machines.js
├── tsconfig.json
└── web-test-runner.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
open_collective: chaijs
================================================
FILE: .github/renovate.json
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"baseBranchPatterns": ["main"],
"extends": ["config:recommended"],
"packageRules": [
{
"groupName": "dependencies",
"matchUpdateTypes": ["minor", "patch"],
"schedule": ["before 9am on monday"]
}
]
}
================================================
FILE: .github/workflows/browsers.yml
================================================
# This workflow will do a clean install of node dependencies, build the source
# code and run tests across different versions of browsers
name: Browsers CI
on:
push:
branches: [ main, 4.x.x ]
pull_request:
branches: [ main, 4.x.x ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
browser-name:
- chromium
- firefox
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: ${{ matrix.browser-name }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build --if-present
- run: npm run test-chrome -- --browsers ${{ matrix.browser-name }}
================================================
FILE: .github/workflows/node.js.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ main, 4.x.x ]
pull_request:
branches: [ main, 4.x.x ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
- run: npm ci
- run: npm run lint
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
- 18 # to be removed 2025-04-30
- 20 # to be removed 2026-04-30
- latest
# See supported Node.js release schedule at https://github.com/nodejs/release#release-schedule
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm run test-node
================================================
FILE: .github/workflows/npm-publish.yml
================================================
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
name: Publish to npm
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build --if-present
- run: npm test
publish-npm:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24.x
registry-url: "https://registry.npmjs.org"
cache: "npm"
- run: npm ci
- run: npm run build --if-present
- run: npm version ${TAG_NAME} --git-tag-version=false
env:
TAG_NAME: ${{ github.ref_name }}
- run: npm publish --provenance --access public
================================================
FILE: .gitignore
================================================
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
build
components
node_modules
npm-debug.log
coverage
test/auth/*
!test/auth/.gitkeep
/index.js
================================================
FILE: .mailmap
================================================
Domenic Denicola <domenic@domenicdenicola.com>
================================================
FILE: .prettierrc.json
================================================
{
"bracketSpacing": false,
"printWidth": 80,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false,
"arrowParens": "always"
}
================================================
FILE: CODEOWNERS
================================================
* @chaijs/chai
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Code of Conduct
> Read in: [Español](http://contributor-covenant.org/version/1/3/0/es/) |
[Français](http://contributor-covenant.org/version/1/3/0/fr/) |
[Italiano](http://contributor-covenant.org/version/1/3/0/it/) |
[Magyar](http://contributor-covenant.org/version/1/3/0/hu/) |
[Polskie](http://contributor-covenant.org/version/1/3/0/pl/) |
[Português](http://contributor-covenant.org/version/1/3/0/pt/) |
[Português do Brasil](http://contributor-covenant.org/version/1/3/0/pt_br/)
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at chaijs@keithcirkel.co.uk. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/
================================================
FILE: CONTRIBUTING.md
================================================
# Chai Contribution Guidelines
We like to encourage you to contribute to the Chai.js repository. This should be as easy as possible for you but there are a few things to consider when contributing. The following guidelines for contribution should be followed if you want to submit a pull request or open an issue.
Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features.
#### Table of Contents
- [TLDR;](#tldr)
- [Contributing](#contributing)
- [Bug Reports](#bugs)
- [Feature Requests](#features)
- [Pull Requests](#pull-requests)
- [Releasing](#releasing)
- [Support](#support)
- [Resources](#resources)
- [Core Contributors](#contributors)
<a name="tldr"></a>
## TLDR;
- Creating an Issue or Pull Request requires a [GitHub](http://github.com) account.
- Issue reports should be **clear**, **concise** and **reproducible**. Check to see if your issue has already been resolved in the [master]() branch or already reported in Chai's [GitHub Issue Tracker](https://github.com/chaijs/chai/issues).
- Pull Requests must adhere to strict [coding style guidelines](https://github.com/chaijs/chai/wiki/Chai-Coding-Style-Guide).
- In general, avoid submitting PRs for new Assertions without asking core contributors first. More than likely it would be better implemented as a plugin.
- Additional support is available via the [Google Group](http://groups.google.com/group/chaijs) or on irc.freenode.net#chaijs.
- **IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same license as that used by the project.
<a name="contributing"></a>
## Contributing
The issue tracker is the preferred channel for [bug reports](#bugs),
[feature requests](#features) and [submitting pull
requests](#pull-requests), but please respect the following restrictions:
* Please **do not** use the issue tracker for personal support requests (use
[Google Group](https://groups.google.com/forum/#!forum/chaijs) or IRC).
* Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others
<a name="bugs"></a>
### Bug Reports
A bug is a **demonstrable problem** that is caused by the code in the repository.
Guidelines for bug reports:
1. **Use the GitHub issue search** — check if the issue has already been reported.
2. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or development branch in the repository.
3. **Isolate the problem** — create a test case to demonstrate your issue. Provide either a repo, gist, or code sample to demonstrate you problem.
A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What browser(s) and/or Node.js versions experience the problem? What would you expect to be the outcome? All these details will help people to fix any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case OR
> ```js
> expect(a).to.equal('a');
> // code sample
> ```
>
> Any other information you want to share that is relevant to the issue being reported. This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits).
<a name="features"></a>
### Feature Requests
Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible.
Furthermore, since Chai.js has a [robust plugin API](http://chaijs.com/guide/plugins/), we encourage you to publish **new Assertions** as plugins. If your feature is an enhancement to an **existing Assertion**, please propose your changes as an issue prior to opening a pull request. If the core Chai.js contributors feel your plugin would be better suited as a core assertion, they will invite you to open a PR in [chaijs/chai](https://github.com/chaijs/chai).
<a name="pull-requests"></a>
### Pull Requests
- PRs for new core-assertions are advised against.
- PRs for core-assertion bug fixes are always welcome.
- PRs for enhancing the interfaces are always welcome.
- PRs that increase test coverage are always welcome.
- PRs are scrutinized for coding-style.
Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope and avoid containing unrelated commits.
**Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project.
Please adhere to the coding conventions used throughout a project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). Please review the [Chai.js Coding Style Guide](https://github.com/chaijs/chai/wiki/Chai-Coding-Style-Guide).
Follow this process if you'd like your work considered for inclusion in the project:
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes:
```bash
# Clone your fork of the repo into the current directory
git clone https://github.com/<your-username>/<repo-name>
# Navigate to the newly cloned directory
cd <repo-name>
# Assign the original repo to a remote called "upstream"
git remote add upstream https://github.com/<upstream-owner>/<repo-name>
```
2. If you cloned a while ago, get the latest changes from upstream:
```bash
git checkout <dev-branch>
git pull upstream <dev-branch>
```
3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix:
```bash
git checkout -b <topic-branch-name>
```
4. Commit your changes in logical chunks. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public.
5. Run you code to make sure it works. If you're still having problems please try to run `make clean` and then test your code again.
```bash
npm test
# when finished running tests...
git checkout chai.js
```
6. Locally merge (or rebase) the upstream development branch into your topic branch:
```bash
git pull [--rebase] upstream <dev-branch>
```
7. Push your topic branch up to your fork:
```bash
git push origin <topic-branch-name>
```
8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description.
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same license as that used by the project.
<a name="releasing"></a>
## Releasing
Releases can be **prepared** by anyone with access to the code.
Simply run `make release-major`, `make release-minor`, or `make-release-patch`
and it will automatically do the following:
- Build chai.js
- Bump the version numbers across the project
- Make a commit within git
All you need to do is push the commit up and make a pull request, one of the core contributors will merge it and publish a release.
### Publishing a Release
Anyone who is a core contributor (see the [Core Contributors Heading in the Readme](https://github.com/chaijs/chai#core-contributors)) can publish a release:
1. Go to the [Releases page on Github](https://github.com/chaijs/chai/releases)
2. Hit "Draft a new release" (if you can't see this, you're not a core contributor!)
3. Write human-friendly Release Notes based on changelog.
- The release title is "x.x.x / YYYY-MM-DD" (where x.x.x is the version number)
- If breaking changes, write migration tutorial(s) and reasoning.
- Callouts for community contributions (PRs) with links to PR and contributing user.
- Callouts for other fixes made by core contributors with links to issue.
4. Hit "Save Draft" and get other core contributors to check your work, or alternatively hit "Publish release"
5. That's it!
<a name="support"></a>
## Support
<a name="resources"></a>
### Resources
For most of the documentation you are going to want to visit [ChaiJS.com](http://chaijs.com).
- [Getting Started Guide](http://chaijs.com/guide/)
- [API Reference](http://chaijs.com/api/)
- [Plugins](http://chaijs.com/plugins/)
Alternatively, the [wiki](https://github.com/chaijs/chai/wiki) might be what you are looking for.
- [Chai Coding Style Guide](https://github.com/chaijs/chai/wiki/Chai-Coding-Style-Guide)
- [Third-party Resources](https://github.com/chaijs/chai/wiki/Third-Party-Resources)
Or finally, you may find a core-contributor or like-minded developer in any of our support channels.
- IRC: irc.freenode.org #chaijs
- [Mailing List / Google Group](https://groups.google.com/forum/#!forum/chaijs)
<a name="contributors"></a>
### Core Contributors
Feel free to reach out to any of the core-contributors with you questions or concerns. We will do our best to respond in a timely manner.
- Jake Luer
- GH: [@logicalparadox](https://github.com/logicalparadox)
- TW: [@jakeluer](http://twitter.com/jakeluer)
- IRC: logicalparadox
- Veselin Todorov
- GH: [@vesln](https://github.com/vesln/)
- TW: [@vesln](http://twitter.com/vesln)
- IRC: vesln
- Keith Cirkel
- GH: [@keithamus](https://github.com/keithamus)
- TW: [@keithamus](http://twitter.com/keithamus)
- IRC: keithamus
- Lucas Fernandes da Costa
- GH: [@lucasfcosta](https://github.com/lucasfcosta)
- TW: [@lfernandescosta](https://twitter.com/lfernandescosta)
- IRC: lucasfcosta
================================================
FILE: History.md
================================================
### Note
As of 3.0.0, the History.md file has been deprecated. [Please refer to the full
commit logs available on GitHub](https://github.com/chaijs/chai/commits).
---
2.3.0 / 2015-04-26
==================
* Merge pull request #423 from ehntoo/patch-1
* Merge pull request #422 from ljharb/fix_descriptor_tests
* Fix a small bug in the .null assertion docs
* Use a regex to account for property ordering issues across engines.
* Add `make test-firefox`
* Merge pull request #417 from astorije/astorije/minimalist-typo
* Remove trailing whitespaces
* Fix super minor typo in an example
* Merge pull request #408 from ljharb/enumerableProperty
* Add `ownPropertyDescriptor` assertion.
2.2.0 / 2015-03-26
==================
* Merge pull request #405 from chaijs/deep-escape-doc-tweaks
* Tweak documentation on `.deep` flag.
* Merge pull request #402 from umireon/escaping-dot-should-be-taken
* Documentation of escaping in `.deep` flag.
* take regular expression apart
* Feature: backslash-escaping in `.deep.property`
* Escaping dot should be taken in deep property
2.1.2 / 2015-03-15
==================
* Merge pull request #396 from chaijs/add-keith-cirkel-contributing-md
* Add Keith Cirkel to CONTRIBUTING.md
* Merge pull request #395 from cjqed/386-assert-operator-no-eval
* No longer using eval on assert operator #386
* Merge pull request #389 from chaijs/update-git-summary
* Update `git summary` in README
2.1.1 / 2015-03-04
==================
* Merge pull request #385 from eldritch-fossicker/master
* updates to reflect code style preference from @keithamus
* fix indexing into array with deep propery
* Merge pull request #382 from astorije/patch-2
* Merge pull request #383 from gurdiga/config-doc-wording-improvement
* config.truncateThreshold docs: simpler wording
* Add missing docstring for showDiff argument of assert
* Merge pull request #381 from astorije/patch-1
* Add a minor precision that empty asserts on strings too.
* Merge pull request #379 from dcneiner/should-primitive-fix
* Primitives now use valueOf in shouldGetter
2.1.0 / 2015-02-23
==================
* Merge pull request #374 from jmm/v2.0.1
* Increment version to 2.0.1.
* Merge pull request #365 from chaijs/fix-travis
* Fix travis.yml deploy
* Merge pull request #356 from Soviut/master
* documented fail methods for expect and should interfaces
* fail method added directly to expect
2.0.0 / 2015-02-09
==================
* Merge pull request #361 from gregglind/b265-keys-object
* fix #359. Add `.keys(object)`
* Merge pull request #359 from gregglind/b359-unexpected-keys-sort
* Fix #359 keys() sorts input unexpectedly
* contrib: publish release strategy and travis npm creds #337
* Merge pull request #357 from danilovaz/master
* Update copyright date
* Merge pull request #349 from toastynerd/add-which-chain-method
* add the which chain method as per issue #347
* Merge pull request #333 from cmpolis/change-assertions
* more `by` cleanup
* cleaned out `.by` for #333
* Merge pull request #335 from DingoEatingFuzz/expose-util
* Expose chai util through the chai object
* cleanup (per notes on pr #333)
* updated `change` to work w/ non-number values + tests
* Merge pull request #334 from hurrymaplelad/patch-1
* Typo, the flag is called 'contains' with an 's'
* updated assertion interface with `change` (#330)
* added `change`,`increase`,`decrease` assertions (#330)
* assert tests for `change`,`increase`,`decrease`
* expect/should tests for `change`,`increase`,`decrease`
* Merge pull request #328 from lo1tuma/issue-327
* Add includes and contains alias (fixes #327)
* Merge pull request #325 from chasenlehara/overwriteChainableMethodDocs
* Fix docs for overwriteChainableMethod parameters
* Merge pull request #317 from jasonkarns/patch-2
* Merge pull request #318 from jasonkarns/patch-3
* Merge pull request #316 from jasonkarns/patch-1
* typos in docs
* minor docs typo
* update docs: getAllFlags -> transferFlags
* Merge pull request #313 from cjqed/254-expect-any-all
* Added the all and any flags for keys assertion, with all being the default behavior
* Merge pull request #312 from cjqed/291-assert-same-deep-members
* Changed public comment of sameDeepMemebers to be more clear
* Fixes issue #291, adds assert.sameDeepMembers
* Merge pull request #311 from cjqed/305-above-below-on-assert
* Merge pull request #308 from prodatakey/hasproperty
* Issue #305 fixed, added assert.isAbove and assert.isBelow
* Fix typo
* More unit tests for new utility functions
* Refactor common functionality, document, test
* Refactor if statement out
* Small unit test fix
* Handle array indexing terminating paths
* Merge pull request #309 from ericdouglas/iterableEqual-couting-once
* couting variables just once
* Fix properties with `undefined` value pass property assertion
* Merge pull request #306 from chaijs/revert-297-noopchainfunc
* Revert "Allows writing lint-friendly tests"
1.10.0 / 2014-11-10
==================
* Merge pull request #297 from prodatakey/noopchainfunc
* Merge pull request #300 from julienw/299-fix-getMessage-test
* Fix #299: the test is defining global variables
* Add a couple more unit tests
* Add unit tests for chained terminating property asserts
* Revise documentation wording
* Add docs for function style NOOP asserts
* Make the NOOP function a shared constant
* Merge pull request #298 from dasilvacontin/negativeZeroLogging
* why not more assertions
* added test for inspecting `-0`
* a more readable/simple condition statement, as pointed out by @keithamus
* added check for logging negative zero
* Change test to not trigger argument bug
* Allows writing lint-friendly tests
* readme: update contributors for 1.9.2
1.9.2 / 2014-09-29
==================
* Merge pull request #268 from charlierudolph/cr-lazyMessages
* Merge pull request #269 from charlierudolph/cr-codeCleanup
* Merge pull request #277 from charlierudolph/fix-doc
* Merge pull request #279 from mohayonao/fix-closeTo
* Merge pull request #292 from boneskull/mocha
* resolves #255: upgrade mocha
* Merge pull request #289 from charlierudolph/cr-dryUpCode
* Dry up code
* Merge pull request #275 from DrRataplan/master
* assert: .closeTo() verify value's type before assertion
* Rewrite pretty-printing HTML elements to prevent throwing internal errors Fixes errors occuring when using a non-native DOM implementation
* Fix assert documentation
* Remove unused argument
* Allow messages to be functions
* Merge pull request #267 from shinnn/master
* Use SVG badge
* Merge pull request #264 from cjthompson/keys_diff
* Show diff for keys assertion
1.9.1 / 2014-03-19
==================
* deps update
* util: [getActual] select actual logic now allows undefined for actual. Closes #183
* docs: [config] make public, express param type
* Merge pull request #251 from romario333/threshold3
* Fix issue #166 - configurable threshold in objDisplay.
* Move configuration options to config.js.
* Merge pull request #233 from Empeeric/master
* Merge pull request #244 from leider/fix_for_contains
* Merge pull request #247 from didoarellano/typo-fixes
* Fix typos
* Merge pull request #245 from lfac-pt/patch-1
* Update `exports.version` to 1.9.0
* aborting loop on finding
* declaring variable only once
* additional test finds incomplete implementation
* simplified code
* fixing #239 (without changing chai.js)
* ssfi as it should be
* Merge pull request #228 from duncanbeevers/deep_members
* Deep equality check for collection membership
1.9.0 / 2014-01-29
==================
* docs: add contributing.md #238
* assert: .throws() returns thrown error. Closes #185
* Merge pull request #232 from laconbass/assert-throws
* assert: .fail() parameter mismatch. Closes #206
* Merge branch 'karma-fixes'
* Add karma phantomjs launcher
* Use latest karma and sauce launcher
* Karma tweaks
* Merge pull request #230 from jkroso/include
* Merge pull request #237 from chaijs/coverage
* Add coverage to npmignore
* Remove lib-cov from test-travisci dependents
* Remove the not longer needed lcov reporter
* Test coverage with istanbul
* Remove jscoverage
* Remove coveralls
* Merge pull request #226 from duncanbeevers/add_has
* Avoid error instantiation if possible on assert.throws
* Merge pull request #231 from duncanbeevers/update_copyright_year
* Update Copyright notices to 2014
* handle negation correctly
* add failing test case
* support `{a:1,b:2}.should.include({a:1})`
* Merge pull request #224 from vbardales/master
* Add `has` to language chains
* Merge pull request #219 from demands/overwrite_chainable
* return error on throw method to chain on error properties, possibly different from message
* util: store chainable behavior in a __methods object on ctx
* util: code style fix
* util: add overwriteChainableMethod utility (for #215)
* Merge pull request #217 from demands/test_cleanup
* test: make it possible to run utilities tests with --watch
* makefile: change location of karma-runner bin script
* Merge pull request #202 from andreineculau/patch-2
* test: add tests for throwing custom errors
* Merge pull request #201 from andreineculau/patch-1
* test: updated for the new assertion errors
* core: improve message for assertion errors (throw assertion)
1.8.1 / 2013-10-10
==================
* pkg: update deep-eql version
1.8.0 / 2013-09-18
==================
* test: [sauce] add a few more browsers
* Merge branch 'refactor/deep-equal'
* util: remove embedded deep equal utility
* util: replace embedded deep equal with external module
* Merge branch 'feature/karma'
* docs: add sauce badge to readme [ci skip]
* test: [sauce] use karma@canary to prevent timeouts
* travis: only run on node 0.10
* test: [karma] use karma phantomjs runner
* Merge pull request #181 from tricknotes/fix-highlight
* Fix highlight for example code
1.7.2 / 2013-06-27
==================
* coverage: add coveralls badge
* test: [coveralls] add coveralls api integration. testing travis-ci integration
* Merge branch 'master' of github.com:chaijs/chai
* Merge branch 'feature/bower'
* Merge pull request #180 from tricknotes/modify-method-title
* Merge pull request #179 from tricknotes/highlight-code-example
* Modify method title to include argument name
* Fix to highlight code example
* bower: granular ignores
1.7.1 / 2013-06-24
==================
* Merge branch 'feature/bower'. #175
* bower: add json file
* build: browser
1.7.0 / 2013-06-17
==================
* error: remove internal assertion error constructor
* core: [assertion-error] replace internal assertion error with dep
* deps: add chaijs/assertion-error@1.0.0
* docs: fix typo in source file. #174
* Merge pull request #174 from piecioshka/master
* typo
* Merge branch 'master' of github.com:chaijs/chai
* pkg: lock mocha/mocha-phantomjs versions (for now)
* Merge pull request #173 from chaijs/inspect-fix
* Fix `utils.inspect` with custom object-returning inspect()s.
* Merge pull request #171 from Bartvds/master
* replaced tabs with 2 spaces
* added assert.notOk()
* Merge pull request #169 from katsgeorgeek/topics/master
* Fix comparison objects.
1.6.1 / 2013-06-05
==================
* Merge pull request #168 from katsgeorgeek/topics/master
* Add test for different RegExp flags.
* Add test for regexp comparison.
* Downgrade mocha version for fix running Phantom tests.
* Fix comparison equality of two regexps.
* Merge pull request #161 from brandonpayton/master
* Fix documented name for assert interfaces isDefined method
1.6.0 / 2013-04-29
==================
* build: browser
* assert: [(not)include] throw on incompatible haystack. Closes #142
* assert: [notInclude] add assert.notInclude. Closes #158
* browser build
* makefile: force browser build on browser-test
* makefile: use component for browser build
* core: [assertions] remove extraneous comments
* Merge branch 'master' of github.com:chaijs/chai
* test: [assert] deep equal ordering
* Merge pull request #153 from NickHeiner/array-assertions
* giving members a no-flag assertion
* Code review comments - changing syntax
* Code review comments
* Adding members and memberEquals assertions for checking for subsets and set equality. Implements chaijs/chai#148.
* Merge pull request #140 from RubenVerborgh/function-prototype
* Restore the `call` and `apply` methods of Function when adding a chainable method.
* readme: 2013
* notes: migration notes for deep equal changes
* test: for ever err() there must be a passing version
1.5.0 / 2013-02-03
==================
* docs: add Release Notes for non-gitlog summary of changes.
* lib: update copyright to 2013
* Merge branch 'refactor/travis'
* makefile: remove test-component for full test run
* pkg: script test now runs make test so travis will test browser
* browser: build
* tests: refactor some tests to support new objDisplay output
* test: [bootstrap] normalize boostrap across all test scenarios
* assertions: refactor some assertions to use objDisplay instead of inspect
* util: [objDisplay] normalize output of functions
* makefile: refactor for full build scenarios
* component: fix build bug where missing util:type file
* assertions: [throw] code cleanup
* Merge branch 'refactor/typeDetection'
* browser: build
* makefile: chai.js is .PHONY so it builds every time
* test: [expect] add arguments type detection test
* core/assertions: [type] (a/an) refactor to use type detection utility
* util: add cross-browser type detection utility
* Merge branch 'feature/component'
* browser: build
* component: add component.json file
* makefile: refactor for fine grain control of testing scenarios
* test: add mochaPhantomJS support and component test file
* deps: add component and mocha-phantomjs for browser testing
* ignore: update ignore files for component support
* travis: run for all branches
* Merge branch 'feature/showDiff'
* test: [Assertion] configruable showDiff flag. Closes #132
* lib: [Assertion] add configurable showDiff flag. #132
* Merge branch 'feature/saucelabs'
* Merge branch 'master' into feature/saucelabs
* browser: build
* support: add mocha cloud runner, client, and html test page
* test: [saucelabs] add auth placeholder
* deps: add mocha-cloud
* Merge pull request #136 from whatthejeff/message_fix
* Merge pull request #138 from timnew/master
* Fix issue #137, test message existence by using message!=null rather than using message
* Fixed backwards negation messages.
* Merge pull request #133 from RubenVerborgh/throw
* Functions throwing strings can reliably be tested.
* Merge pull request #131 from RubenVerborgh/proto
* Cache whether __proto__ is supported.
* Use __proto__ if available.
* Determine the property names to exclude beforehand.
* Merge pull request #126 from RubenVerborgh/eqls
* Add alias eqls for eql.
* Use inherited enumerable properties in deep equality comparison.
* Show inherited properties when inspecting an object.
* Add new getProperties and getEnumerableProperties utils.
* showDiff: force true for equal and eql
1.4.2 / 2012-12-21
==================
* browser build: (object diff support when used with mocha) #106
* test: [display] array test for mocha object diff
* browser: no longer need different AssertionError constructor
1.4.1 / 2012-12-21
==================
* showDiff: force diff for equal and eql. #106
* test: [expect] type null. #122
* Merge pull request #115 from eshao/fix-assert-Throw
* FIX: assert.Throw checks error type/message
* TST: assert.Throw should check error type/message
1.4.0 / 2012-11-29
==================
* pre-release browser build
* clean up index.js to not check for cov, revert package.json to use index.js
* convert tests to use new bootstrap
* refactor testing bootstrap
* use spaces (not tabs). Clean up #114
* Merge pull request #114 from trantorLiu/master
* Add most() (alias: lte) and least() (alias: gte) to the API with new chainers "at" and "of".
* Change `main` to ./lib/chai. Fixes #28.
* Merge pull request #104 from connec/deep_equals_circular_references_
* Merge pull request #109 from nnarhinen/patch-1
* Check for 'actual' type
* Added support for circular references when checking deep (in)equality.
1.3.0 / 2012-10-01
==================
* browser build w/ folio >= 0.3.4. Closes #99
* add back buffer test for deep equal
* do not write flags to assertion.prototype
* remove buffer test from expect
* browser build
* improve documentation of custom error messages
* Merge branch 'master' of git://github.com/Liffft/chai into Liffft-master
* browser build
* improved buffer deep equal checking
* mocha is npm test command
* Cleaning up the js style…
* expect tests now include message pass-through
* packaging up browser-side changes…
* Increasing Throws error message verbosity
* Should syntax: piping message through
* Make globalShould test work in browser too.
* Add a setter for `Object.prototype.should`. Closes #86.
1.2.0 / 2012-08-07
==================
* Merge branch 'feature/errmsg'
* browser build
* comment updates for utilities
* tweak objDislay to only kick in if object inspection is too long
* Merge branch 'master' into feature/errmsg
* add display sample for error message refactor
* first draft of error message refactor. #93
* add `closeTo` assertion to `assert` interface. Closes #89.
* update folio build for better require.js handling. Closes #85
* Merge pull request #92 from paulmillr/topics/add-dom-checks
* Add check for DOM objects.
* browser build
* Merge branch 'master' of github.com:chaijs/chai
* bug - getActual not defaulting to assertion subject
* Merge pull request #88 from pwnall/master
* Don't inspect() assertion arguments if the assertion passes.
1.1.1 / 2012-07-09
==================
* improve commonjs support on browser build
* Merge pull request #83 from tkazec/equals
* Document .equals
* Add .equals as an alias of .equal
* remove unused browser prefix/suffix
* Merge branch 'feature/folio-build'
* browser build
* using folio to compile
* clean up makefile
* early folio 0.3.x support
1.1.0 / 2012-06-26
==================
* browser build
* Disable "Assertion.includeStack is false" test in IE.
* Use `utils.getName` for all function inspections.
* Merge pull request #80 from kilianc/closeTo
* fixes #79
* browser build
* expand docs to indicate change of subject for chaining. Closes #78
* add `that` chain noop
* Merge branch 'bug/74'
* comments on how to property use `length` as chain. Closes #74
* tests for length as chainable property. #74
* add support for `length` as chainable prop/method.
* Merge branch 'bug/77'
* tests for getPathValue when working with nested arrays. Closes #77
* add getPathValue support for nested arrays
* browser build
* fix bug for missing browser utils
* compile tool aware of new folder layout
* Merge branch 'refactor/1dot1'
* move core assertions to own file and refactor all using utils
* rearrange folder structure
1.0.4 / 2012-06-03
==================
* Merge pull request #68 from fizker/itself
* Added itself chain.
* simplify error inspections for cross browser compatibility
* fix safari `addChainableMethod` errors. Closes #69
1.0.3 / 2012-05-27
==================
* Point Travis badge to the right place.
* Make error message for eql/deep.equal more clear.
* Fix .not.deep.equal.
* contributors list
1.0.2 / 2012-05-26
==================
* Merge pull request #67 from chaijs/chaining-and-flags
* Browser build.
* Use `addChainableMethod` to get away from `__proto__` manipulation.
* New `addChainableMethod` utility.
* Replace `getAllFlags` with `transferFlags` utility.
* browser build
* test - get all flags
* utility - get all flags
* Add .mailmap to .npmignore.
* Add a .mailmap file to fix my name in shortlogs.
1.0.1 / 2012-05-18
==================
* browser build
* Fixing "an" vs. "a" grammar in type assertions.
* Uniformize `assert` interface inline docs.
* Don't use `instanceof` for `assert.isArray`.
* Add `deep` flag for equality and property value.
* Merge pull request #64 from chaijs/assertion-docs
* Uniformize assertion inline docs.
* Add npm-debug.log to .gitignore.
* no reserved words as actuals. #62
1.0.0 / 2012-05-15
==================
* readme cleanup
* browser build
* utility comments
* removed docs
* update to package.json
* docs build
* comments / docs updates
* plugins app cleanup
* Merge pull request #61 from joliss/doc
* Fix and improve documentation of assert.equal and friends
* browser build
* doc checkpoint - texture
* Update chai-jquery link
* Use defined return value of Assertion extension functions
* Update utility docs
1.0.0-rc3 / 2012-05-09
==================
* Merge branch 'feature/rc3'
* docs update
* browser build
* assert test conformity for minor refactor api
* assert minor refactor
* update util tests for new add/overwrite prop/method format
* added chai.Assertion.add/overwrite prop/method for plugin toolbox
* add/overwrite prop/method don't make assumptions about context
* doc test suite
* docs don't need coverage
* refactor all simple chains into one forEach loop, for clean documentation
* updated npm ignore
* remove old docs
* docs checkpoint - guide styled
* Merge pull request #59 from joliss/doc
* Document how to run the test suite
* don't need to rebuild docs to view
* dep update
* docs checkpoint - api section
* comment updates for docs
* new doc site checkpoint - plugin directory!
* Merge pull request #57 from kossnocorp/patch-1
* Fix typo: devDependancies → devDependencies
* Using message flag in `getMessage` util instead of old `msg` property.
* Adding self to package.json contributors.
* `getMessage` shouldn't choke on null/omitted messages.
* `return this` not necessary in example.
* `return this` not necessary in example.
* Sinon–Chai has a dash
* updated plugins list for docs
1.0.0-rc2 / 2012-05-06
==================
* Merge branch 'feature/test-cov'
* browser build
* missing assert tests for ownProperty
* appropriate assert equivalent for expect.to.have.property(key, val)
* reset AssertionError to include full stack
* test for plugin utilities
* overwrite Property and Method now ensure chain
* version notes in readme
1.0.0-rc1 / 2012-05-04
==================
* browser build (rc1)
* assert match/notMatch tests
* assert interface - notMatch, ownProperty, notOwnProperty, ownPropertyVal, ownPropertyNotVal
* cleaner should interface export.
* added chai.Assertion.prototype._obj (getter) for quick access to object flag
* moved almostEqual / almostDeepEqual to stats plugin
* added mocha.opts
* Add test for `utils.addMethod`
* Fix a typo
* Add test for `utils.overwriteMethod`
* Fix a typo
* Browser build
* Add undefined assertion
* Add null assertion
* Fix an issue with `mocha --watch`
* travis no longer tests on node 0.4.x
* removing unnecissary carbon dep
* Merge branch 'feature/plugins-app'
* docs build
* templates for docs express app for plugin directory
* express app for plugin and static serving
* added web server deps
* Merge pull request #54 from josher19/master
* Remove old test.assert code
* Use util.inspect instead of inspect for deepAlmostEqual and almostEqual
* browser build
* Added almostEqual and deepAlmostEqual to assert test suite.
* bug - context determinants for utils
* dec=0 means rounding, so assert.deepAlmostEqual({pi: 3.1416}, {pi: 3}, 0) is true
* wrong travis link
* readme updates for version information
* travis tests 0.5.x branch as well
* [bug] util `addProperty` not correctly exporting
* read me version notes
* browser build 1.0.0alpha1
* not using reserved words in internal assertions. #52
* version tick
* clean up redundant tests
* Merge branch 'refs/heads/0.6.x'
* update version tag in package 1.0.0alpha1
* browser build
* added utility tests to browser specs
* beginning utility testing
* updated utility comments
* utility - overwriteMethod
* utility - overwriteProperty
* utility - addMethod
* utility - addProperty
* missing ;
* contributors list update
* Merge branch 'refs/heads/0.6.x-docs' into 0.6.x
* Added guide link to docs. WIP
* Include/contain are now both properties and methods
* Add an alias annotation
* Remove usless function wrapper
* Fix a typo
* A/an are now both properties and methods
* [docs] new site homepage layout / color checkpoint
* Ignore IE-specific error properties.
* Fixing order of error message test.
* New cross-browser `getName` util.
* Fixing up `AssertionError` inheritance.
* backup docs
* Add doctypes
* [bug] was still using `constructor.name` in `throw` assertion
* [bug] flag Object.create(null) instead of new Object
* [test] browser build
* [refactor] all usage of Assertion.prototype.assert now uses template tags and flags
* [refactor] remove Assertion.prototype.inspect for testable object inspection
* [refactor] object to test is now stored in flag, with ssfi and custom message
* [bug] flag util - don't return on `set`
* [docs] comments for getMessage utility
* [feature] getMessage
* [feature] testing utilities
* [refactor] flag doesn't require `call`
* Make order of source files well-defined
* Added support for throw(errorInstance).
* Use a foolproof method of grabbing an error's name.
* Removed constructor.name check from throw.
* disabled stackTrack configuration tests until api is stable again
* first version of line displayed error for node js (unstable)
* refactor core Assertion to use flag utility for negation
* added flag utility
* tests for assert interface negatives. Closed #42
* added assertion negatives that were missing. #42
* Support for expected and actual parameters in assert-style error object
* chai as promised - readme
* Added assert.fail. Closes #40
* better error message for assert.operator. Closes #39
* [refactor] Assertion#property to use getPathValue property
* added getPathValue utility helper
* removed todo about browser build
* version notes
* version bumb 0.6.0
* browser build
* [refactor] browser compile function to replace with `require('./error')' with 'require('./browser/error')'
* [feature] browser uses different error.js
* [refactor] error without chai.fail
* Assertion & interfaces use new utils helper export
* [refactor] primary export for new plugin util usage
* added util index.js helper
* added 2012 to copyright headers
* Added DeepEqual assertions
0.5.3 / 2012-04-21
==================
* Merge branch 'refs/heads/jgonera-oldbrowsers'
* browser build
* fixed reserved names for old browsers in interface/assert
* fixed reserved names for old browsers in interface/should
* fixed: chai.js no longer contains fail()
* fixed reserved names for old browsers in Assertion
* Merge pull request #49 from joliss/build-order
* Make order of source files well-defined
* Merge pull request #43 from zzen/patch-1
* Support for expected and actual parameters in assert-style error object
* chai as promised - readme
0.5.2 / 2012-03-21
==================
* browser build
* Merge branch 'feature/assert-fail'
* Added assert.fail. Closes #40
* Merge branch 'bug/operator-msg'
* better error message for assert.operator. Closes #39
* version notes
0.5.1 / 2012-03-14
==================
* chai.fail no longer exists
* Merge branch 'feature/assertdefined'
* Added asset#isDefined. Closes #37.
* dev docs update for Assertion#assert
0.5.0 / 2012-03-07
==================
* [bug] on inspect of reg on n 0.4.12
* Merge branch 'bug/33-throws'
* Merge pull request #35 from logicalparadox/empty-object
* browser build
* updated #throw docs
* Assertion#throw `should` tests updated
* Assertion#throw `expect` tests
* Should interface supports multiple throw parameters
* Update Assertion#throw to support strings and type checks.
* Add more tests for `empty` in `should`.
* Add more tests for `empty` in `expect`.
* Merge branch 'master' into empty-object
* don't switch act/exp
* Merge pull request #34 from logicalparadox/assert-operator
* Update the compiled verison.
* Add `assert.operator`.
* Notes on messages. #22
* browser build
* have been test
* below tests
* Merge branch 'feature/actexp'
* browser build
* remove unnecessary fail export
* full support for actual/expected where relevant
* Assertion.assert support expected value
* clean up error
* Update the compiled version.
* Add object & sane arguments support to `Assertion#empty`.
0.4.2 / 2012-02-28
==================
* fix for `process` not available in browser when used via browserify. Closes #28
* Merge pull request #31 from joliss/doc
* Document that "should" works in browsers other than IE
* Merge pull request #30 from logicalparadox/assert-tests
* Update the browser version of chai.
* Update `assert.doesNotThrow` test in order to check the use case when type is a string.
* Add test for `assert.ifError`.
* Falsey -> falsy.
* Full coverage for `assert.throws` and `assert.doesNotThrow`.
* Add test for `assert.doesNotThrow`.
* Add test for `assert.throws`.
* Add test for `assert.length`.
* Add test for `assert.include`.
* Add test for `assert.isBoolean`.
* Fix the implementation of `assert.isNumber`.
* Add test for `assert.isNumber`.
* Add test for `assert.isString`.
* Add test for `assert.isArray`.
* Add test for `assert.isUndefined`.
* Add test for `assert.isNotNull`.
* Fix `assert.isNotNull` implementation.
* Fix `assert.isNull` implementation.
* Add test for `assert.isNull`.
* Add test for `assert.notDeepEqual`.
* Add test for `assert.deepEqual`.
* Add test for `assert.notStrictEqual`.
* Add test for `assert.strictEqual`.
* Add test for `assert.notEqual`.
0.4.1 / 2012-02-26
==================
* Merge pull request #27 from logicalparadox/type-fix
* Update the browser version.
* Add should tests for type checks.
* Add function type check test.
* Add more type checks tests.
* Add test for `new Number` type check.
* Fix type of actual checks.
0.4.0 / 2012-02-25
==================
* docs and readme for upcoming 0.4.0
* docs generated
* putting coverage and tests for docs in docs/out/support
* make docs
* makefile copy necessary resources for tests in docs
* rename configuration test
* Merge pull request #21 from logicalparadox/close-to
* Update the browser version.
* Update `closeTo()` docs.
* Add `Assertion.closeTo()` method.
* Add `.closeTo()` should test.
* Add `.closeTo()` expect test.
* Merge pull request #20 from logicalparadox/satisfy
* Update the browser version.
* `..` -> `()` in `.satisfy()` should test.
* Update example for `.satisfy()`.
* Update the compiled browser version.
* Add `Assertion.satisfy()` method.
* Add `.satisfy()` should test.
* Add `.satisfy()` expect test.
* Merge pull request #19 from logicalparadox/respond-to
* Update the compiled browser version.
* Add `respondTo` Assertion.
* Add `respondTo` should test.
* Add `respondTo` expect test.
* Merge branch 'feature/coverage'
* mocha coverage support
* doc contributors
* README contributors
0.3.4 / 2012-02-23
==================
* inline comment typos for #15
* Merge branch 'refs/heads/jeffbski-configErrorStackCompat'
* includeStack documentation for all interfaces
* suite name more generic
* Update test to be compatible with browsers that do not support err.stack
* udpated compiled chai.js and added to browser tests
* Allow inclusion of stack trace for Assert error messages to be configurable
* docs sharing buttons
* sinon-chai link
* doc updates
* read me updates include plugins
0.3.3 / 2012-02-12
==================
* Merge pull request #14 from jfirebaugh/configurable_properties
* Make Assertion.prototype properties configurable
0.3.2 / 2012-02-10
==================
* codex version
* docs
* docs cleanup
0.3.1 / 2012-02-07
==================
* node 0.4.x compat
0.3.0 / 2012-02-07
==================
* Merge branch 'feature/03x'
* browser build
* remove html/json/headers testign
* regex error.message testing
* tests for using plugins
* Merge pull request #11 from domenic/master
* Make `chai.use` a no-op if the function has already been used.
0.2.4 / 2012-02-02
==================
* added in past tense switch for `been`
0.2.3 / 2012-02-01
==================
* try that again
0.2.2 / 2012-02-01
==================
* added `been` (past of `be`) alias
0.2.1 / 2012-01-29
==================
* added Throw, with a capital T, as an alias to `throw` (#7)
0.2.0 / 2012-01-26
==================
* update gitignore for vim *.swp
* Merge branch 'feature/plugins'
* browser build
* interfaces now work with use
* simple .use function. See #9.
* readme notice on browser compat
0.1.7 / 2012-01-25
==================
* added assert tests to browser test runner
* browser update
* `should` interface patch for primitives support in FF
* fix isObject() Thanks @milewise
* travis only on branch `master`
* add instanceof alias `instanceOf`. #6
* some tests for assert module
0.1.6 / 2012-01-02
==================
* commenting for assert interface
* updated codex dep
0.1.5 / 2012-01-02
==================
* browser tests pass
* type in should.not.equal
* test for should (not) exist
* added should.exist and should.not.exist
* browser uses tdd
* convert tests to tdd
0.1.4 / 2011-12-26
==================
* browser lib update for new assert interface compatiblitiy
* inspect typos
* added strict equal + negatives and ifError
* interface assert had doesNotThrow
* added should tests to browser
* new expect empty tests
* should test browser compat
* Fix typo for instanceof docs. Closes #3 [ci skip]
0.1.3 / 2011-12-18
==================
* much cleaner reporting string on error.
0.1.2 / 2011-12-18
==================
* [docs] for upcoming 0.1.2
* browser version built with pre/suffix … all tests passing
* make / compile now use prefix/suffix correctly
* code clean
* prefix/suffix to wrap browser output to prevent conflicts with other `require` methods.
* Merge branch 'feature/should4xcompatibility'
* compile for browser tests.. all pass
* added header/status/html/json
* throw tests
* should.throw & should.not.throw shortcuts
* improved `throw` type detection and messaging
* contain is now `include` … keys modifier is now `contain`
* removed object() test
* removed #respondTo
* Merge branch 'bug/2'
* replaced __defineGetter__ with defineProperty for all uses
* [docs] change mp tracking code
* docs site updated with assert (TDD) interface
* updated doc comments for assert interface
0.1.1 / 2011-12-16
==================
* docs ready for upcoming 0.1.1
* readme image fixed [ci skip]
* more readme tweaks [ci skip]
* réadmet image fixed [ci skip]
* documentation
* codex locked in version 0.0.5
* more comments to assertions for docs
* assertions fully commented, browser library updated
* adding codex as doc dependancy
* prepping for docs
* assertion component completely commented for documentation
* added exist test
* var expect outside of browser if check
* added keywords to package.json
0.1.0 / 2011-12-15
==================
* failing on purpose successful .. back to normal
* testing travis failure
* assert#arguments getter
* readme typo
* updated README
* added travis and npmignore
* copyright notices … think i got them all
* moved expect interface to own file for consistency
* assert ui deepEqual
* browser tests expect (all working)
* browser version built
* chai.fail (should ui)
* expect tests browser compatible
* tests for should and expect (all pass)
* moved fail to primary export
* should compatibility testing
* within, greaterThan, object, keys,
* Aliases
* Assertion#property now correctly works with negate and undefined values
* error message language matches should
* Assertion#respondTo
* Assertion now uses inspect util
* git ignore node modules
* should is exported
* AssertionError __proto__ from Error.prototype
* add should interface for should.js compatibility
* moved eql to until folder and added inspect from (joyent/node)
* added mocha for testing
* browser build for current api
* multiple .property assertions
* added deep equal from node
0.0.2 / 2011-12-07
==================
* cleaner output on error
* improved exists detection
* package remnant artifact
* empty deep equal
* test browser build
* assertion cleanup
* client compile script
* makefile
* most of the basic assertions
* allow no parameters to assertion error
* name change
* assertion error instance
* main exports: assert() & expect()
* initialize
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Chai.js Assertion Library
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<h1 align=center>
<a href="http://chaijs.com" title="Chai Documentation">
<img alt="ChaiJS" src="http://chaijs.com/img/chai-logo.png">
</a>
<br>
chai
</h1>
<p align=center>
Chai is a BDD / TDD assertion library for <a href="http://nodejs.org">node</a> and the browser that can be delightfully paired with any javascript testing framework.
</p>
<p align=center>
<a href="https://www.npmjs.com/package/chai">
<img
alt="downloads:?"
src="https://img.shields.io/npm/dm/chai.svg?style=flat-square"
/>
</a>
<a href="https://www.npmjs.com/package/chai">
<img
alt="node:?"
src="https://img.shields.io/badge/node-%3E=18.0-blue.svg?style=flat-square"
/>
</a>
<br/>
<a href="https://chai-slack.herokuapp.com/">
<img
alt="Join the Slack chat"
src="https://img.shields.io/badge/slack-join%20chat-E2206F.svg?style=flat-square"
/>
</a>
<a href="https://gitter.im/chaijs/chai">
<img
alt="Join the Gitter chat"
src="https://img.shields.io/badge/gitter-join%20chat-D0104D.svg?style=flat-square"
/>
</a>
<a href="https://opencollective.com/chaijs">
<img
alt="OpenCollective Backers"
src="https://opencollective.com/chaijs/backers/badge.svg?style=flat-square"
/>
</a>
</p>
For more information or to download plugins, view the [documentation](http://chaijs.com).
## What is Chai?
Chai is an _assertion library_, similar to Node's built-in `assert`. It makes testing much easier by giving you lots of assertions you can run against your code.
## Installation
### Node.js
`chai` is available on [npm](http://npmjs.org). To install it, type:
$ npm install --save-dev chai
### Browsers
You can also use it within the browser; install via npm and use the `index.js` file found within the download. For example:
```html
<script src="./node_modules/chai/index.js" type="module"></script>
```
## Usage
Import the library in your code, and then pick one of the styles you'd like to use - either `assert`, `expect` or `should`:
```js
import { assert } from 'chai'; // Using Assert style
import { expect } from 'chai'; // Using Expect style
import { should } from 'chai'; // Using Should style
```
### Register the chai testing style globally
```js
import 'chai/register-assert'; // Using Assert style
import 'chai/register-expect'; // Using Expect style
import 'chai/register-should'; // Using Should style
```
### Import assertion styles as local variables
```js
import { assert } from 'chai'; // Using Assert style
import { expect } from 'chai'; // Using Expect style
import { should } from 'chai'; // Using Should style
should(); // Modifies `Object.prototype`
import { expect, use } from 'chai'; // Creates local variables `expect` and `use`; useful for plugin use
```
### Usage with Mocha
```bash
mocha spec.js --require chai/register-assert.js # Using Assert style
mocha spec.js --require chai/register-expect.js # Using Expect style
mocha spec.js --require chai/register-should.js # Using Should style
```
[Read more about these styles in our docs](http://chaijs.com/guide/styles/).
## Plugins
Chai offers a robust Plugin architecture for extending Chai's assertions and interfaces.
- Need a plugin? View the [official plugin list](http://chaijs.com/plugins).
- Want to build a plugin? Read the [plugin api documentation](http://chaijs.com/guide/plugins/).
- Have a plugin and want it listed? Simply add the following keywords to your package.json:
- `chai-plugin`
- `browser` if your plugin works in the browser as well as Node.js
- `browser-only` if your plugin does not work with Node.js
### Related Projects
- [chaijs / chai-docs](https://github.com/chaijs/chai-docs): The chaijs.com website source code.
- [chaijs / assertion-error](https://github.com/chaijs/assertion-error): Custom `Error` constructor thrown upon an assertion failing.
- [chaijs / deep-eql](https://github.com/chaijs/deep-eql): Improved deep equality testing for Node.js and the browser.
- [chaijs / check-error](https://github.com/chaijs/check-error): Error comparison and information related utility for Node.js and the browser.
- [chaijs / loupe](https://github.com/chaijs/loupe): Inspect utility for Node.js and browsers.
- [chaijs / pathval](https://github.com/chaijs/pathval): Object value retrieval given a string path.
### Contributing
Thank you very much for considering to contribute!
Please make sure you follow our [Code Of Conduct](https://github.com/chaijs/chai/blob/master/CODE_OF_CONDUCT.md) and we also strongly recommend reading our [Contributing Guide](https://github.com/chaijs/chai/blob/master/CONTRIBUTING.md).
Here are a few issues other contributors frequently ran into when opening pull requests:
- Please do not commit changes to the `chai.js` build. We do it once per release.
- Before pushing your commits, please make sure you [rebase](https://github.com/chaijs/chai/blob/master/CONTRIBUTING.md#pull-requests) them.
### Contributors
Please see the full
[Contributors Graph](https://github.com/chaijs/chai/graphs/contributors) for our
list of contributors.
### Core Contributors
Feel free to reach out to any of the core contributors with your questions or
concerns. We will do our best to respond in a timely manner.
[](https://github.com/keithamus)
[](https://github.com/43081j)
[](https://github.com/koddsson)
### Core Contributor Alumni
This project would not be what it is without the contributions from our prior
core contributors, for whom we are forever grateful:
[](https://github.com/logicalparadox)
[](https://github.com/vesln)
[](https://github.com/lucasfcosta)
[](https://github.com/meeber)
================================================
FILE: ReleaseNotes.md
================================================
# Release Notes
## Note
As of 3.0.0, the ReleaseNotes.md file has been deprecated. [Please refer to the release notes available on Github](https://github.com/chaijs/chai/releases). Or
[the release notes on the chaijs.com website](https://chaijs.com/releases).
---
## 2.3.0 / 2015-04-26
Added `ownPropertyDescriptor` assertion:
```js
expect('test').to.have.ownPropertyDescriptor('length');
expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 });
expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 });
expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false);
expect('test').ownPropertyDescriptor('length').to.have.keys('value');
```
### Community Contributions
#### Code Features & Fixes
* [#408](https://github.com/chaijs/chai/pull/408) Add `ownPropertyDescriptor`
assertion.
By [@ljharb](https://github.com/ljharb)
* [#422](https://github.com/chaijs/chai/pull/422) Improve ownPropertyDescriptor
tests.
By [@ljharb](https://github.com/ljharb)
#### Documentation fixes
* [#417](https://github.com/chaijs/chai/pull/417) Fix documentation typo
By [@astorije](https://github.com/astorije)
* [#423](https://github.com/chaijs/chai/pull/423) Fix inconsistency in docs.
By [@ehntoo](https://github.com/ehntoo)
## 2.2.0 / 2015-03-26
Deep property strings can now be escaped using `\\` - for example:
```js
var deepCss = { '.link': { '[target]': 42 }};
expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42)
```
### Community Contributions
#### Code Features & Fixes
* [#402](https://github.com/chaijs/chai/pull/402) Allow escaping of deep
property keys.
By [@umireon](https://github.com/umireon)
#### Documentation fixes
* [#405](https://github.com/chaijs/chai/pull/405) Tweak documentation around
deep property escaping.
By [@keithamus](https://github.com/keithamus)
## 2.1.2 / 2015-03-15
A minor bug fix. No new features.
### Community Contributions
#### Code Features & Fixes
* [#395](https://github.com/chaijs/chai/pull/395) Fix eval-related bugs with
assert.operator ([#386](https://github.com/chaijs/chai/pull/386)).
By [@cjqed](https://github.com/cjqed)
## 2.1.1 / 2015-03-04
Two minor bugfixes. No new features.
### Community Contributions
#### Code Features & Fixes
* [#385](https://github.com/chaijs/chai/pull/385) Fix a bug (also described in
[#387](https://github.com/chaijs/chai/pull/385)) where `deep.property` would not work with single
key names. By [@eldritch-fossicker](https://github.com/eldritch-fossicker)
* [#379](https://github.com/chaijs/chai/pull/379) Fix bug where tools which overwrite
primitive prototypes, such as Babel or core-js would fail.
By [@dcneiner](https://github.com/dcneiner)
#### Documentation fixes
* [#382](https://github.com/chaijs/chai/pull/382) Add doc for showDiff argument in assert.
By [@astorije](https://github.com/astorije)
* [#383](https://github.com/chaijs/chai/pull/383) Improve wording for truncateTreshold docs
By [@gurdiga](https://github.com/gurdiga)
* [#381](https://github.com/chaijs/chai/pull/381) Improve wording for assert.empty docs
By [@astorije](https://github.com/astorije)
## 2.1.0 / 2015-02-23
Small release; fixes an issue where the Chai lib was incorrectly reporting the
version number.
Adds new `should.fail()` and `expect.fail()` methods, which are convinience
methods to throw Assertion Errors.
### Community Contributions
#### Code Features & Fixes
* [#356](https://github.com/chaijs/chai/pull/356) Add should.fail(), expect.fail(). By [@Soviut](https://github.com/Soviut)
* [#374](https://github.com/chaijs/chai/pull/374) Increment version. By [@jmm](https://github.com/jmm)
## 2.0.0 / 2015-02-09
Unfortunately with 1.10.0 - compatibility broke with older versions because of
the `addChainableNoop`. This change has been reverted.
Any plugins using `addChainableNoop` should cease to do so.
Any developers wishing for this behaviour can use [dirty-chai](https://www.npmjs.com/package/dirty-chai)
by [@joshperry](https://github.com/joshperry)
### Community Contributions
#### Code Features & Fixes
* [#361](https://github.com/chaijs/chai/pull/361) `.keys()` now accepts Objects, extracting keys from them. By [@gregglind](https://github.com/gregglind)
* [#359](https://github.com/chaijs/chai/pull/359) `.keys()` no longer mutates passed arrays. By [@gregglind](https://github.com/gregglind)
* [#349](https://github.com/chaijs/chai/pull/349) Add a new chainable keyword - `.which`. By [@toastynerd](https://github.com/toastynerd)
* [#333](https://github.com/chaijs/chai/pull/333) Add `.change`, `.increase` and `.decrease` assertions. By [@cmpolis](https://github.com/cmpolis)
* [#335](https://github.com/chaijs/chai/pull/335) `chai.util` is now exposed [@DingoEatingFuzz](https://github.com/DingoEatingFuzz)
* [#328](https://github.com/chaijs/chai/pull/328) Add `.includes` and `.contains` aliases (for `.include` and `.contain`). By [@lo1tuma](https://github.com/lo1tuma)
* [#313](https://github.com/chaijs/chai/pull/313) Add `.any.keys()` and `.all.keys()` qualifiers. By [@cjqed](https://github.com/cjqed)
* [#312](https://github.com/chaijs/chai/pull/312) Add `assert.sameDeepMembers()`. By [@cjqed](https://github.com/cjqed)
* [#311](https://github.com/chaijs/chai/pull/311) Add `assert.isAbove()` and `assert.isBelow()`. By [@cjqed](https://github.com/cjqed)
* [#308](https://github.com/chaijs/chai/pull/308) `property` and `deep.property` now pass if a value is set to `undefined`. By [@prodatakey](https://github.com/prodatakey)
* [#309](https://github.com/chaijs/chai/pull/309) optimize deep equal in Arrays. By [@ericdouglas](https://github.com/ericdouglas)
* [#306](https://github.com/chaijs/chai/pull/306) revert #297 - allowing lint-friendly tests. By [@keithamus](https://github.com/keithamus)
#### Documentation fixes
* [#357](https://github.com/chaijs/chai/pull/357) Copyright year updated in docs. By [@danilovaz](https://github.com/danilovaz)
* [#325](https://github.com/chaijs/chai/pull/325) Fix documentation for overwriteChainableMethod. By [@chasenlehara](https://github.com/chasenlehara)
* [#334](https://github.com/chaijs/chai/pull/334) Typo fix. By [@hurrymaplelad](https://github.com/hurrymaplelad)
* [#317](https://github.com/chaijs/chai/pull/317) Typo fix. By [@jasonkarns](https://github.com/jasonkarns)
* [#318](https://github.com/chaijs/chai/pull/318) Typo fix. By [@jasonkarns](https://github.com/jasonkarns)
* [#316](https://github.com/chaijs/chai/pull/316) Typo fix. By [@jasonkarns](https://github.com/jasonkarns)
## 1.10.0 / 2014-11-10
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required
- **Plugin Developers:**
- Review `addChainableNoop` notes below.
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Noop Function for Terminating Assertion Properties
The following assertions can now also be used in the function-call form:
* ok
* true
* false
* null
* undefined
* exist
* empty
* arguments
* Arguments
The above list of assertions are property getters that assert immediately on
access. Because of that, they were written to be used by terminating the assertion
chain with a property access.
```js
expect(true).to.be.true;
foo.should.be.ok;
```
This syntax is definitely aesthetically pleasing but, if you are linting your
test code, your linter will complain with an error something like "Expected an
assignment or function call and instead saw an expression." Since the linter
doesn't know about the property getter it assumes this line has no side-effects,
and throws a warning in case you made a mistake.
Squelching these errors is not a good solution as test code is getting to be
just as important as, if not more than, production code. Catching syntactical
errors in tests using static analysis is a great tool to help make sure that your
tests are well-defined and free of typos.
A better option was to provide a function-call form for these assertions so that
the code's intent is more clear and the linters stop complaining about something
looking off. This form is added in addition to the existing property access form
and does not impact existing test code.
```js
expect(true).to.be.true();
foo.should.be.ok();
```
These forms can also be mixed in any way, these are all functionally identical:
```js
expect(true).to.be.true.and.not.false();
expect(true).to.be.true().and.not.false;
expect(true).to.be.true.and.not.false;
```
#### Plugin Authors
If you would like to provide this function-call form for your terminating assertion
properties, there is a new function to register these types of asserts. Instead
of using `addProperty` to register terminating assertions, simply use `addChainableNoop`
instead; the arguments to both are identical. The latter will make the assertion
available in both the attribute and function-call forms and should have no impact
on existing users of your plugin.
### Community Contributions
- [#297](https://github.com/chaijs/chai/pull/297) Allow writing lint-friendly tests. [@joshperry](https://github.com/joshperry)
- [#298](https://github.com/chaijs/chai/pull/298) Add check for logging `-0`. [@dasilvacontin](https://github.com/dasilvacontin)
- [#300](https://github.com/chaijs/chai/pull/300) Fix #299: the test is defining global variables [@julienw](https://github.com/julienw)
Thank you to all who took time to contribute!
## 1.9.2 / 2014-09-29
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required
- **Plugin Developers:**
- No changes required
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Community Contributions
- [#264](https://github.com/chaijs/chai/pull/264) Show diff for keys assertions [@cjthompson](https://github.com/cjthompson)
- [#267](https://github.com/chaijs/chai/pull/267) Use SVG badges [@shinnn](https://github.com/shinnn)
- [#268](https://github.com/chaijs/chai/pull/268) Allow messages to be functions (sinon-compat) [@charlierudolph](https://github.com/charlierudolph)
- [#269](https://github.com/chaijs/chai/pull/269) Remove unused argument for #lengthOf [@charlierudolph](https://github.com/charlierudolph)
- [#275](https://github.com/chaijs/chai/pull/275) Rewrite pretty-printing HTML elements to prevent throwing internal errors [@DrRataplan](https://github.com/DrRataplan)
- [#277](https://github.com/chaijs/chai/pull/277) Fix assert documentation for #sameMembers [@charlierudolph](https://github.com/charlierudolph)
- [#279](https://github.com/chaijs/chai/pull/279) closeTo should check value's type before assertion [@mohayonao](https://github.com/mohayonao)
- [#289](https://github.com/chaijs/chai/pull/289) satisfy is called twice [@charlierudolph](https://github.com/charlierudolph)
- [#292](https://github.com/chaijs/chai/pull/292) resolve conflicts with node-webkit and global usage [@boneskull](https://github.com/boneskull)
Thank you to all who took time to contribute!
## 1.9.1 / 2014-03-19
The following changes are required if you are upgrading from the previous version:
- **Users:**
- Migrate configuration options to new interface. (see notes)
- **Plugin Developers:**
- No changes required
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Configuration
There have been requests for changes and additions to the configuration mechanisms
and their impact in the Chai architecture. As such, we have decoupled the
configuration from the `Assertion` constructor. This not only allows for centralized
configuration, but will allow us to shift the responsibility from the `Assertion`
constructor to the `assert` interface in future releases.
These changes have been implemented in a non-breaking way, but a depretiation
warning will be presented to users until they migrate. The old config method will
be removed in either `v1.11.0` or `v2.0.0`, whichever comes first.
#### Quick Migration
```js
// change this:
chai.Assertion.includeStack = true;
chai.Assertion.showDiff = false;
// ... to this:
chai.config.includeStack = true;
chai.config.showDiff = false;
```
#### All Config Options
##### config.includeStack
- **@param** _{Boolean}_
- **@default** `false`
User configurable property, influences whether stack trace is included in
Assertion error message. Default of `false` suppresses stack trace in the error
message.
##### config.showDiff
- **@param** _{Boolean}_
- **@default** `true`
User configurable property, influences whether or not the `showDiff` flag
should be included in the thrown AssertionErrors. `false` will always be `false`;
`true` will be true when the assertion has requested a diff be shown.
##### config.truncateThreshold **(NEW)**
- **@param** _{Number}_
- **@default** `40`
User configurable property, sets length threshold for actual and expected values
in assertion errors. If this threshold is exceeded, the value is truncated.
Set it to zero if you want to disable truncating altogether.
```js
chai.config.truncateThreshold = 0; // disable truncating
```
### Community Contributions
- [#228](https://github.com/chaijs/chai/pull/228) Deep equality check for memebers. [@duncanbeevers](https://github.com/duncanbeevers)
- [#247](https://github.com/chaijs/chai/pull/247) Proofreading. [@didorellano](https://github.com/didoarellano)
- [#244](https://github.com/chaijs/chai/pull/244) Fix `contain`/`include` 1.9.0 regression. [@leider](https://github.com/leider)
- [#233](https://github.com/chaijs/chai/pull/233) Improvements to `ssfi` for `assert` interface. [@refack](https://github.com/refack)
- [#251](https://github.com/chaijs/chai/pull/251) New config option: object display threshold. [@romario333](https://github.com/romario333)
Thank you to all who took time to contribute!
### Other Bug Fixes
- [#183](https://github.com/chaijs/chai/issues/183) Allow `undefined` for actual. (internal api)
- Update Karam(+plugins)/Istanbul to most recent versions.
## 1.9.0 / 2014-01-29
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required
- **Plugin Developers:**
- Review [#219](https://github.com/chaijs/chai/pull/219).
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Community Contributions
- [#202](https://github.com/chaijs/chai/pull/201) Improve error message for .throw(). [@andreineculau](https://github.com/andreineculau)
- [#217](https://github.com/chaijs/chai/pull/217) Chai tests can be run with `--watch`. [@demands](https://github.com/demands)
- [#219](https://github.com/chaijs/chai/pull/219) Add overwriteChainableMethod utility. [@demands](https://github.com/demands)
- [#224](https://github.com/chaijs/chai/pull/224) Return error on throw method to chain on error properties. [@vbardales](https://github.com/vbardales)
- [#226](https://github.com/chaijs/chai/pull/226) Add `has` to language chains. [@duncanbeevers](https://github.com/duncanbeevers)
- [#230](https://github.com/chaijs/chai/pull/230) Support `{a:1,b:2}.should.include({a:1})` [@jkroso](https://github.com/jkroso)
- [#231](https://github.com/chaijs/chai/pull/231) Update Copyright notices to 2014 [@duncanbeevers](https://github.com/duncanbeevers)
- [#232](https://github.com/chaijs/chai/pull/232) Avoid error instantiation if possible on assert.throws. [@laconbass](https://github.com/laconbass)
Thank you to all who took time to contribute!
### Other Bug Fixes
- [#225](https://github.com/chaijs/chai/pull/225) Improved AMD wrapper provided by upstream `component(1)`.
- [#185](https://github.com/chaijs/chai/issues/185) `assert.throws()` returns thrown error for further assertions.
- [#237](https://github.com/chaijs/chai/pull/237) Remove coveralls/jscoverage, include istanbul coverage report in travis test.
- Update Karma and Sauce runner versions for consistent CI results. No more karma@canary.
## 1.8.1 / 2013-10-10
The following changes are required if you are upgrading from the previous version:
- **Users:**
- Refresh `node_modules` folder for updated dependencies.
- **Plugin Developers:**
- No changes required
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Browserify
This is a small patch that updates the dependency tree so browserify users can install
chai. (Remove conditional requires)
## 1.8.0 / 2013-09-18
The following changes are required if you are upgrading from the previous version:
- **Users:**
- See `deep.equal` notes.
- **Plugin Developers:**
- No changes required
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Deep Equals
This version of Chai focused on a overhaul to the deep equal utility. The code for this
tool has been removed from the core lib and can now be found at:
[chai / deep-eql](https://github.com/chaijs/deep-eql). As stated in previous releases,
this is part of a larger initiative to provide transparency, independent testing, and coverage for
some of the more complicated internal tools.
For the most part `.deep.equal` will behave the same as it has. However, in order to provide a
consistent ruleset across all types being tested, the following changes have been made and _might_
require changes to your tests.
**1.** Strict equality for non-traversable nodes according to [egal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
_Previously:_ Non-traversable equal via `===`.
```js
expect(NaN).to.deep.equal(NaN);
expect(-0).to.not.deep.equal(+0);
```
**2.** Arguments are not Arrays (and all types must be equal):
_Previously:_ Some crazy nonsense that led to empty arrays deep equaling empty objects deep equaling dates.
```js
expect(arguments).to.not.deep.equal([]);
expect(Array.prototype.slice.call(arguments)).to.deep.equal([]);
```
- [#156](https://github.com/chaijs/chai/issues/156) Empty object is eql to empty array
- [#192](https://github.com/chaijs/chai/issues/192) empty object is eql to a Date object
- [#194](https://github.com/chaijs/chai/issues/194) refactor deep-equal utility
### CI and Browser Testing
Chai now runs the browser CI suite using [Karma](http://karma-runner.github.io/) directed at
[SauceLabs](https://saucelabs.com/). This means we get to know where our browser support stands...
and we get a cool badge:
[](https://saucelabs.com/u/logicalparadox)
Look for the list of browsers/versions to expand over the coming releases.
- [#195](https://github.com/chaijs/chai/issues/195) karma test framework
## 1.7.2 / 2013-06-27
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required.
- **Plugin Developers:**
- No changes required
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Coverage Reporting
Coverage reporting has always been available for core-developers but the data has never been published
for our end users. In our ongoing effort to improve accountability this data will now be published via
the [coveralls.io](https://coveralls.io/) service. A badge has been added to the README and the full report
can be viewed online at the [chai coveralls project](https://coveralls.io/r/chaijs/chai). Furthermore, PRs
will receive automated messages indicating how their PR impacts test coverage. This service is tied to TravisCI.
### Other Fixes
- [#175](https://github.com/chaijs/chai/issues/175) Add `bower.json`. (Fix ignore all)
## 1.7.1 / 2013-06-24
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required.
- **Plugin Developers:**
- No changes required
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### Official Bower Support
Support has been added for the Bower Package Manager ([bower.io])(http://bower.io/). Though
Chai could be installed via Bower in the past, this update adds official support via the `bower.json`
specification file.
- [#175](https://github.com/chaijs/chai/issues/175) Add `bower.json`.
## 1.7.0 / 2013-06-17
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required.
- **Plugin Developers:**
- Review AssertionError update notice.
- **Core Contributors:**
- Refresh `node_modules` folder for updated dependencies.
### AssertionError Update Notice
Chai now uses [chaijs/assertion-error](https://github.com/chaijs/assertion-error) instead an internal
constructor. This will allow for further iteration/experimentation of the AssertionError constructor
independant of Chai. Future plans include stack parsing for callsite support.
This update constructor has a different constructor param signature that conforms more with the standard
`Error` object. If your plugin throws and `AssertionError` directly you will need to update your plugin
with the new signature.
```js
var AssertionError = require('chai').AssertionError;
/**
* previous
*
* @param {Object} options
*/
throw new AssertionError({
message: 'An assertion error occurred'
, actual: actual
, expect: expect
, startStackFunction: arguments.callee
, showStack: true
});
/**
* new
*
* @param {String} message
* @param {Object} options
* @param {Function} start stack function
*/
throw new AssertionError('An assertion error occurred', {
actual: actual
, expect: expect
, showStack: true
}, arguments.callee);
// other signatures
throw new AssertionError('An assertion error occurred');
throw new AssertionError('An assertion error occurred', null, arguments.callee);
```
#### External Dependencies
This is the first non-developement dependency for Chai. As Chai continues to evolve we will begin adding
more; the next will likely be improved type detection and deep equality. With Chai's userbase continually growing
there is an higher need for accountability and documentation. External dependencies will allow us to iterate and
test on features independent from our interfaces.
Note: The browser packaged version `chai.js` will ALWAYS contain all dependencies needed to run Chai.
### Community Contributions
- [#169](https://github.com/chaijs/chai/pull/169) Fix deep equal comparison for Date/Regexp types. [@katsgeorgeek](https://github.com/katsgeorgeek)
- [#171](https://github.com/chaijs/chai/pull/171) Add `assert.notOk()`. [@Bartvds](https://github.com/Bartvds)
- [#173](https://github.com/chaijs/chai/pull/173) Fix `inspect` utility. [@domenic](https://github.com/domenic)
Thank you to all who took the time to contribute!
## 1.6.1 / 2013-06-05
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required.
- **Plugin Developers:**
- No changes required.
- **Core Contributors:**
- Refresh `node_modules` folder for updated developement dependencies.
### Deep Equality
Regular Expressions are now tested as part of all deep equality assertions. In previous versions
they silently passed for all scenarios. Thanks to [@katsgeorgeek](https://github.com/katsgeorgeek) for the contribution.
### Community Contributions
- [#161](https://github.com/chaijs/chai/pull/161) Fix documented name for assert interface's isDefined method. [@brandonpayton](https://github.com/brandonpayton)
- [#168](https://github.com/chaijs/chai/pull/168) Fix comparison equality of two regexps for when using deep equality. [@katsgeorgeek](https://github.com/katsgeorgeek)
Thank you to all who took the time to contribute!
### Additional Notes
- Mocha has been locked at version `1.8.x` to ensure `mocha-phantomjs` compatibility.
## 1.6.0 / 2013-04-29
The following changes are required if you are upgrading from the previous version:
- **Users:**
- No changes required.
- **Plugin Developers:**
- No changes required.
- **Core Contributors:**
- Refresh `node_modules` folder for updated developement dependencies.
### New Assertions
#### Array Members Inclusion
Asserts that the target is a superset of `set`, or that the target and `set` have the same members.
Order is not taken into account. Thanks to [@NickHeiner](https://github.com/NickHeiner) for the contribution.
```js
// (expect/should) full set
expect([4, 2]).to.have.members([2, 4]);
expect([5, 2]).to.not.have.members([5, 2, 1]);
// (expect/should) inclusion
expect([1, 2, 3]).to.include.members([3, 2]);
expect([1, 2, 3]).to.not.include.members([3, 2, 8]);
// (assert) full set
assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members');
// (assert) inclusion
assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members');
```
#### Non-inclusion for Assert Interface
Most `assert` functions have a negative version, like `instanceOf()` has a corresponding `notInstaceOf()`.
However `include()` did not have a corresponding `notInclude()`. This has been added.
```js
assert.notInclude([ 1, 2, 3 ], 8);
assert.notInclude('foobar', 'baz');
```
### Community Contributions
- [#140](https://github.com/chaijs/chai/pull/140) Restore `call`/`apply` methods for plugin interface. [@RubenVerborgh](https://github.com/RubenVerborgh)
- [#148](https://github.com/chaijs/chai/issues/148)/[#153](https://github.com/chaijs/chai/pull/153) Add `members` and `include.members` assertions. [#NickHeiner](https://github.com/NickHeiner)
Thank you to all who took time to contribute!
### Other Bug Fixes
- [#142](https://github.com/chaijs/chai/issues/142) `assert#include` will no longer silently pass on wrong-type haystack.
- [#158](https://github.com/chaijs/chai/issues/158) `assert#notInclude` has been added.
- Travis-CI now tests Node.js `v0.10.x`. Support for `v0.6.x` has been removed. `v0.8.x` is still tested as before.
## 1.5.0 / 2013-02-03
### Migration Requirements
The following changes are required if you are upgrading from the previous version:
- **Users:**
- _Update [2013-02-04]:_ Some users may notice a small subset of deep equality assertions will no longer pass. This is the result of
[#120](https://github.com/chaijs/chai/issues/120), an improvement to our deep equality algorithm. Users will need to revise their assertions
to be more granular should this occur. Further information: [#139](https://github.com/chaijs/chai/issues/139).
- **Plugin Developers:**
- No changes required.
- **Core Contributors:**
- Refresh `node_modules` folder for updated developement dependencies.
### Community Contributions
- [#126](https://github.com/chaijs/chai/pull/126): Add `eqls` alias for `eql`. [@RubenVerborgh](https://github.com/RubenVerborgh)
- [#127](https://github.com/chaijs/chai/issues/127): Performance refactor for chainable methods. [@RubenVerborgh](https://github.com/RubenVerborgh)
- [#133](https://github.com/chaijs/chai/pull/133): Assertion `.throw` support for primitives. [@RubenVerborgh](https://github.com/RubenVerborgh)
- [#137](https://github.com/chaijs/chai/issues/137): Assertion `.throw` support for empty messages. [@timnew](https://github.com/timnew)
- [#136](https://github.com/chaijs/chai/pull/136): Fix backward negation messages when using `.above()` and `.below()`. [@whatthejeff](https://github.com/whatthejeff)
Thank you to all who took time to contribute!
### Other Bug Fixes
- Improve type detection of `.a()`/`.an()` to work in cross-browser scenarios.
- [#116](https://github.com/chaijs/chai/issues/116): `.throw()` has cleaner display of errors when WebKit browsers.
- [#120](https://github.com/chaijs/chai/issues/120): `.eql()` now works to compare dom nodes in browsers.
### Usage Updates
#### For Users
**1. Component Support:** Chai now included the proper configuration to be installed as a
[component](https://github.com/component/component). Component users are encouraged to consult
[chaijs.com](http://chaijs.com) for the latest version number as using the master branch
does not gaurantee stability.
```js
// relevant component.json
devDependencies: {
"chaijs/chai": "1.5.0"
}
```
Alternatively, bleeding-edge is available:
$ component install chaijs/chai
**2. Configurable showDiff:** Some test runners (such as [mocha](http://visionmedia.github.com/mocha/))
include support for showing the diff of strings and objects when an equality error occurs. Chai has
already included support for this, however some users may not prefer this display behavior. To revert to
no diff display, the following configuration is available:
```js
chai.Assertion.showDiff = false; // diff output disabled
chai.Assertion.showDiff = true; // default, diff output enabled
```
#### For Plugin Developers
**1. New Utility - type**: The new utility `.type()` is available as a better implementation of `typeof`
that can be used cross-browser. It handles the inconsistencies of Array, `null`, and `undefined` detection.
- **@param** _{Mixed}_ object to detect type of
- **@return** _{String}_ object type
```js
chai.use(function (c, utils) {
// some examples
utils.type({}); // 'object'
utils.type(null); // `null'
utils.type(undefined); // `undefined`
utils.type([]); // `array`
});
```
#### For Core Contributors
**1. Browser Testing**: Browser testing of the `./chai.js` file is now available in the command line
via PhantomJS. `make test` and Travis-CI will now also rebuild and test `./chai.js`. Consequently, all
pull requests will now be browser tested in this way.
_Note: Contributors opening pull requests should still NOT include the browser build._
**2. SauceLabs Testing**: Early SauceLab support has been enabled with the file `./support/mocha-cloud.js`.
Those interested in trying it out should create a free [Open Sauce](https://saucelabs.com/signup/plan) account
and include their credentials in `./test/auth/sauce.json`.
================================================
FILE: eslint.config.js
================================================
import jsdoc from "eslint-plugin-jsdoc";
import eslintjs from "@eslint/js";
import globals from "globals";
const {configs: eslintConfigs} = eslintjs;
export default [
jsdoc.configs["flat/recommended"],
eslintConfigs["recommended"],
{
languageOptions: {
globals: {
console: false,
...globals.browser, // EventTarget, Event
}
},
rules: {
"no-var": "error",
"jsdoc/require-param-description": "off",
"jsdoc/require-returns-description": "off",
"jsdoc/tag-lines": ["error", "any", { startLines: 1 }],
"no-unused-vars": ["error", {
argsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_"
}]
},
},
];
================================================
FILE: lib/chai/assertion.js
================================================
/*!
* chai
* http://chaijs.com
* Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/
import {config} from './config.js';
import {AssertionError} from 'assertion-error';
import * as util from './utils/index.js';
export class Assertion {
/** @type {{}} */
__flags = {};
/**
* Creates object for chaining.
* `Assertion` objects contain metadata in the form of flags. Three flags can
* be assigned during instantiation by passing arguments to this constructor:
*
* - `object`: This flag contains the target of the assertion. For example, in
* the assertion `expect(numKittens).to.equal(7);`, the `object` flag will
* contain `numKittens` so that the `equal` assertion can reference it when
* needed.
*
* - `message`: This flag contains an optional custom error message to be
* prepended to the error message that's generated by the assertion when it
* fails.
*
* - `ssfi`: This flag stands for "start stack function indicator". It
* contains a function reference that serves as the starting point for
* removing frames from the stack trace of the error that's created by the
* assertion when it fails. The goal is to provide a cleaner stack trace to
* end users by removing Chai's internal functions. Note that it only works
* in environments that support `Error.captureStackTrace`, and only when
* `Chai.config.includeStack` hasn't been set to `false`.
*
* - `lockSsfi`: This flag controls whether or not the given `ssfi` flag
* should retain its current value, even as assertions are chained off of
* this object. This is usually set to `true` when creating a new assertion
* from within another assertion. It's also temporarily set to `true` before
* an overwritten assertion gets called by the overwriting assertion.
*
* - `eql`: This flag contains the deepEqual function to be used by the assertion.
*
* @param {unknown} obj target of the assertion
* @param {string} [msg] (optional) custom error message
* @param {Function} [ssfi] (optional) starting point for removing stack frames
* @param {boolean} [lockSsfi] (optional) whether or not the ssfi flag is locked
*/
constructor(obj, msg, ssfi, lockSsfi) {
util.flag(this, 'ssfi', ssfi || Assertion);
util.flag(this, 'lockSsfi', lockSsfi);
util.flag(this, 'object', obj);
util.flag(this, 'message', msg);
util.flag(this, 'eql', config.deepEqual || util.eql);
return util.proxify(this);
}
/** @returns {boolean} */
static get includeStack() {
console.warn(
'Assertion.includeStack is deprecated, use chai.config.includeStack instead.'
);
return config.includeStack;
}
/** @param {boolean} value */
static set includeStack(value) {
console.warn(
'Assertion.includeStack is deprecated, use chai.config.includeStack instead.'
);
config.includeStack = value;
}
/** @returns {boolean} */
static get showDiff() {
console.warn(
'Assertion.showDiff is deprecated, use chai.config.showDiff instead.'
);
return config.showDiff;
}
/** @param {boolean} value */
static set showDiff(value) {
console.warn(
'Assertion.showDiff is deprecated, use chai.config.showDiff instead.'
);
config.showDiff = value;
}
/**
* @param {string} name
* @param {Function} fn
*/
static addProperty(name, fn) {
util.addProperty(this.prototype, name, fn);
}
/**
* @param {string} name
* @param {Function} fn
*/
static addMethod(name, fn) {
util.addMethod(this.prototype, name, fn);
}
/**
* @param {string} name
* @param {Function} fn
* @param {Function} chainingBehavior
*/
static addChainableMethod(name, fn, chainingBehavior) {
util.addChainableMethod(this.prototype, name, fn, chainingBehavior);
}
/**
* @param {string} name
* @param {Function} fn
*/
static overwriteProperty(name, fn) {
util.overwriteProperty(this.prototype, name, fn);
}
/**
* @param {string} name
* @param {Function} fn
*/
static overwriteMethod(name, fn) {
util.overwriteMethod(this.prototype, name, fn);
}
/**
* @param {string} name
* @param {Function} fn
* @param {Function} chainingBehavior
*/
static overwriteChainableMethod(name, fn, chainingBehavior) {
util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior);
}
/**
* ### .assert(expression, message, negateMessage, expected, actual, showDiff)
*
* Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass.
*
* @name assert
* @param {unknown} _expr to be tested
* @param {string | Function} msg or function that returns message to display if expression fails
* @param {string | Function} _negateMsg or function that returns negatedMessage to display if negated expression fails
* @param {unknown} expected value (remember to check for negation)
* @param {unknown} _actual (optional) will default to `this.obj`
* @param {boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails
* @returns {void}
*/
assert(_expr, msg, _negateMsg, expected, _actual, showDiff) {
const ok = util.test(this, arguments);
if (false !== showDiff) showDiff = true;
if (undefined === expected && undefined === _actual) showDiff = false;
if (true !== config.showDiff) showDiff = false;
if (!ok) {
msg = util.getMessage(this, arguments);
const actual = util.getActual(this, arguments);
/** @type {Record<PropertyKey, unknown>} */
const assertionErrorObjectProperties = {
actual: actual,
expected: expected,
showDiff: showDiff
};
const operator = util.getOperator(this, arguments);
if (operator) {
assertionErrorObjectProperties.operator = operator;
}
throw new AssertionError(
msg,
assertionErrorObjectProperties,
// @ts-expect-error Not sure what to do about these types yet
config.includeStack ? this.assert : util.flag(this, 'ssfi')
);
}
}
/**
* Quick reference to stored `actual` value for plugin developers.
*
* @returns {unknown}
*/
get _obj() {
return util.flag(this, 'object');
}
/**
* Quick reference to stored `actual` value for plugin developers.
*
* @param {unknown} val
*/
set _obj(val) {
util.flag(this, 'object', val);
}
}
================================================
FILE: lib/chai/config.js
================================================
export const config = {
/**
* ### config.includeStack
*
* User configurable property, influences whether stack trace
* is included in Assertion error message. Default of false
* suppresses stack trace in the error message.
*
* chai.config.includeStack = true; // enable stack on error
*
* @param {boolean}
* @public
*/
includeStack: false,
/**
* ### config.showDiff
*
* User configurable property, influences whether or not
* the `showDiff` flag should be included in the thrown
* AssertionErrors. `false` will always be `false`; `true`
* will be true when the assertion has requested a diff
* be shown.
*
* @param {boolean}
* @public
*/
showDiff: true,
/**
* ### config.truncateThreshold
*
* User configurable property, sets length threshold for actual and
* expected values in assertion errors. If this threshold is exceeded, for
* example for large data structures, the value is replaced with something
* like `[ Array(3) ]` or `{ Object (prop1, prop2) }`.
*
* Set it to zero if you want to disable truncating altogether.
*
* This is especially userful when doing assertions on arrays: having this
* set to a reasonable large value makes the failure messages readily
* inspectable.
*
* chai.config.truncateThreshold = 0; // disable truncating
*
* @param {number}
* @public
*/
truncateThreshold: 40,
/**
* ### config.useProxy
*
* User configurable property, defines if chai will use a Proxy to throw
* an error when a non-existent property is read, which protects users
* from typos when using property-based assertions.
*
* Set it to false if you want to disable this feature.
*
* chai.config.useProxy = false; // disable use of Proxy
*
* This feature is automatically disabled regardless of this config value
* in environments that don't support proxies.
*
* @param {boolean}
* @public
*/
useProxy: true,
/**
* ### config.proxyExcludedKeys
*
* User configurable property, defines which properties should be ignored
* instead of throwing an error if they do not exist on the assertion.
* This is only applied if the environment Chai is running in supports proxies and
* if the `useProxy` configuration setting is enabled.
* By default, `then` and `inspect` will not throw an error if they do not exist on the
* assertion object because the `.inspect` property is read by `util.inspect` (for example, when
* using `console.log` on the assertion object) and `.then` is necessary for promise type-checking.
*
* // By default these keys will not throw an error if they do not exist on the assertion object
* chai.config.proxyExcludedKeys = ['then', 'inspect'];
*
* @param {Array}
* @public
*/
proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON'],
/**
* ### config.deepEqual
*
* User configurable property, defines which a custom function to use for deepEqual
* comparisons.
* By default, the function used is the one from the `deep-eql` package without custom comparator.
*
* // use a custom comparator
* chai.config.deepEqual = (expected, actual) => {
* return chai.util.eql(expected, actual, {
* comparator: (expected, actual) => {
* // for non number comparison, use the default behavior
* if(typeof expected !== 'number') return null;
* // allow a difference of 10 between compared numbers
* return typeof actual === 'number' && Math.abs(actual - expected) < 10
* }
* })
* };
*
* @param {Function}
* @public
*/
deepEqual: null
};
================================================
FILE: lib/chai/core/assertions.js
================================================
/*!
* chai
* http://chaijs.com
* Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/
import {Assertion} from '../assertion.js';
import {AssertionError} from 'assertion-error';
import * as _ from '../utils/index.js';
import {config} from '../config.js';
const {flag} = _;
/**
* ### Language Chains
*
* The following are provided as chainable getters to improve the readability
* of your assertions.
*
* **Chains**
*
* - to
* - be
* - been
* - is
* - that
* - which
* - and
* - has
* - have
* - with
* - at
* - of
* - same
* - but
* - does
* - still
* - also
*
* @name language chains
* @namespace BDD
* @public
*/
[
'to',
'be',
'been',
'is',
'and',
'has',
'have',
'with',
'that',
'which',
'at',
'of',
'same',
'but',
'does',
'still',
'also'
].forEach(function (chain) {
Assertion.addProperty(chain);
});
/**
* ### .not
*
* Negates all assertions that follow in the chain.
*
* expect(function () {}).to.not.throw();
* expect({a: 1}).to.not.have.property('b');
* expect([1, 2]).to.be.an('array').that.does.not.include(3);
*
* Just because you can negate any assertion with `.not` doesn't mean you
* should. With great power comes great responsibility. It's often best to
* assert that the one expected output was produced, rather than asserting
* that one of countless unexpected outputs wasn't produced. See individual
* assertions for specific guidance.
*
* expect(2).to.equal(2); // Recommended
* expect(2).to.not.equal(1); // Not recommended
*
* @name not
* @namespace BDD
* @public
*/
Assertion.addProperty('not', function () {
flag(this, 'negate', true);
});
/**
* ### .deep
*
* Causes all `.equal`, `.include`, `.members`, `.keys`, and `.property`
* assertions that follow in the chain to use deep equality instead of strict
* (`===`) equality. See the `deep-eql` project page for info on the deep
* equality algorithm: https://github.com/chaijs/deep-eql.
*
* // Target object deeply (but not strictly) equals `{a: 1}`
* expect({a: 1}).to.deep.equal({a: 1});
* expect({a: 1}).to.not.equal({a: 1});
*
* // Target array deeply (but not strictly) includes `{a: 1}`
* expect([{a: 1}]).to.deep.include({a: 1});
* expect([{a: 1}]).to.not.include({a: 1});
*
* // Target object deeply (but not strictly) includes `x: {a: 1}`
* expect({x: {a: 1}}).to.deep.include({x: {a: 1}});
* expect({x: {a: 1}}).to.not.include({x: {a: 1}});
*
* // Target array deeply (but not strictly) has member `{a: 1}`
* expect([{a: 1}]).to.have.deep.members([{a: 1}]);
* expect([{a: 1}]).to.not.have.members([{a: 1}]);
*
* // Target set deeply (but not strictly) has key `{a: 1}`
* expect(new Set([{a: 1}])).to.have.deep.keys([{a: 1}]);
* expect(new Set([{a: 1}])).to.not.have.keys([{a: 1}]);
*
* // Target object deeply (but not strictly) has property `x: {a: 1}`
* expect({x: {a: 1}}).to.have.deep.property('x', {a: 1});
* expect({x: {a: 1}}).to.not.have.property('x', {a: 1});
*
* @name deep
* @namespace BDD
* @public
*/
Assertion.addProperty('deep', function () {
flag(this, 'deep', true);
});
/**
* ### .nested
*
* Enables dot- and bracket-notation in all `.property` and `.include`
* assertions that follow in the chain.
*
* expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]');
* expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'});
*
* If `.` or `[]` are part of an actual property name, they can be escaped by
* adding two backslashes before them.
*
* expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\.a.\\[b\\]');
* expect({'.a': {'[b]': 'x'}}).to.nested.include({'\\.a.\\[b\\]': 'x'});
*
* `.nested` cannot be combined with `.own`.
*
* @name nested
* @namespace BDD
* @public
*/
Assertion.addProperty('nested', function () {
flag(this, 'nested', true);
});
/**
* ### .own
*
* Causes all `.property` and `.include` assertions that follow in the chain
* to ignore inherited properties.
*
* Object.prototype.b = 2;
*
* expect({a: 1}).to.have.own.property('a');
* expect({a: 1}).to.have.property('b');
* expect({a: 1}).to.not.have.own.property('b');
*
* expect({a: 1}).to.own.include({a: 1});
* expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2});
*
* `.own` cannot be combined with `.nested`.
*
* @name own
* @namespace BDD
* @public
*/
Assertion.addProperty('own', function () {
flag(this, 'own', true);
});
/**
* ### .ordered
*
* Causes all `.members` assertions that follow in the chain to require that
* members be in the same order.
*
* expect([1, 2]).to.have.ordered.members([1, 2])
* .but.not.have.ordered.members([2, 1]);
*
* When `.include` and `.ordered` are combined, the ordering begins at the
* start of both arrays.
*
* expect([1, 2, 3]).to.include.ordered.members([1, 2])
* .but.not.include.ordered.members([2, 3]);
*
* @name ordered
* @namespace BDD
* @public
*/
Assertion.addProperty('ordered', function () {
flag(this, 'ordered', true);
});
/**
* ### .any
*
* Causes all `.keys` assertions that follow in the chain to only require that
* the target have at least one of the given keys. This is the opposite of
* `.all`, which requires that the target have all of the given keys.
*
* expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');
*
* See the `.keys` doc for guidance on when to use `.any` or `.all`.
*
* @name any
* @namespace BDD
* @public
*/
Assertion.addProperty('any', function () {
flag(this, 'any', true);
flag(this, 'all', false);
});
/**
* ### .all
*
* Causes all `.keys` assertions that follow in the chain to require that the
* target have all of the given keys. This is the opposite of `.any`, which
* only requires that the target have at least one of the given keys.
*
* expect({a: 1, b: 2}).to.have.all.keys('a', 'b');
*
* Note that `.all` is used by default when neither `.all` nor `.any` are
* added earlier in the chain. However, it's often best to add `.all` anyway
* because it improves readability.
*
* See the `.keys` doc for guidance on when to use `.any` or `.all`.
*
* @name all
* @namespace BDD
* @public
*/
Assertion.addProperty('all', function () {
flag(this, 'all', true);
flag(this, 'any', false);
});
const functionTypes = {
function: [
'function',
'asyncfunction',
'generatorfunction',
'asyncgeneratorfunction'
],
asyncfunction: ['asyncfunction', 'asyncgeneratorfunction'],
generatorfunction: ['generatorfunction', 'asyncgeneratorfunction'],
asyncgeneratorfunction: ['asyncgeneratorfunction']
};
/**
* ### .a(type[, msg])
*
* Asserts that the target's type is equal to the given string `type`. Types
* are case insensitive. See the utility file `./type-detect.js` for info on the
* type detection algorithm.
*
* expect('foo').to.be.a('string');
* expect({a: 1}).to.be.an('object');
* expect(null).to.be.a('null');
* expect(undefined).to.be.an('undefined');
* expect(new Error).to.be.an('error');
* expect(Promise.resolve()).to.be.a('promise');
* expect(new Float32Array).to.be.a('float32array');
* expect(Symbol()).to.be.a('symbol');
*
* `.a` supports objects that have a custom type set via `Symbol.toStringTag`.
*
* var myObj = {
* [Symbol.toStringTag]: 'myCustomType'
* };
*
* expect(myObj).to.be.a('myCustomType').but.not.an('object');
*
* It's often best to use `.a` to check a target's type before making more
* assertions on the same target. That way, you avoid unexpected behavior from
* any assertion that does different things based on the target's type.
*
* expect([1, 2, 3]).to.be.an('array').that.includes(2);
* expect([]).to.be.an('array').that.is.empty;
*
* Add `.not` earlier in the chain to negate `.a`. However, it's often best to
* assert that the target is the expected type, rather than asserting that it
* isn't one of many unexpected types.
*
* expect('foo').to.be.a('string'); // Recommended
* expect('foo').to.not.be.an('array'); // Not recommended
*
* `.a` accepts an optional `msg` argument which is a custom error message to
* show when the assertion fails. The message can also be given as the second
* argument to `expect`.
*
* expect(1).to.be.a('string', 'nooo why fail??');
* expect(1, 'nooo why fail??').to.be.a('string');
*
* `.a` can also be used as a language chain to improve the readability of
* your assertions.
*
* expect({b: 2}).to.have.a.property('b');
*
* The alias `.an` can be used interchangeably with `.a`.
*
* @name a
* @alias an
* @param {string} type
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function an(type, msg) {
if (msg) flag(this, 'message', msg);
type = type.toLowerCase();
let obj = flag(this, 'object'),
article = ~['a', 'e', 'i', 'o', 'u'].indexOf(type.charAt(0)) ? 'an ' : 'a ';
const detectedType = _.type(obj).toLowerCase();
if (functionTypes['function'].includes(type)) {
this.assert(
functionTypes[type].includes(detectedType),
'expected #{this} to be ' + article + type,
'expected #{this} not to be ' + article + type
);
} else {
this.assert(
type === detectedType,
'expected #{this} to be ' + article + type,
'expected #{this} not to be ' + article + type
);
}
}
Assertion.addChainableMethod('an', an);
Assertion.addChainableMethod('a', an);
/**
* @param {unknown} a
* @param {unknown} b
* @returns {boolean}
*/
function SameValueZero(a, b) {
return (_.isNaN(a) && _.isNaN(b)) || a === b;
}
/** */
function includeChainingBehavior() {
flag(this, 'contains', true);
}
/**
* ### .include(val[, msg])
*
* When the target is a string, `.include` asserts that the given string `val`
* is a substring of the target.
*
* expect('foobar').to.include('foo');
*
* When the target is an array, `.include` asserts that the given `val` is a
* member of the target.
*
* expect([1, 2, 3]).to.include(2);
*
* When the target is an object, `.include` asserts that the given object
* `val`'s properties are a subset of the target's properties.
*
* expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2});
*
* When the target is a Set or WeakSet, `.include` asserts that the given `val` is a
* member of the target. SameValueZero equality algorithm is used.
*
* expect(new Set([1, 2])).to.include(2);
*
* When the target is a Map, `.include` asserts that the given `val` is one of
* the values of the target. SameValueZero equality algorithm is used.
*
* expect(new Map([['a', 1], ['b', 2]])).to.include(2);
*
* Because `.include` does different things based on the target's type, it's
* important to check the target's type before using `.include`. See the `.a`
* doc for info on testing a target's type.
*
* expect([1, 2, 3]).to.be.an('array').that.includes(2);
*
* By default, strict (`===`) equality is used to compare array members and
* object properties. Add `.deep` earlier in the chain to use deep equality
* instead (WeakSet targets are not supported). See the `deep-eql` project
* page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql.
*
* // Target array deeply (but not strictly) includes `{a: 1}`
* expect([{a: 1}]).to.deep.include({a: 1});
* expect([{a: 1}]).to.not.include({a: 1});
*
* // Target object deeply (but not strictly) includes `x: {a: 1}`
* expect({x: {a: 1}}).to.deep.include({x: {a: 1}});
* expect({x: {a: 1}}).to.not.include({x: {a: 1}});
*
* By default, all of the target's properties are searched when working with
* objects. This includes properties that are inherited and/or non-enumerable.
* Add `.own` earlier in the chain to exclude the target's inherited
* properties from the search.
*
* Object.prototype.b = 2;
*
* expect({a: 1}).to.own.include({a: 1});
* expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2});
*
* Note that a target object is always only searched for `val`'s own
* enumerable properties.
*
* `.deep` and `.own` can be combined.
*
* expect({a: {b: 2}}).to.deep.own.include({a: {b: 2}});
*
* Add `.nested` earlier in the chain to enable dot- and bracket-notation when
* referencing nested properties.
*
* expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'});
*
* If `.` or `[]` are part of an actual property name, they can be escaped by
* adding two backslashes before them.
*
* expect({'.a': {'[b]': 2}}).to.nested.include({'\\.a.\\[b\\]': 2});
*
* `.deep` and `.nested` can be combined.
*
* expect({a: {b: [{c: 3}]}}).to.deep.nested.include({'a.b[0]': {c: 3}});
*
* `.own` and `.nested` cannot be combined.
*
* Add `.not` earlier in the chain to negate `.include`.
*
* expect('foobar').to.not.include('taco');
* expect([1, 2, 3]).to.not.include(4);
*
* However, it's dangerous to negate `.include` when the target is an object.
* The problem is that it creates uncertain expectations by asserting that the
* target object doesn't have all of `val`'s key/value pairs but may or may
* not have some of them. It's often best to identify the exact output that's
* expected, and then write an assertion that only accepts that exact output.
*
* When the target object isn't even expected to have `val`'s keys, it's
* often best to assert exactly that.
*
* expect({c: 3}).to.not.have.any.keys('a', 'b'); // Recommended
* expect({c: 3}).to.not.include({a: 1, b: 2}); // Not recommended
*
* When the target object is expected to have `val`'s keys, it's often best to
* assert that each of the properties has its expected value, rather than
* asserting that each property doesn't have one of many unexpected values.
*
* expect({a: 3, b: 4}).to.include({a: 3, b: 4}); // Recommended
* expect({a: 3, b: 4}).to.not.include({a: 1, b: 2}); // Not recommended
*
* `.include` accepts an optional `msg` argument which is a custom error
* message to show when the assertion fails. The message can also be given as
* the second argument to `expect`.
*
* expect([1, 2, 3]).to.include(4, 'nooo why fail??');
* expect([1, 2, 3], 'nooo why fail??').to.include(4);
*
* `.include` can also be used as a language chain, causing all `.members` and
* `.keys` assertions that follow in the chain to require the target to be a
* superset of the expected set, rather than an identical set. Note that
* `.members` ignores duplicates in the subset when `.include` is added.
*
* // Target object's keys are a superset of ['a', 'b'] but not identical
* expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b');
* expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b');
*
* // Target array is a superset of [1, 2] but not identical
* expect([1, 2, 3]).to.include.members([1, 2]);
* expect([1, 2, 3]).to.not.have.members([1, 2]);
*
* // Duplicates in the subset are ignored
* expect([1, 2, 3]).to.include.members([1, 2, 2, 2]);
*
* Note that adding `.any` earlier in the chain causes the `.keys` assertion
* to ignore `.include`.
*
* // Both assertions are identical
* expect({a: 1}).to.include.any.keys('a', 'b');
* expect({a: 1}).to.have.any.keys('a', 'b');
*
* The aliases `.includes`, `.contain`, and `.contains` can be used
* interchangeably with `.include`.
*
* @name include
* @alias contain
* @alias includes
* @alias contains
* @param {unknown} val
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function include(val, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
objType = _.type(obj).toLowerCase(),
flagMsg = flag(this, 'message'),
negate = flag(this, 'negate'),
ssfi = flag(this, 'ssfi'),
isDeep = flag(this, 'deep'),
descriptor = isDeep ? 'deep ' : '',
isEql = isDeep ? flag(this, 'eql') : SameValueZero;
flagMsg = flagMsg ? flagMsg + ': ' : '';
let included = false;
switch (objType) {
case 'string':
included = obj.indexOf(val) !== -1;
break;
case 'weakset':
if (isDeep) {
throw new AssertionError(
flagMsg + 'unable to use .deep.include with WeakSet',
undefined,
ssfi
);
}
included = obj.has(val);
break;
case 'map':
obj.forEach(function (item) {
included = included || isEql(item, val);
});
break;
case 'set':
if (isDeep) {
obj.forEach(function (item) {
included = included || isEql(item, val);
});
} else {
included = obj.has(val);
}
break;
case 'array':
if (isDeep) {
included = obj.some(function (item) {
return isEql(item, val);
});
} else {
included = obj.indexOf(val) !== -1;
}
break;
default: {
// This block is for asserting a subset of properties in an object.
// `_.expectTypes` isn't used here because `.include` should work with
// objects with a custom `@@toStringTag`.
if (val !== Object(val)) {
throw new AssertionError(
flagMsg +
'the given combination of arguments (' +
objType +
' and ' +
_.type(val).toLowerCase() +
')' +
' is invalid for this assertion. ' +
'You can use an array, a map, an object, a set, a string, ' +
'or a weakset instead of a ' +
_.type(val).toLowerCase(),
undefined,
ssfi
);
}
let props = Object.keys(val);
let firstErr = null;
let numErrs = 0;
props.forEach(function (prop) {
let propAssertion = new Assertion(obj);
_.transferFlags(this, propAssertion, true);
flag(propAssertion, 'lockSsfi', true);
if (!negate || props.length === 1) {
propAssertion.property(prop, val[prop]);
return;
}
try {
propAssertion.property(prop, val[prop]);
} catch (err) {
if (!_.checkError.compatibleConstructor(err, AssertionError)) {
throw err;
}
if (firstErr === null) firstErr = err;
numErrs++;
}
}, this);
// When validating .not.include with multiple properties, we only want
// to throw an assertion error if all of the properties are included,
// in which case we throw the first property assertion error that we
// encountered.
if (negate && props.length > 1 && numErrs === props.length) {
throw firstErr;
}
return;
}
}
// Assert inclusion in collection or substring in a string.
this.assert(
included,
'expected #{this} to ' + descriptor + 'include ' + _.inspect(val),
'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val)
);
}
Assertion.addChainableMethod('include', include, includeChainingBehavior);
Assertion.addChainableMethod('contain', include, includeChainingBehavior);
Assertion.addChainableMethod('contains', include, includeChainingBehavior);
Assertion.addChainableMethod('includes', include, includeChainingBehavior);
/**
* ### .ok
*
* Asserts that the target is a truthy value (considered `true` in boolean context).
* However, it's often best to assert that the target is strictly (`===`) or
* deeply equal to its expected value.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.be.ok; // Not recommended
*
* expect(true).to.be.true; // Recommended
* expect(true).to.be.ok; // Not recommended
*
* Add `.not` earlier in the chain to negate `.ok`.
*
* expect(0).to.equal(0); // Recommended
* expect(0).to.not.be.ok; // Not recommended
*
* expect(false).to.be.false; // Recommended
* expect(false).to.not.be.ok; // Not recommended
*
* expect(null).to.be.null; // Recommended
* expect(null).to.not.be.ok; // Not recommended
*
* expect(undefined).to.be.undefined; // Recommended
* expect(undefined).to.not.be.ok; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(false, 'nooo why fail??').to.be.ok;
*
* @name ok
* @namespace BDD
* @public
*/
Assertion.addProperty('ok', function () {
this.assert(
flag(this, 'object'),
'expected #{this} to be truthy',
'expected #{this} to be falsy'
);
});
/**
* ### .true
*
* Asserts that the target is strictly (`===`) equal to `true`.
*
* expect(true).to.be.true;
*
* Add `.not` earlier in the chain to negate `.true`. However, it's often best
* to assert that the target is equal to its expected value, rather than not
* equal to `true`.
*
* expect(false).to.be.false; // Recommended
* expect(false).to.not.be.true; // Not recommended
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.be.true; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(false, 'nooo why fail??').to.be.true;
*
* @name true
* @namespace BDD
* @public
*/
Assertion.addProperty('true', function () {
this.assert(
true === flag(this, 'object'),
'expected #{this} to be true',
'expected #{this} to be false',
flag(this, 'negate') ? false : true
);
});
Assertion.addProperty('numeric', function () {
const object = flag(this, 'object');
this.assert(
['Number', 'BigInt'].includes(_.type(object)),
'expected #{this} to be numeric',
'expected #{this} to not be numeric',
flag(this, 'negate') ? false : true
);
});
/**
* ### .callable
*
* Asserts that the target a callable function.
*
* expect(console.log).to.be.callable;
*
* A custom error message can be given as the second argument to `expect`.
*
* expect('not a function', 'nooo why fail??').to.be.callable;
*
* @name callable
* @namespace BDD
* @public
*/
Assertion.addProperty('callable', function () {
const val = flag(this, 'object');
const ssfi = flag(this, 'ssfi');
const message = flag(this, 'message');
const msg = message ? `${message}: ` : '';
const negate = flag(this, 'negate');
const assertionMessage = negate
? `${msg}expected ${_.inspect(val)} not to be a callable function`
: `${msg}expected ${_.inspect(val)} to be a callable function`;
const isCallable = [
'Function',
'AsyncFunction',
'GeneratorFunction',
'AsyncGeneratorFunction'
].includes(_.type(val));
if ((isCallable && negate) || (!isCallable && !negate)) {
throw new AssertionError(assertionMessage, undefined, ssfi);
}
});
/**
* ### .false
*
* Asserts that the target is strictly (`===`) equal to `false`.
*
* expect(false).to.be.false;
*
* Add `.not` earlier in the chain to negate `.false`. However, it's often
* best to assert that the target is equal to its expected value, rather than
* not equal to `false`.
*
* expect(true).to.be.true; // Recommended
* expect(true).to.not.be.false; // Not recommended
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.be.false; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(true, 'nooo why fail??').to.be.false;
*
* @name false
* @namespace BDD
* @public
*/
Assertion.addProperty('false', function () {
this.assert(
false === flag(this, 'object'),
'expected #{this} to be false',
'expected #{this} to be true',
flag(this, 'negate') ? true : false
);
});
/**
* ### .null
*
* Asserts that the target is strictly (`===`) equal to `null`.
*
* expect(null).to.be.null;
*
* Add `.not` earlier in the chain to negate `.null`. However, it's often best
* to assert that the target is equal to its expected value, rather than not
* equal to `null`.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.be.null; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(42, 'nooo why fail??').to.be.null;
*
* @name null
* @namespace BDD
* @public
*/
Assertion.addProperty('null', function () {
this.assert(
null === flag(this, 'object'),
'expected #{this} to be null',
'expected #{this} not to be null'
);
});
/**
* ### .undefined
*
* Asserts that the target is strictly (`===`) equal to `undefined`.
*
* expect(undefined).to.be.undefined;
*
* Add `.not` earlier in the chain to negate `.undefined`. However, it's often
* best to assert that the target is equal to its expected value, rather than
* not equal to `undefined`.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.be.undefined; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(42, 'nooo why fail??').to.be.undefined;
*
* @name undefined
* @namespace BDD
* @public
*/
Assertion.addProperty('undefined', function () {
this.assert(
undefined === flag(this, 'object'),
'expected #{this} to be undefined',
'expected #{this} not to be undefined'
);
});
/**
* ### .NaN
*
* Asserts that the target is exactly `NaN`.
*
* expect(NaN).to.be.NaN;
*
* Add `.not` earlier in the chain to negate `.NaN`. However, it's often best
* to assert that the target is equal to its expected value, rather than not
* equal to `NaN`.
*
* expect('foo').to.equal('foo'); // Recommended
* expect('foo').to.not.be.NaN; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(42, 'nooo why fail??').to.be.NaN;
*
* @name NaN
* @namespace BDD
* @public
*/
Assertion.addProperty('NaN', function () {
this.assert(
_.isNaN(flag(this, 'object')),
'expected #{this} to be NaN',
'expected #{this} not to be NaN'
);
});
/**
* ### .exist
*
* Asserts that the target is not strictly (`===`) equal to either `null` or
* `undefined`. However, it's often best to assert that the target is equal to
* its expected value.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.exist; // Not recommended
*
* expect(0).to.equal(0); // Recommended
* expect(0).to.exist; // Not recommended
*
* Add `.not` earlier in the chain to negate `.exist`.
*
* expect(null).to.be.null; // Recommended
* expect(null).to.not.exist; // Not recommended
*
* expect(undefined).to.be.undefined; // Recommended
* expect(undefined).to.not.exist; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect(null, 'nooo why fail??').to.exist;
*
* The alias `.exists` can be used interchangeably with `.exist`.
*
* @name exist
* @alias exists
* @namespace BDD
* @public
*/
function assertExist() {
let val = flag(this, 'object');
this.assert(
val !== null && val !== undefined,
'expected #{this} to exist',
'expected #{this} to not exist'
);
}
Assertion.addProperty('exist', assertExist);
Assertion.addProperty('exists', assertExist);
/**
* ### .empty
*
* When the target is a string or array, `.empty` asserts that the target's
* `length` property is strictly (`===`) equal to `0`.
*
* expect([]).to.be.empty;
* expect('').to.be.empty;
*
* When the target is a map or set, `.empty` asserts that the target's `size`
* property is strictly equal to `0`.
*
* expect(new Set()).to.be.empty;
* expect(new Map()).to.be.empty;
*
* When the target is a non-function object, `.empty` asserts that the target
* doesn't have any own enumerable properties. Properties with Symbol-based
* keys are excluded from the count.
*
* expect({}).to.be.empty;
*
* Because `.empty` does different things based on the target's type, it's
* important to check the target's type before using `.empty`. See the `.a`
* doc for info on testing a target's type.
*
* expect([]).to.be.an('array').that.is.empty;
*
* Add `.not` earlier in the chain to negate `.empty`. However, it's often
* best to assert that the target contains its expected number of values,
* rather than asserting that it's not empty.
*
* expect([1, 2, 3]).to.have.lengthOf(3); // Recommended
* expect([1, 2, 3]).to.not.be.empty; // Not recommended
*
* expect(new Set([1, 2, 3])).to.have.property('size', 3); // Recommended
* expect(new Set([1, 2, 3])).to.not.be.empty; // Not recommended
*
* expect(Object.keys({a: 1})).to.have.lengthOf(1); // Recommended
* expect({a: 1}).to.not.be.empty; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect([1, 2, 3], 'nooo why fail??').to.be.empty;
*
* @name empty
* @namespace BDD
* @public
*/
Assertion.addProperty('empty', function () {
let val = flag(this, 'object'),
ssfi = flag(this, 'ssfi'),
flagMsg = flag(this, 'message'),
itemsCount;
flagMsg = flagMsg ? flagMsg + ': ' : '';
switch (_.type(val).toLowerCase()) {
case 'array':
case 'string':
itemsCount = val.length;
break;
case 'map':
case 'set':
itemsCount = val.size;
break;
case 'weakmap':
case 'weakset':
throw new AssertionError(
flagMsg + '.empty was passed a weak collection',
undefined,
ssfi
);
case 'function': {
const msg = flagMsg + '.empty was passed a function ' + _.getName(val);
throw new AssertionError(msg.trim(), undefined, ssfi);
}
default:
if (val !== Object(val)) {
throw new AssertionError(
flagMsg + '.empty was passed non-string primitive ' + _.inspect(val),
undefined,
ssfi
);
}
itemsCount = Object.keys(val).length;
}
this.assert(
0 === itemsCount,
'expected #{this} to be empty',
'expected #{this} not to be empty'
);
});
/**
* ### .arguments
*
* Asserts that the target is an `arguments` object.
*
* function test () {
* expect(arguments).to.be.arguments;
* }
*
* test();
*
* Add `.not` earlier in the chain to negate `.arguments`. However, it's often
* best to assert which type the target is expected to be, rather than
* asserting that it’s not an `arguments` object.
*
* expect('foo').to.be.a('string'); // Recommended
* expect('foo').to.not.be.arguments; // Not recommended
*
* A custom error message can be given as the second argument to `expect`.
*
* expect({}, 'nooo why fail??').to.be.arguments;
*
* The alias `.Arguments` can be used interchangeably with `.arguments`.
*
* @name arguments
* @alias Arguments
* @namespace BDD
* @public
*/
function checkArguments() {
let obj = flag(this, 'object'),
type = _.type(obj);
this.assert(
'Arguments' === type,
'expected #{this} to be arguments but got ' + type,
'expected #{this} to not be arguments'
);
}
Assertion.addProperty('arguments', checkArguments);
Assertion.addProperty('Arguments', checkArguments);
/**
* ### .equal(val[, msg])
*
* Asserts that the target is strictly (`===`) equal to the given `val`.
*
* expect(1).to.equal(1);
* expect('foo').to.equal('foo');
*
* Add `.deep` earlier in the chain to use deep equality instead. See the
* `deep-eql` project page for info on the deep equality algorithm:
* https://github.com/chaijs/deep-eql.
*
* // Target object deeply (but not strictly) equals `{a: 1}`
* expect({a: 1}).to.deep.equal({a: 1});
* expect({a: 1}).to.not.equal({a: 1});
*
* // Target array deeply (but not strictly) equals `[1, 2]`
* expect([1, 2]).to.deep.equal([1, 2]);
* expect([1, 2]).to.not.equal([1, 2]);
*
* Add `.not` earlier in the chain to negate `.equal`. However, it's often
* best to assert that the target is equal to its expected value, rather than
* not equal to one of countless unexpected values.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.equal(2); // Not recommended
*
* `.equal` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect(1).to.equal(2, 'nooo why fail??');
* expect(1, 'nooo why fail??').to.equal(2);
*
* The aliases `.equals` and `eq` can be used interchangeably with `.equal`.
*
* @name equal
* @alias equals
* @alias eq
* @param {unknown} val
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertEqual(val, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object');
if (flag(this, 'deep')) {
let prevLockSsfi = flag(this, 'lockSsfi');
flag(this, 'lockSsfi', true);
this.eql(val);
flag(this, 'lockSsfi', prevLockSsfi);
} else {
this.assert(
val === obj,
'expected #{this} to equal #{exp}',
'expected #{this} to not equal #{exp}',
val,
this._obj,
true
);
}
}
Assertion.addMethod('equal', assertEqual);
Assertion.addMethod('equals', assertEqual);
Assertion.addMethod('eq', assertEqual);
/**
* ### .eql(obj[, msg])
*
* Asserts that the target is deeply equal to the given `obj`. See the
* `deep-eql` project page for info on the deep equality algorithm:
* https://github.com/chaijs/deep-eql.
*
* // Target object is deeply (but not strictly) equal to {a: 1}
* expect({a: 1}).to.eql({a: 1}).but.not.equal({a: 1});
*
* // Target array is deeply (but not strictly) equal to [1, 2]
* expect([1, 2]).to.eql([1, 2]).but.not.equal([1, 2]);
*
* Add `.not` earlier in the chain to negate `.eql`. However, it's often best
* to assert that the target is deeply equal to its expected value, rather
* than not deeply equal to one of countless unexpected values.
*
* expect({a: 1}).to.eql({a: 1}); // Recommended
* expect({a: 1}).to.not.eql({b: 2}); // Not recommended
*
* `.eql` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect({a: 1}).to.eql({b: 2}, 'nooo why fail??');
* expect({a: 1}, 'nooo why fail??').to.eql({b: 2});
*
* The alias `.eqls` can be used interchangeably with `.eql`.
*
* The `.deep.equal` assertion is almost identical to `.eql` but with one
* difference: `.deep.equal` causes deep equality comparisons to also be used
* for any other assertions that follow in the chain.
*
* @name eql
* @alias eqls
* @param {unknown} obj
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertEql(obj, msg) {
if (msg) flag(this, 'message', msg);
let eql = flag(this, 'eql');
this.assert(
eql(obj, flag(this, 'object')),
'expected #{this} to deeply equal #{exp}',
'expected #{this} to not deeply equal #{exp}',
obj,
this._obj,
true
);
}
Assertion.addMethod('eql', assertEql);
Assertion.addMethod('eqls', assertEql);
/**
* ### .above(n[, msg])
*
* Asserts that the target is a number or a date greater than the given number or date `n` respectively.
* However, it's often best to assert that the target is equal to its expected
* value.
*
* expect(2).to.equal(2); // Recommended
* expect(2).to.be.above(1); // Not recommended
*
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
* or `size` is greater than the given number `n`.
*
* expect('foo').to.have.lengthOf(3); // Recommended
* expect('foo').to.have.lengthOf.above(2); // Not recommended
*
* expect([1, 2, 3]).to.have.lengthOf(3); // Recommended
* expect([1, 2, 3]).to.have.lengthOf.above(2); // Not recommended
*
* Add `.not` earlier in the chain to negate `.above`.
*
* expect(2).to.equal(2); // Recommended
* expect(1).to.not.be.above(2); // Not recommended
*
* `.above` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect(1).to.be.above(2, 'nooo why fail??');
* expect(1, 'nooo why fail??').to.be.above(2);
*
* The aliases `.gt` and `.greaterThan` can be used interchangeably with
* `.above`.
*
* @name above
* @alias gt
* @alias greaterThan
* @param {number} n
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertAbove(n, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
doLength = flag(this, 'doLength'),
flagMsg = flag(this, 'message'),
msgPrefix = flagMsg ? flagMsg + ': ' : '',
ssfi = flag(this, 'ssfi'),
objType = _.type(obj).toLowerCase(),
nType = _.type(n).toLowerCase();
if (doLength && objType !== 'map' && objType !== 'set') {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}
if (!doLength && objType === 'date' && nType !== 'date') {
throw new AssertionError(
msgPrefix + 'the argument to above must be a date',
undefined,
ssfi
);
} else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
throw new AssertionError(
msgPrefix + 'the argument to above must be a number',
undefined,
ssfi
);
} else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
let printObj = objType === 'string' ? "'" + obj + "'" : obj;
throw new AssertionError(
msgPrefix + 'expected ' + printObj + ' to be a number or a date',
undefined,
ssfi
);
}
if (doLength) {
let descriptor = 'length',
itemsCount;
if (objType === 'map' || objType === 'set') {
descriptor = 'size';
itemsCount = obj.size;
} else {
itemsCount = obj.length;
}
this.assert(
itemsCount > n,
'expected #{this} to have a ' +
descriptor +
' above #{exp} but got #{act}',
'expected #{this} to not have a ' + descriptor + ' above #{exp}',
n,
itemsCount
);
} else {
this.assert(
obj > n,
'expected #{this} to be above #{exp}',
'expected #{this} to be at most #{exp}',
n
);
}
}
Assertion.addMethod('above', assertAbove);
Assertion.addMethod('gt', assertAbove);
Assertion.addMethod('greaterThan', assertAbove);
/**
* ### .least(n[, msg])
*
* Asserts that the target is a number or a date greater than or equal to the given
* number or date `n` respectively. However, it's often best to assert that the target is equal to
* its expected value.
*
* expect(2).to.equal(2); // Recommended
* expect(2).to.be.at.least(1); // Not recommended
* expect(2).to.be.at.least(2); // Not recommended
*
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
* or `size` is greater than or equal to the given number `n`.
*
* expect('foo').to.have.lengthOf(3); // Recommended
* expect('foo').to.have.lengthOf.at.least(2); // Not recommended
*
* expect([1, 2, 3]).to.have.lengthOf(3); // Recommended
* expect([1, 2, 3]).to.have.lengthOf.at.least(2); // Not recommended
*
* Add `.not` earlier in the chain to negate `.least`.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.be.at.least(2); // Not recommended
*
* `.least` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect(1).to.be.at.least(2, 'nooo why fail??');
* expect(1, 'nooo why fail??').to.be.at.least(2);
*
* The aliases `.gte` and `.greaterThanOrEqual` can be used interchangeably with
* `.least`.
*
* @name least
* @alias gte
* @alias greaterThanOrEqual
* @param {unknown} n
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertLeast(n, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
doLength = flag(this, 'doLength'),
flagMsg = flag(this, 'message'),
msgPrefix = flagMsg ? flagMsg + ': ' : '',
ssfi = flag(this, 'ssfi'),
objType = _.type(obj).toLowerCase(),
nType = _.type(n).toLowerCase(),
errorMessage,
shouldThrow = true;
if (doLength && objType !== 'map' && objType !== 'set') {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}
if (!doLength && objType === 'date' && nType !== 'date') {
errorMessage = msgPrefix + 'the argument to least must be a date';
} else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
errorMessage = msgPrefix + 'the argument to least must be a number';
} else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
let printObj = objType === 'string' ? "'" + obj + "'" : obj;
errorMessage =
msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
shouldThrow = false;
}
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}
if (doLength) {
let descriptor = 'length',
itemsCount;
if (objType === 'map' || objType === 'set') {
descriptor = 'size';
itemsCount = obj.size;
} else {
itemsCount = obj.length;
}
this.assert(
itemsCount >= n,
'expected #{this} to have a ' +
descriptor +
' at least #{exp} but got #{act}',
'expected #{this} to have a ' + descriptor + ' below #{exp}',
n,
itemsCount
);
} else {
this.assert(
obj >= n,
'expected #{this} to be at least #{exp}',
'expected #{this} to be below #{exp}',
n
);
}
}
Assertion.addMethod('least', assertLeast);
Assertion.addMethod('gte', assertLeast);
Assertion.addMethod('greaterThanOrEqual', assertLeast);
/**
* ### .below(n[, msg])
*
* Asserts that the target is a number or a date less than the given number or date `n` respectively.
* However, it's often best to assert that the target is equal to its expected
* value.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.be.below(2); // Not recommended
*
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
* or `size` is less than the given number `n`.
*
* expect('foo').to.have.lengthOf(3); // Recommended
* expect('foo').to.have.lengthOf.below(4); // Not recommended
*
* expect([1, 2, 3]).to.have.length(3); // Recommended
* expect([1, 2, 3]).to.have.lengthOf.below(4); // Not recommended
*
* Add `.not` earlier in the chain to negate `.below`.
*
* expect(2).to.equal(2); // Recommended
* expect(2).to.not.be.below(1); // Not recommended
*
* `.below` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect(2).to.be.below(1, 'nooo why fail??');
* expect(2, 'nooo why fail??').to.be.below(1);
*
* The aliases `.lt` and `.lessThan` can be used interchangeably with
* `.below`.
*
* @name below
* @alias lt
* @alias lessThan
* @param {unknown} n
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertBelow(n, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
doLength = flag(this, 'doLength'),
flagMsg = flag(this, 'message'),
msgPrefix = flagMsg ? flagMsg + ': ' : '',
ssfi = flag(this, 'ssfi'),
objType = _.type(obj).toLowerCase(),
nType = _.type(n).toLowerCase(),
errorMessage,
shouldThrow = true;
if (doLength && objType !== 'map' && objType !== 'set') {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}
if (!doLength && objType === 'date' && nType !== 'date') {
errorMessage = msgPrefix + 'the argument to below must be a date';
} else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
errorMessage = msgPrefix + 'the argument to below must be a number';
} else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
let printObj = objType === 'string' ? "'" + obj + "'" : obj;
errorMessage =
msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
shouldThrow = false;
}
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}
if (doLength) {
let descriptor = 'length',
itemsCount;
if (objType === 'map' || objType === 'set') {
descriptor = 'size';
itemsCount = obj.size;
} else {
itemsCount = obj.length;
}
this.assert(
itemsCount < n,
'expected #{this} to have a ' +
descriptor +
' below #{exp} but got #{act}',
'expected #{this} to not have a ' + descriptor + ' below #{exp}',
n,
itemsCount
);
} else {
this.assert(
obj < n,
'expected #{this} to be below #{exp}',
'expected #{this} to be at least #{exp}',
n
);
}
}
Assertion.addMethod('below', assertBelow);
Assertion.addMethod('lt', assertBelow);
Assertion.addMethod('lessThan', assertBelow);
/**
* ### .most(n[, msg])
*
* Asserts that the target is a number or a date less than or equal to the given number
* or date `n` respectively. However, it's often best to assert that the target is equal to its
* expected value.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.be.at.most(2); // Not recommended
* expect(1).to.be.at.most(1); // Not recommended
*
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
* or `size` is less than or equal to the given number `n`.
*
* expect('foo').to.have.lengthOf(3); // Recommended
* expect('foo').to.have.lengthOf.at.most(4); // Not recommended
*
* expect([1, 2, 3]).to.have.lengthOf(3); // Recommended
* expect([1, 2, 3]).to.have.lengthOf.at.most(4); // Not recommended
*
* Add `.not` earlier in the chain to negate `.most`.
*
* expect(2).to.equal(2); // Recommended
* expect(2).to.not.be.at.most(1); // Not recommended
*
* `.most` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect(2).to.be.at.most(1, 'nooo why fail??');
* expect(2, 'nooo why fail??').to.be.at.most(1);
*
* The aliases `.lte` and `.lessThanOrEqual` can be used interchangeably with
* `.most`.
*
* @name most
* @alias lte
* @alias lessThanOrEqual
* @param {unknown} n
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertMost(n, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
doLength = flag(this, 'doLength'),
flagMsg = flag(this, 'message'),
msgPrefix = flagMsg ? flagMsg + ': ' : '',
ssfi = flag(this, 'ssfi'),
objType = _.type(obj).toLowerCase(),
nType = _.type(n).toLowerCase(),
errorMessage,
shouldThrow = true;
if (doLength && objType !== 'map' && objType !== 'set') {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}
if (!doLength && objType === 'date' && nType !== 'date') {
errorMessage = msgPrefix + 'the argument to most must be a date';
} else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
errorMessage = msgPrefix + 'the argument to most must be a number';
} else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
let printObj = objType === 'string' ? "'" + obj + "'" : obj;
errorMessage =
msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
shouldThrow = false;
}
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}
if (doLength) {
let descriptor = 'length',
itemsCount;
if (objType === 'map' || objType === 'set') {
descriptor = 'size';
itemsCount = obj.size;
} else {
itemsCount = obj.length;
}
this.assert(
itemsCount <= n,
'expected #{this} to have a ' +
descriptor +
' at most #{exp} but got #{act}',
'expected #{this} to have a ' + descriptor + ' above #{exp}',
n,
itemsCount
);
} else {
this.assert(
obj <= n,
'expected #{this} to be at most #{exp}',
'expected #{this} to be above #{exp}',
n
);
}
}
Assertion.addMethod('most', assertMost);
Assertion.addMethod('lte', assertMost);
Assertion.addMethod('lessThanOrEqual', assertMost);
/**
* ### .within(start, finish[, msg])
*
* Asserts that the target is a number or a date greater than or equal to the given
* number or date `start`, and less than or equal to the given number or date `finish` respectively.
* However, it's often best to assert that the target is equal to its expected
* value.
*
* expect(2).to.equal(2); // Recommended
* expect(2).to.be.within(1, 3); // Not recommended
* expect(2).to.be.within(2, 3); // Not recommended
* expect(2).to.be.within(1, 2); // Not recommended
*
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
* or `size` is greater than or equal to the given number `start`, and less
* than or equal to the given number `finish`.
*
* expect('foo').to.have.lengthOf(3); // Recommended
* expect('foo').to.have.lengthOf.within(2, 4); // Not recommended
*
* expect([1, 2, 3]).to.have.lengthOf(3); // Recommended
* expect([1, 2, 3]).to.have.lengthOf.within(2, 4); // Not recommended
*
* Add `.not` earlier in the chain to negate `.within`.
*
* expect(1).to.equal(1); // Recommended
* expect(1).to.not.be.within(2, 4); // Not recommended
*
* `.within` accepts an optional `msg` argument which is a custom error
* message to show when the assertion fails. The message can also be given as
* the second argument to `expect`.
*
* expect(4).to.be.within(1, 3, 'nooo why fail??');
* expect(4, 'nooo why fail??').to.be.within(1, 3);
*
* @name within
* @param {unknown} start lower bound inclusive
* @param {unknown} finish upper bound inclusive
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
Assertion.addMethod('within', function (start, finish, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
doLength = flag(this, 'doLength'),
flagMsg = flag(this, 'message'),
msgPrefix = flagMsg ? flagMsg + ': ' : '',
ssfi = flag(this, 'ssfi'),
objType = _.type(obj).toLowerCase(),
startType = _.type(start).toLowerCase(),
finishType = _.type(finish).toLowerCase(),
errorMessage,
shouldThrow = true,
range =
startType === 'date' && finishType === 'date'
? start.toISOString() + '..' + finish.toISOString()
: start + '..' + finish;
if (doLength && objType !== 'map' && objType !== 'set') {
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
}
if (
!doLength &&
objType === 'date' &&
(startType !== 'date' || finishType !== 'date')
) {
errorMessage = msgPrefix + 'the arguments to within must be dates';
} else if (
(!_.isNumeric(start) || !_.isNumeric(finish)) &&
(doLength || _.isNumeric(obj))
) {
errorMessage = msgPrefix + 'the arguments to within must be numbers';
} else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
let printObj = objType === 'string' ? "'" + obj + "'" : obj;
errorMessage =
msgPrefix + 'expected ' + printObj + ' to be a number or a date';
} else {
shouldThrow = false;
}
if (shouldThrow) {
throw new AssertionError(errorMessage, undefined, ssfi);
}
if (doLength) {
let descriptor = 'length',
itemsCount;
if (objType === 'map' || objType === 'set') {
descriptor = 'size';
itemsCount = obj.size;
} else {
itemsCount = obj.length;
}
this.assert(
itemsCount >= start && itemsCount <= finish,
'expected #{this} to have a ' + descriptor + ' within ' + range,
'expected #{this} to not have a ' + descriptor + ' within ' + range
);
} else {
this.assert(
obj >= start && obj <= finish,
'expected #{this} to be within ' + range,
'expected #{this} to not be within ' + range
);
}
});
/**
* ### .instanceof(constructor[, msg])
*
* Asserts that the target is an instance of the given `constructor`.
*
* function Cat () { }
*
* expect(new Cat()).to.be.an.instanceof(Cat);
* expect([1, 2]).to.be.an.instanceof(Array);
*
* Add `.not` earlier in the chain to negate `.instanceof`.
*
* expect({a: 1}).to.not.be.an.instanceof(Array);
*
* `.instanceof` accepts an optional `msg` argument which is a custom error
* message to show when the assertion fails. The message can also be given as
* the second argument to `expect`.
*
* expect(1).to.be.an.instanceof(Array, 'nooo why fail??');
* expect(1, 'nooo why fail??').to.be.an.instanceof(Array);
*
* Due to limitations in ES5, `.instanceof` may not always work as expected
* when using a transpiler such as Babel or TypeScript. In particular, it may
* produce unexpected results when subclassing built-in object such as
* `Array`, `Error`, and `Map`. See your transpiler's docs for details:
*
* - ([Babel](https://babeljs.io/docs/usage/caveats/#classes))
* - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))
*
* The alias `.instanceOf` can be used interchangeably with `.instanceof`.
*
* @name instanceof
* @param {unknown} constructor
* @param {string} msg _optional_
* @alias instanceOf
* @namespace BDD
* @public
*/
function assertInstanceOf(constructor, msg) {
if (msg) flag(this, 'message', msg);
let target = flag(this, 'object');
let ssfi = flag(this, 'ssfi');
let flagMsg = flag(this, 'message');
let isInstanceOf;
try {
isInstanceOf = target instanceof constructor;
} catch (err) {
if (err instanceof TypeError) {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg +
'The instanceof assertion needs a constructor but ' +
_.type(constructor) +
' was given.',
undefined,
ssfi
);
}
throw err;
}
let name = _.getName(constructor);
if (name == null) {
name = 'an unnamed constructor';
}
this.assert(
isInstanceOf,
'expected #{this} to be an instance of ' + name,
'expected #{this} to not be an instance of ' + name
);
}
Assertion.addMethod('instanceof', assertInstanceOf);
Assertion.addMethod('instanceOf', assertInstanceOf);
/**
* ### .property(name[, val[, msg]])
*
* Asserts that the target has a property with the given key `name`.
*
* expect({a: 1}).to.have.property('a');
*
* When `val` is provided, `.property` also asserts that the property's value
* is equal to the given `val`.
*
* expect({a: 1}).to.have.property('a', 1);
*
* By default, strict (`===`) equality is used. Add `.deep` earlier in the
* chain to use deep equality instead. See the `deep-eql` project page for
* info on the deep equality algorithm: https://github.com/chaijs/deep-eql.
*
* // Target object deeply (but not strictly) has property `x: {a: 1}`
* expect({x: {a: 1}}).to.have.deep.property('x', {a: 1});
* expect({x: {a: 1}}).to.not.have.property('x', {a: 1});
*
* The target's enumerable and non-enumerable properties are always included
* in the search. By default, both own and inherited properties are included.
* Add `.own` earlier in the chain to exclude inherited properties from the
* search.
*
* Object.prototype.b = 2;
*
* expect({a: 1}).to.have.own.property('a');
* expect({a: 1}).to.have.own.property('a', 1);
* expect({a: 1}).to.have.property('b');
* expect({a: 1}).to.not.have.own.property('b');
*
* `.deep` and `.own` can be combined.
*
* expect({x: {a: 1}}).to.have.deep.own.property('x', {a: 1});
*
* Add `.nested` earlier in the chain to enable dot- and bracket-notation when
* referencing nested properties.
*
* expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]');
* expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]', 'y');
*
* If `.` or `[]` are part of an actual property name, they can be escaped by
* adding two backslashes before them.
*
* expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\.a.\\[b\\]');
*
* `.deep` and `.nested` can be combined.
*
* expect({a: {b: [{c: 3}]}})
* .to.have.deep.nested.property('a.b[0]', {c: 3});
*
* `.own` and `.nested` cannot be combined.
*
* Add `.not` earlier in the chain to negate `.property`.
*
* expect({a: 1}).to.not.have.property('b');
*
* However, it's dangerous to negate `.property` when providing `val`. The
* problem is that it creates uncertain expectations by asserting that the
* target either doesn't have a property with the given key `name`, or that it
* does have a property with the given key `name` but its value isn't equal to
* the given `val`. It's often best to identify the exact output that's
* expected, and then write an assertion that only accepts that exact output.
*
* When the target isn't expected to have a property with the given key
* `name`, it's often best to assert exactly that.
*
* expect({b: 2}).to.not.have.property('a'); // Recommended
* expect({b: 2}).to.not.have.property('a', 1); // Not recommended
*
* When the target is expected to have a property with the given key `name`,
* it's often best to assert that the property has its expected value, rather
* than asserting that it doesn't have one of many unexpected values.
*
* expect({a: 3}).to.have.property('a', 3); // Recommended
* expect({a: 3}).to.not.have.property('a', 1); // Not recommended
*
* `.property` changes the target of any assertions that follow in the chain
* to be the value of the property from the original target object.
*
* expect({a: 1}).to.have.property('a').that.is.a('number');
*
* `.property` accepts an optional `msg` argument which is a custom error
* message to show when the assertion fails. The message can also be given as
* the second argument to `expect`. When not providing `val`, only use the
* second form.
*
* // Recommended
* expect({a: 1}).to.have.property('a', 2, 'nooo why fail??');
* expect({a: 1}, 'nooo why fail??').to.have.property('a', 2);
* expect({a: 1}, 'nooo why fail??').to.have.property('b');
*
* // Not recommended
* expect({a: 1}).to.have.property('b', undefined, 'nooo why fail??');
*
* The above assertion isn't the same thing as not providing `val`. Instead,
* it's asserting that the target object has a `b` property that's equal to
* `undefined`.
*
* The assertions `.ownProperty` and `.haveOwnProperty` can be used
* interchangeably with `.own.property`.
*
* @name property
* @param {string} name
* @param {unknown} val (optional)
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertProperty(name, val, msg) {
if (msg) flag(this, 'message', msg);
let isNested = flag(this, 'nested'),
isOwn = flag(this, 'own'),
flagMsg = flag(this, 'message'),
obj = flag(this, 'object'),
ssfi = flag(this, 'ssfi'),
nameType = typeof name;
flagMsg = flagMsg ? flagMsg + ': ' : '';
if (isNested) {
if (nameType !== 'string') {
throw new AssertionError(
flagMsg +
'the argument to property must be a string when using nested syntax',
undefined,
ssfi
);
}
} else {
if (
nameType !== 'string' &&
nameType !== 'number' &&
nameType !== 'symbol'
) {
throw new AssertionError(
flagMsg +
'the argument to property must be a string, number, or symbol',
undefined,
ssfi
);
}
}
if (isNested && isOwn) {
throw new AssertionError(
flagMsg + 'The "nested" and "own" flags cannot be combined.',
undefined,
ssfi
);
}
if (obj === null || obj === undefined) {
throw new AssertionError(
flagMsg + 'Target cannot be null or undefined.',
undefined,
ssfi
);
}
let isDeep = flag(this, 'deep'),
negate = flag(this, 'negate'),
pathInfo = isNested ? _.getPathInfo(obj, name) : null,
value = isNested ? pathInfo.value : obj[name],
isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
let descriptor = '';
if (isDeep) descriptor += 'deep ';
if (isOwn) descriptor += 'own ';
if (isNested) descriptor += 'nested ';
descriptor += 'property ';
let hasProperty;
if (isOwn) hasProperty = Object.prototype.hasOwnProperty.call(obj, name);
else if (isNested) hasProperty = pathInfo.exists;
else hasProperty = _.hasProperty(obj, name);
// When performing a negated assertion for both name and val, merely having
// a property with the given name isn't enough to cause the assertion to
// fail. It must both have a property with the given name, and the value of
// that property must equal the given val. Therefore, skip this assertion in
// favor of the next.
if (!negate || arguments.length === 1) {
this.assert(
hasProperty,
'expected #{this} to have ' + descriptor + _.inspect(name),
'expected #{this} to not have ' + descriptor + _.inspect(name)
);
}
if (arguments.length > 1) {
this.assert(
hasProperty && isEql(val, value),
'expected #{this} to have ' +
descriptor +
_.inspect(name) +
' of #{exp}, but got #{act}',
'expected #{this} to not have ' +
descriptor +
_.inspect(name) +
' of #{act}',
val,
value
);
}
flag(this, 'object', value);
}
Assertion.addMethod('property', assertProperty);
/**
* @param {unknown} _name
* @param {unknown} _value
* @param {string} _msg
*/
function assertOwnProperty(_name, _value, _msg) {
flag(this, 'own', true);
assertProperty.apply(this, arguments);
}
Assertion.addMethod('ownProperty', assertOwnProperty);
Assertion.addMethod('haveOwnProperty', assertOwnProperty);
/**
* ### .ownPropertyDescriptor(name[, descriptor[, msg]])
*
* Asserts that the target has its own property descriptor with the given key
* `name`. Enumerable and non-enumerable properties are included in the
* search.
*
* expect({a: 1}).to.have.ownPropertyDescriptor('a');
*
* When `descriptor` is provided, `.ownPropertyDescriptor` also asserts that
* the property's descriptor is deeply equal to the given `descriptor`. See
* the `deep-eql` project page for info on the deep equality algorithm:
* https://github.com/chaijs/deep-eql.
*
* expect({a: 1}).to.have.ownPropertyDescriptor('a', {
* configurable: true,
* enumerable: true,
* writable: true,
* value: 1,
* });
*
* Add `.not` earlier in the chain to negate `.ownPropertyDescriptor`.
*
* expect({a: 1}).to.not.have.ownPropertyDescriptor('b');
*
* However, it's dangerous to negate `.ownPropertyDescriptor` when providing
* a `descriptor`. The problem is that it creates uncertain expectations by
* asserting that the target either doesn't have a property descriptor with
* the given key `name`, or that it does have a property descriptor with the
* given key `name` but it’s not deeply equal to the given `descriptor`. It's
* often best to identify the exact output that's expected, and then write an
* assertion that only accepts that exact output.
*
* When the target isn't expected to have a property descriptor with the given
* key `name`, it's often best to assert exactly that.
*
* // Recommended
* expect({b: 2}).to.not.have.ownPropertyDescriptor('a');
*
* // Not recommended
* expect({b: 2}).to.not.have.ownPropertyDescriptor('a', {
* configurable: true,
* enumerable: true,
* writable: true,
* value: 1,
* });
*
* When the target is expected to have a property descriptor with the given
* key `name`, it's often best to assert that the property has its expected
* descriptor, rather than asserting that it doesn't have one of many
* unexpected descriptors.
*
* // Recommended
* expect({a: 3}).to.have.ownPropertyDescriptor('a', {
* configurable: true,
* enumerable: true,
* writable: true,
* value: 3,
* });
*
* // Not recommended
* expect({a: 3}).to.not.have.ownPropertyDescriptor('a', {
* configurable: true,
* enumerable: true,
* writable: true,
* value: 1,
* });
*
* `.ownPropertyDescriptor` changes the target of any assertions that follow
* in the chain to be the value of the property descriptor from the original
* target object.
*
* expect({a: 1}).to.have.ownPropertyDescriptor('a')
* .that.has.property('enumerable', true);
*
* `.ownPropertyDescriptor` accepts an optional `msg` argument which is a
* custom error message to show when the assertion fails. The message can also
* be given as the second argument to `expect`. When not providing
* `descriptor`, only use the second form.
*
* // Recommended
* expect({a: 1}).to.have.ownPropertyDescriptor('a', {
* configurable: true,
* enumerable: true,
* writable: true,
* value: 2,
* }, 'nooo why fail??');
*
* // Recommended
* expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('a', {
* configurable: true,
* enumerable: true,
* writable: true,
* value: 2,
* });
*
* // Recommended
* expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('b');
*
* // Not recommended
* expect({a: 1})
* .to.have.ownPropertyDescriptor('b', undefined, 'nooo why fail??');
*
* The above assertion isn't the same thing as not providing `descriptor`.
* Instead, it's asserting that the target object has a `b` property
* descriptor that's deeply equal to `undefined`.
*
* The alias `.haveOwnPropertyDescriptor` can be used interchangeably with
* `.ownPropertyDescriptor`.
*
* @name ownPropertyDescriptor
* @alias haveOwnPropertyDescriptor
* @param {string} name
* @param {object} descriptor _optional_
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertOwnPropertyDescriptor(name, descriptor, msg) {
if (typeof descriptor === 'string') {
msg = descriptor;
descriptor = null;
}
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object');
let actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
let eql = flag(this, 'eql');
if (actualDescriptor && descriptor) {
this.assert(
eql(descriptor, actualDescriptor),
'expected the own property descriptor for ' +
_.inspect(name) +
' on #{this} to match ' +
_.inspect(descriptor) +
', got ' +
_.inspect(actualDescriptor),
'expected the own property descriptor for ' +
_.inspect(name) +
' on #{this} to not match ' +
_.inspect(descriptor),
descriptor,
actualDescriptor,
true
);
} else {
this.assert(
actualDescriptor,
'expected #{this} to have an own property descriptor for ' +
_.inspect(name),
'expected #{this} to not have an own property descriptor for ' +
_.inspect(name)
);
}
flag(this, 'object', actualDescriptor);
}
Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor);
Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor);
/** */
function assertLengthChain() {
flag(this, 'doLength', true);
}
/**
* ### .lengthOf(n[, msg])
*
* Asserts that the target's `length` or `size` is equal to the given number
* `n`.
*
* expect([1, 2, 3]).to.have.lengthOf(3);
* expect('foo').to.have.lengthOf(3);
* expect(new Set([1, 2, 3])).to.have.lengthOf(3);
* expect(new Map([['a', 1], ['b', 2], ['c', 3]])).to.have.lengthOf(3);
*
* Add `.not` earlier in the chain to negate `.lengthOf`. However, it's often
* best to assert that the target's `length` property is equal to its expected
* value, rather than not equal to one of many unexpected values.
*
* expect('foo').to.have.lengthOf(3); // Recommended
* expect('foo').to.not.have.lengthOf(4); // Not recommended
*
* `.lengthOf` accepts an optional `msg` argument which is a custom error
* message to show when the assertion fails. The message can also be given as
* the second argument to `expect`.
*
* expect([1, 2, 3]).to.have.lengthOf(2, 'nooo why fail??');
* expect([1, 2, 3], 'nooo why fail??').to.have.lengthOf(2);
*
* `.lengthOf` can also be used as a language chain, causing all `.above`,
* `.below`, `.least`, `.most`, and `.within` assertions that follow in the
* chain to use the target's `length` property as the target. However, it's
* often best to assert that the target's `length` property is equal to its
* expected length, rather than asserting that its `length` property falls
* within some range of values.
*
* // Recommended
* expect([1, 2, 3]).to.have.lengthOf(3);
*
* // Not recommended
* expect([1, 2, 3]).to.have.lengthOf.above(2);
* expect([1, 2, 3]).to.have.lengthOf.below(4);
* expect([1, 2, 3]).to.have.lengthOf.at.least(3);
* expect([1, 2, 3]).to.have.lengthOf.at.most(3);
* expect([1, 2, 3]).to.have.lengthOf.within(2,4);
*
* Due to a compatibility issue, the alias `.length` can't be chained directly
* off of an uninvoked method such as `.a`. Therefore, `.length` can't be used
* interchangeably with `.lengthOf` in every situation. It's recommended to
* always use `.lengthOf` instead of `.length`.
*
* expect([1, 2, 3]).to.have.a.length(3); // incompatible; throws error
* expect([1, 2, 3]).to.have.a.lengthOf(3); // passes as expected
*
* @name lengthOf
* @alias length
* @param {number} n
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertLength(n, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
objType = _.type(obj).toLowerCase(),
flagMsg = flag(this, 'message'),
ssfi = flag(this, 'ssfi'),
descriptor = 'length',
itemsCount;
switch (objType) {
case 'map':
case 'set':
descriptor = 'size';
itemsCount = obj.size;
break;
default:
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
itemsCount = obj.length;
}
this.assert(
itemsCount == n,
'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}',
'expected #{this} to not have a ' + descriptor + ' of #{act}',
n,
itemsCount
);
}
Assertion.addChainableMethod('length', assertLength, assertLengthChain);
Assertion.addChainableMethod('lengthOf', assertLength, assertLengthChain);
/**
* ### .match(re[, msg])
*
* Asserts that the target matches the given regular expression `re`.
*
* expect('foobar').to.match(/^foo/);
*
* Add `.not` earlier in the chain to negate `.match`.
*
* expect('foobar').to.not.match(/taco/);
*
* `.match` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`.
*
* expect('foobar').to.match(/taco/, 'nooo why fail??');
* expect('foobar', 'nooo why fail??').to.match(/taco/);
*
* The alias `.matches` can be used interchangeably with `.match`.
*
* @name match
* @alias matches
* @param {RegExp} re
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
function assertMatch(re, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object');
this.assert(
re.exec(obj),
'expected #{this} to match ' + re,
'expected #{this} not to match ' + re
);
}
Assertion.addMethod('match', assertMatch);
Assertion.addMethod('matches', assertMatch);
/**
* ### .string(str[, msg])
*
* Asserts that the target string contains the given substring `str`.
*
* expect('foobar').to.have.string('bar');
*
* Add `.not` earlier in the chain to negate `.string`.
*
* expect('foobar').to.not.have.string('taco');
*
* `.string` accepts an optional `msg` argument which is a custom error
* message to show when the assertion fails. The message can also be given as
* the second argument to `expect`.
*
* expect('foobar').to.have.string('taco', 'nooo why fail??');
* expect('foobar', 'nooo why fail??').to.have.string('taco');
*
* @name string
* @param {string} str
* @param {string} msg _optional_
* @namespace BDD
* @public
*/
Assertion.addMethod('string', function (str, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
flagMsg = flag(this, 'message'),
ssfi = flag(this, 'ssfi');
new Assertion(obj, flagMsg, ssfi, true).is.a('string');
this.assert(
~obj.indexOf(str),
'expected #{this} to contain ' + _.inspect(str),
'expected #{this} to not contain ' + _.inspect(str)
);
});
/**
* ### .keys(key1[, key2[, ...]])
*
* Asserts that the target object, array, map, or set has the given keys. Only
* the target's own inherited properties are included in the search.
*
* When the target is an object or array, keys can be provided as one or more
* string arguments, a single array argument, or a single object argument. In
* the latter case, only the keys in the given object matter; the values are
* ignored.
*
* expect({a: 1, b: 2}).to.have.all.keys('a', 'b');
* expect(['x', 'y']).to.have.all.keys(0, 1);
*
* expect({a: 1, b: 2}).to.have.all.keys(['a', 'b']);
* expect(['x', 'y']).to.have.all.keys([0, 1]);
*
* expect({a: 1, b: 2}).to.have.all.keys({a: 4, b: 5}); // ignore 4 and 5
* expect(['x', 'y']).to.have.all.keys({0: 4, 1: 5}); // ignore 4 and 5
*
* When the target is a map or set, each key must be provided as a separate
* argument.
*
* expect(new Map([['a', 1], ['b', 2]])).to.have.all.keys('a', 'b');
* expect(new Set(['a', 'b'])).to.have.all.keys('a', 'b');
*
* Because `.keys` does different things based on the target's type, it's
* important to check the target's type before using `.keys`. See the `.a` doc
* for info on testing a target's type.
*
* expect({a: 1, b: 2}).to.be.an('object').that.has.all.keys('a', 'b');
*
* By default, strict (`===`) equality is used to compare keys of maps and
* sets. Add `.deep` earlier in the chain to use deep equality instead. See
* the `deep-eql` project page for info on the deep equality algorithm:
* https://github.com/chaijs/deep-eql.
*
* // Target set deeply (but not strictly) has key `{a: 1}`
* expect(new Set([{a: 1}])).to.have.all.deep.keys([{a: 1}]);
* expect(new Set([{a: 1}])).to.not.have.all.keys([{a: 1}]);
*
* By default, the target must have all of the given keys and no more. Add
* `.any` earlier in the chain to only require that the target have at least
* one of the given keys. Also, add `.not` earlier in the chain to negate
* `.keys`. It's often best to add `.any` when negating `.keys`, and to use
* `.all` when asserting `.keys` without negation.
*
* When negating `.keys`, `.any` is preferred because `.not.any.keys` asserts
* exactly what's expected of the output, whereas `.not.all.keys` creates
* uncertain expectations.
*
* // Recommended; asserts that target doesn't have any of the given keys
* expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');
*
* // Not recommended; asserts that target doesn't have all of the given
* // keys but may or may not have some of them
* expect({a: 1, b: 2}).to.not.have.all.keys('c', 'd');
*
* When asserting `.keys` without negation, `.all` is preferred because
* `.all.keys` asserts exactly what's expected of the output, whereas
* `.any.keys` creates uncertain expectations.
*
* // Recommended; asserts that target has all the given keys
* expect({a: 1, b: 2}).to.have.all.keys('a', 'b');
*
* // Not recommended; asserts that target has at least one of the given
* // keys but may or may not have more of them
* expect({a: 1, b: 2}).to.have.any.keys('a', 'b');
*
* Note that `.all` is used by default when neither `.all` nor `.any` appear
* earlier in the chain. However, it's often best to add `.all` anyway because
* it improves readability.
*
* // Both assertions are identical
* expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); // Recommended
* expect({a: 1, b: 2}).to.have.keys('a', 'b'); // Not recommended
*
* Add `.include` earlier in the chain to require that the target's keys be a
* superset of the expected keys, rather than identical sets.
*
* // Target object's keys are a superset of ['a', 'b'] but not identical
* expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b');
* expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b');
*
* However, if `.any` and `.include` are combined, only the `.any` takes
* effect. The `.include` is ignored in this case.
*
* // Both assertions are identical
* expect({a: 1}).to.have.any.keys('a', 'b');
* expect({a: 1}).to.include.any.keys('a', 'b');
*
* A custom error message can be given as the second argument to `expect`.
*
* expect({a: 1}, 'nooo why fail??').to.have.key('b');
*
* The alias `.key` can be used interchangeably with `.keys`.
*
* @name keys
* @alias key
* @param {...string | Array | object} keys
* @namespace BDD
* @public
*/
function assertKeys(keys) {
let obj = flag(this, 'object'),
objType = _.type(obj),
keysType = _.type(keys),
ssfi = flag(this, 'ssfi'),
isDeep = flag(this, 'deep'),
str,
deepStr = '',
actual,
ok = true,
flagMsg = flag(this, 'message');
flagMsg = flagMsg ? flagMsg + ': ' : '';
let mixedArgsMsg =
flagMsg +
'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments';
if (objType === 'Map' || objType === 'Set') {
deepStr = isDeep ? 'deeply ' : '';
actual = [];
// Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach.
obj.forEach(function (val, key) {
actual.push(key);
});
if (keysType !== 'Array') {
keys = Array.prototype.slice.call(arguments);
}
} else {
actual = _.getOwnEnumerableProperties(obj);
switch (keysType) {
case 'Array':
if (arguments.length > 1) {
throw new AssertionError(mixedArgsMsg, undefined, ssfi);
}
break;
case 'Object':
if (arguments.length > 1) {
throw new AssertionError(mixedArgsMsg, undefined, ssfi);
}
keys = Object.keys(keys);
break;
default:
keys = Array.prototype.slice.call(arguments);
}
// Only stringify non-Symbols because Symbols would become "Symbol()"
keys = keys.map(function (val) {
return typeof val === 'symbol' ? val : String(val);
});
}
if (!keys.length) {
throw new AssertionError(flagMsg + 'keys required', undefined, ssfi);
}
let len = keys.length,
any = flag(this, 'any'),
all = flag(this, 'all'),
expected = keys,
isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
if (!any && !all) {
all = true;
}
const uniqueExpected = [...new Set(expected)];
// Has any
if (any) {
ok = uniqueExpected.some(function (expectedKey) {
return actual.some(function (actualKey) {
return isEql(expectedKey, actualKey);
});
});
}
// Has all
if (all) {
ok = uniqueExpected.every(function (expectedKey) {
return actual.some(function (actualKey) {
return isEql(expectedKey, actualKey);
});
});
if (!flag(this, 'contains')) {
ok = ok && uniqueExpected.length == actual.length;
}
}
// Key string
if (len > 1) {
keys = keys.map(function (key) {
return _.inspect(key);
});
let last = keys.pop();
if (all) {
str = keys.join(', ') + ', and ' + last;
}
if (any) {
str = keys.join(', ') + ', or ' + last;
}
} else {
str = _.inspect(keys[0]);
}
// Form
str = (len > 1 ? 'keys ' : 'key ') + str;
// Have / include
str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
// Assertion
this.assert(
ok,
'expected #{this} to ' + deepStr + str,
'expected #{this} to not ' + deepStr + str,
expected.slice(0).sort(_.compareByInspect),
actual.sort(_.compareByInspect),
true
);
}
Assertion.addMethod('keys', assertKeys);
Assertion.addMethod('key', assertKeys);
/**
* ### .throw([errorLike], [errMsgMatcher], [msg])
*
* When no arguments are provided, `.throw` invokes the target function and
* asserts that an error is thrown.
*
* var badFn = function () { throw new TypeError('Illegal salmon!'); };
* expect(badFn).to.throw();
*
* When one argument is provided, and it's an error constructor, `.throw`
* invokes the target function and asserts that an error is thrown that's an
* instance of that error constructor.
*
* var badFn = function () { throw new TypeError('Illegal salmon!'); };
* expect(badFn).to.throw(TypeError);
*
* When one argument is provided, and it's an error instance, `.throw` invokes
* the target function and asserts that an error is thrown that's strictly
* (`===`) equal to that error instance.
*
* var err = new TypeError('Illegal salmon!');
* var badFn = function () { throw err; };
*
* expect(badFn).to.throw(err);
*
* When one argument is provided, and it's a string, `.throw` invokes the
* target function and asserts that an error is thrown with a message that
* contains that string.
*
* var badFn = function () { throw new TypeError('Illegal salmon!'); };
* expect(badFn).to.throw('salmon');
*
* When one argument is provided, and it's a regular expression, `.throw`
* invokes the target function and asserts that an error is thrown with a
* message that matches that regular expression.
*
* var badFn = function () { throw new TypeError('Illegal salmon!'); };
* expect(badFn).to.throw(/salmon/);
*
* When two arguments are provided, and the first is an error instance or
* constructor, and the second is a string or regular expression, `.throw`
* invokes the function and asserts that an error is thrown that fulfills both
* conditions as described above.
*
* var err = new TypeError('Illegal salmon!');
* var badFn = function () { throw err; };
*
* expect(badFn).to.throw(TypeError, 'salmon');
* expect(badFn).to.throw(TypeError, /salmon/);
* expect(badFn).to.throw(err, 'salmon');
* expect(badFn).to.throw(err, /salmon/);
*
* Add `.not` earlier in the chain to negate `.throw`.
*
* var goodFn = function () {};
* expect(goodFn).to.not.throw();
*
* However, it's dangerous to negate `.throw` when providing any arguments.
* The problem is that it creates uncertain expectations by asserting that the
* target either doesn't throw an error, or that it throws an error but of a
* different type than the given type, or that it throws an error of the given
* type but with a message that doesn't include the given string. It's often
* best to identify the exact output that's expected, and then write an
* assertion that only accepts that exact output.
*
* When the target isn't expected to throw an error, it's often best to assert
* exactly that.
*
* var goodFn = function () {};
*
* expect(goodFn).to.not.throw(); // Recommended
* expect(goodFn).to.not.throw(ReferenceError, 'x'); // Not recommended
*
* When the target is expected to throw an error, it's often best to assert
* that the error is of its expected type, and has a message that includes an
* expected string, rather than asserting that it doesn't have one of many
* unexpected types, and doesn't have a message that includes some string.
*
* var badFn = function () { throw new TypeError('Illegal salmon!'); };
*
* expect(badFn).to.throw(TypeError, 'salmon'); // Recommended
* expect(badFn).to.not.throw(ReferenceError, 'x'); // Not recommended
*
* `.throw` changes the target of any assertions that follow in the chain to
* be the error object that's thrown.
*
* var err = new TypeError('Illegal salmon!');
* err.code = 42;
* var badFn = function () { throw err; };
*
* expect(badFn).to.throw(TypeError).with.property('code', 42);
*
* `.throw` accepts an optional `msg` argument which is a custom error message
* to show when the assertion fails. The message can also be given as the
* second argument to `expect`. When not providing two arguments, always use
* the second form.
*
* var goodFn = function () {};
*
* expect(goodFn).to.throw(TypeError, 'x', 'nooo why fail??');
* expect(goodFn, 'nooo why fail??').to.throw();
*
* Due to limitations in ES5, `.throw` may not always work as expected when
* using a transpiler such as Babel or TypeScript. In particular, it may
* produce unexpected results when subclassing the built-in `Error` object and
* then passing the subclassed constructor to `.throw`. See your transpiler's
* docs for details:
*
* - ([Babel](https://babeljs.io/docs/usage/caveats/#classes))
* - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))
*
* Beware of some common mistakes when using the `throw` assertion. One common
* mistake is to accidentally invoke the function yourself instead of letting
* the `throw` assertion invoke the function for you. For example, when
* testing if a function named `fn` throws, provide `fn` instead of `fn()` as
* the target for the assertion.
*
* expect(fn).to.throw(); // Good! Tests `fn` as desired
* expect(fn()).to.throw(); // Bad! Tests result of `fn()`, not `fn`
*
* If you need to assert that your function `fn` throws when passed certain
* arguments, then wrap a call to `fn` inside of another function.
*
* expect(function () { fn(42); }).to.throw(); // Function expression
* expect(() => fn(42)).to.throw(); // ES6 arrow function
*
* Another common mistake is to provide an object method (or any stand-alone
* function that relies on `this`) as the target of the assertion. Doing so is
* problematic because the `this` context will be lost when the function is
* invoked by `.throw`; there's no way for it to know what `this` is supposed
* to be. There are two ways around this problem. One solution is to wrap the
* method or function call inside of another function. Another solution is to
* use `bind`.
*
* expect(function () { cat.meow(); }).to.throw(); // Function expression
* expect(() => cat.meow()).to.throw(); // ES6 arrow function
* expect(cat.meow.bind(cat)).to.throw(); // Bind
*
* Finally, it's worth mentioning that it's a best practice in JavaScript to
* only throw `Error` and derivatives of `Error` such as `ReferenceError`,
* `TypeError`, and user-defined objects that extend `Error`. No other type of
* value will generate a stack trace when initialized. With that said, the
* `throw` assertion does technically support any type of value being thrown,
* not just `Error` and its derivatives.
*
* The aliases `.throws` and `.Throw` can be used interchangeably with
* `.throw`.
*
* @name throw
* @alias throws
* @alias Throw
* @param {Error} errorLike
* @param {string | RegExp} errMsgMatcher error message
* @param {string} msg _optional_
* @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
* @returns {void} error for chaining (null if no error)
* @namespace BDD
* @public
*/
function assertThrows(errorLike, errMsgMatcher, msg) {
if (msg) flag(this, 'message', msg);
let obj = flag(this, 'object'),
ssfi = flag(this, 'ssfi'),
flagMsg = flag(this, 'message'),
negate = flag(this, 'negate') || false;
new Assertion(obj, flagMsg, ssfi, true).is.a('function');
if (_.isRegExp(errorLike) || typeof errorLike === 'string') {
errMsgMatcher = errorLike;
errorLike = null;
}
let caughtErr;
let errorWasThrown = false;
try {
obj();
} catch (err) {
errorWasThrown = true;
caughtErr = err;
}
// If we have the negate flag enabled and at least one valid argument it means we do expect an error
// but we want it to match a given set of criteria
let everyArgIsUndefined =
errorLike === undefined && errMsgMatcher === undefined;
// If we've got the negate flag enabled and both args, we should only fail if both aren't compatible
// See Issue #551 and PR #683@GitHub
let everyArgIsDefined = Boolean(errorLike && errMsgMatcher);
let errorLikeFail = false;
let errMsgMatcherFail = false;
// Checking if error was thrown
if (everyArgIsUndefined || (!everyArgIsUndefined && !negate)) {
// We need this to display results correctly according to their types
let errorLikeString = 'an error';
if (errorLike instanceof Error) {
errorLikeString = '#{exp}';
} else if (errorLike) {
errorLikeString = _.checkError.getConstructorName(errorLike);
}
let actual = caughtErr;
if (caughtErr instanceof Error) {
actual = caughtErr.toString();
} else if (typeof caughtErr === 'string') {
actual = caughtErr;
} else if (
caughtErr &&
(typeof caughtErr === 'object' || typeof caughtErr === 'function')
) {
try {
actual = _.checkError.getConstructorName(caughtErr);
} catch (_err) {
// somehow wasn't a constructor, maybe we got a function thrown
// or similar
}
}
this.assert(
errorWasThrown,
'expected #{this} to throw ' + errorLikeString,
'expected #{this} to not throw an error but #{act} was thrown',
errorLike && errorLike.toString(),
actual
);
}
if (errorLike && caughtErr) {
// We should compare instances only if `errorLike` is an instance of `Error`
if (errorLike instanceof Error) {
let isCompatibleInstance = _.checkError.compatibleInstance(
caughtErr,
errorLike
);
if (isCompatibleInstance === negate) {
// These checks were created to ensure we won't fail too soon when we've got both args and a negate
// See Issue #551 and PR #683@GitHub
if (everyArgIsDefined && negate) {
errorLikeFail = true;
} else {
this.assert(
negate,
'expected #{this} to throw #{exp} but #{act} was thrown',
'expected #{this} to not throw #{exp}' +
(caughtErr && !negate ? ' but #{act} was thrown' : ''),
errorLike.toString(),
caughtErr.toString()
);
}
}
}
let isCompatibleConstructor = _.checkError.compatibleConstructor(
caughtErr,
errorLike
);
if (isCompatibleConstructor === negate) {
if (everyArgIsDefined && negate) {
errorLikeFail = true;
} else {
this.assert(
negate,
'expected #{this} to throw #{exp} but #{act} was thrown',
'expected #{this} to not throw #{exp}' +
(caughtErr ? ' but #{act} was thrown' : ''),
errorLike instanceof Error
? errorLike.toString()
: errorLike && _.checkError.getConstructorName(errorLike),
caughtErr instanceof Error
? caughtErr.toString()
: caughtErr && _.checkError.getConstructorName(caughtErr)
);
}
}
}
if (caughtErr && errMsgMatcher !== undefined && errMsgMatcher !== null) {
// Here we check compatible messages
let placeholder = 'including';
if (_.isRegExp(errMsgMatcher)) {
placeholder = 'matching';
}
let isCompatibleMessage = _.checkError.compatibleMessage(
caughtErr,
errMsgMatcher
);
if (isCompatibleMessage === negate) {
if (everyArgIsDefined && negate) {
errMsgMatcherFail = true;
} else {
this.assert(
negate,
'expected #{this} to throw error ' +
placeholder +
' #{exp} but got #{act}',
'expected #{this} to throw error not ' + placeholder + ' #{exp}',
errMsgMatcher,
_.checkError.getMessage(caughtErr)
);
}
}
}
// If both assertions failed and both should've matched we throw an error
if (errorLikeFail && errMsgMatcherFail) {
this.assert(
negate,
'expected #{this} to throw #{exp} but #{act} was thrown',
'expected #{this} to not throw #{exp}' +
(caughtErr ? ' but #{act} was thrown' : ''),
errorLike instanceof Error
? errorLike.toString()
: errorLike && _.checkError.getConstructorName(errorLike),
caughtErr instanceof Error
? caughtErr.toString()
: caughtErr && _.checkError.getConstructorName(caughtErr)
);
}
flag(this, 'object', caughtErr);
}
Assertion.addMethod('throw', assertThrows);
Assertion.addMethod('throws', assertThrows);
Assertion.addMethod('Throw', assertThrows);
/**
* ### .respondTo(method[, msg])
*
* When the target is a non-function object, `.respondTo` asserts that the
* target has a method with the given name `method`. The method can be own or
* inherited, and it can be enumerable or non-enumerable.
*
* function Cat () {}
* Cat.prototype.meow = function () {};
*
* expect(new Cat()).to.respondTo('meow');
*
* When the target is a function, `.respondTo` asserts that the target's
* `prototype` property has a method with the given name `method`. Again, the
* method can be own or inherited, and it can be enumerable or non-enumerable.
*
* function Cat () {}
* Cat.prototype.meow = function () {};
*
* expect(Cat).to.respondTo('meow');
*
* Add `.itself` earlier in the chain to force `.respondTo` to treat the
* target as a non-function object, even if it's a function. Thus, it asserts
* that the target has a method with the given name `method`, rather than
* asserting that the target's `prototype` property has a method with the
* given name `method`.
*
* function Cat () {}
*
gitextract_qa5zm9sp/ ├── .github/ │ ├── FUNDING.yml │ ├── renovate.json │ └── workflows/ │ ├── browsers.yml │ ├── node.js.yml │ └── npm-publish.yml ├── .gitignore ├── .mailmap ├── .prettierrc.json ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── History.md ├── LICENSE ├── README.md ├── ReleaseNotes.md ├── eslint.config.js ├── lib/ │ ├── chai/ │ │ ├── assertion.js │ │ ├── config.js │ │ ├── core/ │ │ │ └── assertions.js │ │ ├── interface/ │ │ │ ├── assert.js │ │ │ ├── expect.js │ │ │ └── should.js │ │ └── utils/ │ │ ├── addChainableMethod.js │ │ ├── addLengthGuard.js │ │ ├── addMethod.js │ │ ├── addProperty.js │ │ ├── compareByInspect.js │ │ ├── events.js │ │ ├── expectTypes.js │ │ ├── flag.js │ │ ├── getActual.js │ │ ├── getMessage.js │ │ ├── getOperator.js │ │ ├── getOwnEnumerableProperties.js │ │ ├── getOwnEnumerablePropertySymbols.js │ │ ├── getProperties.js │ │ ├── index.js │ │ ├── inspect.js │ │ ├── isNaN.js │ │ ├── isProxyEnabled.js │ │ ├── objDisplay.js │ │ ├── overwriteChainableMethod.js │ │ ├── overwriteMethod.js │ │ ├── overwriteProperty.js │ │ ├── proxify.js │ │ ├── test.js │ │ ├── transferFlags.js │ │ └── type-detect.js │ └── chai.js ├── package.json ├── register-assert.js ├── register-expect.js ├── register-should.js ├── test/ │ ├── assert.js │ ├── auth/ │ │ └── .gitkeep │ ├── bootstrap/ │ │ └── index.js │ ├── configuration.js │ ├── display/ │ │ ├── errors.js │ │ └── message.js │ ├── expect.js │ ├── globalErr.js │ ├── globalShould.js │ ├── plugins.js │ ├── should.js │ ├── subset.js │ ├── type-detect/ │ │ ├── deno-test.ts │ │ ├── dom.js │ │ ├── index.js │ │ ├── new-ecmascript-types.js │ │ ├── node.js │ │ └── tostringtag-extras.js │ ├── utilities.js │ └── virtual-machines.js ├── tsconfig.json └── web-test-runner.config.js
SYMBOL INDEX (142 symbols across 45 files)
FILE: lib/chai.js
function use (line 30) | function use(fn) {
FILE: lib/chai/assertion.js
class Assertion (line 12) | class Assertion {
method constructor (line 51) | constructor(obj, msg, ssfi, lockSsfi) {
method includeStack (line 62) | static get includeStack() {
method includeStack (line 70) | static set includeStack(value) {
method showDiff (line 78) | static get showDiff() {
method showDiff (line 86) | static set showDiff(value) {
method addProperty (line 97) | static addProperty(name, fn) {
method addMethod (line 105) | static addMethod(name, fn) {
method addChainableMethod (line 114) | static addChainableMethod(name, fn, chainingBehavior) {
method overwriteProperty (line 122) | static overwriteProperty(name, fn) {
method overwriteMethod (line 130) | static overwriteMethod(name, fn) {
method overwriteChainableMethod (line 139) | static overwriteChainableMethod(name, fn, chainingBehavior) {
method assert (line 157) | assert(_expr, msg, _negateMsg, expected, _actual, showDiff) {
method _obj (line 192) | get _obj() {
method _obj (line 201) | set _obj(val) {
FILE: lib/chai/core/assertions.js
function an (line 328) | function an(type, msg) {
function SameValueZero (line 359) | function SameValueZero(a, b) {
function includeChainingBehavior (line 364) | function includeChainingBehavior() {
function include (line 514) | function include(val, msg) {
function assertExist (line 925) | function assertExist() {
function checkArguments (line 1060) | function checkArguments() {
function assertEqual (line 1117) | function assertEqual(val, msg) {
function assertEql (line 1181) | function assertEql(obj, msg) {
function assertAbove (line 1239) | function assertAbove(n, msg) {
function assertLeast (line 1349) | function assertLeast(n, msg) {
function assertBelow (line 1455) | function assertBelow(n, msg) {
function assertMost (line 1562) | function assertMost(n, msg) {
function assertInstanceOf (line 1773) | function assertInstanceOf(constructor, msg) {
function assertProperty (line 1923) | function assertProperty(name, val, msg) {
function assertOwnProperty (line 2031) | function assertOwnProperty(_name, _value, _msg) {
function assertOwnPropertyDescriptor (line 2157) | function assertOwnPropertyDescriptor(name, descriptor, msg) {
function assertLengthChain (line 2199) | function assertLengthChain() {
function assertLength (line 2260) | function assertLength(n, msg) {
function assertMatch (line 2319) | function assertMatch(re, msg) {
function assertKeys (line 2473) | function assertKeys(keys) {
function assertThrows (line 2760) | function assertThrows(errorLike, errMsgMatcher, msg) {
function respondTo (line 2994) | function respondTo(method, msg) {
function satisfy (line 3073) | function satisfy(matcher, msg) {
function closeTo (line 3126) | function closeTo(expected, delta, msg) {
function isSubsetOf (line 3176) | function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
function oneOf (line 3381) | function oneOf(list, msg) {
function assertChanges (line 3520) | function assertChanges(subject, prop, msg) {
function assertIncreases (line 3636) | function assertIncreases(subject, prop, msg) {
function assertDecreases (line 3754) | function assertDecreases(subject, prop, msg) {
function assertDelta (line 3859) | function assertDelta(delta, msg) {
function compareSubset (line 4078) | function compareSubset(expected, actual) {
FILE: lib/chai/interface/assert.js
function assert (line 26) | function assert(express, errmsg) {
FILE: lib/chai/interface/expect.js
function expect (line 16) | function expect(val, message) {
FILE: lib/chai/interface/should.js
function loadShould (line 13) | function loadShould() {
FILE: lib/chai/utils/addChainableMethod.js
class PluginAddChainableMethodEvent (line 40) | class PluginAddChainableMethodEvent extends PluginEvent {
method constructor (line 41) | constructor(type, name, fn, chainingBehavior) {
function addChainableMethod (line 75) | function addChainableMethod(ctx, name, method, chainingBehavior) {
FILE: lib/chai/utils/addLengthGuard.js
function addLengthGuard (line 43) | function addLengthGuard(fn, assertionName, isChainable) {
FILE: lib/chai/utils/addMethod.js
function addMethod (line 39) | function addMethod(ctx, name, method) {
FILE: lib/chai/utils/addProperty.js
function addProperty (line 38) | function addProperty(ctx, name, getter) {
FILE: lib/chai/utils/compareByInspect.js
function compareByInspect (line 24) | function compareByInspect(a, b) {
FILE: lib/chai/utils/events.js
class PluginEvent (line 10) | class PluginEvent extends Event {
method constructor (line 11) | constructor(type, name, fn) {
FILE: lib/chai/utils/expectTypes.js
function expectTypes (line 24) | function expectTypes(obj, types) {
FILE: lib/chai/utils/flag.js
function flag (line 27) | function flag(obj, key, value) {
FILE: lib/chai/utils/getActual.js
function getActual (line 18) | function getActual(obj, args) {
FILE: lib/chai/utils/getMessage.js
function getMessage (line 30) | function getMessage(obj, args) {
FILE: lib/chai/utils/getOperator.js
function isObjectType (line 8) | function isObjectType(obj) {
function getOperator (line 31) | function getOperator(obj, args) {
FILE: lib/chai/utils/getOwnEnumerableProperties.js
function getOwnEnumerableProperties (line 22) | function getOwnEnumerableProperties(obj) {
FILE: lib/chai/utils/getOwnEnumerablePropertySymbols.js
function getOwnEnumerablePropertySymbols (line 20) | function getOwnEnumerablePropertySymbols(obj) {
FILE: lib/chai/utils/getProperties.js
function getProperties (line 19) | function getProperties(object) {
FILE: lib/chai/utils/index.js
function getName (line 50) | function getName(fn) {
function isRegExp (line 109) | function isRegExp(obj) {
function isNumeric (line 119) | function isNumeric(obj) {
FILE: lib/chai/utils/inspect.js
function inspect (line 23) | function inspect(obj, showHidden, depth, colors) {
FILE: lib/chai/utils/isProxyEnabled.js
function isProxyEnabled (line 20) | function isProxyEnabled() {
FILE: lib/chai/utils/objDisplay.js
function objDisplay (line 23) | function objDisplay(obj) {
FILE: lib/chai/utils/overwriteChainableMethod.js
function overwriteChainableMethod (line 42) | function overwriteChainableMethod(ctx, name, method, chainingBehavior) {
FILE: lib/chai/utils/overwriteMethod.js
function overwriteMethod (line 46) | function overwriteMethod(ctx, name, method) {
FILE: lib/chai/utils/overwriteProperty.js
function overwriteProperty (line 44) | function overwriteProperty(ctx, name, getter) {
FILE: lib/chai/utils/proxify.js
function proxify (line 34) | function proxify(obj, nonChainableMethodName) {
function stringDistanceCapped (line 125) | function stringDistanceCapped(strA, strB, cap) {
FILE: lib/chai/utils/test.js
function test (line 20) | function test(obj, args) {
FILE: lib/chai/utils/transferFlags.js
function transferFlags (line 28) | function transferFlags(assertion, object, includeAll) {
FILE: lib/chai/utils/type-detect.js
function type (line 5) | function type(obj) {
FILE: test/assert.js
function Foo (line 197) | function Foo(){}
function Thing (line 236) | function Thing(){}
function CrashyObject (line 260) | function CrashyObject() {}
function Foo (line 268) | function Foo(){}
function Foo (line 315) | function Foo(){}
function Foo (line 333) | function Foo(){}
class CustomError (line 1676) | class CustomError extends Error {}
function CustomError (line 1737) | function CustomError(message) {
function FakeArgs (line 2808) | function FakeArgs() {}
function FakeArgs (line 2901) | function FakeArgs() {}
FILE: test/bootstrap/index.js
function globalErr (line 30) | function globalErr(fn, val, skipStackTest) {
FILE: test/configuration.js
function clone (line 14) | function clone(o) {
function badPropertyAssertion (line 73) | function badPropertyAssertion() {
function badOverwrittenPropertyAssertion (line 76) | function badOverwrittenPropertyAssertion() {
function badMethodAssertion (line 79) | function badMethodAssertion() {
function badOverwrittenMethodAssertion (line 82) | function badOverwrittenMethodAssertion() {
function badChainableMethodAssertion (line 85) | function badChainableMethodAssertion() {
function badOverwrittenChainableMethodAssertion (line 88) | function badOverwrittenChainableMethodAssertion() {
function badPropertyAssertion (line 367) | function badPropertyAssertion() {
function badOverwrittenPropertyAssertion (line 370) | function badOverwrittenPropertyAssertion() {
function badMethodAssertion (line 373) | function badMethodAssertion() {
function badOverwrittenMethodAssertion (line 376) | function badOverwrittenMethodAssertion() {
function badChainableMethodAssertion (line 379) | function badChainableMethodAssertion() {
function badOverwrittenChainableMethodAssertion (line 382) | function badOverwrittenChainableMethodAssertion() {
FILE: test/expect.js
function test (line 213) | function test(chain) {
function Foo (line 468) | function Foo(){}
function Thing (line 511) | function Thing(){}
function FakeArgs (line 1549) | function FakeArgs() {}
function CustomError (line 3062) | function CustomError(message) {
function Foo (line 3224) | function Foo(){}
FILE: test/globalErr.js
function f1 (line 98) | function f1 () {
function f2 (line 102) | function f2 () {
FILE: test/plugins.js
function plugin (line 5) | function plugin (chai) {
method get (line 38) | get() {
function anotherPlugin (line 49) | function anotherPlugin (chai) {
FILE: test/should.js
function test (line 214) | function test(chain) {
function assert (line 414) | function assert(value) {
function Foo (line 460) | function Foo(){}
function Thing (line 499) | function Thing(){}
function FakeArgs (line 1287) | function FakeArgs() {}
function CustomError (line 2532) | function CustomError(message) {
function Foo (line 2715) | function Foo(){}
FILE: test/type-detect/dom.js
function assert (line 3) | function assert (expr, msg) {
function describeIf (line 11) | function describeIf(condition) {
function itIf (line 14) | function itIf(condition) {
FILE: test/type-detect/index.js
function assert (line 3) | function assert (expr, msg) {
function Noop (line 67) | function Noop() {}
method get (line 80) | get() {
function stubObjectToStringOnce (line 118) | function stubObjectToStringOnce(staticValue) {
function Thing (line 124) | function Thing() {}
FILE: test/type-detect/new-ecmascript-types.js
function assert (line 3) | function assert (expr, msg) {
function itIf (line 28) | function itIf(condition) {
function noop (line 82) | function noop() {}
FILE: test/type-detect/node.js
function assert (line 3) | function assert (expr, msg) {
function describeIf (line 12) | function describeIf(condition) {
FILE: test/type-detect/tostringtag-extras.js
function assert (line 3) | function assert (expr, msg) {
function describeIf (line 13) | function describeIf(condition) {
FILE: test/utilities.js
function expected (line 1370) | function expected () {
function expected (line 1450) | function expected () {
FILE: test/virtual-machines.js
function runCodeInVm (line 13) | function runCodeInVm(code) {
Condensed preview — 75 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (891K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 23,
"preview": "open_collective: chaijs"
},
{
"path": ".github/renovate.json",
"chars": 301,
"preview": "{\n \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n \"baseBranchPatterns\": [\"main\"],\n \"extends\": [\"con"
},
{
"path": ".github/workflows/browsers.yml",
"chars": 767,
"preview": "# This workflow will do a clean install of node dependencies, build the source\n# code and run tests across different ver"
},
{
"path": ".github/workflows/node.js.yml",
"chars": 1379,
"preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
},
{
"path": ".github/workflows/npm-publish.yml",
"chars": 1303,
"preview": "# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created\n# For "
},
{
"path": ".gitignore",
"chars": 168,
"preview": "lib-cov\n*.seed\n*.log\n*.csv\n*.dat\n*.out\n*.pid\n*.gz\n\npids\nlogs\nresults\nbuild\ncomponents\n\nnode_modules\nnpm-debug.log\n\ncover"
},
{
"path": ".mailmap",
"chars": 47,
"preview": "Domenic Denicola <domenic@domenicdenicola.com>\n"
},
{
"path": ".prettierrc.json",
"chars": 180,
"preview": "{\n \"bracketSpacing\": false,\n \"printWidth\": 80,\n \"semi\": true,\n \"singleQuote\": true,\n \"tabWidth\": 2,\n \"trailingComm"
},
{
"path": "CODEOWNERS",
"chars": 21,
"preview": "* @chaijs/chai\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 2863,
"preview": "# Contributor Code of Conduct\n\n> Read in: [Español](http://contributor-covenant.org/version/1/3/0/es/) |\n[Français](http"
},
{
"path": "CONTRIBUTING.md",
"chars": 10129,
"preview": "# Chai Contribution Guidelines\n\nWe like to encourage you to contribute to the Chai.js repository. This should be as easy"
},
{
"path": "History.md",
"chars": 37589,
"preview": "### Note\n\nAs of 3.0.0, the History.md file has been deprecated. [Please refer to the full\ncommit logs available on GitHu"
},
{
"path": "LICENSE",
"chars": 1082,
"preview": "MIT License\n\nCopyright (c) 2017 Chai.js Assertion Library\n\nPermission is hereby granted, free of charge, to any person o"
},
{
"path": "README.md",
"chars": 6221,
"preview": "<h1 align=center>\n <a href=\"http://chaijs.com\" title=\"Chai Documentation\">\n <img alt=\"ChaiJS\" src=\"http://chaijs.com"
},
{
"path": "ReleaseNotes.md",
"chars": 30024,
"preview": "# Release Notes\n\n## Note\n\nAs of 3.0.0, the ReleaseNotes.md file has been deprecated. [Please refer to the release notes "
},
{
"path": "eslint.config.js",
"chars": 702,
"preview": "import jsdoc from \"eslint-plugin-jsdoc\";\nimport eslintjs from \"@eslint/js\";\nimport globals from \"globals\";\n\nconst {confi"
},
{
"path": "lib/chai/assertion.js",
"chars": 6525,
"preview": "/*!\n * chai\n * http://chaijs.com\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimp"
},
{
"path": "lib/chai/config.js",
"chars": 3785,
"preview": "export const config = {\n /**\n * ### config.includeStack\n *\n * User configurable property, influences whether stac"
},
{
"path": "lib/chai/core/assertions.js",
"chars": 135719,
"preview": "/*!\n * chai\n * http://chaijs.com\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimp"
},
{
"path": "lib/chai/interface/assert.js",
"chars": 91016,
"preview": "/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimport * as chai from '."
},
{
"path": "lib/chai/interface/expect.js",
"chars": 1252,
"preview": "/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimport * as chai from '."
},
{
"path": "lib/chai/interface/should.js",
"chars": 6039,
"preview": "/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimport {Assertion} from "
},
{
"path": "lib/chai/utils/addChainableMethod.js",
"chars": 5698,
"preview": "/*!\n * Chai - addChainingMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n "
},
{
"path": "lib/chai/utils/addLengthGuard.js",
"chars": 2529,
"preview": "const fnLengthDesc = Object.getOwnPropertyDescriptor(function () {}, 'length');\n\n/*!\n * Chai - addLengthGuard utility\n *"
},
{
"path": "lib/chai/utils/addMethod.js",
"chars": 2291,
"preview": "/*!\n * Chai - addMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimpo"
},
{
"path": "lib/chai/utils/addProperty.js",
"chars": 2511,
"preview": "/*!\n * Chai - addProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nim"
},
{
"path": "lib/chai/utils/compareByInspect.js",
"chars": 770,
"preview": "/*!\n * Chai - compareByInspect utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n *"
},
{
"path": "lib/chai/utils/events.js",
"chars": 330,
"preview": "/*!\n * Chai - events utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n// Glob"
},
{
"path": "lib/chai/utils/expectTypes.js",
"chars": 1465,
"preview": "/*!\n * Chai - expectTypes utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nim"
},
{
"path": "lib/chai/utils/flag.js",
"chars": 881,
"preview": "/*!\n * Chai - flag utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ##"
},
{
"path": "lib/chai/utils/getActual.js",
"chars": 484,
"preview": "/*!\n * Chai - getActual utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n"
},
{
"path": "lib/chai/utils/getMessage.js",
"chars": 1397,
"preview": "/*!\n * Chai - message composition utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed"
},
{
"path": "lib/chai/utils/getOperator.js",
"chars": 1324,
"preview": "import {flag} from './flag.js';\nimport {type} from './type-detect.js';\n\n/**\n * @param {unknown} obj\n * @returns {boolean"
},
{
"path": "lib/chai/utils/getOwnEnumerableProperties.js",
"chars": 736,
"preview": "/*!\n * Chai - getOwnEnumerableProperties utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT L"
},
{
"path": "lib/chai/utils/getOwnEnumerablePropertySymbols.js",
"chars": 800,
"preview": "/*!\n * Chai - getOwnEnumerablePropertySymbols utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * "
},
{
"path": "lib/chai/utils/getProperties.js",
"chars": 816,
"preview": "/*!\n * Chai - getProperties utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n"
},
{
"path": "lib/chai/utils/index.js",
"chars": 2780,
"preview": "/*!\n * chai\n * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n// Dependencies that are used"
},
{
"path": "lib/chai/utils/inspect.js",
"chars": 1120,
"preview": "// This is (almost) directly from Node.js utils\n// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3"
},
{
"path": "lib/chai/utils/isNaN.js",
"chars": 164,
"preview": "/*!\n * Chai - isNaN utility\n * Copyright(c) 2012-2015 Sakthipriyan Vairamani <thechargingvolcano@gmail.com>\n * MIT Licen"
},
{
"path": "lib/chai/utils/isProxyEnabled.js",
"chars": 601,
"preview": "import {config} from '../config.js';\n\n/*!\n * Chai - isProxyEnabled helper\n * Copyright(c) 2012-2014 Jake Luer <jake@alog"
},
{
"path": "lib/chai/utils/objDisplay.js",
"chars": 1240,
"preview": "/*!\n * Chai - flag utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimport {i"
},
{
"path": "lib/chai/utils/overwriteChainableMethod.js",
"chars": 2165,
"preview": "/*!\n * Chai - overwriteChainableMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Lic"
},
{
"path": "lib/chai/utils/overwriteMethod.js",
"chars": 3124,
"preview": "/*!\n * Chai - overwriteMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */"
},
{
"path": "lib/chai/utils/overwriteProperty.js",
"chars": 3235,
"preview": "/*!\n * Chai - overwriteProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n "
},
{
"path": "lib/chai/utils/proxify.js",
"chars": 5493,
"preview": "import {config} from '../config.js';\nimport {flag} from './flag.js';\nimport {getProperties} from './getProperties.js';\ni"
},
{
"path": "lib/chai/utils/test.js",
"chars": 477,
"preview": "/*!\n * Chai - test utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimport {f"
},
{
"path": "lib/chai/utils/transferFlags.js",
"chars": 1402,
"preview": "/*!\n * Chai - transferFlags utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n"
},
{
"path": "lib/chai/utils/type-detect.js",
"chars": 384,
"preview": "/**\n * @param {unknown} obj\n * @returns {string}\n */\nexport function type(obj) {\n if (typeof obj === 'undefined') {\n "
},
{
"path": "lib/chai.js",
"chars": 1276,
"preview": "/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nimport * as util from '."
},
{
"path": "package.json",
"chars": 2097,
"preview": "{\n \"author\": \"Jake Luer <jake@alogicalparadox.com>\",\n \"name\": \"chai\",\n \"type\": \"module\",\n \"description\": \"BDD/TDD as"
},
{
"path": "register-assert.js",
"chars": 64,
"preview": "import {assert} from './index.js';\n\nglobalThis.assert = assert;\n"
},
{
"path": "register-expect.js",
"chars": 64,
"preview": "import {expect} from './index.js';\n\nglobalThis.expect = expect;\n"
},
{
"path": "register-should.js",
"chars": 66,
"preview": "import {should} from './index.js';\n\nglobalThis.should = should();\n"
},
{
"path": "test/assert.js",
"chars": 98795,
"preview": "import * as chai from '../index.js';\nimport {globalErr as err} from './bootstrap/index.js';\n\ndescribe('assert', function"
},
{
"path": "test/auth/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "test/bootstrap/index.js",
"chars": 2006,
"preview": "import * as chai from '../../index.js';\n\nvar isStackSupported = false;\nif (typeof Error.captureStackTrace !== 'undefined"
},
{
"path": "test/configuration.js",
"chars": 25815,
"preview": "import * as chai from '../index.js';\nimport {globalErr as err} from './bootstrap/index.js';\n\nimport '../register-should."
},
{
"path": "test/display/errors.js",
"chars": 219,
"preview": "import * as chai from '../../index.js';\n\nvar expect = chai.expect;\n\nchai.config.includeStack = true;\n\ndescribe('error di"
},
{
"path": "test/display/message.js",
"chars": 857,
"preview": "import * as chai from '../../index.js'\n\nconst expect = chai.expect\n\nvar deepObj = {\n green: { tea: 'matcha' }\n , tea"
},
{
"path": "test/expect.js",
"chars": 140512,
"preview": "import * as chai from '../index.js';\nimport {globalErr as err} from './bootstrap/index.js';\n\ndescribe('expect', function"
},
{
"path": "test/globalErr.js",
"chars": 8505,
"preview": "import * as chai from '../index.js';\nimport {globalErr as err} from './bootstrap/index.js';\n\ndescribe('globalErr', funct"
},
{
"path": "test/globalShould.js",
"chars": 357,
"preview": "import * as chai from '../index.js';\n\ndescribe('global should', function () {\n it('works', function () {\n var theGlo"
},
{
"path": "test/plugins.js",
"chars": 1526,
"preview": "import * as chai from '../index.js';\n\ndescribe('plugins', function () {\n\n function plugin (chai) {\n if (chai.Asserti"
},
{
"path": "test/should.js",
"chars": 111147,
"preview": "import * as chai from '../index.js';\nimport {globalErr as err} from './bootstrap/index.js';\n\ndescribe('should', function"
},
{
"path": "test/subset.js",
"chars": 5538,
"preview": "import * as chai from '../index.js';\n\ndescribe('containsSubset', function () {\n const {assert, expect} = chai;\n const "
},
{
"path": "test/type-detect/deno-test.ts",
"chars": 243,
"preview": "/* global Deno:readonly */\n// @ts-nocheck\nimport { assertEquals } from 'https://deno.land/std/testing/asserts.ts';\nimpor"
},
{
"path": "test/type-detect/dom.js",
"chars": 10865,
"preview": "import * as chai from '../../index.js';\n\nfunction assert (expr, msg) {\n if (!expr) {\n throw new Error(msg || 'Assert"
},
{
"path": "test/type-detect/index.js",
"chars": 7607,
"preview": "import * as chai from '../../index.js';\n\nfunction assert (expr, msg) {\n if (!expr) {\n throw new Error(msg || 'Assert"
},
{
"path": "test/type-detect/new-ecmascript-types.js",
"chars": 4486,
"preview": "import * as chai from '../../index.js';\n\nfunction assert (expr, msg) {\n if (!expr) {\n throw new Error(msg || 'Assert"
},
{
"path": "test/type-detect/node.js",
"chars": 552,
"preview": "import * as chai from '../../index.js';\n\nfunction assert (expr, msg) {\n if (!expr) {\n throw new Error(msg || 'Assert"
},
{
"path": "test/type-detect/tostringtag-extras.js",
"chars": 668,
"preview": "import * as chai from '../../index.js';\n\nfunction assert (expr, msg) {\n if (!expr) {\n throw new Error(msg || 'Assert"
},
{
"path": "test/utilities.js",
"chars": 50378,
"preview": "import * as chai from '../index.js';\n\ndescribe('utilities', function () {\n const expect = chai.expect;\n\n after(functio"
},
{
"path": "test/virtual-machines.js",
"chars": 822,
"preview": "import vm from 'node:vm';\nimport * as chai from '../index.js';\n\nconst {assert} = chai;\nconst vmContext = {assert};\nvm.cr"
},
{
"path": "tsconfig.json",
"chars": 367,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"esnext\",\n \"module\": \"nodenext\",\n \"moduleResolution\": \"nodenext\",\n \"type"
},
{
"path": "web-test-runner.config.js",
"chars": 450,
"preview": "import { fromRollup } from \"@web/dev-server-rollup\";\nimport rollupCommonjs from \"@rollup/plugin-commonjs\";\n\nconst common"
}
]
About this extraction
This page contains the full source code of the chaijs/chai GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 75 files (836.6 KB), approximately 237.2k tokens, and a symbol index with 142 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.