├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── CLI-screenshot.png ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── build └── k6chaijs.min.js ├── catalog-info.yaml ├── package-lock.json ├── package.json ├── src ├── assert.ts ├── config.ts ├── constants.ts ├── custom-typings.d.ts ├── describe.ts ├── exceptions.ts ├── index.ts ├── matchers.ts ├── types.ts └── utils │ ├── index.ts │ ├── predicate.ts │ ├── regex.ts │ └── string.ts ├── tests ├── all-examples-from-docs.js ├── chai-should-syntax.js ├── check-aggregation.js ├── exit-on-error.js ├── simple.js └── test.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Default 2 | [*] 3 | charset = utf-8 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | 8 | # JavaScript 9 | [*.js] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # JSON 14 | [*.json] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | # Markdown 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | indent_style = space 22 | indent_size = 4 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "plugins": ["@typescript-eslint", "prettier"], 4 | "extends": [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:prettier/recommended", 8 | "prettier" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | pnpm-lock.yaml -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "printWidth": 80, 6 | "trailingComma": "none" 7 | } -------------------------------------------------------------------------------- /CLI-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/k6-jslib-k6chaijs/e03711b53911eab3bc95c2b289f37d88fd6cb0dc/CLI-screenshot.png -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @grafana/k6-frontend 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting our Developer Relations team, avocados@k6.io. 59 | 60 | All complaints will be reviewed and investigated and will result in a response that 61 | is deemed necessary and appropriate to the circumstances. The project team is 62 | obligated to maintain confidentiality with regard to the reporter of an incident. 63 | Further details of specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 72 | available at [http://contributor-covenant.org/version/1/4][version] 73 | 74 | [homepage]: http://contributor-covenant.org 75 | [version]: http://contributor-covenant.org/version/1/4/ 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # k6Chaijs - ChaiJS Assertion Library for k6.io 2 | 3 | This is a [chaijs](https://www.chaijs.com/) library with a few modifications to make it runnable in k6. 4 | 5 | Installation docs: https://www.chaijs.com/api/bdd/ 6 | 7 | API docs: https://grafana.com/docs/k6/latest/javascript-api/jslib/k6chaijs 8 | 9 | Download from: https://jslib.k6.io/ 10 | 11 | ## Example 12 | 13 | ```js 14 | import http from 'k6/http'; 15 | import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.0/index.js'; 16 | 17 | export let options = { 18 | thresholds: { 19 | checks: [{ threshold: 'rate == 1.00', abortOnFail: true }], 20 | http_req_failed: [{ threshold: 'rate == 0.00', abortOnFail: true }], 21 | }, 22 | }; 23 | 24 | export default function testSuite() { 25 | 26 | describe('[Crocs service] Fetch list of crocs', () => { 27 | let response = http.get('https://test-api.k6.io/public/crocodiles'); 28 | 29 | expect(response.status, "response status").to.equal(200) 30 | expect(response).to.have.validJsonBody() 31 | expect(response.json().length, "Number of crocs").to.be.above(4) 32 | }) 33 | 34 | describe('Dummy example', () => { 35 | expect(10).to.be.within(8,12); // OK 36 | expect(42).to.equal(44); // fails 37 | expect(true).to.be.ok; // doesn't run because the previous assertion failed. 38 | }); 39 | 40 | } 41 | 42 | ``` 43 | 44 | ![CLI screenshot](./CLI-screenshot.png) 45 | 46 | 47 | ## Development 48 | 49 | 50 | #### Build 51 | ``` 52 | npm install 53 | npm run-script build 54 | ``` 55 | 56 | #### Deploy new version 57 | 1. Build. 58 | 2. Use the `./build/k6chaijs.min.js` to make a PR to [jslib.k6.io](https://github.com/grafana/jslib.k6.io). 59 | 3. Release version should follow the chaijs version. Currently `4.3.4.0`. 60 | -------------------------------------------------------------------------------- /build/k6chaijs.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var Ar=Object.create;var Le=Object.defineProperty;var Or=Object.getOwnPropertyDescriptor;var Nr=Object.getOwnPropertyNames;var qr=Object.getPrototypeOf,jr=Object.prototype.hasOwnProperty;var N=(s,o)=>()=>(o||s((o={exports:{}}).exports,o),o.exports),Tr=(s,o)=>{for(var t in o)Le(s,t,{get:o[t],enumerable:!0})},mt=(s,o,t,c)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of Nr(o))!jr.call(s,e)&&e!==t&&Le(s,e,{get:()=>o[e],enumerable:!(c=Or(o,e))||c.enumerable});return s};var vt=(s,o,t)=>(t=s!=null?Ar(qr(s)):{},mt(o||!s||!s.__esModule?Le(t,"default",{value:s,enumerable:!0}):t,s)),Dr=s=>mt(Le({},"__esModule",{value:!0}),s);var Ye=N((ei,xt)=>{function wt(){var s=[].slice.call(arguments);function o(t,c){Object.keys(c).forEach(function(e){~s.indexOf(e)||(t[e]=c[e])})}return function(){for(var c=[].slice.call(arguments),e=0,n={};e{"use strict";function Et(s,o){return typeof s>"u"||s===null?!1:o in Object(s)}function Mt(s){var o=s.replace(/([^\\])\[/g,"$1.["),t=o.match(/(\\\.|[^.]+?)+/g);return t.map(function(e){if(e==="constructor"||e==="__proto__"||e==="prototype")return{};var n=/^\[(\d+)\]$/,r=n.exec(e),i=null;return r?i={i:parseFloat(r[1])}:i={p:e.replace(/\\([.[\]])/g,"$1")},i})}function St(s,o,t){var c=s,e=null;t=typeof t>"u"?o.length:t;for(var n=0;n"u"?c=c[r.i]:c=c[r.p],n===t-1&&(e=c))}return e}function Ir(s,o,t){for(var c=s,e=t.length,n=null,r=0;r"u"?n.i:n.p,c[i]=o;else if(typeof n.p<"u"&&c[n.p])c=c[n.p];else if(typeof n.i<"u"&&c[n.i])c=c[n.i];else{var v=t[r+1];i=typeof n.p>"u"?n.i:n.p,l=typeof v.p>"u"?[]:{},c[i]=l,c=c[i]}}}function Pt(s,o){var t=Mt(o),c=t[t.length-1],e={parent:t.length>1?St(s,t,t.length-1):s,name:c.p||c.i,value:St(s,t)};return e.exists=Et(e.parent,e.name),e}function kr(s,o){var t=Pt(s,o);return t.value}function Cr(s,o,t){var c=Mt(o);return Ir(s,t,c),s}At.exports={hasProperty:Et,getPathInfo:Pt,getPathValue:kr,setPathValue:Cr}});var X=N((ni,Nt)=>{Nt.exports=function(o,t,c){var e=o.__flags||(o.__flags=Object.create(null));if(arguments.length===3)e[t]=c;else return e[t]}});var jt=N((ri,qt)=>{var zr=X();qt.exports=function(o,t){var c=zr(o,"negate"),e=t[0];return c?!e:e}});var Me=N((He,et)=>{(function(s,o){typeof He=="object"&&typeof et<"u"?et.exports=o():typeof define=="function"&&define.amd?define(o):(s=typeof globalThis<"u"?globalThis:s||self,s.typeDetect=o())})(He,function(){"use strict";var s=typeof Promise=="function",o=function(z){if(typeof globalThis=="object")return globalThis;Object.defineProperty(z,"typeDetectGlobalObject",{get:function(){return this},configurable:!0});var ne=typeDetectGlobalObject;return delete z.typeDetectGlobalObject,ne}(Object.prototype),t=typeof Symbol<"u",c=typeof Map<"u",e=typeof Set<"u",n=typeof WeakMap<"u",r=typeof WeakSet<"u",i=typeof DataView<"u",l=t&&typeof Symbol.iterator<"u",v=t&&typeof Symbol.toStringTag<"u",E=e&&typeof Set.prototype.entries=="function",K=c&&typeof Map.prototype.entries=="function",H=E&&Object.getPrototypeOf(new Set().entries()),R=K&&Object.getPrototypeOf(new Map().entries()),V=l&&typeof Array.prototype[Symbol.iterator]=="function",te=V&&Object.getPrototypeOf([][Symbol.iterator]()),Z=l&&typeof String.prototype[Symbol.iterator]=="function",de=Z&&Object.getPrototypeOf(""[Symbol.iterator]()),pe=8,ge=-1;function ye(z){var ne=typeof z;if(ne!=="object")return ne;if(z===null)return"null";if(z===o)return"global";if(Array.isArray(z)&&(v===!1||!(Symbol.toStringTag in z)))return"Array";if(typeof window=="object"&&window!==null){if(typeof window.location=="object"&&z===window.location)return"Location";if(typeof window.document=="object"&&z===window.document)return"Document";if(typeof window.navigator=="object"){if(typeof window.navigator.mimeTypes=="object"&&z===window.navigator.mimeTypes)return"MimeTypeArray";if(typeof window.navigator.plugins=="object"&&z===window.navigator.plugins)return"PluginArray"}if((typeof window.HTMLElement=="function"||typeof window.HTMLElement=="object")&&z instanceof window.HTMLElement){if(z.tagName==="BLOCKQUOTE")return"HTMLQuoteElement";if(z.tagName==="TD")return"HTMLTableDataCellElement";if(z.tagName==="TH")return"HTMLTableHeaderCellElement"}}var _=v&&z[Symbol.toStringTag];if(typeof _=="string")return _;var L=Object.getPrototypeOf(z);return L===RegExp.prototype?"RegExp":L===Date.prototype?"Date":s&&L===Promise.prototype?"Promise":e&&L===Set.prototype?"Set":c&&L===Map.prototype?"Map":r&&L===WeakSet.prototype?"WeakSet":n&&L===WeakMap.prototype?"WeakMap":i&&L===DataView.prototype?"DataView":c&&L===R?"Map Iterator":e&&L===H?"Set Iterator":V&&L===te?"Array Iterator":Z&&L===de?"String Iterator":L===null?"Object":Object.prototype.toString.call(z).slice(pe,ge)}return ye})});var Dt=N((oi,Tt)=>{var Br=Ye(),tt=X(),Fr=Me();Tt.exports=function(o,t){var c=tt(o,"message"),e=tt(o,"ssfi");c=c?c+": ":"",o=tt(o,"object"),t=t.map(function(i){return i.toLowerCase()}),t.sort();var n=t.map(function(i,l){var v=~["a","e","i","o","u"].indexOf(i.charAt(0))?"an":"a",E=t.length>1&&l===t.length-1?"or ":"";return E+v+" "+i}).join(", "),r=Fr(o).toLowerCase();if(!t.some(function(i){return r===i}))throw new Br(c+"object tested must be "+n+", but "+r+" given",void 0,e)}});var nt=N((ii,It)=>{It.exports=function(o,t){return t.length>4?t[4]:o._obj}});var Ke=N((si,kt)=>{"use strict";var Vr=Function.prototype.toString,Rr=/\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\s\(\/]+)/,Lr=512;function Kr(s){if(typeof s!="function")return null;var o="";if(typeof Function.prototype.name>"u"&&typeof s.name>"u"){var t=Vr.call(s);if(t.indexOf("(")>Lr)return o;var c=t.match(Rr);c&&(o=c[1])}else o=s.name;return o}kt.exports=Kr});var Ct=N(()=>{});var Bt=N((Ge,zt)=>{(function(s,o){typeof Ge=="object"&&typeof zt<"u"?o(Ge):typeof define=="function"&&define.amd?define(["exports"],o):(s=typeof globalThis<"u"?globalThis:s||self,o(s.loupe={}))})(Ge,function(s){"use strict";function o(u){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?o=function(f){return typeof f}:o=function(f){return f&&typeof Symbol=="function"&&f.constructor===Symbol&&f!==Symbol.prototype?"symbol":typeof f},o(u)}function t(u,f){return c(u)||e(u,f)||n(u,f)||i()}function c(u){if(Array.isArray(u))return u}function e(u,f){if(!(typeof Symbol>"u"||!(Symbol.iterator in Object(u)))){var g=[],S=!0,M=!1,q=void 0;try{for(var D=u[Symbol.iterator](),B;!(S=(B=D.next()).done)&&(g.push(B.value),!(f&&g.length===f));S=!0);}catch(W){M=!0,q=W}finally{try{!S&&D.return!=null&&D.return()}finally{if(M)throw q}}return g}}function n(u,f){if(!!u){if(typeof u=="string")return r(u,f);var g=Object.prototype.toString.call(u).slice(8,-1);if(g==="Object"&&u.constructor&&(g=u.constructor.name),g==="Map"||g==="Set")return Array.from(u);if(g==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(g))return r(u,f)}}function r(u,f){(f==null||f>u.length)&&(f=u.length);for(var g=0,S=new Array(f);g0&&arguments[0]!==void 0?arguments[0]:{},f=u.showHidden,g=f===void 0?!1:f,S=u.depth,M=S===void 0?2:S,q=u.colors,D=q===void 0?!1:q,B=u.customInspect,W=B===void 0?!0:B,U=u.showProxy,Q=U===void 0?!1:U,ue=u.maxArrayLength,Qe=ue===void 0?1/0:ue,Se=u.breakLength,ve=Se===void 0?1/0:Se,Ee=u.seen,Er=Ee===void 0?[]:Ee,yt=u.truncate,Mr=yt===void 0?1/0:yt,bt=u.stylize,Pr=bt===void 0?String:bt,Xe={showHidden:Boolean(g),depth:Number(M),colors:Boolean(D),customInspect:Boolean(W),showProxy:Boolean(Q),maxArrayLength:Number(Qe),breakLength:Number(ve),truncate:Number(Mr),seen:Er,stylize:Pr};return Xe.colors&&(Xe.stylize=K),Xe}function R(u,f){var g=arguments.length>2&&arguments[2]!==void 0?arguments[2]:E;u=String(u);var S=g.length,M=u.length;return S>f&&M>S?g:M>f&&M>S?"".concat(u.slice(0,f-S)).concat(g):u}function V(u,f,g){var S=arguments.length>3&&arguments[3]!==void 0?arguments[3]:", ";g=g||f.inspect;var M=u.length;if(M===0)return"";for(var q=f.truncate,D="",B="",W="",U=0;Uq&&D.length+W.length<=q||!Q&&!ue&&Ee>q||(B=Q?"":g(u[U+1],f)+(ue?"":S),!Q&&ue&&Ee>q&&ve+B.length>q))break;if(D+=Se,!Q&&!ue&&ve+B.length>=q){W="".concat(E,"(").concat(u.length-U-1,")");break}W=""}return"".concat(D).concat(W)}function te(u){return u.match(/^[a-zA-Z_][a-zA-Z_0-9]*$/)?u:JSON.stringify(u).replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'")}function Z(u,f){var g=t(u,2),S=g[0],M=g[1];return f.truncate-=2,typeof S=="string"?S=te(S):typeof S!="number"&&(S="[".concat(f.inspect(S,f),"]")),f.truncate-=S.length,M=f.inspect(M,f),"".concat(S,": ").concat(M)}function de(u,f){var g=Object.keys(u).slice(u.length);if(!u.length&&!g.length)return"[]";f.truncate-=4;var S=V(u,f);f.truncate-=S.length;var M="";return g.length&&(M=V(g.map(function(q){return[q,u[q]]}),f,Z)),"[ ".concat(S).concat(M?", ".concat(M):""," ]")}var pe=Function.prototype.toString,ge=/\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\s\(\/]+)/;function ye(u){if(typeof u!="function")return null;var f="";if(typeof Function.prototype.name>"u"&&typeof u.name>"u"){var g=pe.call(u).match(ge);g&&(f=g[1])}else f=u.name;return f}var z=ye,ne=function(f){return typeof Buffer=="function"&&f instanceof Buffer?"Buffer":f[Symbol.toStringTag]?f[Symbol.toStringTag]:z(f.constructor)};function _(u,f){var g=ne(u);f.truncate-=g.length+4;var S=Object.keys(u).slice(u.length);if(!u.length&&!S.length)return"".concat(g,"[]");for(var M="",q=0;q ").concat(M)}function De(u){var f=[];return u.forEach(function(g,S){f.push([S,g])}),f}function Ie(u,f){var g=u.size-1;return g<=0?"Map{}":(f.truncate-=7,"Map{ ".concat(V(De(u),f,Te)," }"))}var $e=Number.isNaN||function(u){return u!==u};function ke(u,f){return $e(u)?f.stylize("NaN","number"):u===1/0?f.stylize("Infinity","number"):u===-1/0?f.stylize("-Infinity","number"):u===0?f.stylize(1/u===1/0?"+0":"-0","number"):f.stylize(R(u,f.truncate),"number")}function xe(u,f){var g=R(u.toString(),f.truncate-1);return g!==E&&(g+="n"),f.stylize(g,"bigint")}function Ce(u,f){var g=u.toString().split("/")[2],S=f.truncate-(2+g.length),M=u.source;return f.stylize("/".concat(R(M,S),"/").concat(g),"regexp")}function ze(u){var f=[];return u.forEach(function(g){f.push(g)}),f}function Je(u,f){return u.size===0?"Set{}":(f.truncate-=7,"Set{ ".concat(V(ze(u),f)," }"))}var a=new RegExp("['\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]","g"),h={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r","'":"\\'","\\":"\\\\"},p=16,y=4;function m(u){return h[u]||"\\u".concat("0000".concat(u.charCodeAt(0).toString(p)).slice(-y))}function w(u,f){return a.test(u)&&(u=u.replace(a,m)),f.stylize("'".concat(R(u,f.truncate-2),"'"),"string")}function b(u){return"description"in Symbol.prototype?u.description?"Symbol(".concat(u.description,")"):"Symbol()":u.toString()}var d=function(){return"Promise{\u2026}"};try{var x=process.binding("util"),P=x.getPromiseDetails,A=x.kPending,k=x.kRejected;Array.isArray(P(Promise.resolve()))&&(d=function(f,g){var S=P(f),M=t(S,2),q=M[0],D=M[1];return q===A?"Promise{}":"Promise".concat(q===k?"!":"","{").concat(g.inspect(D,g),"}")})}catch{}var j=d;function O(u,f){var g=Object.getOwnPropertyNames(u),S=Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(u):[];if(g.length===0&&S.length===0)return"{}";if(f.truncate-=4,f.seen=f.seen||[],f.seen.indexOf(u)>=0)return"[Circular]";f.seen.push(u);var M=V(g.map(function(B){return[B,u[B]]}),f,Z),q=V(S.map(function(B){return[B,u[B]]}),f,Z);f.seen.pop();var D="";return M&&q&&(D=", "),"{ ".concat(M).concat(D).concat(q," }")}var T=typeof Symbol<"u"&&Symbol.toStringTag?Symbol.toStringTag:!1;function F(u,f){var g="";return T&&T in u&&(g=u[T]),g=g||z(u.constructor),(!g||g==="_class")&&(g=""),f.truncate-=g.length,"".concat(g).concat(O(u,f))}function G(u,f){return u.length===0?"Arguments[]":(f.truncate-=13,"Arguments[ ".concat(V(u,f)," ]"))}var oe=["stack","line","column","name","message","fileName","lineNumber","columnNumber","number","description"];function $(u,f){var g=Object.getOwnPropertyNames(u).filter(function(D){return oe.indexOf(D)===-1}),S=u.name;f.truncate-=S.length;var M="";typeof u.message=="string"?M=R(u.message,f.truncate):g.unshift("message"),M=M?": ".concat(M):"",f.truncate-=M.length+5;var q=V(g.map(function(D){return[D,u[D]]}),f,Z);return"".concat(S).concat(M).concat(q?" { ".concat(q," }"):"")}function re(u,f){var g=t(u,2),S=g[0],M=g[1];return f.truncate-=3,M?"".concat(f.stylize(S,"yellow"),"=").concat(f.stylize('"'.concat(M,'"'),"string")):"".concat(f.stylize(S,"yellow"))}function Ze(u,f){return V(u,f,ht,` 3 | `)}function ht(u,f){var g=u.getAttributeNames(),S=u.tagName.toLowerCase(),M=f.stylize("<".concat(S),"special"),q=f.stylize(">","special"),D=f.stylize(""),"special");f.truncate-=S.length*2+5;var B="";g.length>0&&(B+=" ",B+=V(g.map(function(Q){return[Q,u.getAttribute(Q)]}),f,re," ")),f.truncate-=B.length;var W=f.truncate,U=Ze(u.children,f);return U&&U.length>W&&(U="".concat(E,"(").concat(u.children.length,")")),"".concat(M).concat(B).concat(q).concat(U).concat(D)}var br=typeof Symbol=="function"&&typeof Symbol.for=="function",Be=br?Symbol.for("chai/inspect"):"@@chai/inspect",me=!1;try{var dt=Ct();me=dt.inspect?dt.inspect.custom:!1}catch{me=!1}function pt(){this.key="chai/loupe__"+Math.random()+Date.now()}pt.prototype={get:function(f){return f[this.key]},has:function(f){return this.key in f},set:function(f,g){Object.isExtensible(f)&&Object.defineProperty(f,this.key,{value:g,configurable:!0})}};var Fe=new(typeof WeakMap=="function"?WeakMap:pt),Ve={},gt={undefined:function(f,g){return g.stylize("undefined","undefined")},null:function(f,g){return g.stylize(null,"null")},boolean:function(f,g){return g.stylize(f,"boolean")},Boolean:function(f,g){return g.stylize(f,"boolean")},number:ke,Number:ke,bigint:xe,BigInt:xe,string:w,String:w,function:be,Function:be,symbol:b,Symbol:b,Array:de,Date:L,Map:Ie,Set:Je,RegExp:Ce,Promise:j,WeakSet:function(f,g){return g.stylize("WeakSet{\u2026}","special")},WeakMap:function(f,g){return g.stylize("WeakMap{\u2026}","special")},Arguments:G,Int8Array:_,Uint8Array:_,Uint8ClampedArray:_,Int16Array:_,Uint16Array:_,Int32Array:_,Uint32Array:_,Float32Array:_,Float64Array:_,Generator:function(){return""},DataView:function(){return""},ArrayBuffer:function(){return""},Error:$,HTMLCollection:Ze,NodeList:Ze},mr=function(f,g,S){return Be in f&&typeof f[Be]=="function"?f[Be](g):me&&me in f&&typeof f[me]=="function"?f[me](g.depth,g):"inspect"in f&&typeof f.inspect=="function"?f.inspect(g.depth,g):"constructor"in f&&Fe.has(f.constructor)?Fe.get(f.constructor)(f,g):Ve[S]?Ve[S](f,g):""},vr=Object.prototype.toString;function Re(u,f){f=H(f),f.inspect=Re;var g=f,S=g.customInspect,M=u===null?"null":o(u);if(M==="object"&&(M=vr.call(u).slice(8,-1)),gt[M])return gt[M](u,f);if(S&&u){var q=mr(u,f,M);if(q)return typeof q=="string"?q:Re(q,f)}var D=u?Object.getPrototypeOf(u):!1;return D===Object.prototype||D===null?O(u,f):u&&typeof HTMLElement=="function"&&u instanceof HTMLElement?ht(u,f):"constructor"in u?u.constructor!==Object?F(u,f):O(u,f):u===Object(u)?O(u,f):f.stylize(String(u),M)}function wr(u,f){return Fe.has(u)?!1:(Fe.set(u,f),!0)}function xr(u,f){return u in Ve?!1:(Ve[u]=f,!0)}var Sr=Be;s.custom=Sr,s.default=Re,s.inspect=Re,s.registerConstructor=wr,s.registerStringTag=xr,Object.defineProperty(s,"__esModule",{value:!0})})});var fe=N((ci,Ft)=>{Ft.exports={includeStack:!1,showDiff:!0,truncateThreshold:40,useProxy:!0,proxyExcludedKeys:["then","catch","inspect","toJSON"],deepEqual:null}});var _e=N((li,Rt)=>{var fi=Ke(),Gr=Bt(),Vt=fe();Rt.exports=_r;function _r(s,o,t,c){var e={colors:c,depth:typeof t>"u"?2:t,showHidden:o,truncate:Vt.truncateThreshold?Vt.truncateThreshold:1/0};return Gr.inspect(s,e)}});var rt=N((hi,Kt)=>{var Ur=_e(),Lt=fe();Kt.exports=function(o){var t=Ur(o),c=Object.prototype.toString.call(o);if(Lt.truncateThreshold&&t.length>=Lt.truncateThreshold){if(c==="[object Function]")return!o.name||o.name===""?"[Function]":"[Function: "+o.name+"]";if(c==="[object Array]")return"[ Array("+o.length+") ]";if(c==="[object Object]"){var e=Object.keys(o),n=e.length>2?e.splice(0,2).join(", ")+", ...":e.join(", ");return"{ Object ("+n+") }"}else return t}else return t}});var _t=N((di,Gt)=>{var ot=X(),Wr=nt(),it=rt();Gt.exports=function(o,t){var c=ot(o,"negate"),e=ot(o,"object"),n=t[3],r=Wr(o,t),i=c?t[2]:t[1],l=ot(o,"message");return typeof i=="function"&&(i=i()),i=i||"",i=i.replace(/#\{this\}/g,function(){return it(e)}).replace(/#\{act\}/g,function(){return it(r)}).replace(/#\{exp\}/g,function(){return it(n)}),l?l+": "+i:i}});var ie=N((pi,Ut)=>{Ut.exports=function(o,t,c){var e=o.__flags||(o.__flags=Object.create(null));t.__flags||(t.__flags=Object.create(null)),c=arguments.length===3?c:!0;for(var n in e)(c||n!=="object"&&n!=="ssfi"&&n!=="lockSsfi"&&n!="message")&&(t.__flags[n]=e[n])}});var rn=N((gi,ut)=>{"use strict";var Wt=Me();function en(){this._key="chai/deep-eql__"+Math.random()+Date.now()}en.prototype={get:function(o){return o[this._key]},set:function(o,t){Object.isExtensible(o)&&Object.defineProperty(o,this._key,{value:t,configurable:!0})}};var at=typeof WeakMap=="function"?WeakMap:en;function $t(s,o,t){if(!t||we(s)||we(o))return null;var c=t.get(s);if(c){var e=c.get(o);if(typeof e=="boolean")return e}return null}function Ue(s,o,t,c){if(!(!t||we(s)||we(o))){var e=t.get(s);e?e.set(o,c):(e=new at,e.set(o,c),t.set(s,e))}}ut.exports=We;ut.exports.MemoizeMap=at;function We(s,o,t){if(t&&t.comparator)return Jt(s,o,t);var c=tn(s,o);return c!==null?c:Jt(s,o,t)}function tn(s,o){return s===o?s!==0||1/s===1/o:s!==s&&o!==o?!0:we(s)||we(o)?!1:null}function Jt(s,o,t){t=t||{},t.memoize=t.memoize===!1?!1:t.memoize||new at;var c=t&&t.comparator,e=$t(s,o,t.memoize);if(e!==null)return e;var n=$t(o,s,t.memoize);if(n!==null)return n;if(c){var r=c(s,o);if(r===!1||r===!0)return Ue(s,o,t.memoize,r),r;var i=tn(s,o);if(i!==null)return i}var l=Wt(s);if(l!==Wt(o))return Ue(s,o,t.memoize,!1),!1;Ue(s,o,t.memoize,!0);var v=$r(s,o,l,t);return Ue(s,o,t.memoize,v),v}function $r(s,o,t,c){switch(t){case"String":case"Number":case"Boolean":case"Date":return We(s.valueOf(),o.valueOf());case"Promise":case"Symbol":case"function":case"WeakMap":case"WeakSet":return s===o;case"Error":return nn(s,o,["name","message","code"],c);case"Arguments":case"Int8Array":case"Uint8Array":case"Uint8ClampedArray":case"Int16Array":case"Uint16Array":case"Int32Array":case"Uint32Array":case"Float32Array":case"Float64Array":case"Array":return le(s,o,c);case"RegExp":return Jr(s,o);case"Generator":return Zr(s,o,c);case"DataView":return le(new Uint8Array(s.buffer),new Uint8Array(o.buffer),c);case"ArrayBuffer":return le(new Uint8Array(s),new Uint8Array(o),c);case"Set":return Zt(s,o,c);case"Map":return Zt(s,o,c);case"Temporal.PlainDate":case"Temporal.PlainTime":case"Temporal.PlainDateTime":case"Temporal.Instant":case"Temporal.ZonedDateTime":case"Temporal.PlainYearMonth":case"Temporal.PlainMonthDay":return s.equals(o);case"Temporal.Duration":return s.total("nanoseconds")===o.total("nanoseconds");case"Temporal.TimeZone":case"Temporal.Calendar":return s.toString()===o.toString();default:return Xr(s,o,c)}}function Jr(s,o){return s.toString()===o.toString()}function Zt(s,o,t){try{if(s.size!==o.size)return!1;if(s.size===0)return!0}catch{return!1}var c=[],e=[];return s.forEach(function(r,i){c.push([r,i])}),o.forEach(function(r,i){e.push([r,i])}),le(c.sort(),e.sort(),t)}function le(s,o,t){var c=s.length;if(c!==o.length)return!1;if(c===0)return!0;for(var e=-1;++e{var Yr=fe();on.exports=function(){return Yr.useProxy&&typeof Proxy<"u"&&typeof Reflect<"u"}});var un=N((bi,an)=>{var Hr=se(),sn=X(),eo=Pe(),to=ie();an.exports=function(o,t,c){c=c===void 0?function(){}:c,Object.defineProperty(o,t,{get:function e(){!eo()&&!sn(this,"lockSsfi")&&sn(this,"ssfi",e);var n=c.call(this);if(n!==void 0)return n;var r=new Hr.Assertion;return to(this,r),r},configurable:!0})}});var Ae=N((mi,cn)=>{var no=Object.getOwnPropertyDescriptor(function(){},"length");cn.exports=function(o,t,c){return no.configurable&&Object.defineProperty(o,"length",{get:function(){throw Error(c?"Invalid Chai property: "+t+'.length. Due to a compatibility issue, "length" cannot directly follow "'+t+'". Use "'+t+'.lengthOf" instead.':"Invalid Chai property: "+t+'.length. See docs for proper usage of "'+t+'".')}}),o}});var ln=N((vi,fn)=>{fn.exports=function(o){var t=Object.getOwnPropertyNames(o);function c(n){t.indexOf(n)===-1&&t.push(n)}for(var e=Object.getPrototypeOf(o);e!==null;)Object.getOwnPropertyNames(e).forEach(c),e=Object.getPrototypeOf(e);return t}});var Oe=N((wi,pn)=>{var ro=fe(),hn=X(),oo=ln(),io=Pe();var dn=["__flags","__methods","_obj","assert"];pn.exports=function(o,t){return io()?new Proxy(o,{get:function c(e,n){if(typeof n=="string"&&ro.proxyExcludedKeys.indexOf(n)===-1&&!Reflect.has(e,n)){if(t)throw Error("Invalid Chai property: "+t+"."+n+'. See docs for proper usage of "'+t+'".');var r=null,i=4;throw oo(e).forEach(function(l){if(!Object.prototype.hasOwnProperty(l)&&dn.indexOf(l)===-1){var v=so(n,l,i);v=t)return t;for(var c=[],e=0;e<=s.length;e++)c[e]=Array(o.length+1).fill(0),c[e][0]=e;for(var n=0;n=t){c[e][n]=t;continue}c[e][n]=Math.min(c[e-1][n]+1,c[e][n-1]+1,c[e-1][n-1]+(r===o.charCodeAt(n-1)?0:1))}return c[s.length][o.length]}});var bn=N((xi,yn)=>{var ao=Ae(),uo=se(),gn=X(),co=Oe(),fo=ie();yn.exports=function(o,t,c){var e=function(){gn(this,"lockSsfi")||gn(this,"ssfi",e);var n=c.apply(this,arguments);if(n!==void 0)return n;var r=new uo.Assertion;return fo(this,r),r};ao(e,t,!1),o[t]=co(e,t)}});var vn=N((Si,mn)=>{var lo=se(),Ne=X(),ho=Pe(),po=ie();mn.exports=function(o,t,c){var e=Object.getOwnPropertyDescriptor(o,t),n=function(){};e&&typeof e.get=="function"&&(n=e.get),Object.defineProperty(o,t,{get:function r(){!ho()&&!Ne(this,"lockSsfi")&&Ne(this,"ssfi",r);var i=Ne(this,"lockSsfi");Ne(this,"lockSsfi",!0);var l=c(n).call(this);if(Ne(this,"lockSsfi",i),l!==void 0)return l;var v=new lo.Assertion;return po(this,v),v},configurable:!0})}});var xn=N((Ei,wn)=>{var go=Ae(),yo=se(),qe=X(),bo=Oe(),mo=ie();wn.exports=function(o,t,c){var e=o[t],n=function(){throw new Error(t+" is not a function")};e&&typeof e=="function"&&(n=e);var r=function(){qe(this,"lockSsfi")||qe(this,"ssfi",r);var i=qe(this,"lockSsfi");qe(this,"lockSsfi",!0);var l=c(n).apply(this,arguments);if(qe(this,"lockSsfi",i),l!==void 0)return l;var v=new yo.Assertion;return mo(this,v),v};go(r,t,!1),o[t]=bo(r,t)}});var An=N((Mi,Pn)=>{var vo=Ae(),wo=se(),Sn=X(),xo=Oe(),En=ie();var So=typeof Object.setPrototypeOf=="function",Mn=function(){},Eo=Object.getOwnPropertyNames(Mn).filter(function(s){var o=Object.getOwnPropertyDescriptor(Mn,s);return typeof o!="object"?!0:!o.configurable}),Mo=Function.prototype.call,Po=Function.prototype.apply;Pn.exports=function(o,t,c,e){typeof e!="function"&&(e=function(){});var n={method:c,chainingBehavior:e};o.__methods||(o.__methods={}),o.__methods[t]=n,Object.defineProperty(o,t,{get:function(){n.chainingBehavior.call(this);var i=function(){Sn(this,"lockSsfi")||Sn(this,"ssfi",i);var E=n.method.apply(this,arguments);if(E!==void 0)return E;var K=new wo.Assertion;return En(this,K),K};if(vo(i,t,!0),So){var l=Object.create(this);l.call=Mo,l.apply=Po,Object.setPrototypeOf(i,l)}else{var v=Object.getOwnPropertyNames(o);v.forEach(function(E){if(Eo.indexOf(E)===-1){var K=Object.getOwnPropertyDescriptor(o,E);Object.defineProperty(i,E,K)}})}return En(this,i),xo(i)},configurable:!0})}});var jn=N((Pi,qn)=>{var On=se(),Nn=ie();qn.exports=function(o,t,c,e){var n=o.__methods[t],r=n.chainingBehavior;n.chainingBehavior=function(){var v=e(r).call(this);if(v!==void 0)return v;var E=new On.Assertion;return Nn(this,E),E};var i=n.method;n.method=function(){var v=c(i).apply(this,arguments);if(v!==void 0)return v;var E=new On.Assertion;return Nn(this,E),E}}});var In=N((Ai,Dn)=>{var Tn=_e();Dn.exports=function(o,t){return Tn(o){kn.exports=function(o){return typeof Object.getOwnPropertySymbols!="function"?[]:Object.getOwnPropertySymbols(o).filter(function(t){return Object.getOwnPropertyDescriptor(o,t).enumerable})}});var zn=N((Ni,Cn)=>{var Ao=ct();Cn.exports=function(o){return Object.keys(o).concat(Ao(o))}});var Fn=N((qi,Bn)=>{"use strict";var ft=Ke();function Oo(s,o){return o instanceof Error&&s===o}function No(s,o){return o instanceof Error?s.constructor===o.constructor||s instanceof o.constructor:o.prototype instanceof Error||o===Error?s.constructor===o||s instanceof o:!1}function qo(s,o){var t=typeof s=="string"?s:s.message;return o instanceof RegExp?o.test(t):typeof o=="string"?t.indexOf(o)!==-1:!1}function jo(s){var o=s;if(s instanceof Error)o=ft(s.constructor);else if(typeof s=="function"&&(o=ft(s),o==="")){var t=ft(new s);o=t||o}return o}function To(s){var o="";return s&&s.message?o=s.message:typeof s=="string"&&(o=s),o}Bn.exports={compatibleInstance:Oo,compatibleConstructor:No,compatibleMessage:qo,getMessage:To,getConstructorName:jo}});var Rn=N((ji,Vn)=>{function Do(s){return s!==s}Vn.exports=Number.isNaN||Do});var Gn=N((Ti,Kn)=>{var Io=Me(),Ln=X();function ko(s){var o=Io(s),t=["Array","Object","function"];return t.indexOf(o)!==-1}Kn.exports=function(o,t){var c=Ln(o,"operator"),e=Ln(o,"negate"),n=t[3],r=e?t[2]:t[1];if(c)return c;if(typeof r=="function"&&(r=r()),r=r||"",!!r&&!/\shave\s/.test(r)){var i=ko(n);return/\snot\s/.test(r)?i?"notDeepStrictEqual":"notStrictEqual":i?"deepStrictEqual":"strictEqual"}}});var Un=N(I=>{var _n=Ot();I.test=jt();I.type=Me();I.expectTypes=Dt();I.getMessage=_t();I.getActual=nt();I.inspect=_e();I.objDisplay=rt();I.flag=X();I.transferFlags=ie();I.eql=rn();I.getPathInfo=_n.getPathInfo;I.hasProperty=_n.hasProperty;I.getName=Ke();I.addProperty=un();I.addMethod=bn();I.overwriteProperty=vn();I.overwriteMethod=xn();I.addChainableMethod=An();I.overwriteChainableMethod=jn();I.compareByInspect=In();I.getOwnEnumerablePropertySymbols=ct();I.getOwnEnumerableProperties=zn();I.checkError=Fn();I.proxify=Oe();I.addLengthGuard=Ae();I.isProxyEnabled=Pe();I.isNaN=Rn();I.getOperator=Gn()});var $n=N((Ii,Wn)=>{var he=fe();Wn.exports=function(s,o){var t=s.AssertionError,c=o.flag;s.Assertion=e;function e(n,r,i,l){return c(this,"ssfi",i||e),c(this,"lockSsfi",l),c(this,"object",n),c(this,"message",r),c(this,"eql",he.deepEqual||o.eql),o.proxify(this)}Object.defineProperty(e,"includeStack",{get:function(){return console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),he.includeStack},set:function(n){console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),he.includeStack=n}}),Object.defineProperty(e,"showDiff",{get:function(){return console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),he.showDiff},set:function(n){console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),he.showDiff=n}}),e.addProperty=function(n,r){o.addProperty(this.prototype,n,r)},e.addMethod=function(n,r){o.addMethod(this.prototype,n,r)},e.addChainableMethod=function(n,r,i){o.addChainableMethod(this.prototype,n,r,i)},e.overwriteProperty=function(n,r){o.overwriteProperty(this.prototype,n,r)},e.overwriteMethod=function(n,r){o.overwriteMethod(this.prototype,n,r)},e.overwriteChainableMethod=function(n,r,i){o.overwriteChainableMethod(this.prototype,n,r,i)},e.prototype.assert=function(n,r,i,l,v,E){var K=o.test(this,arguments);if(E!==!1&&(E=!0),l===void 0&&v===void 0&&(E=!1),he.showDiff!==!0&&(E=!1),!K){r=o.getMessage(this,arguments);var H=o.getActual(this,arguments),R={actual:H,expected:l,showDiff:E},V=o.getOperator(this,arguments);throw V&&(R.operator=V),new t(r,R,he.includeStack?this.assert:c(this,"ssfi"))}};Object.defineProperty(e.prototype,"_obj",{get:function(){return c(this,"object")},set:function(n){c(this,"object",n)}})}});var Zn=N((ki,Jn)=>{Jn.exports=function(s,o){var t=s.Assertion,c=s.AssertionError,e=o.flag;["to","be","been","is","and","has","have","with","that","which","at","of","same","but","does","still","also"].forEach(function(a){t.addProperty(a)}),t.addProperty("not",function(){e(this,"negate",!0)}),t.addProperty("deep",function(){e(this,"deep",!0)}),t.addProperty("nested",function(){e(this,"nested",!0)}),t.addProperty("own",function(){e(this,"own",!0)}),t.addProperty("ordered",function(){e(this,"ordered",!0)}),t.addProperty("any",function(){e(this,"any",!0),e(this,"all",!1)}),t.addProperty("all",function(){e(this,"all",!0),e(this,"any",!1)});function n(a,h){h&&e(this,"message",h),a=a.toLowerCase();var p=e(this,"object"),y=~["a","e","i","o","u"].indexOf(a.charAt(0))?"an ":"a ";this.assert(a===o.type(p).toLowerCase(),"expected #{this} to be "+y+a,"expected #{this} not to be "+y+a)}t.addChainableMethod("an",n),t.addChainableMethod("a",n);function r(a,h){return o.isNaN(a)&&o.isNaN(h)||a===h}function i(){e(this,"contains",!0)}function l(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=o.type(p).toLowerCase(),m=e(this,"message"),w=e(this,"negate"),b=e(this,"ssfi"),d=e(this,"deep"),x=d?"deep ":"",P=d?e(this,"eql"):r;m=m?m+": ":"";var A=!1;switch(y){case"string":A=p.indexOf(a)!==-1;break;case"weakset":if(d)throw new c(m+"unable to use .deep.include with WeakSet",void 0,b);A=p.has(a);break;case"map":p.forEach(function(T){A=A||P(T,a)});break;case"set":d?p.forEach(function(T){A=A||P(T,a)}):A=p.has(a);break;case"array":d?A=p.some(function(T){return P(T,a)}):A=p.indexOf(a)!==-1;break;default:if(a!==Object(a))throw new c(m+"the given combination of arguments ("+y+" and "+o.type(a).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 "+o.type(a).toLowerCase(),void 0,b);var k=Object.keys(a),j=null,O=0;if(k.forEach(function(T){var F=new t(p);if(o.transferFlags(this,F,!0),e(F,"lockSsfi",!0),!w||k.length===1){F.property(T,a[T]);return}try{F.property(T,a[T])}catch(G){if(!o.checkError.compatibleConstructor(G,c))throw G;j===null&&(j=G),O++}},this),w&&k.length>1&&O===k.length)throw j;return}this.assert(A,"expected #{this} to "+x+"include "+o.inspect(a),"expected #{this} to not "+x+"include "+o.inspect(a))}t.addChainableMethod("include",l,i),t.addChainableMethod("contain",l,i),t.addChainableMethod("contains",l,i),t.addChainableMethod("includes",l,i),t.addProperty("ok",function(){this.assert(e(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")}),t.addProperty("true",function(){this.assert(e(this,"object")===!0,"expected #{this} to be true","expected #{this} to be false",!e(this,"negate"))}),t.addProperty("false",function(){this.assert(e(this,"object")===!1,"expected #{this} to be false","expected #{this} to be true",!!e(this,"negate"))}),t.addProperty("null",function(){this.assert(e(this,"object")===null,"expected #{this} to be null","expected #{this} not to be null")}),t.addProperty("undefined",function(){this.assert(e(this,"object")===void 0,"expected #{this} to be undefined","expected #{this} not to be undefined")}),t.addProperty("NaN",function(){this.assert(o.isNaN(e(this,"object")),"expected #{this} to be NaN","expected #{this} not to be NaN")});function v(){var a=e(this,"object");this.assert(a!=null,"expected #{this} to exist","expected #{this} to not exist")}t.addProperty("exist",v),t.addProperty("exists",v),t.addProperty("empty",function(){var a=e(this,"object"),h=e(this,"ssfi"),p=e(this,"message"),y;switch(p=p?p+": ":"",o.type(a).toLowerCase()){case"array":case"string":y=a.length;break;case"map":case"set":y=a.size;break;case"weakmap":case"weakset":throw new c(p+".empty was passed a weak collection",void 0,h);case"function":var m=p+".empty was passed a function "+o.getName(a);throw new c(m.trim(),void 0,h);default:if(a!==Object(a))throw new c(p+".empty was passed non-string primitive "+o.inspect(a),void 0,h);y=Object.keys(a).length}this.assert(y===0,"expected #{this} to be empty","expected #{this} not to be empty")});function E(){var a=e(this,"object"),h=o.type(a);this.assert(h==="Arguments","expected #{this} to be arguments but got "+h,"expected #{this} to not be arguments")}t.addProperty("arguments",E),t.addProperty("Arguments",E);function K(a,h){h&&e(this,"message",h);var p=e(this,"object");if(e(this,"deep")){var y=e(this,"lockSsfi");e(this,"lockSsfi",!0),this.eql(a),e(this,"lockSsfi",y)}else this.assert(a===p,"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",a,this._obj,!0)}t.addMethod("equal",K),t.addMethod("equals",K),t.addMethod("eq",K);function H(a,h){h&&e(this,"message",h);var p=e(this,"eql");this.assert(p(a,e(this,"object")),"expected #{this} to deeply equal #{exp}","expected #{this} to not deeply equal #{exp}",a,this._obj,!0)}t.addMethod("eql",H),t.addMethod("eqls",H);function R(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"doLength"),m=e(this,"message"),w=m?m+": ":"",b=e(this,"ssfi"),d=o.type(p).toLowerCase(),x=o.type(a).toLowerCase(),P,A=!0;if(y&&d!=="map"&&d!=="set"&&new t(p,m,b,!0).to.have.property("length"),!y&&d==="date"&&x!=="date")P=w+"the argument to above must be a date";else if(x!=="number"&&(y||d==="number"))P=w+"the argument to above must be a number";else if(!y&&d!=="date"&&d!=="number"){var k=d==="string"?"'"+p+"'":p;P=w+"expected "+k+" to be a number or a date"}else A=!1;if(A)throw new c(P,void 0,b);if(y){var j="length",O;d==="map"||d==="set"?(j="size",O=p.size):O=p.length,this.assert(O>a,"expected #{this} to have a "+j+" above #{exp} but got #{act}","expected #{this} to not have a "+j+" above #{exp}",a,O)}else this.assert(p>a,"expected #{this} to be above #{exp}","expected #{this} to be at most #{exp}",a)}t.addMethod("above",R),t.addMethod("gt",R),t.addMethod("greaterThan",R);function V(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"doLength"),m=e(this,"message"),w=m?m+": ":"",b=e(this,"ssfi"),d=o.type(p).toLowerCase(),x=o.type(a).toLowerCase(),P,A=!0;if(y&&d!=="map"&&d!=="set"&&new t(p,m,b,!0).to.have.property("length"),!y&&d==="date"&&x!=="date")P=w+"the argument to least must be a date";else if(x!=="number"&&(y||d==="number"))P=w+"the argument to least must be a number";else if(!y&&d!=="date"&&d!=="number"){var k=d==="string"?"'"+p+"'":p;P=w+"expected "+k+" to be a number or a date"}else A=!1;if(A)throw new c(P,void 0,b);if(y){var j="length",O;d==="map"||d==="set"?(j="size",O=p.size):O=p.length,this.assert(O>=a,"expected #{this} to have a "+j+" at least #{exp} but got #{act}","expected #{this} to have a "+j+" below #{exp}",a,O)}else this.assert(p>=a,"expected #{this} to be at least #{exp}","expected #{this} to be below #{exp}",a)}t.addMethod("least",V),t.addMethod("gte",V),t.addMethod("greaterThanOrEqual",V);function te(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"doLength"),m=e(this,"message"),w=m?m+": ":"",b=e(this,"ssfi"),d=o.type(p).toLowerCase(),x=o.type(a).toLowerCase(),P,A=!0;if(y&&d!=="map"&&d!=="set"&&new t(p,m,b,!0).to.have.property("length"),!y&&d==="date"&&x!=="date")P=w+"the argument to below must be a date";else if(x!=="number"&&(y||d==="number"))P=w+"the argument to below must be a number";else if(!y&&d!=="date"&&d!=="number"){var k=d==="string"?"'"+p+"'":p;P=w+"expected "+k+" to be a number or a date"}else A=!1;if(A)throw new c(P,void 0,b);if(y){var j="length",O;d==="map"||d==="set"?(j="size",O=p.size):O=p.length,this.assert(O=a&&G<=h,"expected #{this} to have a "+F+" within "+O,"expected #{this} to not have a "+F+" within "+O)}else this.assert(y>=a&&y<=h,"expected #{this} to be within "+O,"expected #{this} to not be within "+O)});function de(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"ssfi"),m=e(this,"message");try{var w=p instanceof a}catch(d){throw d instanceof TypeError?(m=m?m+": ":"",new c(m+"The instanceof assertion needs a constructor but "+o.type(a)+" was given.",void 0,y)):d}var b=o.getName(a);b===null&&(b="an unnamed constructor"),this.assert(w,"expected #{this} to be an instance of "+b,"expected #{this} to not be an instance of "+b)}t.addMethod("instanceof",de),t.addMethod("instanceOf",de);function pe(a,h,p){p&&e(this,"message",p);var y=e(this,"nested"),m=e(this,"own"),w=e(this,"message"),b=e(this,"object"),d=e(this,"ssfi"),x=typeof a;if(w=w?w+": ":"",y){if(x!=="string")throw new c(w+"the argument to property must be a string when using nested syntax",void 0,d)}else if(x!=="string"&&x!=="number"&&x!=="symbol")throw new c(w+"the argument to property must be a string, number, or symbol",void 0,d);if(y&&m)throw new c(w+'The "nested" and "own" flags cannot be combined.',void 0,d);if(b==null)throw new c(w+"Target cannot be null or undefined.",void 0,d);var P=e(this,"deep"),A=e(this,"negate"),k=y?o.getPathInfo(b,a):null,j=y?k.value:b[a],O=P?e(this,"eql"):(G,oe)=>G===oe,T="";P&&(T+="deep "),m&&(T+="own "),y&&(T+="nested "),T+="property ";var F;m?F=Object.prototype.hasOwnProperty.call(b,a):y?F=k.exists:F=o.hasProperty(b,a),(!A||arguments.length===1)&&this.assert(F,"expected #{this} to have "+T+o.inspect(a),"expected #{this} to not have "+T+o.inspect(a)),arguments.length>1&&this.assert(F&&O(h,j),"expected #{this} to have "+T+o.inspect(a)+" of #{exp}, but got #{act}","expected #{this} to not have "+T+o.inspect(a)+" of #{act}",h,j),e(this,"object",j)}t.addMethod("property",pe);function ge(a,h,p){e(this,"own",!0),pe.apply(this,arguments)}t.addMethod("ownProperty",ge),t.addMethod("haveOwnProperty",ge);function ye(a,h,p){typeof h=="string"&&(p=h,h=null),p&&e(this,"message",p);var y=e(this,"object"),m=Object.getOwnPropertyDescriptor(Object(y),a),w=e(this,"eql");m&&h?this.assert(w(h,m),"expected the own property descriptor for "+o.inspect(a)+" on #{this} to match "+o.inspect(h)+", got "+o.inspect(m),"expected the own property descriptor for "+o.inspect(a)+" on #{this} to not match "+o.inspect(h),h,m,!0):this.assert(m,"expected #{this} to have an own property descriptor for "+o.inspect(a),"expected #{this} to not have an own property descriptor for "+o.inspect(a)),e(this,"object",m)}t.addMethod("ownPropertyDescriptor",ye),t.addMethod("haveOwnPropertyDescriptor",ye);function z(){e(this,"doLength",!0)}function ne(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=o.type(p).toLowerCase(),m=e(this,"message"),w=e(this,"ssfi"),b="length",d;switch(y){case"map":case"set":b="size",d=p.size;break;default:new t(p,m,w,!0).to.have.property("length"),d=p.length}this.assert(d==a,"expected #{this} to have a "+b+" of #{exp} but got #{act}","expected #{this} to not have a "+b+" of #{act}",a,d)}t.addChainableMethod("length",ne,z),t.addChainableMethod("lengthOf",ne,z);function _(a,h){h&&e(this,"message",h);var p=e(this,"object");this.assert(a.exec(p),"expected #{this} to match "+a,"expected #{this} not to match "+a)}t.addMethod("match",_),t.addMethod("matches",_),t.addMethod("string",function(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"message"),m=e(this,"ssfi");new t(p,y,m,!0).is.a("string"),this.assert(~p.indexOf(a),"expected #{this} to contain "+o.inspect(a),"expected #{this} to not contain "+o.inspect(a))});function L(a){var h=e(this,"object"),p=o.type(h),y=o.type(a),m=e(this,"ssfi"),w=e(this,"deep"),b,d="",x,P=!0,A=e(this,"message");A=A?A+": ":"";var k=A+"when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments";if(p==="Map"||p==="Set")d=w?"deeply ":"",x=[],h.forEach(function($,re){x.push(re)}),y!=="Array"&&(a=Array.prototype.slice.call(arguments));else{switch(x=o.getOwnEnumerableProperties(h),y){case"Array":if(arguments.length>1)throw new c(k,void 0,m);break;case"Object":if(arguments.length>1)throw new c(k,void 0,m);a=Object.keys(a);break;default:a=Array.prototype.slice.call(arguments)}a=a.map(function($){return typeof $=="symbol"?$:String($)})}if(!a.length)throw new c(A+"keys required",void 0,m);var j=a.length,O=e(this,"any"),T=e(this,"all"),F=a,G=w?e(this,"eql"):($,re)=>$===re;if(!O&&!T&&(T=!0),O&&(P=F.some(function($){return x.some(function(re){return G($,re)})})),T&&(P=F.every(function($){return x.some(function(re){return G($,re)})}),e(this,"contains")||(P=P&&a.length==x.length)),j>1){a=a.map(function($){return o.inspect($)});var oe=a.pop();T&&(b=a.join(", ")+", and "+oe),O&&(b=a.join(", ")+", or "+oe)}else b=o.inspect(a[0]);b=(j>1?"keys ":"key ")+b,b=(e(this,"contains")?"contain ":"have ")+b,this.assert(P,"expected #{this} to "+d+b,"expected #{this} to not "+d+b,F.slice(0).sort(o.compareByInspect),x.sort(o.compareByInspect),!0)}t.addMethod("keys",L),t.addMethod("key",L);function be(a,h,p){p&&e(this,"message",p);var y=e(this,"object"),m=e(this,"ssfi"),w=e(this,"message"),b=e(this,"negate")||!1;new t(y,w,m,!0).is.a("function"),(a instanceof RegExp||typeof a=="string")&&(h=a,a=null);var d;try{y()}catch(oe){d=oe}var x=a===void 0&&h===void 0,P=Boolean(a&&h),A=!1,k=!1;if(x||!x&&!b){var j="an error";a instanceof Error?j="#{exp}":a&&(j=o.checkError.getConstructorName(a)),this.assert(d,"expected #{this} to throw "+j,"expected #{this} to not throw an error but #{act} was thrown",a&&a.toString(),d instanceof Error?d.toString():typeof d=="string"?d:d&&o.checkError.getConstructorName(d))}if(a&&d){if(a instanceof Error){var O=o.checkError.compatibleInstance(d,a);O===b&&(P&&b?A=!0:this.assert(b,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}"+(d&&!b?" but #{act} was thrown":""),a.toString(),d.toString()))}var T=o.checkError.compatibleConstructor(d,a);T===b&&(P&&b?A=!0:this.assert(b,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}"+(d?" but #{act} was thrown":""),a instanceof Error?a.toString():a&&o.checkError.getConstructorName(a),d instanceof Error?d.toString():d&&o.checkError.getConstructorName(d)))}if(d&&h!==void 0&&h!==null){var F="including";h instanceof RegExp&&(F="matching");var G=o.checkError.compatibleMessage(d,h);G===b&&(P&&b?k=!0:this.assert(b,"expected #{this} to throw error "+F+" #{exp} but got #{act}","expected #{this} to throw error not "+F+" #{exp}",h,o.checkError.getMessage(d)))}A&&k&&this.assert(b,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}"+(d?" but #{act} was thrown":""),a instanceof Error?a.toString():a&&o.checkError.getConstructorName(a),d instanceof Error?d.toString():d&&o.checkError.getConstructorName(d)),e(this,"object",d)}t.addMethod("throw",be),t.addMethod("throws",be),t.addMethod("Throw",be);function Te(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"itself"),m=typeof p=="function"&&!y?p.prototype[a]:p[a];this.assert(typeof m=="function","expected #{this} to respond to "+o.inspect(a),"expected #{this} to not respond to "+o.inspect(a))}t.addMethod("respondTo",Te),t.addMethod("respondsTo",Te),t.addProperty("itself",function(){e(this,"itself",!0)});function De(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=a(p);this.assert(y,"expected #{this} to satisfy "+o.objDisplay(a),"expected #{this} to not satisfy"+o.objDisplay(a),!e(this,"negate"),y)}t.addMethod("satisfy",De),t.addMethod("satisfies",De);function Ie(a,h,p){p&&e(this,"message",p);var y=e(this,"object"),m=e(this,"message"),w=e(this,"ssfi");if(new t(y,m,w,!0).is.a("number"),typeof a!="number"||typeof h!="number"){m=m?m+": ":"";var b=h===void 0?", and a delta is required":"";throw new c(m+"the arguments to closeTo or approximately must be numbers"+b,void 0,w)}this.assert(Math.abs(y-a)<=h,"expected #{this} to be close to "+a+" +/- "+h,"expected #{this} not to be close to "+a+" +/- "+h)}t.addMethod("closeTo",Ie),t.addMethod("approximately",Ie);function $e(a,h,p,y,m){if(!y){if(a.length!==h.length)return!1;h=h.slice()}return a.every(function(w,b){if(m)return p?p(w,h[b]):w===h[b];if(!p){var d=h.indexOf(w);return d===-1?!1:(y||h.splice(d,1),!0)}return h.some(function(x,P){return p(w,x)?(y||h.splice(P,1),!0):!1})})}t.addMethod("members",function(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"message"),m=e(this,"ssfi");new t(p,y,m,!0).to.be.an("array"),new t(a,y,m,!0).to.be.an("array");var w=e(this,"contains"),b=e(this,"ordered"),d,x,P;w?(d=b?"an ordered superset":"a superset",x="expected #{this} to be "+d+" of #{exp}",P="expected #{this} to not be "+d+" of #{exp}"):(d=b?"ordered members":"members",x="expected #{this} to have the same "+d+" as #{exp}",P="expected #{this} to not have the same "+d+" as #{exp}");var A=e(this,"deep")?e(this,"eql"):void 0;this.assert($e(a,p,A,w,b),x,P,a,p,!0)});function ke(a,h){h&&e(this,"message",h);var p=e(this,"object"),y=e(this,"message"),m=e(this,"ssfi"),w=e(this,"contains"),b=e(this,"deep"),d=e(this,"eql");new t(a,y,m,!0).to.be.an("array"),w?this.assert(a.some(function(x){return p.indexOf(x)>-1}),"expected #{this} to contain one of #{exp}","expected #{this} to not contain one of #{exp}",a,p):b?this.assert(a.some(function(x){return d(p,x)}),"expected #{this} to deeply equal one of #{exp}","expected #{this} to deeply equal one of #{exp}",a,p):this.assert(a.indexOf(p)>-1,"expected #{this} to be one of #{exp}","expected #{this} to not be one of #{exp}",a,p)}t.addMethod("oneOf",ke);function xe(a,h,p){p&&e(this,"message",p);var y=e(this,"object"),m=e(this,"message"),w=e(this,"ssfi");new t(y,m,w,!0).is.a("function");var b;h?(new t(a,m,w,!0).to.have.property(h),b=a[h]):(new t(a,m,w,!0).is.a("function"),b=a()),y();var d=h==null?a():a[h],x=h==null?b:"."+h;e(this,"deltaMsgObj",x),e(this,"initialDeltaValue",b),e(this,"finalDeltaValue",d),e(this,"deltaBehavior","change"),e(this,"realDelta",d!==b),this.assert(b!==d,"expected "+x+" to change","expected "+x+" to not change")}t.addMethod("change",xe),t.addMethod("changes",xe);function Ce(a,h,p){p&&e(this,"message",p);var y=e(this,"object"),m=e(this,"message"),w=e(this,"ssfi");new t(y,m,w,!0).is.a("function");var b;h?(new t(a,m,w,!0).to.have.property(h),b=a[h]):(new t(a,m,w,!0).is.a("function"),b=a()),new t(b,m,w,!0).is.a("number"),y();var d=h==null?a():a[h],x=h==null?b:"."+h;e(this,"deltaMsgObj",x),e(this,"initialDeltaValue",b),e(this,"finalDeltaValue",d),e(this,"deltaBehavior","increase"),e(this,"realDelta",d-b),this.assert(d-b>0,"expected "+x+" to increase","expected "+x+" to not increase")}t.addMethod("increase",Ce),t.addMethod("increases",Ce);function ze(a,h,p){p&&e(this,"message",p);var y=e(this,"object"),m=e(this,"message"),w=e(this,"ssfi");new t(y,m,w,!0).is.a("function");var b;h?(new t(a,m,w,!0).to.have.property(h),b=a[h]):(new t(a,m,w,!0).is.a("function"),b=a()),new t(b,m,w,!0).is.a("number"),y();var d=h==null?a():a[h],x=h==null?b:"."+h;e(this,"deltaMsgObj",x),e(this,"initialDeltaValue",b),e(this,"finalDeltaValue",d),e(this,"deltaBehavior","decrease"),e(this,"realDelta",b-d),this.assert(d-b<0,"expected "+x+" to decrease","expected "+x+" to not decrease")}t.addMethod("decrease",ze),t.addMethod("decreases",ze);function Je(a,h){h&&e(this,"message",h);var p=e(this,"deltaMsgObj"),y=e(this,"initialDeltaValue"),m=e(this,"finalDeltaValue"),w=e(this,"deltaBehavior"),b=e(this,"realDelta"),d;w==="change"?d=Math.abs(m-y)===Math.abs(a):d=b===Math.abs(a),this.assert(d,"expected "+p+" to "+w+" by "+a,"expected "+p+" to not "+w+" by "+a)}t.addMethod("by",Je),t.addProperty("extensible",function(){var a=e(this,"object"),h=a===Object(a)&&Object.isExtensible(a);this.assert(h,"expected #{this} to be extensible","expected #{this} to not be extensible")}),t.addProperty("sealed",function(){var a=e(this,"object"),h=a===Object(a)?Object.isSealed(a):!0;this.assert(h,"expected #{this} to be sealed","expected #{this} to not be sealed")}),t.addProperty("frozen",function(){var a=e(this,"object"),h=a===Object(a)?Object.isFrozen(a):!0;this.assert(h,"expected #{this} to be frozen","expected #{this} to not be frozen")}),t.addProperty("finite",function(a){var h=e(this,"object");this.assert(typeof h=="number"&&isFinite(h),"expected #{this} to be a finite number","expected #{this} to not be a finite number")})}});var Xn=N((Ci,Qn)=>{Qn.exports=function(s,o){s.expect=function(t,c){return new s.Assertion(t,c)},s.expect.fail=function(t,c,e,n){throw arguments.length<2&&(e=t,t=void 0),e=e||"expect.fail()",new s.AssertionError(e,{actual:t,expected:c,operator:n},s.expect.fail)}}});var Hn=N((zi,Yn)=>{Yn.exports=function(s,o){var t=s.Assertion;function c(){function e(){return this instanceof String||this instanceof Number||this instanceof Boolean||typeof Symbol=="function"&&this instanceof Symbol||typeof BigInt=="function"&&this instanceof BigInt?new t(this.valueOf(),null,e):new t(this,null,e)}function n(i){Object.defineProperty(this,"should",{value:i,enumerable:!0,configurable:!0,writable:!0})}Object.defineProperty(Object.prototype,"should",{set:n,get:e,configurable:!0});var r={};return r.fail=function(i,l,v,E){throw arguments.length<2&&(v=i,i=void 0),v=v||"should.fail()",new s.AssertionError(v,{actual:i,expected:l,operator:E},r.fail)},r.equal=function(i,l,v){new t(i,v).to.equal(l)},r.Throw=function(i,l,v,E){new t(i,E).to.Throw(l,v)},r.exist=function(i,l){new t(i,l).to.exist},r.not={},r.not.equal=function(i,l,v){new t(i,v).to.not.equal(l)},r.not.Throw=function(i,l,v,E){new t(i,E).to.not.Throw(l,v)},r.not.exist=function(i,l){new t(i,l).to.not.exist},r.throw=r.Throw,r.not.throw=r.not.Throw,r}s.should=c,s.Should=c}});var tr=N((Bi,er)=>{er.exports=function(s,o){var t=s.Assertion,c=o.flag;var e=s.assert=function(n,r){var i=new t(null,null,s.assert,!0);i.assert(n,r,"[ negation message unavailable ]")};e.fail=function(n,r,i,l){throw arguments.length<2&&(i=n,n=void 0),i=i||"assert.fail()",new s.AssertionError(i,{actual:n,expected:r,operator:l},e.fail)},e.isOk=function(n,r){new t(n,r,e.isOk,!0).is.ok},e.isNotOk=function(n,r){new t(n,r,e.isNotOk,!0).is.not.ok},e.equal=function(n,r,i){var l=new t(n,i,e.equal,!0);l.assert(r==c(l,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",r,n,!0)},e.notEqual=function(n,r,i){var l=new t(n,i,e.notEqual,!0);l.assert(r!=c(l,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",r,n,!0)},e.strictEqual=function(n,r,i){new t(n,i,e.strictEqual,!0).to.equal(r)},e.notStrictEqual=function(n,r,i){new t(n,i,e.notStrictEqual,!0).to.not.equal(r)},e.deepEqual=e.deepStrictEqual=function(n,r,i){new t(n,i,e.deepEqual,!0).to.eql(r)},e.notDeepEqual=function(n,r,i){new t(n,i,e.notDeepEqual,!0).to.not.eql(r)},e.isAbove=function(n,r,i){new t(n,i,e.isAbove,!0).to.be.above(r)},e.isAtLeast=function(n,r,i){new t(n,i,e.isAtLeast,!0).to.be.least(r)},e.isBelow=function(n,r,i){new t(n,i,e.isBelow,!0).to.be.below(r)},e.isAtMost=function(n,r,i){new t(n,i,e.isAtMost,!0).to.be.most(r)},e.isTrue=function(n,r){new t(n,r,e.isTrue,!0).is.true},e.isNotTrue=function(n,r){new t(n,r,e.isNotTrue,!0).to.not.equal(!0)},e.isFalse=function(n,r){new t(n,r,e.isFalse,!0).is.false},e.isNotFalse=function(n,r){new t(n,r,e.isNotFalse,!0).to.not.equal(!1)},e.isNull=function(n,r){new t(n,r,e.isNull,!0).to.equal(null)},e.isNotNull=function(n,r){new t(n,r,e.isNotNull,!0).to.not.equal(null)},e.isNaN=function(n,r){new t(n,r,e.isNaN,!0).to.be.NaN},e.isNotNaN=function(n,r){new t(n,r,e.isNotNaN,!0).not.to.be.NaN},e.exists=function(n,r){new t(n,r,e.exists,!0).to.exist},e.notExists=function(n,r){new t(n,r,e.notExists,!0).to.not.exist},e.isUndefined=function(n,r){new t(n,r,e.isUndefined,!0).to.equal(void 0)},e.isDefined=function(n,r){new t(n,r,e.isDefined,!0).to.not.equal(void 0)},e.isFunction=function(n,r){new t(n,r,e.isFunction,!0).to.be.a("function")},e.isNotFunction=function(n,r){new t(n,r,e.isNotFunction,!0).to.not.be.a("function")},e.isObject=function(n,r){new t(n,r,e.isObject,!0).to.be.a("object")},e.isNotObject=function(n,r){new t(n,r,e.isNotObject,!0).to.not.be.a("object")},e.isArray=function(n,r){new t(n,r,e.isArray,!0).to.be.an("array")},e.isNotArray=function(n,r){new t(n,r,e.isNotArray,!0).to.not.be.an("array")},e.isString=function(n,r){new t(n,r,e.isString,!0).to.be.a("string")},e.isNotString=function(n,r){new t(n,r,e.isNotString,!0).to.not.be.a("string")},e.isNumber=function(n,r){new t(n,r,e.isNumber,!0).to.be.a("number")},e.isNotNumber=function(n,r){new t(n,r,e.isNotNumber,!0).to.not.be.a("number")},e.isFinite=function(n,r){new t(n,r,e.isFinite,!0).to.be.finite},e.isBoolean=function(n,r){new t(n,r,e.isBoolean,!0).to.be.a("boolean")},e.isNotBoolean=function(n,r){new t(n,r,e.isNotBoolean,!0).to.not.be.a("boolean")},e.typeOf=function(n,r,i){new t(n,i,e.typeOf,!0).to.be.a(r)},e.notTypeOf=function(n,r,i){new t(n,i,e.notTypeOf,!0).to.not.be.a(r)},e.instanceOf=function(n,r,i){new t(n,i,e.instanceOf,!0).to.be.instanceOf(r)},e.notInstanceOf=function(n,r,i){new t(n,i,e.notInstanceOf,!0).to.not.be.instanceOf(r)},e.include=function(n,r,i){new t(n,i,e.include,!0).include(r)},e.notInclude=function(n,r,i){new t(n,i,e.notInclude,!0).not.include(r)},e.deepInclude=function(n,r,i){new t(n,i,e.deepInclude,!0).deep.include(r)},e.notDeepInclude=function(n,r,i){new t(n,i,e.notDeepInclude,!0).not.deep.include(r)},e.nestedInclude=function(n,r,i){new t(n,i,e.nestedInclude,!0).nested.include(r)},e.notNestedInclude=function(n,r,i){new t(n,i,e.notNestedInclude,!0).not.nested.include(r)},e.deepNestedInclude=function(n,r,i){new t(n,i,e.deepNestedInclude,!0).deep.nested.include(r)},e.notDeepNestedInclude=function(n,r,i){new t(n,i,e.notDeepNestedInclude,!0).not.deep.nested.include(r)},e.ownInclude=function(n,r,i){new t(n,i,e.ownInclude,!0).own.include(r)},e.notOwnInclude=function(n,r,i){new t(n,i,e.notOwnInclude,!0).not.own.include(r)},e.deepOwnInclude=function(n,r,i){new t(n,i,e.deepOwnInclude,!0).deep.own.include(r)},e.notDeepOwnInclude=function(n,r,i){new t(n,i,e.notDeepOwnInclude,!0).not.deep.own.include(r)},e.match=function(n,r,i){new t(n,i,e.match,!0).to.match(r)},e.notMatch=function(n,r,i){new t(n,i,e.notMatch,!0).to.not.match(r)},e.property=function(n,r,i){new t(n,i,e.property,!0).to.have.property(r)},e.notProperty=function(n,r,i){new t(n,i,e.notProperty,!0).to.not.have.property(r)},e.propertyVal=function(n,r,i,l){new t(n,l,e.propertyVal,!0).to.have.property(r,i)},e.notPropertyVal=function(n,r,i,l){new t(n,l,e.notPropertyVal,!0).to.not.have.property(r,i)},e.deepPropertyVal=function(n,r,i,l){new t(n,l,e.deepPropertyVal,!0).to.have.deep.property(r,i)},e.notDeepPropertyVal=function(n,r,i,l){new t(n,l,e.notDeepPropertyVal,!0).to.not.have.deep.property(r,i)},e.ownProperty=function(n,r,i){new t(n,i,e.ownProperty,!0).to.have.own.property(r)},e.notOwnProperty=function(n,r,i){new t(n,i,e.notOwnProperty,!0).to.not.have.own.property(r)},e.ownPropertyVal=function(n,r,i,l){new t(n,l,e.ownPropertyVal,!0).to.have.own.property(r,i)},e.notOwnPropertyVal=function(n,r,i,l){new t(n,l,e.notOwnPropertyVal,!0).to.not.have.own.property(r,i)},e.deepOwnPropertyVal=function(n,r,i,l){new t(n,l,e.deepOwnPropertyVal,!0).to.have.deep.own.property(r,i)},e.notDeepOwnPropertyVal=function(n,r,i,l){new t(n,l,e.notDeepOwnPropertyVal,!0).to.not.have.deep.own.property(r,i)},e.nestedProperty=function(n,r,i){new t(n,i,e.nestedProperty,!0).to.have.nested.property(r)},e.notNestedProperty=function(n,r,i){new t(n,i,e.notNestedProperty,!0).to.not.have.nested.property(r)},e.nestedPropertyVal=function(n,r,i,l){new t(n,l,e.nestedPropertyVal,!0).to.have.nested.property(r,i)},e.notNestedPropertyVal=function(n,r,i,l){new t(n,l,e.notNestedPropertyVal,!0).to.not.have.nested.property(r,i)},e.deepNestedPropertyVal=function(n,r,i,l){new t(n,l,e.deepNestedPropertyVal,!0).to.have.deep.nested.property(r,i)},e.notDeepNestedPropertyVal=function(n,r,i,l){new t(n,l,e.notDeepNestedPropertyVal,!0).to.not.have.deep.nested.property(r,i)},e.lengthOf=function(n,r,i){new t(n,i,e.lengthOf,!0).to.have.lengthOf(r)},e.hasAnyKeys=function(n,r,i){new t(n,i,e.hasAnyKeys,!0).to.have.any.keys(r)},e.hasAllKeys=function(n,r,i){new t(n,i,e.hasAllKeys,!0).to.have.all.keys(r)},e.containsAllKeys=function(n,r,i){new t(n,i,e.containsAllKeys,!0).to.contain.all.keys(r)},e.doesNotHaveAnyKeys=function(n,r,i){new t(n,i,e.doesNotHaveAnyKeys,!0).to.not.have.any.keys(r)},e.doesNotHaveAllKeys=function(n,r,i){new t(n,i,e.doesNotHaveAllKeys,!0).to.not.have.all.keys(r)},e.hasAnyDeepKeys=function(n,r,i){new t(n,i,e.hasAnyDeepKeys,!0).to.have.any.deep.keys(r)},e.hasAllDeepKeys=function(n,r,i){new t(n,i,e.hasAllDeepKeys,!0).to.have.all.deep.keys(r)},e.containsAllDeepKeys=function(n,r,i){new t(n,i,e.containsAllDeepKeys,!0).to.contain.all.deep.keys(r)},e.doesNotHaveAnyDeepKeys=function(n,r,i){new t(n,i,e.doesNotHaveAnyDeepKeys,!0).to.not.have.any.deep.keys(r)},e.doesNotHaveAllDeepKeys=function(n,r,i){new t(n,i,e.doesNotHaveAllDeepKeys,!0).to.not.have.all.deep.keys(r)},e.throws=function(n,r,i,l){(typeof r=="string"||r instanceof RegExp)&&(i=r,r=null);var v=new t(n,l,e.throws,!0).to.throw(r,i);return c(v,"object")},e.doesNotThrow=function(n,r,i,l){(typeof r=="string"||r instanceof RegExp)&&(i=r,r=null),new t(n,l,e.doesNotThrow,!0).to.not.throw(r,i)},e.operator=function(n,r,i,l){var v;switch(r){case"==":v=n==i;break;case"===":v=n===i;break;case">":v=n>i;break;case">=":v=n>=i;break;case"<":v=n{var nr=[];J.version="4.3.8";J.AssertionError=Ye();var rr=Un();J.use=function(s){return~nr.indexOf(s)||(s(J,rr),nr.push(s)),J};J.util=rr;var Co=fe();J.config=Co;var zo=$n();J.use(zo);var Bo=Zn();J.use(Bo);var Fo=Xn();J.use(Fo);var Vo=Hn();J.use(Vo);var Ro=tr();J.use(Ro)});var ir=N((Vi,or)=>{or.exports=se()});var Yo={};Tr(Yo,{default:()=>Qo,describe:()=>yr,expect:()=>Xo});module.exports=Dr(Yo);var Y=vt(ir(),1),Ri=Y.default.expect,Li=Y.default.version,Ki=Y.default.Assertion,Gi=Y.default.AssertionError,_i=Y.default.util,Ui=Y.default.config,Wi=Y.default.use,$i=Y.default.should,Ji=Y.default.assert,Zi=Y.default.core,ee=Y.default;var ur=require("k6"),cr=vt(require("k6/execution"));var ae=(s="")=>new RegExp(`#{${s}}`,"g");var sr=s=>typeof s=="function";var ar=(s="",o=250)=>s.length>o?`${s.substring(0,o)}...`:s;var lt=s=>C.util.objDisplay(s),je=s=>ar(s,C.config.truncateVariableThreshold);function Lo(s,o){let[t,c,e,n]=o,r=C.util.flag(s,"negate"),i=C.util.flag(s,"anonymizeMsgFunction"),l=r?e:c;return l=l.replace("but ",""),i&&(l=i(l)),sr(l)&&(l=l()),l=l||"",l=l.replace(ae("exp"),()=>je(lt(n))),l}function Ko(s,o="",t){let c=C.util.flag(s,"object"),e=C.util.getActual(s,t),n=C.util.flag(s,"message"),r=o.replace(ae("this"),()=>je(lt(c))).replace(ae("act"),()=>je(lt(e)));return n&&!C.config.aggregateChecks&&(r=n?n+": "+r:r),r}function Go(s,o=""){let t=C.util.flag(s,"message"),c=o.replace(ae("this"),()=>t||"${this}").replace(ae("act"),()=>"${actual}");return je(c)}function fr(){return function(s,o,t,c,e,n){n=!c&&!e;let r=this,i=[s,o,t,c,e,n],l=C.util.test(r,i),v=C.util.getActual(r,i),E=Lo(r,i),K=Ko(r,E,i),H=C.config.aggregateChecks?Go(r,E):K;if((0,ur.check)(null,{[H]:()=>l}),!l){let R=je(K),V=C.util.getOperator(r,i),te={actual:v,expected:c,showDiff:n,operator:V};throw C.config.logFailures&&console.warn(R),C.config.exitOnError&&cr.default.test.abort(R),new C.AssertionError(R,te,C.config.includeStack?C.assert:C.util.flag(r,"ssfi"))}}}var _o=(s="")=>s.replace(ae("this"),()=>"");function lr(s=_o){C.util.flag(this,"anonymizeMsgFunction",s)}function hr(){let s=C.util.flag(this,"object"),o=!0;try{s.json("__unlikelyidefintifier1")}catch{o=!1}C.assert(o,"has valid json body","does not have a valid json body",null,null)}ee.config.truncateVariableThreshold=100;ee.config.truncateMsgThreshold=300;ee.config.aggregateChecks=!0;ee.config.logFailures=!1;ee.config.exitOnError=!1;ee.Assertion.addMethod("anonymize",lr);ee.Assertion.addMethod("validJsonBody",hr);ee.Assertion.overwriteMethod("assert",fr);var C=ee;var gr=require("k6");var dr=require("k6"),pr=(s,o)=>{console.error(`Exception raised in test "${o}". Failing the test and continuing. 4 | ${s}`),(0,dr.check)(null,{[`Exception raised "${s}"`]:()=>!1})};function yr(s,o){let t=!0;return(0,gr.group)(s,()=>{try{o(),t=!0}catch(c){c.name!=="AssertionError"&&pr(c,s),t=!1}}),t}var Qo=C,Xo=C.expect; 5 | -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: k6-jslib-k6chaijs 5 | title: k6-jslib-k6chaijs 6 | description: | 7 | Chai Assertion Library for k6.io 8 | annotations: 9 | github.com/project-slug: grafana/k6-jslib-k6chaijs 10 | spec: 11 | type: library 12 | owner: group:default/k6-frontend 13 | lifecycle: production 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "k6chaijs", 3 | "version": "1.0.0", 4 | "description": "Create a chaijs k6 build", 5 | "main": "src/index.js", 6 | "engines": {}, 7 | "scripts": { 8 | "build": "esbuild ./src/index.ts --minify --bundle --log-level=info --external:k6 --format=cjs --legal-comments=none --outfile=build/k6chaijs.min.js" 9 | }, 10 | "keywords": [ 11 | "k6" 12 | ], 13 | "author": "k6 team", 14 | "license": "MIT", 15 | "dependencies": { 16 | "chai": "^4.5.0" 17 | }, 18 | "devDependencies": { 19 | "@types/chai": "^4.3.1", 20 | "@types/k6": "^0.37.0", 21 | "@types/node": "^18.0.6", 22 | "@typescript-eslint/eslint-plugin": "^5.30.7", 23 | "@typescript-eslint/parser": "^5.30.7", 24 | "esbuild": "^0.14.51", 25 | "eslint": "^8.20.0", 26 | "eslint-config-prettier": "^8.5.0", 27 | "eslint-plugin-prettier": "^4.2.1", 28 | "prettier": "^2.7.1", 29 | "typescript": "^4.7.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/assert.ts: -------------------------------------------------------------------------------- 1 | import { check } from 'k6'; 2 | import exec from 'k6/execution'; 3 | import { Assert, AssertionArgs } from './types'; 4 | import chai from './config'; 5 | import { isFunction, regexTag, truncate } from './utils'; 6 | 7 | const getObjectDisplay = (obj: object) => { 8 | return chai.util.objDisplay(obj) as unknown as string; 9 | }; 10 | 11 | const truncateByVariableThreshold = (str: string) => { 12 | return truncate(str, chai.config.truncateVariableThreshold); 13 | }; 14 | 15 | /** 16 | * Create the base expectation message template 17 | * 18 | * Example: "expected #{this} to be above 4" 19 | */ 20 | function createExpectationTemplate(context: object, params: AssertionArgs) { 21 | const [expression, successMessage, failureMessage, expected] = params; 22 | const negate = chai.util.flag(context, 'negate'); 23 | const anonymizeMsgFunction = chai.util.flag(context, 'anonymizeMsgFunction'); 24 | 25 | let message = negate ? failureMessage : successMessage; 26 | 27 | // Chai only prints messages when something fails, for this reason phrasing is often 28 | // assuming failure. k6 wants to collect both failed and successful checks so messages must be 29 | // neutral. for this reason we are changing the phrasing from 30 | // expected { a: 1, b: 2, c: 3 } to have property 'b' of 2, but got 2 31 | // to expected { a: 1, b: 2, c: 3 } to have property 'b' of 2, got 2 32 | message = message.replace('but ', ''); 33 | 34 | if (anonymizeMsgFunction) { 35 | message = anonymizeMsgFunction(message); 36 | } 37 | 38 | if (isFunction(message)) { 39 | message = message(); 40 | } 41 | 42 | message = message || ''; 43 | message = message.replace(regexTag('exp'), () => 44 | truncateByVariableThreshold(getObjectDisplay(expected)) 45 | ); 46 | 47 | return message; 48 | } 49 | 50 | /** 51 | * Create the final expectation message 52 | * 53 | * Example: "Number of crocs: expected 8 to be above 4" 54 | */ 55 | function createExpectationText( 56 | context: object, 57 | str = '', 58 | params: AssertionArgs 59 | ) { 60 | const object = chai.util.flag(context, 'object'); 61 | const actual = chai.util.getActual(context, params); 62 | const message = chai.util.flag(context, 'message'); 63 | 64 | let result = str 65 | .replace(regexTag('this'), () => 66 | truncateByVariableThreshold(getObjectDisplay(object)) 67 | ) 68 | .replace(regexTag('act'), () => 69 | truncateByVariableThreshold(getObjectDisplay(actual)) 70 | ); 71 | 72 | if (message && !chai.config.aggregateChecks) { 73 | result = message ? message + ': ' + result : result; 74 | } 75 | 76 | return result; 77 | } 78 | 79 | /** 80 | * Create the test name 81 | * 82 | * Example: "expected Number of crocs to be above 4" 83 | */ 84 | function createTestName(context: object, str = '') { 85 | const message = chai.util.flag(context, 'message'); 86 | 87 | const testName = str 88 | .replace(regexTag('this'), () => message || '${this}') 89 | .replace(regexTag('act'), () => '${actual}'); 90 | 91 | return truncateByVariableThreshold(testName); 92 | } 93 | 94 | /** 95 | * Overriding Chai's main assert() function to inject check() calls for both 96 | * successful and failed assertions. 97 | * 98 | * The original chai.util.getMessage did not truncate strings. 99 | * We are overriding it to prevent users from shooting themselves in the foot by 100 | * asserting large request.body and getting it printed on the terminal as a check message. 101 | */ 102 | export function assert(): Assert { 103 | return function ( 104 | expression, 105 | successMessage, 106 | failureMessage, 107 | expected, 108 | _actual, 109 | showDiff 110 | ) { 111 | showDiff = !expected && !_actual; 112 | 113 | const context = this as object; 114 | const params: AssertionArgs = [ 115 | expression, 116 | successMessage, 117 | failureMessage, 118 | expected, 119 | _actual, 120 | showDiff 121 | ]; 122 | 123 | const ok = chai.util.test(context, params); 124 | const actual = chai.util.getActual(context, params); 125 | 126 | const template = createExpectationTemplate(context, params); 127 | const testExpectation = createExpectationText(context, template, params); 128 | 129 | const testName = chai.config.aggregateChecks 130 | ? createTestName(context, template) 131 | : testExpectation; 132 | 133 | check(null, { 134 | [testName]: () => ok 135 | }); 136 | 137 | if (!ok) { 138 | const truncatedExpectation = truncateByVariableThreshold(testExpectation); 139 | const operator = chai.util.getOperator(context, params); 140 | 141 | const error = { 142 | actual, 143 | expected, 144 | showDiff, 145 | operator 146 | }; 147 | 148 | if (chai.config.logFailures) { 149 | console.warn(truncatedExpectation); 150 | } 151 | 152 | if (chai.config.exitOnError) { 153 | exec.test.abort(truncatedExpectation); 154 | } 155 | 156 | throw new chai.AssertionError( 157 | truncatedExpectation, 158 | error, 159 | chai.config.includeStack ? chai.assert : chai.util.flag(context, 'ssfi') 160 | ); 161 | } 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import { 3 | AGGREGATE_CHECKS, 4 | EXIT_ON_ERROR, 5 | LOG_FAILURES, 6 | TRUNCATE_VARIABLE_THRESHOLD, 7 | TRUNCATE_MSG_THRESHOLD 8 | } from './constants'; 9 | import { assert } from './assert'; 10 | import { anonymize, validJsonBody } from './matchers'; 11 | 12 | chai.config.truncateVariableThreshold = TRUNCATE_VARIABLE_THRESHOLD; // individual variables should be up to X chars after rendering.. 13 | chai.config.truncateMsgThreshold = TRUNCATE_MSG_THRESHOLD; // whole check() message must be below X chars. 14 | chai.config.aggregateChecks = AGGREGATE_CHECKS; // the {#this} and {#exp} are not interpolated to aggregate checks. 15 | chai.config.logFailures = LOG_FAILURES; // console.warn(full_message) 16 | chai.config.exitOnError = EXIT_ON_ERROR; 17 | 18 | chai.Assertion.addMethod('anonymize', anonymize); 19 | chai.Assertion.addMethod('validJsonBody', validJsonBody); 20 | chai.Assertion.overwriteMethod('assert', assert); 21 | 22 | export default chai; 23 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const AGGREGATE_CHECKS = true; 2 | export const EXIT_ON_ERROR = false; 3 | export const LOG_FAILURES = false; 4 | export const TRUNCATE_VARIABLE_THRESHOLD = 100; 5 | export const TRUNCATE_MSG_THRESHOLD = 300; 6 | -------------------------------------------------------------------------------- /src/custom-typings.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Chai { 2 | export interface AssertStatic { 3 | ( 4 | expression: unknown, 5 | message: string, 6 | negateMsg: string, 7 | expected: object | null, 8 | _actual?: unknown, 9 | showDiff?: boolean 10 | ): asserts expression; 11 | } 12 | 13 | export interface Config { 14 | truncateVariableThreshold: number; 15 | truncateMsgThreshold: number; 16 | aggregateChecks: boolean; 17 | logFailures: boolean; 18 | exitOnError: boolean; 19 | } 20 | 21 | export interface ChaiUtils { 22 | getOperator(object: object, arguments: unknown): operator | undefined; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/describe.ts: -------------------------------------------------------------------------------- 1 | import { group } from 'k6'; 2 | import { handleUnexpectedException } from './exceptions'; 3 | 4 | /** 5 | * Handle assertion grouping the K6 way 6 | */ 7 | export function describe(name: string, fn: (...xs: unknown[]) => unknown) { 8 | let success = true; 9 | 10 | group(name, () => { 11 | try { 12 | fn(); 13 | 14 | success = true; 15 | } catch (error: any) { 16 | if (error.name !== 'AssertionError') { 17 | handleUnexpectedException(error, name); 18 | } 19 | 20 | success = false; 21 | } 22 | }); 23 | 24 | return success; 25 | } 26 | -------------------------------------------------------------------------------- /src/exceptions.ts: -------------------------------------------------------------------------------- 1 | import { check } from 'k6'; 2 | 3 | /** 4 | * Handle exceptions the K6 way 5 | */ 6 | export const handleUnexpectedException = (error: string, testName: string) => { 7 | console.error( 8 | `Exception raised in test "${testName}". Failing the test and continuing. \n${error}` 9 | ); 10 | 11 | check(null, { 12 | [`Exception raised "${error}"`]: () => false 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import chai from './config'; 2 | export { describe } from './describe'; 3 | 4 | export default chai; 5 | export const expect = chai.expect; 6 | -------------------------------------------------------------------------------- /src/matchers.ts: -------------------------------------------------------------------------------- 1 | import chai from './config'; 2 | import { regexTag } from './utils'; 3 | 4 | const fallbackAnonymize = (msg = '') => { 5 | return msg.replace(regexTag('this'), () => { 6 | return ''; 7 | }); 8 | }; 9 | 10 | /** 11 | * Anonymizes the value of "this" in the message 12 | // useful for hiding tokens/passwords in the check messages. 13 | */ 14 | export function anonymize(fn = fallbackAnonymize) { 15 | chai.util.flag(this, 'anonymizeMsgFunction', fn); 16 | } 17 | 18 | /** 19 | * Determines whether the object is valid JSON 20 | */ 21 | export function validJsonBody() { 22 | const response = chai.util.flag(this, 'object'); 23 | let isCheckSuccessful = true; 24 | 25 | try { 26 | response.json('__unlikelyidefintifier1'); 27 | } catch (e) { 28 | isCheckSuccessful = false; 29 | } 30 | 31 | chai.assert( 32 | isCheckSuccessful, 33 | `has valid json body`, 34 | 'does not have a valid json body', 35 | null, // expected 36 | null // actual 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type AssertionArgsWithoutExpression = [ 2 | successMessage: string, 3 | failureMessage: string, 4 | expected: object, 5 | actual?: object, 6 | showDiff?: boolean 7 | ]; 8 | 9 | export type Assert = ( 10 | expression: object, 11 | ...args: AssertionArgsWithoutExpression 12 | ) => asserts expression; 13 | 14 | export type AssertionArgs = [ 15 | expression: object, 16 | ...args: AssertionArgsWithoutExpression 17 | ]; 18 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './regex'; 2 | export * from './predicate'; 3 | export * from './string'; 4 | -------------------------------------------------------------------------------- /src/utils/predicate.ts: -------------------------------------------------------------------------------- 1 | export const isFunction = (x: unknown): x is (...xs: T[]) => R => { 2 | return typeof x === 'function'; 3 | }; 4 | -------------------------------------------------------------------------------- /src/utils/regex.ts: -------------------------------------------------------------------------------- 1 | export const regexTag = (value = '') => new RegExp(`#{${value}}`, 'g'); 2 | -------------------------------------------------------------------------------- /src/utils/string.ts: -------------------------------------------------------------------------------- 1 | export const truncate = (str = '', len = 250) => { 2 | return str.length > len ? `${str.substring(0, len)}...` : str; 3 | }; 4 | -------------------------------------------------------------------------------- /tests/all-examples-from-docs.js: -------------------------------------------------------------------------------- 1 | // autogenerated script from all examples in the Chaijs docs https://www.chaijs.com/api/bdd/ 2 | import chai, { 3 | describe, 4 | expect 5 | } from 'https://jslib.k6.io/k6chaijs/4.3.4.1/index.js'; 6 | 7 | chai.config.aggregateChecks = false; 8 | chai.config.logFailures = true; 9 | 10 | export default function testSuite() { 11 | describe('docs example 0', () => { 12 | expect(() => null).to.not.throw(); 13 | expect({ a: 1 }).to.not.have.property('b'); 14 | expect([1, 2]).to.be.an('array').that.does.not.include(3); 15 | }); 16 | 17 | describe('docs example 1', () => { 18 | expect(2).to.equal(2); // Recommended 19 | expect(2).to.not.equal(1); // Not recommended 20 | }); 21 | 22 | describe('docs example 2', () => { 23 | // Target object deeply (but not strictly) equals `{a: 1}` 24 | expect({ a: 1 }).to.deep.equal({ a: 1 }); 25 | expect({ a: 1 }).to.not.equal({ a: 1 }); 26 | 27 | // Target array deeply (but not strictly) includes `{a: 1}` 28 | expect([{ a: 1 }]).to.deep.include({ a: 1 }); 29 | expect([{ a: 1 }]).to.not.include({ a: 1 }); 30 | 31 | // Target object deeply (but not strictly) includes `x: {a: 1}` 32 | expect({ x: { a: 1 } }).to.deep.include({ x: { a: 1 } }); 33 | expect({ x: { a: 1 } }).to.not.include({ x: { a: 1 } }); 34 | 35 | // Target array deeply (but not strictly) has member `{a: 1}` 36 | expect([{ a: 1 }]).to.have.deep.members([{ a: 1 }]); 37 | expect([{ a: 1 }]).to.not.have.members([{ a: 1 }]); 38 | 39 | // Target set deeply (but not strictly) has key `{a: 1}` 40 | expect(new Set([{ a: 1 }])).to.have.deep.keys([{ a: 1 }]); 41 | expect(new Set([{ a: 1 }])).to.not.have.keys([{ a: 1 }]); 42 | 43 | // Target object deeply (but not strictly) has property `x: {a: 1}` 44 | expect({ x: { a: 1 } }).to.have.deep.property('x', { a: 1 }); 45 | expect({ x: { a: 1 } }).to.not.have.property('x', { a: 1 }); 46 | }); 47 | 48 | describe('docs example 3', () => { 49 | expect({ a: { b: ['x', 'y'] } }).to.have.nested.property('a.b[1]'); 50 | expect({ a: { b: ['x', 'y'] } }).to.nested.include({ 'a.b[1]': 'y' }); 51 | }); 52 | 53 | describe('docs example 4', () => { 54 | expect({ '.a': { '[b]': 'x' } }).to.have.nested.property('\\.a.\\[b\\]'); 55 | expect({ '.a': { '[b]': 'x' } }).to.nested.include({ '\\.a.\\[b\\]': 'x' }); 56 | }); 57 | 58 | describe('docs example 5', () => { 59 | Object.prototype.b = 2; 60 | 61 | expect({ a: 1 }).to.have.own.property('a'); 62 | expect({ a: 1 }).to.have.property('b'); 63 | expect({ a: 1 }).to.not.have.own.property('b'); 64 | 65 | expect({ a: 1 }).to.own.include({ a: 1 }); 66 | expect({ a: 1 }).to.include({ b: 2 }).but.not.own.include({ b: 2 }); 67 | }); 68 | 69 | describe('docs example 6', () => { 70 | expect([1, 2]) 71 | .to.have.ordered.members([1, 2]) 72 | .but.not.have.ordered.members([2, 1]); 73 | }); 74 | 75 | describe('docs example 7', () => { 76 | expect([1, 2, 3]) 77 | .to.include.ordered.members([1, 2]) 78 | .but.not.include.ordered.members([2, 3]); 79 | }); 80 | 81 | describe('docs example 8', () => { 82 | expect({ a: 1, b: 2 }).to.not.have.any.keys('c', 'd'); 83 | }); 84 | 85 | describe('docs example 9', () => { 86 | expect({ a: 1, b: 2 }).to.have.all.keys('a', 'b'); 87 | }); 88 | 89 | describe('docs example 10', () => { 90 | expect('foo').to.be.a('string'); 91 | expect({ a: 1 }).to.be.an('object'); 92 | expect(null).to.be.a('null'); 93 | expect(undefined).to.be.an('undefined'); 94 | expect(new Error()).to.be.an('error'); 95 | expect(Promise.resolve()).to.be.a('promise'); 96 | expect(new Float32Array()).to.be.a('float32array'); 97 | expect(Symbol()).to.be.a('symbol'); 98 | }); 99 | 100 | describe('docs example 11', () => { 101 | var myObj = { 102 | [Symbol.toStringTag]: 'myCustomType' 103 | }; 104 | 105 | expect(myObj).to.be.a('myCustomType').but.not.an('object'); 106 | }); 107 | 108 | describe('docs example 12', () => { 109 | expect([1, 2, 3]).to.be.an('array').that.includes(2); 110 | expect([]).to.be.an('array').that.is.empty; 111 | }); 112 | 113 | describe('docs example 13', () => { 114 | expect('foo').to.be.a('string'); // Recommended 115 | expect('foo').to.not.be.an('array'); // Not recommended 116 | }); 117 | 118 | describe('docs example 14', () => { 119 | expect(1).to.be.a('string', 'nooo why fail??'); 120 | expect(1, 'nooo why fail??').to.be.a('string'); 121 | }); 122 | 123 | describe('docs example 15', () => { 124 | expect({ b: 2 }).to.have.a.property('b'); 125 | }); 126 | 127 | describe('docs example 16', () => { 128 | expect('foobar').to.include('foo'); 129 | }); 130 | 131 | describe('docs example 17', () => { 132 | expect([1, 2, 3]).to.include(2); 133 | }); 134 | 135 | describe('docs example 18', () => { 136 | expect({ a: 1, b: 2, c: 3 }).to.include({ a: 1, b: 2 }); 137 | }); 138 | 139 | describe('docs example 19', () => { 140 | expect(new Set([1, 2])).to.include(2); 141 | }); 142 | 143 | describe('docs example 20', () => { 144 | expect( 145 | new Map([ 146 | ['a', 1], 147 | ['b', 2] 148 | ]) 149 | ).to.include(2); 150 | }); 151 | 152 | describe('docs example 21', () => { 153 | expect([1, 2, 3]).to.be.an('array').that.includes(2); 154 | }); 155 | 156 | describe('docs example 22', () => { 157 | // Target array deeply (but not strictly) includes `{a: 1}` 158 | expect([{ a: 1 }]).to.deep.include({ a: 1 }); 159 | expect([{ a: 1 }]).to.not.include({ a: 1 }); 160 | 161 | // Target object deeply (but not strictly) includes `x: {a: 1}` 162 | expect({ x: { a: 1 } }).to.deep.include({ x: { a: 1 } }); 163 | expect({ x: { a: 1 } }).to.not.include({ x: { a: 1 } }); 164 | }); 165 | 166 | describe('docs example 23', () => { 167 | Object.prototype.b = 2; 168 | 169 | expect({ a: 1 }).to.own.include({ a: 1 }); 170 | expect({ a: 1 }).to.include({ b: 2 }).but.not.own.include({ b: 2 }); 171 | }); 172 | 173 | describe('docs example 24', () => { 174 | expect({ a: { b: 2 } }).to.deep.own.include({ a: { b: 2 } }); 175 | }); 176 | 177 | describe('docs example 25', () => { 178 | expect({ a: { b: ['x', 'y'] } }).to.nested.include({ 'a.b[1]': 'y' }); 179 | }); 180 | 181 | describe('docs example 26', () => { 182 | expect({ '.a': { '[b]': 2 } }).to.nested.include({ '\\.a.\\[b\\]': 2 }); 183 | }); 184 | 185 | describe('docs example 27', () => { 186 | expect({ a: { b: [{ c: 3 }] } }).to.deep.nested.include({ 187 | 'a.b[0]': { c: 3 } 188 | }); 189 | }); 190 | 191 | describe('docs example 28', () => { 192 | expect('foobar').to.not.include('taco'); 193 | expect([1, 2, 3]).to.not.include(4); 194 | }); 195 | 196 | describe('docs example 29', () => { 197 | expect({ c: 3 }).to.not.have.any.keys('a', 'b'); // Recommended 198 | expect({ c: 3 }).to.not.include({ a: 1, b: 2 }); // Not recommended 199 | }); 200 | 201 | describe('docs example 30', () => { 202 | expect({ a: 3, b: 4 }).to.include({ a: 3, b: 4 }); // Recommended 203 | expect({ a: 3, b: 4 }).to.not.include({ a: 1, b: 2 }); // Not recommended 204 | }); 205 | 206 | describe('docs example 31', () => { 207 | expect([1, 2, 3]).to.include(4, 'nooo why fail??'); 208 | expect([1, 2, 3], 'nooo why fail??').to.include(4); 209 | }); 210 | 211 | describe('docs example 32', () => { 212 | // Target object's keys are a superset of ['a', 'b'] but not identical 213 | expect({ a: 1, b: 2, c: 3 }).to.include.all.keys('a', 'b'); 214 | expect({ a: 1, b: 2, c: 3 }).to.not.have.all.keys('a', 'b'); 215 | 216 | // Target array is a superset of [1, 2] but not identical 217 | expect([1, 2, 3]).to.include.members([1, 2]); 218 | expect([1, 2, 3]).to.not.have.members([1, 2]); 219 | 220 | // Duplicates in the subset are ignored 221 | expect([1, 2, 3]).to.include.members([1, 2, 2, 2]); 222 | }); 223 | 224 | describe('docs example 33', () => { 225 | // Both assertions are identical 226 | expect({ a: 1 }).to.include.any.keys('a', 'b'); 227 | expect({ a: 1 }).to.have.any.keys('a', 'b'); 228 | }); 229 | 230 | describe('docs example 34', () => { 231 | expect(1).to.equal(1); // Recommended 232 | expect(1).to.be.ok; // Not recommended 233 | 234 | expect(true).to.be.true; // Recommended 235 | expect(true).to.be.ok; // Not recommended 236 | }); 237 | 238 | describe('docs example 35', () => { 239 | expect(0).to.equal(0); // Recommended 240 | expect(0).to.not.be.ok; // Not recommended 241 | 242 | expect(false).to.be.false; // Recommended 243 | expect(false).to.not.be.ok; // Not recommended 244 | 245 | expect(null).to.be.null; // Recommended 246 | expect(null).to.not.be.ok; // Not recommended 247 | 248 | expect(undefined).to.be.undefined; // Recommended 249 | expect(undefined).to.not.be.ok; // Not recommended 250 | }); 251 | 252 | describe('docs example 36', () => { 253 | expect(false, 'nooo why fail??').to.be.ok; 254 | }); 255 | 256 | describe('docs example 37', () => { 257 | expect(true).to.be.true; 258 | }); 259 | 260 | describe('docs example 38', () => { 261 | expect(false).to.be.false; // Recommended 262 | expect(false).to.not.be.true; // Not recommended 263 | 264 | expect(1).to.equal(1); // Recommended 265 | expect(1).to.not.be.true; // Not recommended 266 | }); 267 | 268 | describe('docs example 39', () => { 269 | expect(false, 'nooo why fail??').to.be.true; 270 | }); 271 | 272 | describe('docs example 40', () => { 273 | expect(false).to.be.false; 274 | }); 275 | 276 | describe('docs example 41', () => { 277 | expect(true).to.be.true; // Recommended 278 | expect(true).to.not.be.false; // Not recommended 279 | 280 | expect(1).to.equal(1); // Recommended 281 | expect(1).to.not.be.false; // Not recommended 282 | }); 283 | 284 | describe('docs example 42', () => { 285 | expect(true, 'nooo why fail??').to.be.false; 286 | }); 287 | 288 | describe('docs example 43', () => { 289 | expect(null).to.be.null; 290 | }); 291 | 292 | describe('docs example 44', () => { 293 | expect(1).to.equal(1); // Recommended 294 | expect(1).to.not.be.null; // Not recommended 295 | }); 296 | 297 | describe('docs example 45', () => { 298 | expect(42, 'nooo why fail??').to.be.null; 299 | }); 300 | 301 | describe('docs example 46', () => { 302 | expect(undefined).to.be.undefined; 303 | }); 304 | 305 | describe('docs example 47', () => { 306 | expect(1).to.equal(1); // Recommended 307 | expect(1).to.not.be.undefined; // Not recommended 308 | }); 309 | 310 | describe('docs example 48', () => { 311 | expect(42, 'nooo why fail??').to.be.undefined; 312 | }); 313 | 314 | describe('docs example 49', () => { 315 | expect(NaN).to.be.NaN; 316 | }); 317 | 318 | describe('docs example 50', () => { 319 | expect('foo').to.equal('foo'); // Recommended 320 | expect('foo').to.not.be.NaN; // Not recommended 321 | }); 322 | 323 | describe('docs example 51', () => { 324 | expect(42, 'nooo why fail??').to.be.NaN; 325 | }); 326 | 327 | describe('docs example 52', () => { 328 | expect(1).to.equal(1); // Recommended 329 | expect(1).to.exist; // Not recommended 330 | 331 | expect(0).to.equal(0); // Recommended 332 | expect(0).to.exist; // Not recommended 333 | }); 334 | 335 | describe('docs example 53', () => { 336 | expect(null).to.be.null; // Recommended 337 | expect(null).to.not.exist; // Not recommended 338 | 339 | expect(undefined).to.be.undefined; // Recommended 340 | expect(undefined).to.not.exist; // Not recommended 341 | }); 342 | 343 | describe('docs example 54', () => { 344 | expect(null, 'nooo why fail??').to.exist; 345 | }); 346 | 347 | describe('docs example 55', () => { 348 | expect([]).to.be.empty; 349 | expect('').to.be.empty; 350 | }); 351 | 352 | describe('docs example 56', () => { 353 | expect(new Set()).to.be.empty; 354 | expect(new Map()).to.be.empty; 355 | }); 356 | 357 | describe('docs example 57', () => { 358 | expect({}).to.be.empty; 359 | }); 360 | 361 | describe('docs example 58', () => { 362 | expect([]).to.be.an('array').that.is.empty; 363 | }); 364 | 365 | describe('docs example 59', () => { 366 | expect([1, 2, 3]).to.have.lengthOf(3); // Recommended 367 | expect([1, 2, 3]).to.not.be.empty; // Not recommended 368 | 369 | expect(new Set([1, 2, 3])).to.have.property('size', 3); // Recommended 370 | expect(new Set([1, 2, 3])).to.not.be.empty; // Not recommended 371 | 372 | expect(Object.keys({ a: 1 })).to.have.lengthOf(1); // Recommended 373 | expect({ a: 1 }).to.not.be.empty; // Not recommended 374 | }); 375 | 376 | describe('docs example 60', () => { 377 | expect([1, 2, 3], 'nooo why fail??').to.be.empty; 378 | }); 379 | 380 | describe('docs example 61', () => { 381 | function test() { 382 | expect(arguments).to.be.arguments; 383 | } 384 | 385 | test(); 386 | }); 387 | 388 | describe('docs example 62', () => { 389 | expect('foo').to.be.a('string'); // Recommended 390 | expect('foo').to.not.be.arguments; // Not recommended 391 | }); 392 | 393 | describe('docs example 63', () => { 394 | expect({}, 'nooo why fail??').to.be.arguments; 395 | }); 396 | 397 | describe('docs example 64', () => { 398 | expect(1).to.equal(1); 399 | expect('foo').to.equal('foo'); 400 | }); 401 | 402 | describe('docs example 65', () => { 403 | // Target object deeply (but not strictly) equals `{a: 1}` 404 | expect({ a: 1 }).to.deep.equal({ a: 1 }); 405 | expect({ a: 1 }).to.not.equal({ a: 1 }); 406 | 407 | // Target array deeply (but not strictly) equals `[1, 2]` 408 | expect([1, 2]).to.deep.equal([1, 2]); 409 | expect([1, 2]).to.not.equal([1, 2]); 410 | }); 411 | 412 | describe('docs example 66', () => { 413 | expect(1).to.equal(1); // Recommended 414 | expect(1).to.not.equal(2); // Not recommended 415 | }); 416 | 417 | describe('docs example 67', () => { 418 | expect(1).to.equal(2, 'nooo why fail??'); 419 | expect(1, 'nooo why fail??').to.equal(2); 420 | }); 421 | 422 | describe('docs example 68', () => { 423 | // Target object is deeply (but not strictly) equal to {a: 1} 424 | expect({ a: 1 }).to.eql({ a: 1 }).but.not.equal({ a: 1 }); 425 | 426 | // Target array is deeply (but not strictly) equal to [1, 2] 427 | expect([1, 2]).to.eql([1, 2]).but.not.equal([1, 2]); 428 | }); 429 | 430 | describe('docs example 69', () => { 431 | expect({ a: 1 }).to.eql({ a: 1 }); // Recommended 432 | expect({ a: 1 }).to.not.eql({ b: 2 }); // Not recommended 433 | }); 434 | 435 | describe('docs example 70', () => { 436 | expect({ a: 1 }).to.eql({ b: 2 }, 'nooo why fail??'); 437 | expect({ a: 1 }, 'nooo why fail??').to.eql({ b: 2 }); 438 | }); 439 | 440 | describe('docs example 71', () => { 441 | expect(2).to.equal(2); // Recommended 442 | expect(2).to.be.above(1); // Not recommended 443 | }); 444 | 445 | describe('docs example 72', () => { 446 | expect('foo').to.have.lengthOf(3); // Recommended 447 | expect('foo').to.have.lengthOf.above(2); // Not recommended 448 | 449 | expect([1, 2, 3]).to.have.lengthOf(3); // Recommended 450 | expect([1, 2, 3]).to.have.lengthOf.above(2); // Not recommended 451 | }); 452 | 453 | describe('docs example 73', () => { 454 | expect(2).to.equal(2); // Recommended 455 | expect(1).to.not.be.above(2); // Not recommended 456 | }); 457 | 458 | describe('docs example 74', () => { 459 | expect(1).to.be.above(2, 'nooo why fail??'); 460 | expect(1, 'nooo why fail??').to.be.above(2); 461 | }); 462 | 463 | describe('docs example 75', () => { 464 | expect(2).to.equal(2); // Recommended 465 | expect(2).to.be.at.least(1); // Not recommended 466 | expect(2).to.be.at.least(2); // Not recommended 467 | }); 468 | 469 | describe('docs example 76', () => { 470 | expect('foo').to.have.lengthOf(3); // Recommended 471 | expect('foo').to.have.lengthOf.at.least(2); // Not recommended 472 | 473 | expect([1, 2, 3]).to.have.lengthOf(3); // Recommended 474 | expect([1, 2, 3]).to.have.lengthOf.at.least(2); // Not recommended 475 | }); 476 | 477 | describe('docs example 77', () => { 478 | expect(1).to.equal(1); // Recommended 479 | expect(1).to.not.be.at.least(2); // Not recommended 480 | }); 481 | 482 | describe('docs example 78', () => { 483 | expect(1).to.be.at.least(2, 'nooo why fail??'); 484 | expect(1, 'nooo why fail??').to.be.at.least(2); 485 | }); 486 | 487 | describe('docs example 79', () => { 488 | expect(1).to.equal(1); // Recommended 489 | expect(1).to.be.below(2); // Not recommended 490 | }); 491 | 492 | describe('docs example 80', () => { 493 | expect('foo').to.have.lengthOf(3); // Recommended 494 | expect('foo').to.have.lengthOf.below(4); // Not recommended 495 | 496 | expect([1, 2, 3]).to.have.length(3); // Recommended 497 | expect([1, 2, 3]).to.have.lengthOf.below(4); // Not recommended 498 | }); 499 | 500 | describe('docs example 81', () => { 501 | expect(2).to.equal(2); // Recommended 502 | expect(2).to.not.be.below(1); // Not recommended 503 | }); 504 | 505 | describe('docs example 82', () => { 506 | expect(2).to.be.below(1, 'nooo why fail??'); 507 | expect(2, 'nooo why fail??').to.be.below(1); 508 | }); 509 | 510 | describe('docs example 83', () => { 511 | expect(1).to.equal(1); // Recommended 512 | expect(1).to.be.at.most(2); // Not recommended 513 | expect(1).to.be.at.most(1); // Not recommended 514 | }); 515 | 516 | describe('docs example 84', () => { 517 | expect('foo').to.have.lengthOf(3); // Recommended 518 | expect('foo').to.have.lengthOf.at.most(4); // Not recommended 519 | 520 | expect([1, 2, 3]).to.have.lengthOf(3); // Recommended 521 | expect([1, 2, 3]).to.have.lengthOf.at.most(4); // Not recommended 522 | }); 523 | 524 | describe('docs example 85', () => { 525 | expect(2).to.equal(2); // Recommended 526 | expect(2).to.not.be.at.most(1); // Not recommended 527 | }); 528 | 529 | describe('docs example 86', () => { 530 | expect(2).to.be.at.most(1, 'nooo why fail??'); 531 | expect(2, 'nooo why fail??').to.be.at.most(1); 532 | }); 533 | 534 | describe('docs example 87', () => { 535 | expect(2).to.equal(2); // Recommended 536 | expect(2).to.be.within(1, 3); // Not recommended 537 | expect(2).to.be.within(2, 3); // Not recommended 538 | expect(2).to.be.within(1, 2); // Not recommended 539 | }); 540 | 541 | describe('docs example 88', () => { 542 | expect('foo').to.have.lengthOf(3); // Recommended 543 | expect('foo').to.have.lengthOf.within(2, 4); // Not recommended 544 | 545 | expect([1, 2, 3]).to.have.lengthOf(3); // Recommended 546 | expect([1, 2, 3]).to.have.lengthOf.within(2, 4); // Not recommended 547 | }); 548 | 549 | describe('docs example 89', () => { 550 | expect(1).to.equal(1); // Recommended 551 | expect(1).to.not.be.within(2, 4); // Not recommended 552 | }); 553 | 554 | describe('docs example 90', () => { 555 | expect(4).to.be.within(1, 3, 'nooo why fail??'); 556 | expect(4, 'nooo why fail??').to.be.within(1, 3); 557 | }); 558 | 559 | describe('docs example 91', () => { 560 | function Cat() {} 561 | 562 | expect(new Cat()).to.be.an.instanceof(Cat); 563 | expect([1, 2]).to.be.an.instanceof(Array); 564 | }); 565 | 566 | describe('docs example 92', () => { 567 | expect({ a: 1 }).to.not.be.an.instanceof(Array); 568 | }); 569 | 570 | describe('docs example 93', () => { 571 | expect(1).to.be.an.instanceof(Array, 'nooo why fail??'); 572 | expect(1, 'nooo why fail??').to.be.an.instanceof(Array); 573 | }); 574 | 575 | describe('docs example 94', () => { 576 | expect({ a: 1 }).to.have.property('a'); 577 | }); 578 | 579 | describe('docs example 95', () => { 580 | expect({ a: 1 }).to.have.property('a', 1); 581 | }); 582 | 583 | describe('docs example 96', () => { 584 | // Target object deeply (but not strictly) has property `x: {a: 1}` 585 | expect({ x: { a: 1 } }).to.have.deep.property('x', { a: 1 }); 586 | expect({ x: { a: 1 } }).to.not.have.property('x', { a: 1 }); 587 | }); 588 | 589 | describe('docs example 97', () => { 590 | Object.prototype.b = 2; 591 | 592 | expect({ a: 1 }).to.have.own.property('a'); 593 | expect({ a: 1 }).to.have.own.property('a', 1); 594 | expect({ a: 1 }).to.have.property('b'); 595 | expect({ a: 1 }).to.not.have.own.property('b'); 596 | }); 597 | 598 | describe('docs example 98', () => { 599 | expect({ x: { a: 1 } }).to.have.deep.own.property('x', { a: 1 }); 600 | }); 601 | 602 | describe('docs example 99', () => { 603 | expect({ a: { b: ['x', 'y'] } }).to.have.nested.property('a.b[1]'); 604 | expect({ a: { b: ['x', 'y'] } }).to.have.nested.property('a.b[1]', 'y'); 605 | }); 606 | 607 | describe('docs example 100', () => { 608 | expect({ '.a': { '[b]': 'x' } }).to.have.nested.property('\\.a.\\[b\\]'); 609 | }); 610 | 611 | describe('docs example 101', () => { 612 | expect({ a: { b: [{ c: 3 }] } }).to.have.deep.nested.property('a.b[0]', { 613 | c: 3 614 | }); 615 | }); 616 | 617 | describe('docs example 102', () => { 618 | expect({ a: 1 }).to.not.have.property('b'); 619 | }); 620 | 621 | describe('docs example 103', () => { 622 | expect({ b: 2 }).to.not.have.property('a'); // Recommended 623 | expect({ b: 2 }).to.not.have.property('a', 1); // Not recommended 624 | }); 625 | 626 | describe('docs example 104', () => { 627 | expect({ a: 3 }).to.have.property('a', 3); // Recommended 628 | expect({ a: 3 }).to.not.have.property('a', 1); // Not recommended 629 | }); 630 | 631 | describe('docs example 105', () => { 632 | expect({ a: 1 }).to.have.property('a').that.is.a('number'); 633 | }); 634 | 635 | describe('docs example 106', () => { 636 | // Recommended 637 | expect({ a: 1 }).to.have.property('a', 2, 'nooo why fail??'); 638 | expect({ a: 1 }, 'nooo why fail??').to.have.property('a', 2); 639 | expect({ a: 1 }, 'nooo why fail??').to.have.property('b'); 640 | 641 | // Not recommended 642 | expect({ a: 1 }).to.have.property('b', undefined, 'nooo why fail??'); 643 | }); 644 | 645 | describe('docs example 107', () => { 646 | expect({ a: 1 }).to.have.ownPropertyDescriptor('a'); 647 | }); 648 | 649 | describe('docs example 108', () => { 650 | expect({ a: 1 }).to.have.ownPropertyDescriptor('a', { 651 | configurable: true, 652 | enumerable: true, 653 | writable: true, 654 | value: 1 655 | }); 656 | }); 657 | 658 | describe('docs example 109', () => { 659 | expect({ a: 1 }).to.not.have.ownPropertyDescriptor('b'); 660 | }); 661 | 662 | describe('docs example 110', () => { 663 | // Recommended 664 | expect({ b: 2 }).to.not.have.ownPropertyDescriptor('a'); 665 | 666 | // Not recommended 667 | expect({ b: 2 }).to.not.have.ownPropertyDescriptor('a', { 668 | configurable: true, 669 | enumerable: true, 670 | writable: true, 671 | value: 1 672 | }); 673 | }); 674 | 675 | describe('docs example 111', () => { 676 | // Recommended 677 | expect({ a: 3 }).to.have.ownPropertyDescriptor('a', { 678 | configurable: true, 679 | enumerable: true, 680 | writable: true, 681 | value: 3 682 | }); 683 | 684 | // Not recommended 685 | expect({ a: 3 }).to.not.have.ownPropertyDescriptor('a', { 686 | configurable: true, 687 | enumerable: true, 688 | writable: true, 689 | value: 1 690 | }); 691 | }); 692 | 693 | describe('docs example 112', () => { 694 | expect({ a: 1 }) 695 | .to.have.ownPropertyDescriptor('a') 696 | .that.has.property('enumerable', true); 697 | }); 698 | 699 | describe('docs example 113', () => { 700 | // Recommended 701 | expect({ a: 1 }).to.have.ownPropertyDescriptor( 702 | 'a', 703 | { 704 | configurable: true, 705 | enumerable: true, 706 | writable: true, 707 | value: 2 708 | }, 709 | 'nooo why fail??' 710 | ); 711 | 712 | // Recommended 713 | expect({ a: 1 }, 'nooo why fail??').to.have.ownPropertyDescriptor('a', { 714 | configurable: true, 715 | enumerable: true, 716 | writable: true, 717 | value: 2 718 | }); 719 | 720 | // Recommended 721 | expect({ a: 1 }, 'nooo why fail??').to.have.ownPropertyDescriptor('b'); 722 | 723 | // Not recommended 724 | expect({ a: 1 }).to.have.ownPropertyDescriptor( 725 | 'b', 726 | undefined, 727 | 'nooo why fail??' 728 | ); 729 | }); 730 | 731 | describe('docs example 114', () => { 732 | expect([1, 2, 3]).to.have.lengthOf(3); 733 | expect('foo').to.have.lengthOf(3); 734 | expect(new Set([1, 2, 3])).to.have.lengthOf(3); 735 | expect( 736 | new Map([ 737 | ['a', 1], 738 | ['b', 2], 739 | ['c', 3] 740 | ]) 741 | ).to.have.lengthOf(3); 742 | }); 743 | 744 | describe('docs example 115', () => { 745 | expect('foo').to.have.lengthOf(3); // Recommended 746 | expect('foo').to.not.have.lengthOf(4); // Not recommended 747 | }); 748 | 749 | describe('docs example 116', () => { 750 | expect([1, 2, 3]).to.have.lengthOf(2, 'nooo why fail??'); 751 | expect([1, 2, 3], 'nooo why fail??').to.have.lengthOf(2); 752 | }); 753 | 754 | describe('docs example 117', () => { 755 | // Recommended 756 | expect([1, 2, 3]).to.have.lengthOf(3); 757 | 758 | // Not recommended 759 | expect([1, 2, 3]).to.have.lengthOf.above(2); 760 | expect([1, 2, 3]).to.have.lengthOf.below(4); 761 | expect([1, 2, 3]).to.have.lengthOf.at.least(3); 762 | expect([1, 2, 3]).to.have.lengthOf.at.most(3); 763 | expect([1, 2, 3]).to.have.lengthOf.within(2, 4); 764 | }); 765 | 766 | describe('docs example 118', () => { 767 | expect([1, 2, 3]).to.have.a.length(3); // incompatible; throws error 768 | expect([1, 2, 3]).to.have.a.lengthOf(3); // passes as expected 769 | }); 770 | 771 | describe('docs example 119', () => { 772 | expect('foobar').to.match(/^foo/); 773 | }); 774 | 775 | describe('docs example 120', () => { 776 | expect('foobar').to.not.match(/taco/); 777 | }); 778 | 779 | describe('docs example 121', () => { 780 | expect('foobar').to.match(/taco/, 'nooo why fail??'); 781 | expect('foobar', 'nooo why fail??').to.match(/taco/); 782 | }); 783 | 784 | describe('docs example 122', () => { 785 | expect('foobar').to.have.string('bar'); 786 | }); 787 | 788 | describe('docs example 123', () => { 789 | expect('foobar').to.not.have.string('taco'); 790 | }); 791 | 792 | describe('docs example 124', () => { 793 | expect('foobar').to.have.string('taco', 'nooo why fail??'); 794 | expect('foobar', 'nooo why fail??').to.have.string('taco'); 795 | }); 796 | 797 | describe('docs example 125', () => { 798 | expect({ a: 1, b: 2 }).to.have.all.keys('a', 'b'); 799 | expect(['x', 'y']).to.have.all.keys(0, 1); 800 | 801 | expect({ a: 1, b: 2 }).to.have.all.keys(['a', 'b']); 802 | expect(['x', 'y']).to.have.all.keys([0, 1]); 803 | 804 | expect({ a: 1, b: 2 }).to.have.all.keys({ a: 4, b: 5 }); // ignore 4 and 5 805 | expect(['x', 'y']).to.have.all.keys({ 0: 4, 1: 5 }); // ignore 4 and 5 806 | }); 807 | 808 | describe('docs example 126', () => { 809 | expect( 810 | new Map([ 811 | ['a', 1], 812 | ['b', 2] 813 | ]) 814 | ).to.have.all.keys('a', 'b'); 815 | expect(new Set(['a', 'b'])).to.have.all.keys('a', 'b'); 816 | }); 817 | 818 | describe('docs example 127', () => { 819 | expect({ a: 1, b: 2 }).to.be.an('object').that.has.all.keys('a', 'b'); 820 | }); 821 | 822 | describe('docs example 128', () => { 823 | // Target set deeply (but not strictly) has key `{a: 1}` 824 | expect(new Set([{ a: 1 }])).to.have.all.deep.keys([{ a: 1 }]); 825 | expect(new Set([{ a: 1 }])).to.not.have.all.keys([{ a: 1 }]); 826 | }); 827 | 828 | describe('docs example 129', () => { 829 | // Recommended; asserts that target doesn't have any of the given keys 830 | expect({ a: 1, b: 2 }).to.not.have.any.keys('c', 'd'); 831 | 832 | // Not recommended; asserts that target doesn't have all of the given 833 | // keys but may or may not have some of them 834 | expect({ a: 1, b: 2 }).to.not.have.all.keys('c', 'd'); 835 | }); 836 | 837 | describe('docs example 130', () => { 838 | // Recommended; asserts that target has all the given keys 839 | expect({ a: 1, b: 2 }).to.have.all.keys('a', 'b'); 840 | 841 | // Not recommended; asserts that target has at least one of the given 842 | // keys but may or may not have more of them 843 | expect({ a: 1, b: 2 }).to.have.any.keys('a', 'b'); 844 | }); 845 | 846 | describe('docs example 131', () => { 847 | // Both assertions are identical 848 | expect({ a: 1, b: 2 }).to.have.all.keys('a', 'b'); // Recommended 849 | expect({ a: 1, b: 2 }).to.have.keys('a', 'b'); // Not recommended 850 | }); 851 | 852 | describe('docs example 132', () => { 853 | // Target object's keys are a superset of ['a', 'b'] but not identical 854 | expect({ a: 1, b: 2, c: 3 }).to.include.all.keys('a', 'b'); 855 | expect({ a: 1, b: 2, c: 3 }).to.not.have.all.keys('a', 'b'); 856 | }); 857 | 858 | describe('docs example 133', () => { 859 | // Both assertions are identical 860 | expect({ a: 1 }).to.have.any.keys('a', 'b'); 861 | expect({ a: 1 }).to.include.any.keys('a', 'b'); 862 | }); 863 | 864 | describe('docs example 134', () => { 865 | expect({ a: 1 }, 'nooo why fail??').to.have.key('b'); 866 | }); 867 | 868 | describe('docs example 135', () => { 869 | var badFn = function () { 870 | throw new TypeError('Illegal salmon!'); 871 | }; 872 | 873 | expect(badFn).to.throw(); 874 | }); 875 | 876 | describe('docs example 136', () => { 877 | var badFn = function () { 878 | throw new TypeError('Illegal salmon!'); 879 | }; 880 | 881 | expect(badFn).to.throw(TypeError); 882 | }); 883 | 884 | describe('docs example 137', () => { 885 | var err = new TypeError('Illegal salmon!'); 886 | var badFn = function () { 887 | throw err; 888 | }; 889 | 890 | expect(badFn).to.throw(err); 891 | }); 892 | 893 | describe('docs example 138', () => { 894 | var badFn = function () { 895 | throw new TypeError('Illegal salmon!'); 896 | }; 897 | 898 | expect(badFn).to.throw('salmon'); 899 | }); 900 | 901 | describe('docs example 139', () => { 902 | var badFn = function () { 903 | throw new TypeError('Illegal salmon!'); 904 | }; 905 | 906 | expect(badFn).to.throw(/salmon/); 907 | }); 908 | 909 | describe('docs example 140', () => { 910 | var err = new TypeError('Illegal salmon!'); 911 | var badFn = function () { 912 | throw err; 913 | }; 914 | 915 | expect(badFn).to.throw(TypeError, 'salmon'); 916 | expect(badFn).to.throw(TypeError, /salmon/); 917 | expect(badFn).to.throw(err, 'salmon'); 918 | expect(badFn).to.throw(err, /salmon/); 919 | }); 920 | 921 | describe('docs example 141', () => { 922 | var goodFn = function () {}; 923 | 924 | expect(goodFn).to.not.throw(); 925 | }); 926 | 927 | describe('docs example 142', () => { 928 | var goodFn = function () {}; 929 | 930 | expect(goodFn).to.not.throw(); // Recommended 931 | expect(goodFn).to.not.throw(ReferenceError, 'x'); // Not recommended 932 | }); 933 | 934 | describe('docs example 143', () => { 935 | var badFn = function () { 936 | throw new TypeError('Illegal salmon!'); 937 | }; 938 | 939 | expect(badFn).to.throw(TypeError, 'salmon'); // Recommended 940 | expect(badFn).to.not.throw(ReferenceError, 'x'); // Not recommended 941 | }); 942 | 943 | describe('docs example 144', () => { 944 | var err = new TypeError('Illegal salmon!'); 945 | err.code = 42; 946 | var badFn = function () { 947 | throw err; 948 | }; 949 | 950 | expect(badFn).to.throw(TypeError).with.property('code', 42); 951 | }); 952 | 953 | describe('docs example 145', () => { 954 | var goodFn = function () {}; 955 | 956 | expect(goodFn).to.throw(TypeError, 'x', 'nooo why fail??'); 957 | expect(goodFn, 'nooo why fail??').to.throw(); 958 | }); 959 | 960 | describe('docs example 146', () => { 961 | var fn = function () { 962 | throw new TypeError('Illegal salmon!'); 963 | }; 964 | 965 | expect(fn).to.throw(); // Good! Tests `fn` as desired 966 | expect(fn()).to.throw(); // Bad! Tests result of `fn()`, not `fn` 967 | }); 968 | 969 | describe('docs example 147', () => { 970 | expect(function () { 971 | fn(42); 972 | }).to.throw(); // Function expression 973 | expect(() => fn(42)).to.throw(); // ES6 arrow function 974 | }); 975 | 976 | describe('docs example 148', () => { 977 | expect(function () { 978 | cat.meow(); 979 | }).to.throw(); // Function expression 980 | expect(() => cat.meow()).to.throw(); // ES6 arrow function 981 | expect(cat.meow.bind(cat)).to.throw(); // Bind 982 | }); 983 | 984 | describe('docs example 149', () => { 985 | function Cat() {} 986 | Cat.prototype.meow = function () {}; 987 | 988 | expect(new Cat()).to.respondTo('meow'); 989 | }); 990 | 991 | describe('docs example 150', () => { 992 | function Cat() {} 993 | Cat.prototype.meow = function () {}; 994 | 995 | expect(Cat).to.respondTo('meow'); 996 | }); 997 | 998 | describe('docs example 151', () => { 999 | function Cat() {} 1000 | Cat.prototype.meow = function () {}; 1001 | Cat.hiss = function () {}; 1002 | 1003 | expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow'); 1004 | }); 1005 | 1006 | describe('docs example 152', () => { 1007 | function Cat() {} 1008 | Cat.prototype.meow = function () {}; 1009 | 1010 | expect(new Cat()).to.be.an('object').that.respondsTo('meow'); 1011 | }); 1012 | 1013 | describe('docs example 153', () => { 1014 | function Dog() {} 1015 | Dog.prototype.bark = function () {}; 1016 | 1017 | expect(new Dog()).to.not.respondTo('meow'); 1018 | }); 1019 | 1020 | describe('docs example 154', () => { 1021 | expect({}).to.respondTo('meow', 'nooo why fail??'); 1022 | expect({}, 'nooo why fail??').to.respondTo('meow'); 1023 | }); 1024 | 1025 | describe('docs example 155', () => { 1026 | function Cat() {} 1027 | Cat.prototype.meow = function () {}; 1028 | Cat.hiss = function () {}; 1029 | 1030 | expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow'); 1031 | }); 1032 | 1033 | describe('docs example 156', () => { 1034 | expect(1).to.satisfy(function (num) { 1035 | return num > 0; 1036 | }); 1037 | }); 1038 | 1039 | describe('docs example 157', () => { 1040 | expect(1).to.not.satisfy(function (num) { 1041 | return num > 2; 1042 | }); 1043 | }); 1044 | 1045 | describe('docs example 158', () => { 1046 | expect(1).to.satisfy(function (num) { 1047 | return num > 2; 1048 | }, 'nooo why fail??'); 1049 | 1050 | expect(1, 'nooo why fail??').to.satisfy(function (num) { 1051 | return num > 2; 1052 | }); 1053 | }); 1054 | 1055 | describe('docs example 159', () => { 1056 | // Recommended 1057 | expect(1.5).to.equal(1.5); 1058 | 1059 | // Not recommended 1060 | expect(1.5).to.be.closeTo(1, 0.5); 1061 | expect(1.5).to.be.closeTo(2, 0.5); 1062 | expect(1.5).to.be.closeTo(1, 1); 1063 | }); 1064 | 1065 | describe('docs example 160', () => { 1066 | expect(1.5).to.equal(1.5); // Recommended 1067 | expect(1.5).to.not.be.closeTo(3, 1); // Not recommended 1068 | }); 1069 | 1070 | describe('docs example 161', () => { 1071 | expect(1.5).to.be.closeTo(3, 1, 'nooo why fail??'); 1072 | expect(1.5, 'nooo why fail??').to.be.closeTo(3, 1); 1073 | }); 1074 | 1075 | describe('docs example 162', () => { 1076 | expect([1, 2, 3]).to.have.members([2, 1, 3]); 1077 | expect([1, 2, 2]).to.have.members([2, 1, 2]); 1078 | }); 1079 | 1080 | describe('docs example 163', () => { 1081 | // Target array deeply (but not strictly) has member `{a: 1}` 1082 | expect([{ a: 1 }]).to.have.deep.members([{ a: 1 }]); 1083 | expect([{ a: 1 }]).to.not.have.members([{ a: 1 }]); 1084 | }); 1085 | 1086 | describe('docs example 164', () => { 1087 | expect([1, 2, 3]).to.have.ordered.members([1, 2, 3]); 1088 | expect([1, 2, 3]) 1089 | .to.have.members([2, 1, 3]) 1090 | .but.not.ordered.members([2, 1, 3]); 1091 | }); 1092 | 1093 | describe('docs example 165', () => { 1094 | // Target array is a superset of [1, 2] but not identical 1095 | expect([1, 2, 3]).to.include.members([1, 2]); 1096 | expect([1, 2, 3]).to.not.have.members([1, 2]); 1097 | 1098 | // Duplicates in the subset are ignored 1099 | expect([1, 2, 3]).to.include.members([1, 2, 2, 2]); 1100 | }); 1101 | 1102 | describe('docs example 166', () => { 1103 | expect([{ a: 1 }, { b: 2 }, { c: 3 }]) 1104 | .to.include.deep.ordered.members([{ a: 1 }, { b: 2 }]) 1105 | .but.not.include.deep.ordered.members([{ b: 2 }, { c: 3 }]); 1106 | }); 1107 | 1108 | describe('docs example 167', () => { 1109 | expect([1, 2]).to.not.include(3).and.not.include(4); // Recommended 1110 | expect([1, 2]).to.not.have.members([3, 4]); // Not recommended 1111 | }); 1112 | 1113 | describe('docs example 168', () => { 1114 | expect([1, 2]).to.have.members([1, 2, 3], 'nooo why fail??'); 1115 | expect([1, 2], 'nooo why fail??').to.have.members([1, 2, 3]); 1116 | }); 1117 | 1118 | describe('docs example 169', () => { 1119 | expect(1).to.equal(1); // Recommended 1120 | expect(1).to.be.oneOf([1, 2, 3]); // Not recommended 1121 | }); 1122 | 1123 | describe('docs example 170', () => { 1124 | expect(1).to.equal(1); // Recommended 1125 | expect(1).to.not.be.oneOf([2, 3, 4]); // Not recommended 1126 | }); 1127 | 1128 | describe('docs example 171', () => { 1129 | expect('Today is sunny').to.contain.oneOf(['sunny', 'cloudy']); 1130 | expect('Today is rainy').to.not.contain.oneOf(['sunny', 'cloudy']); 1131 | expect([1, 2, 3]).to.contain.oneOf([3, 4, 5]); 1132 | expect([1, 2, 3]).to.not.contain.oneOf([4, 5, 6]); 1133 | }); 1134 | 1135 | describe('docs example 172', () => { 1136 | expect(1).to.be.oneOf([2, 3, 4], 'nooo why fail??'); 1137 | expect(1, 'nooo why fail??').to.be.oneOf([2, 3, 4]); 1138 | }); 1139 | 1140 | describe('docs example 173', () => { 1141 | var dots = '', 1142 | addDot = function () { 1143 | dots += '.'; 1144 | }, 1145 | getDots = function () { 1146 | return dots; 1147 | }; 1148 | 1149 | // Recommended 1150 | expect(getDots()).to.equal(''); 1151 | addDot(); 1152 | expect(getDots()).to.equal('.'); 1153 | 1154 | // Not recommended 1155 | expect(addDot).to.change(getDots); 1156 | }); 1157 | 1158 | describe('docs example 174', () => { 1159 | var myObj = { dots: '' }, 1160 | addDot = function () { 1161 | myObj.dots += '.'; 1162 | }; 1163 | 1164 | // Recommended 1165 | expect(myObj).to.have.property('dots', ''); 1166 | addDot(); 1167 | expect(myObj).to.have.property('dots', '.'); 1168 | 1169 | // Not recommended 1170 | expect(addDot).to.change(myObj, 'dots'); 1171 | }); 1172 | 1173 | describe('docs example 175', () => { 1174 | var dots = '', 1175 | noop = function () {}, 1176 | getDots = function () { 1177 | return dots; 1178 | }; 1179 | 1180 | expect(noop).to.not.change(getDots); 1181 | 1182 | var myObj = { dots: '' }, 1183 | noop = function () {}; 1184 | 1185 | expect(noop).to.not.change(myObj, 'dots'); 1186 | }); 1187 | 1188 | describe('docs example 176', () => { 1189 | var myObj = { dots: '' }, 1190 | addDot = function () { 1191 | myObj.dots += '.'; 1192 | }; 1193 | 1194 | expect(addDot).to.not.change(myObj, 'dots', 'nooo why fail??'); 1195 | 1196 | var dots = '', 1197 | addDot = function () { 1198 | dots += '.'; 1199 | }, 1200 | getDots = function () { 1201 | return dots; 1202 | }; 1203 | 1204 | expect(addDot, 'nooo why fail??').to.not.change(getDots); 1205 | }); 1206 | 1207 | describe('docs example 177', () => { 1208 | var myObj = { val: 1 }, 1209 | addTwo = function () { 1210 | myObj.val += 2; 1211 | }, 1212 | subtractTwo = function () { 1213 | myObj.val -= 2; 1214 | }; 1215 | 1216 | expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended 1217 | expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended 1218 | 1219 | expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended 1220 | expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended 1221 | }); 1222 | 1223 | describe('docs example 178', () => { 1224 | var val = 1, 1225 | addTwo = function () { 1226 | val += 2; 1227 | }, 1228 | getVal = function () { 1229 | return val; 1230 | }; 1231 | 1232 | expect(addTwo).to.increase(getVal).by(2); // Recommended 1233 | expect(addTwo).to.increase(getVal); // Not recommended 1234 | }); 1235 | 1236 | describe('docs example 179', () => { 1237 | var myObj = { val: 1 }, 1238 | addTwo = function () { 1239 | myObj.val += 2; 1240 | }; 1241 | 1242 | expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended 1243 | expect(addTwo).to.increase(myObj, 'val'); // Not recommended 1244 | }); 1245 | 1246 | describe('docs example 180', () => { 1247 | var myObj = { val: 1 }, 1248 | subtractTwo = function () { 1249 | myObj.val -= 2; 1250 | }; 1251 | 1252 | expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended 1253 | expect(subtractTwo).to.not.increase(myObj, 'val'); // Not recommended 1254 | }); 1255 | 1256 | describe('docs example 181', () => { 1257 | var myObj = { val: 1 }, 1258 | noop = function () {}; 1259 | 1260 | expect(noop).to.not.change(myObj, 'val'); // Recommended 1261 | expect(noop).to.not.increase(myObj, 'val'); // Not recommended 1262 | }); 1263 | 1264 | describe('docs example 182', () => { 1265 | var myObj = { val: 1 }, 1266 | noop = function () {}; 1267 | 1268 | expect(noop).to.increase(myObj, 'val', 'nooo why fail??'); 1269 | 1270 | var val = 1, 1271 | noop = function () {}, 1272 | getVal = function () { 1273 | return val; 1274 | }; 1275 | 1276 | expect(noop, 'nooo why fail??').to.increase(getVal); 1277 | }); 1278 | 1279 | describe('docs example 183', () => { 1280 | var val = 1, 1281 | subtractTwo = function () { 1282 | val -= 2; 1283 | }, 1284 | getVal = function () { 1285 | return val; 1286 | }; 1287 | 1288 | expect(subtractTwo).to.decrease(getVal).by(2); // Recommended 1289 | expect(subtractTwo).to.decrease(getVal); // Not recommended 1290 | }); 1291 | 1292 | describe('docs example 184', () => { 1293 | var myObj = { val: 1 }, 1294 | subtractTwo = function () { 1295 | myObj.val -= 2; 1296 | }; 1297 | 1298 | expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended 1299 | expect(subtractTwo).to.decrease(myObj, 'val'); // Not recommended 1300 | }); 1301 | 1302 | describe('docs example 185', () => { 1303 | var myObj = { val: 1 }, 1304 | addTwo = function () { 1305 | myObj.val += 2; 1306 | }; 1307 | 1308 | expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended 1309 | expect(addTwo).to.not.decrease(myObj, 'val'); // Not recommended 1310 | }); 1311 | 1312 | describe('docs example 186', () => { 1313 | var myObj = { val: 1 }, 1314 | noop = function () {}; 1315 | 1316 | expect(noop).to.not.change(myObj, 'val'); // Recommended 1317 | expect(noop).to.not.decrease(myObj, 'val'); // Not recommended 1318 | }); 1319 | 1320 | describe('docs example 187', () => { 1321 | var myObj = { val: 1 }, 1322 | noop = function () {}; 1323 | 1324 | expect(noop).to.decrease(myObj, 'val', 'nooo why fail??'); 1325 | 1326 | var val = 1, 1327 | noop = function () {}, 1328 | getVal = function () { 1329 | return val; 1330 | }; 1331 | 1332 | expect(noop, 'nooo why fail??').to.decrease(getVal); 1333 | }); 1334 | 1335 | describe('docs example 188', () => { 1336 | var myObj = { val: 1 }, 1337 | addTwo = function () { 1338 | myObj.val += 2; 1339 | }; 1340 | 1341 | expect(addTwo).to.increase(myObj, 'val').by(2); 1342 | }); 1343 | 1344 | describe('docs example 189', () => { 1345 | var myObj = { val: 1 }, 1346 | subtractTwo = function () { 1347 | myObj.val -= 2; 1348 | }; 1349 | 1350 | expect(subtractTwo).to.decrease(myObj, 'val').by(2); 1351 | }); 1352 | 1353 | describe('docs example 190', () => { 1354 | var myObj = { val: 1 }, 1355 | addTwo = function () { 1356 | myObj.val += 2; 1357 | }, 1358 | subtractTwo = function () { 1359 | myObj.val -= 2; 1360 | }; 1361 | 1362 | expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended 1363 | expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended 1364 | 1365 | expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended 1366 | expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended 1367 | }); 1368 | 1369 | describe('docs example 191', () => { 1370 | var myObj = { val: 1 }, 1371 | addTwo = function () { 1372 | myObj.val += 2; 1373 | }; 1374 | 1375 | // Recommended 1376 | expect(addTwo).to.increase(myObj, 'val').by(2); 1377 | 1378 | // Not recommended 1379 | expect(addTwo).to.increase(myObj, 'val').but.not.by(3); 1380 | }); 1381 | 1382 | describe('docs example 192', () => { 1383 | var myObj = { val: 1 }, 1384 | addTwo = function () { 1385 | myObj.val += 2; 1386 | }; 1387 | 1388 | expect(addTwo).to.increase(myObj, 'val').by(3, 'nooo why fail??'); 1389 | expect(addTwo, 'nooo why fail??').to.increase(myObj, 'val').by(3); 1390 | }); 1391 | 1392 | describe('docs example 193', () => { 1393 | expect({ a: 1 }).to.be.extensible; 1394 | }); 1395 | 1396 | describe('docs example 194', () => { 1397 | var nonExtensibleObject = Object.preventExtensions({}), 1398 | sealedObject = Object.seal({}), 1399 | frozenObject = Object.freeze({}); 1400 | 1401 | expect(nonExtensibleObject).to.not.be.extensible; 1402 | expect(sealedObject).to.not.be.extensible; 1403 | expect(frozenObject).to.not.be.extensible; 1404 | expect(1).to.not.be.extensible; 1405 | }); 1406 | 1407 | describe('docs example 195', () => { 1408 | expect(1, 'nooo why fail??').to.be.extensible; 1409 | }); 1410 | 1411 | describe('docs example 196', () => { 1412 | var sealedObject = Object.seal({}); 1413 | var frozenObject = Object.freeze({}); 1414 | 1415 | expect(sealedObject).to.be.sealed; 1416 | expect(frozenObject).to.be.sealed; 1417 | expect(1).to.be.sealed; 1418 | }); 1419 | 1420 | describe('docs example 197', () => { 1421 | expect({ a: 1 }).to.not.be.sealed; 1422 | }); 1423 | 1424 | describe('docs example 198', () => { 1425 | expect({ a: 1 }, 'nooo why fail??').to.be.sealed; 1426 | }); 1427 | 1428 | describe('docs example 199', () => { 1429 | var frozenObject = Object.freeze({}); 1430 | 1431 | expect(frozenObject).to.be.frozen; 1432 | expect(1).to.be.frozen; 1433 | }); 1434 | 1435 | describe('docs example 200', () => { 1436 | expect({ a: 1 }).to.not.be.frozen; 1437 | }); 1438 | 1439 | describe('docs example 201', () => { 1440 | expect({ a: 1 }, 'nooo why fail??').to.be.frozen; 1441 | }); 1442 | 1443 | describe('docs example 202', () => { 1444 | expect(1).to.be.finite; 1445 | }); 1446 | 1447 | describe('docs example 203', () => { 1448 | expect('foo').to.be.a('string'); // Recommended 1449 | expect('foo').to.not.be.finite; // Not recommended 1450 | }); 1451 | 1452 | describe('docs example 204', () => { 1453 | expect(NaN).to.be.NaN; // Recommended 1454 | expect(NaN).to.not.be.finite; // Not recommended 1455 | }); 1456 | 1457 | describe('docs example 205', () => { 1458 | expect(Infinity).to.equal(Infinity); // Recommended 1459 | expect(Infinity).to.not.be.finite; // Not recommended 1460 | }); 1461 | 1462 | describe('docs example 206', () => { 1463 | expect(-Infinity).to.equal(-Infinity); // Recommended 1464 | expect(-Infinity).to.not.be.finite; // Not recommended 1465 | }); 1466 | 1467 | describe('docs example 207', () => { 1468 | expect('foo', 'nooo why fail??').to.be.finite; 1469 | }); 1470 | 1471 | describe('docs example 208', () => { 1472 | expect.fail(); 1473 | expect.fail('custom error message'); 1474 | expect.fail(1, 2); 1475 | expect.fail(1, 2, 'custom error message'); 1476 | expect.fail(1, 2, 'custom error message', '>'); 1477 | expect.fail(1, 2, undefined, '>'); 1478 | }); 1479 | 1480 | // describe('docs example 209', () => { 1481 | // should.fail(); 1482 | // should.fail("custom error message"); 1483 | // should.fail(1, 2); 1484 | // should.fail(1, 2, "custom error message"); 1485 | // should.fail(1, 2, "custom error message", ">"); 1486 | // should.fail(1, 2, undefined, ">"); 1487 | 1488 | // }); 1489 | } 1490 | -------------------------------------------------------------------------------- /tests/chai-should-syntax.js: -------------------------------------------------------------------------------- 1 | import chai, { describe } from '../build/k6chaijs.min.js'; 2 | 3 | chai.config.aggregateChecks = false; 4 | chai.config.logFailures = true; 5 | 6 | export default function testSuite() { 7 | let response = { 8 | status: (__ITER % 5) + 199 9 | }; 10 | chai.should(); 11 | 12 | var foo = 'bar'; 13 | var beverages = { tea: ['chai', 'matcha', 'oolong'] }; 14 | 15 | describe('Testing different values for expect', () => { 16 | response.status.should.be.a('number'); 17 | foo.should.be.a('string'); 18 | foo.should.equal('bar'); 19 | foo.should.have.lengthOf(3); 20 | beverages.should.have.property('tea').with.lengthOf(3); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /tests/check-aggregation.js: -------------------------------------------------------------------------------- 1 | import chai, { describe, expect } from '../build/k6chaijs.min.js'; 2 | import { sleep } from 'k6'; 3 | 4 | // set aggregateChecks=false to see how checks are behaving with multiple values interpolated into 5 | // the check name (deaggregation is not recommended unless you are running 1 iteration) 6 | chai.config.aggregateChecks = true; 7 | 8 | // Even when checks are aggregated, you can print the full message by setting logFailures=true 9 | chai.config.logFailures = true; 10 | 11 | export let options = { 12 | iterations: 3 13 | }; 14 | 15 | export default function testSuite() { 16 | let fakeResponse = { 17 | status: (__ITER % 5) + 199 18 | }; 19 | 20 | describe('Testing check aggregation', () => { 21 | expect(fakeResponse.status, 'response status').to.equal(200); 22 | }); 23 | 24 | sleep(1); 25 | } 26 | -------------------------------------------------------------------------------- /tests/exit-on-error.js: -------------------------------------------------------------------------------- 1 | import chai, { describe, expect } from '../build/k6chaijs.min.js'; 2 | import { sleep } from 'k6'; 3 | 4 | // Set exitOnError=true to exit k6 on the first failed check. 5 | chai.config.exitOnError = true; 6 | 7 | export let options = { 8 | iterations: 3 9 | }; 10 | 11 | export default function testSuite() { 12 | let fakeResponse = { 13 | status: 401 14 | }; 15 | 16 | describe('Testing check aggregation', () => { 17 | expect(fakeResponse.status, 'response status').to.equal(200); 18 | }); 19 | 20 | sleep(1); 21 | } 22 | -------------------------------------------------------------------------------- /tests/simple.js: -------------------------------------------------------------------------------- 1 | import http from 'k6/http'; 2 | import chai, { describe, expect } from '../build/k6chaijs.min.js'; 3 | 4 | export let options = { 5 | thresholds: { 6 | checks: [{ threshold: 'rate == 1.00', abortOnFail: true }], 7 | http_req_failed: [{ threshold: 'rate == 0.00', abortOnFail: true }] 8 | } 9 | }; 10 | 11 | chai.config.aggregateChecks = false; 12 | 13 | export default function testSuite() { 14 | describe('[Crocs service] Fetch list of crocs', () => { 15 | let response = http.get('https://test-api.k6.io/public/crocodiles'); 16 | 17 | expect(response.status, 'response status').to.equal(200); 18 | expect(response).to.have.validJsonBody(); 19 | expect(response.json().length, 'Number of crocs').to.be.above(4); 20 | }); 21 | 22 | describe('Dummy example', () => { 23 | expect(10).to.be.within(8, 12); // OK 24 | expect(42).to.equal(44); // fails 25 | expect(true).to.be.ok; // doesn't run because the previous assertion failed. 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | import { describe, expect } from '../build/k6chaijs.min.js'; 2 | import { Httpx, Get } from 'https://jslib.k6.io/httpx/0.0.4/index.js'; 3 | import { randomString } from 'https://jslib.k6.io/k6-utils/1.0.0/index.js'; 4 | 5 | export let options = { 6 | thresholds: { 7 | // fail the test if any checks fail or any requests fail 8 | checks: [{ threshold: 'rate == 1.00', abortOnFail: true }], 9 | http_req_failed: [{ threshold: 'rate == 0.00', abortOnFail: true }] 10 | }, 11 | vus: 100, 12 | iterations: 100 13 | }; 14 | 15 | let session = new Httpx(); 16 | session.setBaseUrl('https://test-api.k6.io'); 17 | 18 | function validateContractsPublicCrocodileService() { 19 | describe('[Crocs service] Fetch public crocs', () => { 20 | let responses = session.batch([ 21 | new Get('/public/crocodiles/1/'), 22 | new Get('/public/crocodiles/2/') 23 | ]); 24 | 25 | responses.forEach((response) => { 26 | expect(response.status, 'response status').to.equal(200); 27 | expect(response, 'My response 1').to.have.validJsonBody(); 28 | // expect(response.json(), "Croc API schema").to.matchSchema(crocodileAPIContract) 29 | }); 30 | }); 31 | 32 | describe('[Crocs service] Fetch list of crocs', () => { 33 | let response = session.get('/public/crocodiles'); 34 | 35 | expect(response.status, 'response status').to.equal(200); 36 | expect(response).to.have.validJsonBody(); 37 | // expect(response.json(), "Croc List schema").to.matchSchema(crocodileListAPIcontract) 38 | }); 39 | } 40 | 41 | function validateAuthService() { 42 | const USERNAME = `${randomString(10)}@example.com`; 43 | const PASSWORD = 'superCroc2021'; 44 | 45 | describe('[Registration service] user registration', () => { 46 | let sampleUser = { 47 | username: USERNAME, 48 | password: PASSWORD, 49 | email: USERNAME, 50 | first_name: 'John', 51 | last_name: 'Smith' 52 | }; 53 | 54 | let response = session.post(`/user/register/`, sampleUser); 55 | 56 | expect(response.status, 'status').to.equal(201); 57 | expect(response).to.have.validJsonBody(); 58 | }); 59 | 60 | describe('[Auth service] user authentication', () => { 61 | let authData = { 62 | username: USERNAME, 63 | password: PASSWORD 64 | }; 65 | 66 | let resp = session.post(`/auth/token/login/`, authData); 67 | 68 | expect(resp.status, 'Auth status').to.be.within(200, 204); 69 | expect(resp).to.have.validJsonBody(); 70 | expect(resp.json('access'), 'auth token').anonymize().to.be.a('string'); 71 | 72 | let authToken = resp.json('access'); 73 | // set the authorization header on the session for the subsequent requests. 74 | session.addHeader('Authorization', `Bearer ${authToken}`); 75 | }); 76 | } 77 | 78 | function validateContractCreateCrocodileService() { 79 | // authentication happened before this call. 80 | 81 | describe('[Croc service] Create a new crocodile', () => { 82 | let payload = { 83 | name: `Croc Name`, 84 | sex: 'M', 85 | date_of_birth: '2019-01-01' 86 | }; 87 | 88 | let resp = session.post(`/my/crocodiles/`, payload); 89 | 90 | expect(resp.status, 'Croc creation status').to.equal(201); 91 | expect(resp).to.have.validJsonBody(); 92 | 93 | session.newCrocId = resp.json('id'); // caching croc ID for the future. 94 | }); 95 | 96 | describe('[Croc service] Fetch private crocs', () => { 97 | let response = session.get('/my/crocodiles/'); 98 | 99 | expect(response.status, 'response status').to.equal(200); 100 | expect(response).to.have.validJsonBody(); 101 | expect(response.json().length, 'number of crocs').to.equal(1); 102 | }); 103 | } 104 | 105 | export default function testSuite() { 106 | validateContractsPublicCrocodileService(); 107 | validateAuthService(); 108 | validateContractCreateCrocodileService(); 109 | } 110 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": ["esnext"], 5 | "skipLibCheck": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "noImplicitThis": false 17 | }, 18 | "include": ["**/*.ts"], 19 | "exclude": ["node_modules"] 20 | } 21 | --------------------------------------------------------------------------------