| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /* eslint-disable jsdoc/require-jsdoc */
- /**
- * Chai spies plugin
- *
- * @param {*} chai
- * @param {*} _
- */
- /* prettier-ignore */
- export function chaiSpiesPlugin(chai, _) {
- const Assertion = chai.Assertion;
- Assertion.addProperty('spy', function () {
- this.assert(
- this._obj.__isSpy === true
- , 'expected ' + this._obj + ' to be a spy'
- , 'expected ' + this._obj + ' to not be a spy');
- return this;
- });
- function assertCalled (n) {
- new Assertion(this._obj).to.be.spy;
- const spy = this._obj;
- if (n != undefined) {
- this.assert(
- spy.calls.length === n
- , 'expected ' + this._obj + ' to have been called #{exp} but got #{act}'
- , 'expected ' + this._obj + ' to have not been called #{exp}'
- , n
- , spy.calls.length
- );
- } else {
- this.assert(
- spy.called === true
- , 'expected ' + this._obj + ' to have been called'
- , 'expected ' + this._obj + ' to not have been called'
- );
- }
- }
- function assertCalledChain () {
- new Assertion(this._obj).to.be.spy;
- }
- Assertion.addChainableMethod('called', assertCalled, assertCalledChain);
- Assertion.addProperty('once', function () {
- new Assertion(this._obj).to.be.spy;
- this.assert(
- this._obj.calls.length === 1
- , 'expected ' + this._obj + ' to have been called once but got #{act}'
- , 'expected ' + this._obj + ' to not have been called once'
- , 1
- , this._obj.calls.length );
- });
- Assertion.addProperty('twice', function () {
- new Assertion(this._obj).to.be.spy;
- this.assert(
- this._obj.calls.length === 2
- , 'expected ' + this._obj + ' to have been called twice but got #{act}'
- , 'expected ' + this._obj + ' to not have been called twice'
- , 2
- , this._obj.calls.length
- );
- });
- function nthCallWith(spy, n, expArgs) {
- if (spy.calls.length <= n) return false;
- const actArgs = spy.calls[n].args;
- if (actArgs.length !== expArgs.length) return false;
- // проверка каждого ожидаемого аргумента на строгое
- // соответствие позиции и значения
- for (let i = 0; i < expArgs.length; i++) {
- if (!_.eql(actArgs[i], expArgs[i])) {
- return false;
- }
- }
- return true;
- }
- function numberOfCallsWith(spy, expArgs) {
- let found = 0;
- const calls = spy.calls;
- for (let i = 0; i < calls.length; i++) {
- if (nthCallWith(spy, i, expArgs)) {
- found++;
- }
- }
- return found;
- }
- Assertion.addProperty('first', function () {
- if (this._obj.__isSpy) {
- _.flag(this, 'spy nth call with', 1);
- }
- });
- Assertion.addProperty('second', function () {
- if (this._obj.__isSpy) {
- _.flag(this, 'spy nth call with', 2);
- }
- });
- Assertion.addProperty('third', function () {
- if (this._obj.__isSpy) {
- _.flag(this, 'spy nth call with', 3);
- }
- });
- Assertion.addProperty('on');
- Assertion.addChainableMethod('nth', function (n) {
- if (this._obj.__isSpy) {
- _.flag(this, 'spy nth call with', n);
- }
- });
- function generateOrdinalNumber(n) {
- if (n === 1) return 'first';
- if (n === 2) return 'second';
- if (n === 3) return 'third';
- return n + 'th';
- }
- function assertWith() {
- new Assertion(this._obj).to.be.spy;
- const expArgs = [].slice.call(arguments, 0)
- , spy = this._obj
- , calls = spy.calls
- , always = _.flag(this, 'spy always')
- , nthCall = _.flag(this, 'spy nth call with');
- if (always) {
- const passed = numberOfCallsWith(spy, expArgs);
- this.assert(
- arguments.length
- ? calls.length && passed === calls.length
- : calls.length === 0
- , 'expected ' + this._obj + ' to have been always called with #{exp} but got ' + passed + ' out of ' + calls.length
- , 'expected ' + this._obj + ' to have not always been called with #{exp}'
- , expArgs
- );
- } else if (nthCall) {
- const ordinalNumber = generateOrdinalNumber(nthCall),
- actArgs = calls[nthCall - 1];
- new Assertion(this._obj).to.be.have.been.called.min(nthCall);
- this.assert(
- nthCallWith(spy, nthCall - 1, expArgs)
- , 'expected ' + this._obj + ' to have been called at the ' + ordinalNumber + ' time with #{exp} but got #{act}'
- , 'expected ' + this._obj + ' to have not been called at the ' + ordinalNumber + ' time with #{exp}'
- , expArgs
- , actArgs
- );
- } else {
- const passed = numberOfCallsWith(spy, expArgs);
- this.assert(
- passed > 0
- , 'expected ' + this._obj + ' to have been called with #{exp}'
- , 'expected ' + this._obj + ' to have not been called with #{exp} but got ' + passed + ' times'
- , expArgs
- );
- }
- }
- function assertWithChain () {
- if (this._obj.__isSpy) {
- _.flag(this, 'spy with', true);
- }
- }
- Assertion.addChainableMethod('with', assertWith, assertWithChain);
- Assertion.addProperty('always', function () {
- if (this._obj.__isSpy) {
- _.flag(this, 'spy always', true);
- }
- });
- Assertion.addMethod('exactly', function () {
- new Assertion(this._obj).to.be.spy;
- const args = [].slice.call(arguments, 0);
- this.assert(
- this._obj.calls.length === args[0]
- , 'expected ' + this._obj + ' to have been called #{exp} times but got #{act}'
- , 'expected ' + this._obj + ' to not have been called #{exp} times'
- , args[0]
- , this._obj.calls.length
- );
- });
- function above (_super) {
- return function (n) {
- if (this._obj.__isSpy) {
- new Assertion(this._obj).to.be.spy;
- this.assert(
- this._obj.calls.length > n
- , 'expected ' + this._obj + ' to have been called more than #{exp} times but got #{act}'
- , 'expected ' + this._obj + ' to have been called at most #{exp} times but got #{act}'
- , n
- , this._obj.calls.length
- );
- } else {
- _super.apply(this, arguments);
- }
- }
- }
- Assertion.overwriteMethod('above', above);
- Assertion.overwriteMethod('gt', above);
- function below (_super) {
- return function (n) {
- if (this._obj.__isSpy) {
- new Assertion(this._obj).to.be.spy;
- this.assert(
- this._obj.calls.length < n
- , 'expected ' + this._obj + ' to have been called fewer than #{exp} times but got #{act}'
- , 'expected ' + this._obj + ' to have been called at least #{exp} times but got #{act}'
- , n
- , this._obj.calls.length
- );
- } else {
- _super.apply(this, arguments);
- }
- }
- }
- Assertion.overwriteMethod('below', below);
- Assertion.overwriteMethod('lt', below);
- function min (_super) {
- return function (n) {
- if (this._obj.__isSpy) {
- new Assertion(this._obj).to.be.spy;
- this.assert(
- this._obj.calls.length >= n
- , 'expected ' + this._obj + ' to have been called at least #{exp} times but got #{act}'
- , 'expected ' + this._obj + ' to have been called fewer than #{exp} times but got #{act}'
- , n
- , this._obj.calls.length
- );
- } else {
- _super.apply(this, arguments);
- }
- }
- }
- Assertion.overwriteMethod('min', min);
- Assertion.overwriteMethod('least', min);
- function max (_super) {
- return function (n) {
- if (this._obj.__isSpy) {
- new Assertion(this._obj).to.be.spy;
- this.assert(
- this._obj.calls.length <= n
- , 'expected ' + this._obj + ' to have been called at most #{exp} times but got #{act}'
- , 'expected ' + this._obj + ' to have been called more than #{exp} times but got #{act}'
- , n
- , this._obj.calls.length
- );
- } else {
- _super.apply(this, arguments);
- }
- }
- }
- Assertion.overwriteMethod('max', max);
- Assertion.overwriteMethod('most', max);
- }
|