{"id":23413647,"url":"https://github.com/rmdm/assert-match","last_synced_at":"2025-04-12T05:43:54.666Z","repository":{"id":57185024,"uuid":"86216845","full_name":"rmdm/assert-match","owner":"rmdm","description":"assert + matchers \u003c3","archived":false,"fork":false,"pushed_at":"2017-10-14T13:56:28.000Z","size":99,"stargazers_count":29,"open_issues_count":0,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-24T18:55:05.264Z","etag":null,"topics":["assert","assertions","ismatch","match","matchers"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rmdm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-26T07:58:25.000Z","updated_at":"2023-01-09T23:10:53.000Z","dependencies_parsed_at":"2022-09-14T10:11:07.371Z","dependency_job_id":null,"html_url":"https://github.com/rmdm/assert-match","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fassert-match","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fassert-match/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fassert-match/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdm%2Fassert-match/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rmdm","download_url":"https://codeload.github.com/rmdm/assert-match/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248525156,"owners_count":21118616,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assert","assertions","ismatch","match","matchers"],"created_at":"2024-12-22T19:53:55.951Z","updated_at":"2025-04-12T05:43:54.610Z","avatar_url":"https://github.com/rmdm.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/rmdm/assert-match.svg?branch=master)](https://travis-ci.org/rmdm/assert-match)\n[![Coverage Status](https://coveralls.io/repos/github/rmdm/assert-match/badge.svg?branch=master)](https://coveralls.io/github/rmdm/assert-match?branch=master)\n\nassert-match\n===============\n\n`assert-match` is the enhancement of the standard `assert` module with matchers.\n\nShort example\n=============\n\n```javascript\nimport assert from 'assert-match'\nimport { loose, arrayOf, type } from 'assert-match/matchers'\n// or const { loose, arrayOf, type } = assert.matchers\n\nconst actual = {\n        str: 'abc',\n        obj: { b: 1, c: 2 },\n        nums: [ 1, 2, 'x' ],\n    },\n    expected = {\n        str: 'abc',\n        obj: loose({ b: 1 }),\n        nums: arrayOf(type('number')),\n    }\n\nassert.deepEqual(actual, expected)\n\n//  AssertionError: { str: 'abc', obj: { b: 1 }, nums: [ 1, 2, 'x' ] } deepEqual\n//  { str: 'abc',  obj: { b: 1 }, nums: [ 1, 2, { '[typeof]': 'number' } ] }\n//        + expected - actual\n//\n//         {\n//           \"nums\": [\n//             1\n//             2\n//        -    \"x\"\n//        +    {\n//        +      \"[typeof]\": \"number\"\n//        +    }\n//           ]\n\n```\n\nInstallation\n============\n\n```sh\n    npm install assert-match\n```\n\nUsage\n=====\n\nUse `assert-match` in all the same places where you would use built-in `assert`:\n\n```javascript\nconst assert = require('assert-match')\n\n// ...\n\nassert.deepEqual(actual, expected)\n```\n\nAssertions\n----------\n\n`assert-match` enhances standard `assert`'s `deep`-family assertions:\n\n- ```assert.deepEqual (actual, expected, [message])```\n- ```assert.deepStrictEqual (actual, expected, [message])```\n- ```assert.notDeepEqual (actual, expected, [message])```\n- ```assert.notDeepStrictEqual (actual, expected, [message])```\n\n`assert-match` allows you to check **actual** value (or its property) not\nagainst a specific **expected** value as standard `deep` assertions do, but\nagainst a matcher or a combination of them.\nWithout using matchers these assertions behave exactly like their standard\ncounterparts which [has been tested](test/core/test-assert.spec.js) against the\nsame set of tests as the standard ones.\n\nOther assertions of `assert` are also exported by `assert-match` but not\nenhanced with matchers support.\n\nMatchers\n--------\n\nA matcher is an objects used to check if a value satisfies some requirements\ndefined by the matcher.\n\nMatchers can be placed on the top level of **expected** value or on some of its\nproperties.\n\nAn awesome point about matchers is the ability to combine them! It gives you a\nway to create powerful matching structures using small set of matchers.\n\nMatchers and combinations of them can be reused and recombined across multiple\nassertions.\n\nIn cases of assertion errors matchers participate in providing your test runner\nwith error details.\n\n`assert-match` defines the following matchers:\n\n- [strict (expected)](#strict-expected)\n- [loose (expected)](#loose-expected)\n- [any (expected)](#any-expected)\n- [not (expected)](#not-expected)\n- [every (expected)](#every-expected)\n- [some (expected)](#some-expected)\n- [arrayOf (expected)](#arrayof-expected)\n- [contains (expected)](#contains-expected1-expected2)\n- [type (expected)](#type-expected)\n- [primitive (expected)](#primitive-expected)\n- [regex (expected)](#regex-expected)\n- [gt (expected)](#gt-expected)\n- [gte (expected)](#gte-expected)\n- [lt (expected)](#lt-expected)\n- [lte (expected)](#lte-expected)\n- [custom (expectedFn)](#custom-expectedfn)\n\nIn all of the following matchers descriptions **actual** refers to **actual**\nvalue or its property, corresponding to the matcher in **expected**, both passed\nto an assertion.\n\n### `strict (expected)`\n\nReturns an instance of the root matchers class. All other matchers inherit from\nthat class. It checks whether two values are equal in depth. Actual comparison\noperator (== or ===) for primitives depends on assertion in which this matcher\nis used (for example, == is used for `deepEqual` whereas === is used for\n`deepStrictEqual`). If **expected** contains a matcher somewhere on it, then\ncheck for corresponding **actual** value is passed to that matcher.\nIf applied to another matcher it produces equivalent one, meaning that for\nexample `strict(aMatcher(expected))` returns matcher equivalent to\n`aMatcher(expected)`. Actually, `deepEqual` and `deepStrictEqual` assertions\nwrap its **expected** argument in `strict` matcher implicitly.\n\n```javascript\nassert.deepEqual({ a: 1, b: 2 }, strict({ a: 1, b: 2 }))   // passes\nassert.deepEqual({ a: 1, b: 2 }, strict({ a: 1 }))         // throws\nassert.deepEqual({ a: 1 }, strict({ a: 1, b: 2 }))         // throws\n```\n\n### `loose (expected)`\n\nSimilar to `strict` matcher but requires only subset of **actual** properties to\nbe equal in depth to those of **expected**.\n\n```javascript\nassert.deepEqual({ a: 1, b: 2 }, loose({ a: 1, b: 2 }))     // passes\nassert.deepEqual({ a: 1, b: 2 }, loose({ a: 1 }))           // passes\nassert.deepEqual({ a: 1 }, loose({ a: 1, b: 2 }))           // throws\n```\n\n### `any (expected)`\n\nMatches anything. Can be used if value or existence of a specific **actual**\nproperty does not matter. It is supposed to be used in context of `strict`\nmatcher, in context of `loose` matcher it makes a little sense.\n\n```javascript\nassert.deepEqual(undefined, any())                                  // passes\nassert.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: any() })    // passes\nassert.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 5, c: any() })    // throws\n```\n\n### `not (expected)`\n\nIt implicitly wraps **expected** in `strict` matcher, matches **actual** value\nagainst it and inverts result. `notDeepEqual` and `notDeepStrictEqual`\nassertions wrap its **expected** argument in `not` matcher implicitly.\n\n```javascript\nassert.deepEqual({ a: 1, b: 2 }, not({ a: 1, b: 2 }))  // throws\nassert.deepEqual({ a: 1, b: 2 }, not({ a: 1 }))        // passes\nassert.deepEqual({ a: 1 }, not({ a: 1, b: 2 }))        // passes\n```\n\n### `every (expected)`\n\n**expected** should be an array. If it is not, than it is treated as one-element\narray. Each element of **expected** array is wrapped implicitly in `strict`\nmatcher. `every` matcher checks whether **actual** value matches all matchers of\n**expected**.\n\n```javascript\nassert.deepEqual({ a: 1, b: 2 }, every([ loose({ a: 1 }), loose({ b: 2 }) ]))   // passes\nassert.deepEqual({ a: 1, b: 2 }, every([ loose({ a: 1 }), loose({ c: 3 }) ]))   // throws\nassert.deepEqual({ a: 1, b: 2 }, every([ { c: 3 } ]))                           // throws\nassert.deepEqual({ a: 1, b: 2 }, every(loose({ a: 1 })))                        // passes\n```\n\n### `some (expected)`\n\n**expected** should be an array. If it is not, than it is treated as one-element\narray. Each element of **expected** array is wrapped implicitly in `strict`\nmatcher. `some` matcher checks whether **actual** value matches at least one\nmatcher of **expected**.\n\n```javascript\nassert.deepEqual({ a: 1, b: 2 }, some([ loose({ a: 1 }), loose({ b: 2 }) ]))    // passes\nassert.deepEqual({ a: 1, b: 2 }, some([ loose({ a: 1 }), loose({ c: 3 }) ]))    // passes\nassert.deepEqual({ a: 1, b: 2 }, some([ { c: 3 } ]))                            // throws\nassert.deepEqual({ a: 1, b: 2 }, some(loose({ a: 1 })))                         // passes\n```\n\n### `arrayOf (expected)`\n\nExpects **actual** value to be a non-empty array, check fails if it is not.\nImplicitly wraps **expected** in `strict` matcher. Checks that all elements of\nthe array match **expected**.\n\n```javascript\nassert.deepEqual([ 1, 1, 1 ], arrayOf(1))   // passes\nassert.deepEqual([ 1, 1, 'a' ], arrayOf(1)) // throws\nassert.deepEqual(1, arrayOf(1))             // throws\n```\n\n### `contains (expected1 [, expected2, ...])`\n\nExpects **actual** value to be a non-empty array, check fails if it is not.\nAccepts a list of **expected**. Checks that each element of the **expected**\nlist matches at least one element in the **actual** array.\n\n```javascript\nassert.deepEqual([ 1, 1, 1 ], contains(1))       // passes\nassert.deepEqual([ 1, 'a', 'a' ], contains(1))   // passes\nassert.deepEqual([ 'a', 'a', 'a' ], contains(1)) // throws\nassert.deepEqual(1, contains(1))                 // throws\nassert.deepEqual([ 1, 2, 3 ], contains(1, 2))    // passes\nassert.deepEqual([ 1, 2, 3 ], contains(1, 10))   // throws\n```\n\n### `type (expected)`\n\nif **expected** is a string than **actual** is checked to be a primitive of that\ntype. If **expected** is a constructor than **actual** is checked to be an\ninstance of that type.\n\n```javascript\nassert.deepEqual(5, type('number'))            // passes\nassert.deepEqual([ 1, 2, 3 ], type(Array))     // passes\nassert.deepEqual(5, type('string'))            // throws\nassert.deepEqual({ a: 1 }, type({ a: 1 }))     // throws\n```\n\n### `primitive (expected)`\n\nIf **expected** is a matcher than **actual** is converted to primitive and\nmatched against **expected**. Otherwise, **actual** and **expected** both\nconverted to primitive and compared (actual operator == or === depends on\nassertion used).\n\n```javascript\nassert.deepEqual({}, primitive('[object Object]'))              // passes\nassert.deepEqual(new String('abc'), primitive('abc'))           // passes\nassert.deepEqual({ toString: () =\u003e 'abc' }, primitive('abc'))   // passes\nassert.deepEqual(1, primitive(1))                               // passes\nassert.deepEqual(10, primitive(1))                              // throws\nassert.deepEqual(1, primitive('1'))                             // passes\nassert.deepStrictEqual(1, primitive('1'))                       // throws\nassert.deepEqual({}, primitive(regex('obj')))                   // passes\nassert.deepEqual({}, primitive(regex('abc')))                   // throws\n```\n\n### `regex (expected)`\n\n**expected** is converted to a RegExp and **actual** is tested against it.\n\n```javascript\nassert.deepEqual('abc', regex('^a'))               // passes\nassert.deepEqual('[object Object]', regex({}))     // passes\nassert.deepEqual('123', regex(/^\\d+$/))            // passes\nassert.deepEqual('123', regex('^\\D+$'))            // throws\n```\n\n### `gt (expected)`\n\nChecks if **actual** is greater than **expected**.\n\n```javascript\nassert.deepEqual('b', gt('a'))                              // passes\nassert.deepEqual('a', gt('b'))                              // throws\nassert.deepEqual(1, gt(0))                                  // passes\nassert.deepEqual(0, gt(0))                                  // throws\nassert.deepEqual([ 1, 2, 3 ], loose({ length: gt(1) }))     // passes\nassert.deepEqual([ 1 ], loose({ length: gt(1) }))           // throws\n```\n\n### `gte (expected)`\n\nChecks if **actual** is greater than or equal to **expected**.\n\n```javascript\nassert.deepEqual('b', gte('a'))                             // passes\nassert.deepEqual('a', gte('b'))                             // throws\nassert.deepEqual(1, gte(0))                                 // passes\nassert.deepEqual(0, gte(0))                                 // passes\nassert.deepEqual([ 1, 2, 3 ], loose({ length: gte(1) }))    // passes\nassert.deepEqual([ 1 ], loose({ length: gte(1) }))          // passes\n```\n\n### `lt (expected)`\n\nChecks if **actual** is less than **expected**.\n\n```javascript\nassert.deepEqual('a', lt('b'))                              // passes\nassert.deepEqual('b', lt('a'))                              // throws\nassert.deepEqual(0, lt(1))                                  // passes\nassert.deepEqual(0, lt(0))                                  // throws\nassert.deepEqual([ 1, 2, 3 ], loose({ length: lt(1) }))     // throws\nassert.deepEqual([ 1 ], loose({ length: lt(1) }))           // throws\n```\n\n### `lte (expected)`\n\nChecks if **actual** is less than or equal to **expected**.\n\n```javascript\nassert.deepEqual('a', lte('b'))                             // passes\nassert.deepEqual('b', lte('a'))                             // throws\nassert.deepEqual(0, lte(1))                                 // passes\nassert.deepEqual(0, lte(0))                                 // passes\nassert.deepEqual([ 1, 2, 3 ], loose({ length: lte(1) }))    // throws\nassert.deepEqual([ 1 ], loose({ length: lte(1) }))          // passes\n```\n\n### `custom (expectedFn)`\n\nIf **expectedFn** is not a function than this matcher falls back to `strict`\nmatcher. An **actual** value is passed to **expectedFn** to check.\n**expectedFn** should return either boolean result or an object with\nthe `match` and `expected` fields. boolean `match` property says whether check\npassed and `expected` is used in error reporting. It is possible to return from\ncustom **expectedFn** results of another matcher.\n\n```javascript\nassert.deepEqual({ a: 1 }, custom( actual =\u003e actual.a === 1) )      // passes\nassert.deepEqual({ a: 1 }, custom( actual =\u003e actual.a !== 1) )      // throws\nassert.deepEqual({ a: 1 }, custom( actual =\u003e ({                     // passes\n    match: actual.a === 1,\n    expected: 1,\n}) ))\nassert.deepEqual({ a: 1 }, custom( actual =\u003e ({                     // throws\n    match: actual.a !== 1,\n    expected: '[\"a\" should not be equal to 1]',\n}) ))\n\n// return results of another matcher\nassert.deepEqual([1, 1, 1], custom(                                 // passes\n    (actual, comparator) =\u003e arrayOf(gt(0)).match(actual, comparator)\n))\nassert.deepEqual([1, 1, 'a'], custom(                               // throws\n    (actual, comparator) =\u003e arrayOf(1).match(actual, comparator)\n))\n```\n\nFAQ\n===\n\n### Why enhancing assert with matchers?\n\nThere are cases when you care more not about specific values but rather about\ntheir shapes or features. `assert-match` provides you with a way to achieve that\nthrough matchers.\n\n### Why yet another matchers?\n\nExisting assertion libraries provide you with tons of crazy named matchers and\neach new use case requires them (or you) to introduce completely new matcher. On\nthe other hand `assert-match` provides you with succinct set of combinable\nmatchers, sufficient to reproduce all the matchers of that libs in a clear way.\n\n### Why does matchers are strict by default?\n\nThe more strict your tests the less probability to introduce bugs into your\nsystem and the more probability to detect them. However, as noted above, there\nare cases when you care more not about specific values but rather about their\nshapes or features. `assert-match` tries to consistently address these two\npoints.\n\n### What about [`power-assert`](https://github.com/power-assert-js/power-assert)?\n[Yes, we have it `\u003e:3`.](https://github.com/rmdm/power-assert-match)\n\n### Why no extension API?\n\nFor matchers to be combinable means that not many of them can not be expressed\nby existing ones, so this feature would not be in great demand. Additionally,\n`custom` matcher may be used for this purpose to some extent. However, you are\nalways welcome to issues to provide your points why this or any other feature is\nrequired.\n\nRelated projects\n================\n- [power-assert-match](https://github.com/rmdm/power-assert-match)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmdm%2Fassert-match","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frmdm%2Fassert-match","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmdm%2Fassert-match/lists"}