jasmine-auto-spies
Advanced tools
Comparing version 3.2.1 to 4.0.0
{ | ||
"name": "jasmine-auto-spies", | ||
"version": "3.2.1", | ||
"version": "4.0.0", | ||
"repository": { | ||
@@ -12,3 +12,3 @@ "type": "git", | ||
"scripts": { | ||
"clean": "rimraf src/*.js* src/*.d.ts *.d.ts", | ||
"clean": "rimraf src/**/*.js* src/**/*.d.ts *.d.ts", | ||
"commit": "git-cz", | ||
@@ -59,3 +59,2 @@ "build": "tsc", | ||
"@types/webpack": "4.4.11", | ||
"@types/window-or-global": "1.0.0", | ||
"awesome-typescript-loader": "^3.1.3", | ||
@@ -88,11 +87,8 @@ "commitizen": "2.10.1", | ||
"typescript": "^2.9.2", | ||
"webpack": "2.7.0", | ||
"window-or-global": "1.0.1" | ||
"webpack": "2.7.0" | ||
}, | ||
"dependencies": { | ||
"deep-equal": "1.0.1", | ||
"window-or-global": "1.0.1" | ||
"deep-equal": "1.0.1" | ||
}, | ||
"peerDependencies": { | ||
"core-js": "^2.4.1", | ||
"jasmine": "^2.6.0", | ||
@@ -99,0 +95,0 @@ "rxjs": "^6.0.0", |
134
README.md
@@ -9,10 +9,7 @@ # jasmine-auto-spies | ||
## IMPORTANT: compatibility | ||
* Version `2.x` and above requires **RxJS 6.0** and above. | ||
* Version `3.x` and above requires **TypeScript 2.8** and above. | ||
- Version `2.x` and above requires **RxJS 6.0** and above. | ||
- Version `3.x` and above requires **TypeScript 2.8** and above. | ||
## What is it? | ||
@@ -22,3 +19,3 @@ | ||
If you need to create a spy from any class, just do: | ||
If you need to create a spy from any class, just do: | ||
@@ -39,3 +36,2 @@ ```js | ||
## What is it good for? | ||
@@ -53,9 +49,7 @@ | ||
## Usage (JavaScript) | ||
```js | ||
// my-spec.js | ||
// my-spec.js | ||
import { createSpyFromClass } from 'jasmine-auto-spies'; | ||
@@ -110,12 +104,10 @@ import { MyService } from './my-service'; | ||
} | ||
``` | ||
## Usage (TypeScript) | ||
### TypeScript Setup | ||
Set these 2 properties in your `tsconfig.json` - | ||
Set these 2 properties in your `tsconfig.json` - | ||
```json | ||
@@ -125,3 +117,3 @@ { | ||
"experimentalDecorators": true, | ||
"emitDecoratorMetadata": true, | ||
"emitDecoratorMetadata": true | ||
} | ||
@@ -131,7 +123,5 @@ } | ||
### 1. Spying on regular sync methods | ||
```ts | ||
// my-spec.ts | ||
@@ -150,3 +140,3 @@ | ||
myServiceSpy.getName.and.returnValue('Fake Name'); | ||
... (the rest of the test) ... | ||
@@ -163,3 +153,2 @@ }); | ||
} | ||
``` | ||
@@ -169,17 +158,4 @@ | ||
First, annotate the method with `@AsyncSpyable` - | ||
```ts | ||
import { AsyncSpyable } from 'jasmine-auto-spies'; | ||
Use the `resolveWith` or `rejectWith` methods - | ||
export class MyService{ | ||
@AsyncSpyable() // <-- MUST ADD THIS | ||
getItems(): Promise<any> { | ||
return Promise.resolve( itemsList ); | ||
} | ||
} | ||
``` | ||
Now you can use the `resolveWith` or `rejectWith` methods - | ||
```ts | ||
@@ -190,32 +166,17 @@ import { Spy, createSpyFromClass } from 'jasmine-auto-spies'; | ||
beforeEach( ()=> { | ||
myServiceSpy = createSpyFromClass( MyService ) | ||
beforeEach(() => { | ||
myServiceSpy = createSpyFromClass(MyService); | ||
}); | ||
it( ()=>{ | ||
myServiceSpy.getItems.and.resolveWith( fakeItemsList ); | ||
it(() => { | ||
myServiceSpy.getItems.and.resolveWith(fakeItemsList); | ||
// OR | ||
myServiceSpy.getItems.and.rejectWith( fakeError ); | ||
myServiceSpy.getItems.and.rejectWith(fakeError); | ||
}); | ||
``` | ||
### 3. Spy on a `Observable` returning method | ||
First, annotate your Observable returning method with `@AsyncSpyable` - | ||
```ts | ||
import { AsyncSpyable } from 'jasmine-auto-spies'; | ||
Use the `nextWith` or `throwWith` and other methods - | ||
export class MyService{ | ||
@AsyncSpyable() // <-- MUST ADD THIS | ||
getProducts(): Observable<any> { | ||
return Observable.of( productsList ); | ||
} | ||
} | ||
``` | ||
Now you can use the `nextWith` or `throwWith` and other methods - | ||
```ts | ||
@@ -226,19 +187,18 @@ import { Spy, createSpyFromClass } from 'jasmine-auto-spies'; | ||
beforeEach( ()=> { | ||
myServiceSpy = createSpyFromClass( MyService ) | ||
beforeEach(() => { | ||
myServiceSpy = createSpyFromClass(MyService); | ||
}); | ||
it( ()=>{ | ||
myServiceSpy.getProducts.and.nextWith( fakeProductsList ); | ||
it(() => { | ||
myServiceSpy.getProducts.and.nextWith(fakeProductsList); | ||
// OR | ||
myServiceSpy.getProducts.and.nextOneTimeWith( fakeProductsList ); // emits one value and completes | ||
myServiceSpy.getProducts.and.nextOneTimeWith(fakeProductsList); // emits one value and completes | ||
// OR | ||
myServiceSpy.getProducts.and.throwWith( fakeError ); | ||
myServiceSpy.getProducts.and.throwWith(fakeError); | ||
// OR | ||
myServiceSpy.getProducts.and.complete(); | ||
}); | ||
``` | ||
### Use `calledWith()` to configure mocks easily | ||
### Use `calledWith()` to configure conditional return values | ||
@@ -249,38 +209,56 @@ You can setup the expected arguments ahead of time | ||
```ts | ||
myServiceSpy.getProducts.calledWith(1).returnValue(true) | ||
myServiceSpy.getProducts.calledWith(1).returnValue(true); | ||
``` | ||
is equal to: | ||
and it will only return this value if your subject was called with `getProducts(1)`. | ||
#### Oh, and it also works with Promises / Observables: | ||
```ts | ||
myServiceSpy.getProducts.and.returnValue(true) | ||
myServiceSpy.getProductsPromise.calledWith(1).resolveWith(true); | ||
expect(myServiceSpy.getProducts).toHaveBeenCalledWith(1); | ||
// OR | ||
myServiceSpy.getProducts$.calledWith(1).nextWith(true); | ||
// OR ANY OTHER ASYNC CONFIGURATION METHOD... | ||
``` | ||
You can also use it with async method: | ||
### Use `throwOnMismatch()` to turn a conditional stub into a mock | ||
```ts | ||
myServiceSpy.getProducts.calledWith(1).resolveWith(true) | ||
myServiceSpy.getProducts | ||
.calledWith(1) | ||
.returnValue(true) | ||
.throwOnMismatch(); | ||
``` | ||
// OR | ||
is equal to: | ||
myServiceSpy.getProducts.calledWith(1).nextWith(true) | ||
```ts | ||
myServiceSpy.getProducts.and.returnValue(true); | ||
// OR ANY OTHER ASYNC CONFIGURATION METHOD... | ||
expect(myServiceSpy.getProducts).toHaveBeenCalledWith(1); | ||
``` | ||
But the difference is that the error is being thrown during `getProducts()` call and not in the `expect(...)` call. | ||
### Manual Setup | ||
If you need to manually configure async methods by names you could pass them as arrays of strings - | ||
If you need to manually add methods that you want to be spies by passing an array of names as the second param of the `createSpyFromClass` function: | ||
```ts | ||
let spy = createSpyFromClass(MyClass, ['customMethod1', 'customMethod2']); | ||
``` | ||
let spy = createSpyFromClass( | ||
MyClass, | ||
['promiseMethod1', 'promiseMethod2'], | ||
['observableMethod1', 'observableMethod2'] | ||
); | ||
This is good for times where a method is not part of the `prototype` of the Class but instead being defined in its constructor. | ||
```ts | ||
class MyClass { | ||
constructor() { | ||
this.customMethod1 = function() { | ||
// This definition is not part of MyClass' prototype | ||
}; | ||
} | ||
} | ||
``` |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function AsyncSpyable() { | ||
return function (target, propertyKey, descriptor) { | ||
}; | ||
// tslint:disable-next-line:no-console | ||
console.warn("The \"AsyncSpyable\" is depcracated,\n You don't need to use it anymore.\n\n IT WILL GET REMOVED IN THE NEXT MAJOR VERSION\n So please remove it from your code."); | ||
return function (target, propertyKey, descriptor) { }; | ||
} | ||
exports.AsyncSpyable = AsyncSpyable; | ||
//# sourceMappingURL=async-spyable-decorator.js.map |
@@ -1,5 +0,5 @@ | ||
import { Spy } from './spy-types'; | ||
import { Spy } from './spy.types'; | ||
export declare function createSpyFromClass<T>(ObjectClass: { | ||
new (...args: any[]): T; | ||
[key: string]: any; | ||
}, providedPromiseMethodNames?: string[], providedObservableMethodNames?: string[]): Spy<T>; | ||
}, providedMethodNames?: string[]): Spy<T>; |
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spread = (this && this.__spread) || function () { | ||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
}; | ||
var __values = (this && this.__values) || function (o) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; | ||
if (m) return m.call(o); | ||
return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -7,22 +37,14 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
var deep_equal_1 = __importDefault(require("deep-equal")); | ||
var error_handling_1 = require("./error-handling"); | ||
var rxjs_1 = require("rxjs"); | ||
var window_or_global_1 = __importDefault(require("window-or-global")); | ||
var Reflect = window_or_global_1.default.Reflect; | ||
function createSpyFromClass(ObjectClass, providedPromiseMethodNames, providedObservableMethodNames) { | ||
var error_handling_1 = require("./errors/error-handling"); | ||
var observable_spy_utils_1 = require("./observables/observable-spy-utils"); | ||
var promises_spy_utils_1 = require("./promises/promises-spy-utils"); | ||
function createSpyFromClass(ObjectClass, providedMethodNames) { | ||
var proto = ObjectClass.prototype; | ||
var methodNames = getAllMethodNames(proto); | ||
if (providedMethodNames && providedMethodNames.length > 0) { | ||
methodNames.push.apply(methodNames, __spread(providedMethodNames)); | ||
} | ||
var autoSpy = {}; | ||
methodNames.forEach(function (methodName) { | ||
var returnTypeClass = Reflect.getMetadata('design:returntype', proto, methodName); | ||
var spyMethod = createSpyFunction(methodName); | ||
if (doesMethodReturnPromise(providedPromiseMethodNames, methodName, returnTypeClass)) { | ||
autoSpy[methodName] = createPromiseSpyFunction(spyMethod); | ||
} | ||
else if (doesMethodReturnObservable(providedObservableMethodNames, methodName, returnTypeClass)) { | ||
autoSpy[methodName] = createObservableSpyFunction(spyMethod); | ||
} | ||
else { | ||
autoSpy[methodName] = spyMethod; | ||
} | ||
autoSpy[methodName] = createSpyFunction(methodName); | ||
}); | ||
@@ -32,18 +54,21 @@ return autoSpy; | ||
exports.createSpyFromClass = createSpyFromClass; | ||
function createObservableSpyFunction(spyFunction) { | ||
var subject = new rxjs_1.ReplaySubject(1); | ||
spyFunction.and.returnValue(subject); | ||
spyFunction.and.nextWith = function nextWith(value) { | ||
subject.next(value); | ||
function createSpyFunction(name) { | ||
var spyFunction = jasmine.createSpy(name); | ||
var calledWithObject = { | ||
calledWithMethodWasCalled: false, | ||
shouldThrow: false, | ||
calledWithMap: new Map() | ||
}; | ||
spyFunction.and.nextOneTimeWith = function nextOneTimeWith(value) { | ||
subject.next(value); | ||
subject.complete(); | ||
var valueContainer = { | ||
value: undefined | ||
}; | ||
spyFunction.and.throwWith = function throwWith(value) { | ||
subject.error(value); | ||
}; | ||
spyFunction.and.complete = function complete() { | ||
subject.complete(); | ||
}; | ||
promises_spy_utils_1.promisifySpyFunction(spyFunction, valueContainer); | ||
observable_spy_utils_1.observablifySpyFunction(spyFunction, valueContainer); | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
return spyFunctionCallFakeImplementation(calledWithObject, valueContainer, actualArgs); | ||
}); | ||
spyFunction.calledWith = function () { | ||
@@ -54,132 +79,45 @@ var calledWithArgs = []; | ||
} | ||
return { | ||
nextWith: function (value) { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
subject.next(value); | ||
return subject; | ||
}); | ||
}, | ||
nextOneTimeWith: function (value) { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
subject.next(value); | ||
subject.complete(); | ||
return subject; | ||
}); | ||
}, | ||
throwWith: function (value) { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
subject.error(value); | ||
return subject; | ||
}); | ||
}, | ||
complete: function () { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
subject.complete(); | ||
return subject; | ||
}); | ||
} | ||
}; | ||
calledWithObject.calledWithMethodWasCalled = true; | ||
calledWithObject = addSyncHandlingToCalledWith(calledWithObject, calledWithArgs); | ||
calledWithObject = promises_spy_utils_1.addPromiseHandlingToCalledWith(calledWithObject, calledWithArgs); | ||
calledWithObject = observable_spy_utils_1.addObservableHandlingToCalledWith(calledWithObject, calledWithArgs); | ||
return calledWithObject; | ||
}; | ||
return spyFunction; | ||
} | ||
function createPromiseSpyFunction(spyFunction) { | ||
spyFunction.and.returnValue(new Promise(function (resolveWith, rejectWith) { | ||
spyFunction.and.resolveWith = resolveWith; | ||
spyFunction.and.rejectWith = rejectWith; | ||
})); | ||
spyFunction.calledWith = function () { | ||
var calledWithArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
calledWithArgs[_i] = arguments[_i]; | ||
function spyFunctionCallFakeImplementation(calledWithObject, valueContainer, actualArgs) { | ||
var e_1, _a; | ||
if (calledWithObject.calledWithMethodWasCalled) { | ||
try { | ||
for (var _b = __values(calledWithObject.calledWithMap.keys()), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var storedCalledWithArgs = _c.value; | ||
if (deep_equal_1.default(storedCalledWithArgs, actualArgs)) { | ||
return calledWithObject.calledWithMap.get(storedCalledWithArgs); | ||
} | ||
} | ||
} | ||
return { | ||
resolveWith: function (value) { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
return Promise.resolve(value); | ||
}); | ||
}, | ||
rejectWith: function (value) { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
return Promise.reject(value); | ||
}); | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
}; | ||
}; | ||
return spyFunction; | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
if (calledWithObject.shouldThrow) { | ||
error_handling_1.throwArgumentsError(actualArgs); | ||
} | ||
} | ||
return valueContainer.value; | ||
} | ||
function createSpyFunction(name) { | ||
var spyFunction = jasmine.createSpy(name); | ||
spyFunction.calledWith = function () { | ||
var calledWithArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
calledWithArgs[_i] = arguments[_i]; | ||
} | ||
function addSyncHandlingToCalledWith(calledWithObject, calledWithArgs) { | ||
calledWithObject.returnValue = function (value) { | ||
calledWithObject.calledWithMap.set(calledWithArgs, value); | ||
return { | ||
returnValue: function (value) { | ||
spyFunction.and.callFake(function () { | ||
var actualArgs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
actualArgs[_i] = arguments[_i]; | ||
} | ||
if (!deep_equal_1.default(calledWithArgs, actualArgs)) { | ||
error_handling_1.throwArgumentsError(calledWithArgs, actualArgs); | ||
} | ||
return value; | ||
}); | ||
throwOnMismatch: function () { | ||
calledWithObject.shouldThrow = true; | ||
} | ||
}; | ||
}; | ||
return spyFunction; | ||
return calledWithObject; | ||
} | ||
function doesMethodReturnPromise(promiseMethodsList, methodName, returnTypeClass) { | ||
return ((promiseMethodsList && promiseMethodsList.indexOf(methodName) !== -1) || | ||
returnTypeClass === Promise); | ||
} | ||
function doesMethodReturnObservable(observableMethodsList, methodName, returnTypeClass) { | ||
return ((observableMethodsList && observableMethodsList.indexOf(methodName) !== -1) || | ||
returnTypeClass === rxjs_1.Observable || | ||
(returnTypeClass && returnTypeClass.prototype instanceof rxjs_1.Observable)); | ||
} | ||
function getAllMethodNames(obj) { | ||
@@ -195,5 +133,4 @@ var methods = []; | ||
} | ||
// .filter(methodName => typeof proto[methodName] == 'function') | ||
return methods; | ||
} | ||
//# sourceMappingURL=create-spy-from-class.js.map |
@@ -1,3 +0,3 @@ | ||
export * from './spy-types'; | ||
export * from './spy.types'; | ||
export { AsyncSpyable } from './async-spyable-decorator'; | ||
export { createSpyFromClass } from './create-spy-from-class'; |
@@ -11,2 +11,3 @@ { | ||
"sourceMap": true, | ||
"downlevelIteration": true, | ||
"lib": ["es2015", "es2016"], | ||
@@ -13,0 +14,0 @@ "pretty": true, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
311240
4
35
36
426
252
1
- Removedwindow-or-global@1.0.1
- Removedcore-js@2.6.12(transitive)
- Removedwindow-or-global@1.0.1(transitive)