New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

leonardojs

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

leonardojs - npm Package Compare versions

Comparing version 1.0.0 to 1.0.8

extension/angular-deckgrid.js

6

bower.json

@@ -10,5 +10,7 @@ {

"authors": [
"sagivf <sagivf@gmail.com> (www.sagivfrankel.com)"
"sagivf <sagivf@gmail.com>",
"dwido <dbuchbut@outbrain.com>",
"tsachis <tsachishushan@gmail.com>"
],
"description": "secnario runner",
"description": "scenario runner",
"main": [

@@ -15,0 +17,0 @@ "dist/leonardo.js",

angular.module('leonardo', ['leonardo.templates', 'ngMockE2E'])
/* wrap $httpbackend with a proxy in order to support delaying its responses
* we are using the approach described in Endless Indirection:
* https://endlessindirection.wordpress.com/2013/05/18/angularjs-delay-response-from-httpbackend/
*/
.config(['$provide', function($provide) {
$provide.decorator('$httpBackend', ['$delegate', function($delegate) {
.config(['$provide', '$httpProvider', function($provide, $httpProvider) {
$httpProvider.interceptors.push('leoHttpInterceptor');
$provide.decorator('$httpBackend', ['$delegate', '$timeout', function($delegate, $timeout) {
var proxy = function(method, url, data, callback, headers) {

@@ -12,3 +11,3 @@ var interceptor = function() {

_arguments = arguments;
setTimeout(function() {
$timeout(function() {
callback.apply(_this, _arguments);

@@ -75,10 +74,30 @@ }, proxy.delay || 0);

}]);
}]);
}])
.run(['leoConfiguration', function(leoConfiguration) {
leoConfiguration.loadSavedStates();
}]);
angular.module('leonardo').provider('$leonardo', function LeonardoProvider() {
var pref = '';
this.setAppPrefix = function (prefix) {
pref = prefix;
};
this.$get = [function leonardoProvider() {
return {
getAppPrefix: function () {
return pref;
}
};
}];
});
angular.module('leonardo').factory('leoConfiguration',
['leoStorage', '$httpBackend', function(leoStorage, $httpBackend) {
['leoStorage', '$httpBackend', '$rootScope', function(leoStorage, $httpBackend, $rootScope) {
var states = [],
_scenarios = {},
responseHandlers = {},
_requestsLog = [],
_savedStates = [],
// Core API

@@ -100,4 +119,9 @@ // ----------------

setActiveScenario: setActiveScenario,
getRecordedStates: getRecordedStates,
getRequestsLog: getRequestsLog,
loadSavedStates: loadSavedStates,
addSavedState: addSavedState,
//Private api for passing through unregistered urls to $htto
_requestSubmitted: requestSubmitted
_requestSubmitted: requestSubmitted,
_logRequest: logRequest
};

@@ -157,3 +181,3 @@ return api;

function sync(){
fetchStates().forEach(function (state) {
fetchStates().forEach(function (state, i) {
var option, responseHandler;

@@ -165,2 +189,3 @@ if (state.url) {

responseHandler.respond(function () {
console.log(i);
$httpBackend.setDelay(option.delay);

@@ -177,11 +202,16 @@ return [option.status, angular.isFunction(option.data) ? option.data() : option.data];

function getResponseHandler(state) {
if (!responseHandlers[state.url + '_' + state.verb]) {
var url = state.url;
var verb = state.verb === 'jsonp' ? state.verb : state.verb.toUpperCase();
var key = (url + '_' + verb).toUpperCase();
var escapedUrl = url.replace(/[?]/g, '\\?');
if (!responseHandlers[key]) {
if (state.verb === 'jsonp'){
responseHandlers[state.url + '_' + state.verb] = $httpBackend.whenJSONP(new RegExp(state.url));
responseHandlers[key] = $httpBackend.whenJSONP(new RegExp(escapedUrl));
}
else {
responseHandlers[state.url + '_' + state.verb] = $httpBackend.when(state.verb || 'GET', new RegExp(state.url));
responseHandlers[key] = $httpBackend.when(verb || 'GET', new RegExp(escapedUrl));
}
}
return responseHandlers[state.url + '_' + state.verb];
return responseHandlers[key];
}

@@ -206,8 +236,14 @@

});
$rootScope.$broadcast('leonardo:stateChanged', stateObj);
}
function addStates(statesArr) {
statesArr.forEach(function(stateObj) {
addState(stateObj);
});
if (angular.isArray(statesArr)) {
statesArr.forEach(function(stateObj) {
addState(stateObj);
});
} else {
console.warn('addStates should get an array');
}
}

@@ -221,3 +257,3 @@

status = stateObj.status || 200,
data = stateObj.data || {},
data = angular.isDefined(stateObj.data) ? stateObj.data : {},
delay = stateObj.delay || 0;

@@ -318,8 +354,81 @@ var defaultState = {};

}
function logRequest(method, url, data, status) {
if (method && url && !(url.indexOf(".html") > 0)) {
var req = {
verb: method,
data: data,
url: url.trim(),
status: status,
timestamp: new Date()
};
req.state = getStateByRequest(req);
_requestsLog.push(req);
}
}
function getStateByRequest(req) {
return fetchStates().filter(function(state) {
if (!state.url) return false;
return state.url === req.url && state.verb.toLowerCase() === req.verb.toLowerCase();
})[0];
}
function getRequestsLog() {
return _requestsLog;
}
function loadSavedStates() {
_savedStates = leoStorage.getSavedStates();
addStates(_savedStates);
}
function addSavedState(state) {
_savedStates.push(state);
leoStorage.setSavedStates(_savedStates);
addState(state);
}
function getRecordedStates() {
var requestsArr = _requestsLog
.map(function(req){
var state = getStateByRequest(req);
return {
name: state ? state.name : req.verb + " " + req.url,
verb: req.verb,
url: req.url,
options: [{
name: req.status >= 200 && req.status < 300 ? 'Success' : 'Failure',
status: req.status,
data: req.data
}]
}
});
console.log(angular.toJson(requestsArr, true));
return requestsArr;
}
}]);
angular.module('leonardo').factory('leoStorage', ['$rootScope', function storageService($rootScope) {
var STATES_STORE_KEY = 'leonardo-states';
function getItem(key) {
var item = localStorage.getItem(key);
angular.module('leonardo').factory('leoHttpInterceptor', ['leoConfiguration', '$q', function(leoConfiguration, $q) {
return {
'request': function(request) {
return $q.when(request);
},
'response': function(response) {
leoConfiguration._logRequest(response.config.method, response.config.url, response.data, response.status);
return $q.when(response);
},
'responseError': function(rejection) {
leoConfiguration._logRequest(rejection.config.method, rejection.config.url, rejection.data, rejection.status);
return $q.reject(rejection);
}
};
}]);
angular.module('leonardo').factory('leoStorage', ['$rootScope', '$window', '$leonardo', function storageService($rootScope, $window, $leonardo) {
var APP_PREFIX = $leonardo.getAppPrefix() + '_',
STATES_STORE_KEY = APP_PREFIX + 'leonardo-states',
SAVED_STATES_KEY = APP_PREFIX + 'leonardo-unregistered-states';
function _getItem(key) {
var item = $window.localStorage.getItem(key);
if (!item) {

@@ -331,20 +440,28 @@ return null;

function setItem(key, data) {
localStorage.setItem(key, angular.toJson(data));
function _setItem(key, data) {
$window.localStorage.setItem(key, angular.toJson(data));
}
function getStates() {
return getItem(STATES_STORE_KEY) || {};
return _getItem(STATES_STORE_KEY) || {};
}
function setStates(states) {
setItem(STATES_STORE_KEY, states);
_setItem(STATES_STORE_KEY, states);
$rootScope.$emit('leonardo:setStates');
}
function getSavedStates() {
return _getItem(SAVED_STATES_KEY) || [];
}
function setSavedStates(states) {
_setItem(SAVED_STATES_KEY, states);
}
return {
getItem: getItem,
setItem: setItem,
setStates: setStates,
getStates: getStates
getStates: getStates,
getSavedStates: getSavedStates,
setSavedStates: setSavedStates
};

@@ -356,2 +473,9 @@ }]);

restrict: 'A',
controllerAs: 'leonardo',
controller: function () {
this.activeTab = 'scenarios';
this.selectTab = function (name) {
this.activeTab = name;
};
},
link: function(scope, elem) {

@@ -366,3 +490,5 @@ var el = angular.element('<div ng-click="activate()" class="leonardo-activator"></div>');

'<li>LEONARDO</li>',
'<li>Scenarios</li>',
'<li ng-class="{ \'leo-selected-tab\': leonardo.activeTab === \'scenarios\' }" ng-click="leonardo.selectTab(\'scenarios\')">Scenarios</li>',
'<li ng-class="{ \'leo-selected-tab\': leonardo.activeTab === \'recorder\' }"ng-click="leonardo.selectTab(\'recorder\')">Recorder</li>',
'<li ng-class="{ \'leo-selected-tab\': leonardo.activeTab === \'export\' }"ng-click="leonardo.selectTab(\'export\')">Exported Code</li>',
'</ul>',

@@ -402,3 +528,3 @@ '</div>',

angular.module('leonardo').directive('leoWindowBody',
['$http', 'leoConfiguration', function windowBodyDirective($http, leoConfiguration) {
['$http', 'leoConfiguration', '$timeout', function windowBodyDirective($http, leoConfiguration, $timeout) {
return {

@@ -409,14 +535,20 @@ restrict: 'E',

replace: true,
controller: ['$scope', function($scope){
$scope.selectedItem = 'activate';
$scope.NothasUrl = function(option){
require: '^leoActivator',
controller: ['$scope', function($scope) {
$scope.detail = {
option: 'success',
delay: 0,
status: 200
};
$scope.NothasUrl = function (option) {
return !option.url;
};
$scope.hasUrl = function(option){
$scope.hasUrl = function (option) {
return !!option.url;
};
$scope.deactivate = function() {
$scope.states.forEach(function(state){
state.active = false;
$scope.deactivate = function () {
$scope.states.forEach(function (state) {
state.active = false;
});

@@ -426,8 +558,8 @@ leoConfiguration.deactivateAllStates();

$scope.updateState = function(state){
$scope.updateState = function (state) {
if (state.active) {
console.log('activate state option:' + state.name + ': ' + state.activeOption.name);
console.log('activate state option:' + state.name + ': ' + state.activeOption.name);
leoConfiguration.activateStateOption(state.name, state.activeOption.name);
} else {
console.log('deactivating state: ' + state.name);
console.log('deactivating state: ' + state.name);
leoConfiguration.deactivateState(state.name);

@@ -441,3 +573,3 @@ }

$scope.activateScenario = function(scenario){
$scope.activateScenario = function (scenario) {
$scope.activeScenario = scenario;

@@ -447,4 +579,91 @@ leoConfiguration.setActiveScenario(scenario);

};
$scope.requests = leoConfiguration.getRequestsLog();
$scope.$watch('detail.value', function(value){
if (!value) {
return;
}
try {
$scope.detail.stringValue = value ? JSON.stringify(value, null, 4) : '';
$scope.detail.error = '';
}
catch (e) {
$scope.detail.error = e.message;
}
});
$scope.$watch('detail.stringValue', function(value){
try {
$scope.detail.value = value ? JSON.parse(value) : {};
$scope.detail.error = '';
}
catch(e) {
$scope.detail.error = e.message;
}
});
$scope.requestSelect = function (request) {
$scope.requests.forEach(function (request) {
request.active = false;
});
request.active = true;
if (request.state && request.state.name) {
var optionName = request.state.name + ' option ' + request.state.options.length;
}
angular.extend($scope.detail, {
state : (request.state && request.state.name) || '',
option: optionName || '',
delay: 0,
status: 200,
stateActive: !!request.state,
value: request.data || {}
});
$scope.detail._unregisteredState = request;
};
$scope.$on('leonardo:stateChanged', function(event, stateObj) {
$scope.states = leoConfiguration.getStates();
var state = $scope.states.filter(function(state){
return state.name === stateObj.name;
})[0];
if (state) {
state.highlight = true;
$timeout(function(){
state.highlight = false;
}, 3000);
}
});
$scope.getStatesForExport = function () {
$scope.exportStates = leoConfiguration.getStates();
}
}],
link: function(scope) {
link: function(scope, el, attr, leoActivator) {
scope.saveUnregisteredState = function () {
var stateName = scope.detail.state;
leoConfiguration.addSavedState({
name: stateName,
verb: scope.detail._unregisteredState.verb,
url: scope.detail._unregisteredState.url,
options: [
{
name: scope.detail.option,
status: scope.detail.status,
data: scope.detail.value
}
]
});
leoActivator.selectTab('scenarios');
};
scope.test = {

@@ -468,2 +687,18 @@ url: '',

angular.module('leonardo').directive('leoRequest', function () {
return {
restrict: 'E',
templateUrl: 'request.html',
scope: {
request: '=',
onSelect: '&'
},
controller: ['$scope', function ($scope) {
$scope.select = function () {
$scope.onSelect();
}
}]
}
});
(function(module) {

@@ -476,5 +711,29 @@ try {

module.run(['$templateCache', function($templateCache) {
$templateCache.put('request.html',
'<a href="#" class="leo-list-item" ng-click="select()" ng-class="{active:request.active}"><span class="leo-request-name">{{request.url}}</span> <span ng-if="!!request.state" class="leo-request leo-request-existing">{{request.state.name}}</span> <span ng-if="!request.state" class="leo-request leo-request-new">new</span> <span ng-if="!!request.state && request.state.active" class="leo-request leo-request-mocked">mocked</span></a>');
}]);
})();
(function(module) {
try {
module = angular.module('leonardo.templates');
} catch (e) {
module = angular.module('leonardo.templates', []);
}
module.run(['$templateCache', function($templateCache) {
$templateCache.put('window-body.html',
'<div class="leonardo-window-body"><div class="leonardo-scenario-nav"><div class="leonardo-breadcrumbs">SCENARIOS > {{activeScenario}}</div><div class="leonardo-scenario-title">SCENARIOS</div></div><div ng-switch="selectedItem" class="leonardo-window-options"><div ng-switch-when="configure" class="leonardo-configure"><table><thead><tr><th>State</th><th>URL</th><th>Options</th></tr></thead><tbody><tr ng-repeat="state in states"><td>{{state.name}}</td><td>{{state.url}}</td><td><ul><li ng-repeat="option in state.options">Name: {{option.name}}<br>Status: {{option.status}}<br>Data: {{option.data}}<br></li></ul></td></tr></tbody></table></div><div ng-switch-when="activate" class="leonardo-activate"><div class="leonardo-menu"><ul><li ng-class="{ \'selected\': scenario === activeScenario }" ng-repeat="scenario in scenarios" ng-click="activateScenario(scenario)">{{scenario}}</li></ul></div><ul><li><h3>Non Ajax States</h3></li><li ng-repeat="state in states | filter:NothasUrl"><div><div class="onoffswitch"><input ng-model="state.active" ng-click="updateState(state)" class="onoffswitch-checkbox" id="{{state.name}}" type="checkbox" name="{{state.name}}" value="{{state.name}}"> <label class="onoffswitch-label" for="{{state.name}}"><span class="onoffswitch-inner"></span> <span class="onoffswitch-switch"></span></label></div></div><div><h4>{{state.name}}</h4></div><div><select ng-model="state.activeOption" ng-options="option.name for option in state.options" ng-change="updateState(state)"></select></div></li><li><h3>Ajax States</h3></li><li ng-repeat="state in states | filter:hasUrl"><div><div class="onoffswitch"><input ng-model="state.active" ng-click="updateState(state)" class="onoffswitch-checkbox" id="{{state.name}}" type="checkbox" name="{{state.name}}" value="{{state.name}}"> <label class="onoffswitch-label" for="{{state.name}}"><span class="onoffswitch-inner"></span> <span class="onoffswitch-switch"></span></label></div></div><div><h4>{{state.name}}</h4>&nbsp;&nbsp; - {{state.url}}</div><div><select ng-model="state.activeOption" ng-options="option.name for option in state.options" ng-change="updateState(state)"></select></div></li></ul></div><div ng-switch-when="test" class="leonardo-test"><div><label for="url"></label>URL: <input id="url" type="text" ng-model="test.url"> <input type="button" ng-click="submit(test.url)" value="submit"></div><textarea>{{test.value | json}}</textarea></div></div></div>');
'<div class="leonardo-window-body"><div ng-switch="leonardo.activeTab" class="leonardo-window-options"><div ng-switch-when="configure" class="leonardo-configure"><table><thead><tr><th>State</th><th>URL</th><th>Options</th></tr></thead><tbody><tr ng-repeat="state in states"><td>{{state.name}}</td><td>{{state.url}}</td><td><ul><li ng-repeat="option in state.options">Name: {{option.name}}<br>Status: {{option.status}}<br>Data: {{option.data}}<br></li></ul></td></tr></tbody></table></div><div ng-switch-when="recorder" class="leonardo-recorder"><div class="leo-list"><div class="list-group"><leo-request ng-repeat="request in requests" request="request" on-select="requestSelect(request)"></leo-request></div></div><div class="leo-detail"><div class="leo-detail-header"><div ng-if="!detail.stateActive"><span>Add new state:</span> <input class="leo-detail-state" ng-model="detail.state" placeholder="Enter state name"></div><div ng-if="detail.stateActive" class="leo-detail-state">Add mocked response for "{{detail.state}}"</div></div><div class="leo-detail-option"><div>Response name: <input ng-model="detail.option"></div><div>Status code: <input ng-model="detail.status"></div><div>Delay: <input ng-model="detail.delay"></div><div class="leo-detail-option-json">Response JSON:<div class="leo-error">{{detail.error}}</div><textarea ng-model="detail.stringValue"></textarea></div></div><div class="leo-action-row"><button ng-click="saveUnregisteredState()">{{ detail.stateActive ? \'Add Option\' : \'Add State\' }}</button></div></div></div><div ng-switch-when="export" class="leonardo-export" style="padding: 30px"><code contenteditable="" ng-init="getStatesForExport()">\n' +
'\n' +
' <div>angular.module(\'leonardo\').run([\'leoConfiguration\', function(leoConfiguration) {</div>\n' +
'\n' +
' <div ng-repeat="state in exportStates">\n' +
' <div style="margin-left: 10px">leoConfiguration.addStates([</div>\n' +
' <pre style="margin-left: 20px">{{state | json}}</pre>\n' +
' <div style="margin-left: 10px">])</div>\n' +
' </div>\n' +
'\n' +
' <div>])</div>\n' +
'\n' +
' </code></div><div ng-switch-when="scenarios" class="leonardo-activate"><div class="leonardo-menu"><div>SCENARIOS</div><ul><li ng-class="{ \'selected\': scenario === activeScenario }" ng-repeat="scenario in scenarios" ng-click="activateScenario(scenario)">{{scenario}}</li></ul></div><ul><li class="leo-non-ajax"><h3>Non Ajax States</h3></li><li ng-repeat="state in states | filter:NothasUrl"><div><div class="onoffswitch"><input ng-model="state.active" ng-click="updateState(state)" class="onoffswitch-checkbox" id="{{state.name}}" type="checkbox" name="{{state.name}}" value="{{state.name}}"> <label class="onoffswitch-label" for="{{state.name}}"><span class="onoffswitch-inner"></span> <span class="onoffswitch-switch"></span></label></div></div><div><h4>{{state.name}}</h4></div><div><select ng-disabled="!state.active" ng-model="state.activeOption" ng-options="option.name for option in state.options" ng-change="updateState(state)"></select></div></li><li><h3>Ajax States</h3></li><li ng-repeat="state in states | filter:hasUrl track by $index" ng-class="{ \'leo-highlight\': state.highlight }"><div><div class="onoffswitch"><input ng-model="state.active" ng-click="updateState(state)" class="onoffswitch-checkbox" id="{{state.name}}" type="checkbox" name="{{state.name}}" value="{{state.name}}"> <label class="onoffswitch-label" for="{{state.name}}"><span class="onoffswitch-inner"></span> <span class="onoffswitch-switch"></span></label></div></div><div><h4>{{state.name}}</h4>&nbsp;&nbsp; - {{state.url}}</div><div><select ng-disabled="!state.active" ng-model="state.activeOption" ng-options="option.name for option in state.options" ng-change="updateState(state)"></select></div></li></ul></div><div ng-switch-when="test" class="leonardo-test"><div><label for="url"></label>URL: <input id="url" type="text" ng-model="test.url"> <input type="button" ng-click="submit(test.url)" value="submit"></div><textarea>{{test.value | json}}</textarea></div></div></div>');
}]);
})();

@@ -33,3 +33,3 @@ var gulp = require('gulp'),

}))
.pipe(gulp.dest('./tmp'))
.pipe(gulp.dest('./tmp'));
});

@@ -47,3 +47,3 @@

}))
.pipe(rename('leonardo.templates.min.js'))
.pipe(concat('leonardo.templates.min.js'))
.pipe(gulp.dest('./tmp'));

@@ -56,6 +56,9 @@ });

'./src/leonardo/module.js',
'./src/leonardo/leonardo.prov.js',
'./src/leonardo/configuration.srv.js',
'./src/leonardo/httpInterceptor.srv.js',
'./src/leonardo/storage.srv.js',
'./src/leonardo/activator.drv.js',
'./src/leonardo/window-body.drv.js',
'./src/leonardo/request.drv.js',
'./tmp/leonardo.templates.min.js'

@@ -62,0 +65,0 @@ ])

"use strict";
function getRandomIntInclusive(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var Flicker = angular.module('flicker-example', ['leonardo','akoenig.deckgrid'])
.config(function ($locationProvider) {
var Flicker = angular.module('flicker-example', ['leonardo', 'akoenig.deckgrid'])
.config(['$locationProvider', '$leonardoProvider', function ($locationProvider, $leonardoProvider) {
$leonardoProvider.setAppPrefix('flicker-example');
$locationProvider.html5Mode(false);
})
.controller('flickerCtrl', function ($scope, flickerGetter) {
}])
.controller('flickerCtrl', ['$scope', 'flickerGetter', function ($scope, flickerGetter) {
$scope.loadClicked = function () {

@@ -12,6 +16,4 @@ $scope.loading = true;

$scope.photos = data;
console.log(data);
}).finally(function () {
$scope.loading = false;
}, function () {
$scope.loading = false;
});

@@ -52,3 +54,3 @@

});
}]);

@@ -58,13 +60,11 @@ Flicker.factory('flickerGetter', ['$q', '$http', function ($q, $http) {

getData: function(){
var defer = $q.defer();
$http.jsonp(' http://api.flickr.com/services/feeds/photos_public.gne', {
return $http.jsonp('http://api.flickr.com/services/feeds/photos_public.gne', {
method: 'jsonp',
params: {
group_id: 'tmnt',
tagmode: "any",
format: 'json',
jsoncallback: 'JSON_CALLBACK'
}
}).success(function (data) {
data = data.items.map(function (item) {
}).then(function (response) {
return response.data.items.map(function (item) {
var imageUrl = item.media.m;

@@ -75,13 +75,6 @@ return {

});
defer.resolve(data);
}).error(function () {
defer.resolve();
});
return defer.promise;
},
getNinjaData: function () {
var defer = $q.defer();
$http.jsonp('https://api.flickr.com/services/rest', {
return $http.jsonp('https://api.flickr.com/services/rest', {
method: 'jsonp',

@@ -96,13 +89,9 @@ params: {

}
}).success(function (data) {
defer.resolve(data.photoset.photo.map(function (photo) {
}).then(function (response) {
return response.data.photoset.photo.map(function (photo) {
return {
imageUrl: 'https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}_b.jpg'.replace('{farm-id}', photo.farm).replace('{server-id}', photo.server).replace('{id}', photo.id).replace('{secret}', photo.secret)
};
}));
}).error(function () {
defer.resolve();
});
});
return defer.promise;
}

@@ -109,0 +98,0 @@ };

{
"name": "leonardojs",
"version": "1.0.0",
"version": "1.0.8",
"description": "Leonardo ========",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -1,9 +0,32 @@

![Leonardo logo](extension/images/leonardo.png) Leonardo Docs
=============
## Leonardo
Mocking and testing made simple and consistent.
Developed by Outbrain.
[![npm version](https://badge.fury.io/js/leonardojs.svg)](http://badge.fury.io/js/leonardojs)
[![Bower version](https://badge.fury.io/bo/leonardo.svg)](http://badge.fury.io/bo/leonardo)
## Requirements
[![Package Quality](http://npm.packagequality.com/badge/leonardojs.png)](http://packagequality.com/#?package=leonardojs)
![Mocking and testing made simple and consistent. Developed by Outbrain.](extension/images/example.png)
[Demo](http://outbrain.github.io/Leonardo/)
## Install
__Dependencies__
* __[Angular](https://github.com/angular/bower-angular)__
* __[Angular Mocks](https://github.com/angular/bower-angular-mocks)__
Installing via `npm` or `bower` will bring in the above dependencies as well.
__npm__
```sh
$ npm install leonardojs
```
__bower__
```sh
$ bower install leonardo
```
#### Load Dependency scripts

@@ -24,3 +47,3 @@

//.....
<script src="[bower_componenets|node_modules|other]/leonardos/leonardos.js"></script>
<script src="[bower_componenets|node_modules|other]/leonardo/leonardo.js"></script>
</body>

@@ -37,3 +60,3 @@ </html>

//.....
<link rel="stylesheet" media="all" href="[bower_componenets|node_modules|other]/leonardos/leonardo.min.css" />
<link rel="stylesheet" media="all" href="[bower_componenets|node_modules|other]/leonardo/leonardo.min.css" />
</head>

@@ -43,3 +66,3 @@ </html>

#### Add Angular module dependancy
#### Add Angular module dependency

@@ -53,2 +76,3 @@ ```html

var myApp = angular.module("app", ["leonardo"]);
//.....
</script>

@@ -69,7 +93,55 @@ </body>

A plunker demonstration http://plnkr.co/edit/w8oaELXwQldv6AeZjnhD?p=preview
## API
#### Add States
```javascript
//.....
myApp.run(["leoConfiguration", function(leoConfiguration){
leoConfiguration.addStates([
{
name: 'Get Data',
url: '/api/user/43435',
options: [
{name: 'success', status: 200, data: { name: "Master Splinter" }},
{name: 'error 500', status: 500},
{name: 'error 401', status: 401}
]
},
{
name: 'Update Data',
url: '/api/user/43435',
verb: 'PUT',
options: [
{name: 'success', status: 200},
{name: 'error 500', status: 500},
{name: 'error 400', status: 400}
]
}
]);
}]);
```
## Screen
![example image](extension/images/example.png)
#### Activate State Option
Activates state option, mocked response will be returned when calling the state url
```javascript
//.....
leoConfiguration.activateStateOption('Update Data', 'success');
$http.put('/api/user/43435', { name: "Master Splinter" }).success(function(data, status) {
console.log(status); // 200
});
leoConfiguration.activateStateOption('Update Data', 'error 500');
$http.put('/api/user/43435', { name: "Master Splinter" }).error(function(data, status) {
console.log(status); // 500
});
//.....
```
#### Deactivate State
Deactivates a specific state, when calling the state url request will pass through to the server
```javascript
//.....
leoConfiguration.deactivateState('Update Data');
//.....
```
## Documentation

@@ -116,1 +188,9 @@ http://outbrain.github.io/Leonardo/docs/configuration.srv.html

or `cd` into the project folder
```bash
gulp serve
```
## License
Copyright &copy; 2015 MIT License
angular.module('leonardo').directive('leoActivator', ['$compile', function activatorDirective($compile) {
return {
restrict: 'A',
controllerAs: 'leonardo',
controller: function () {
this.activeTab = 'scenarios';
this.selectTab = function (name) {
this.activeTab = name;
};
},
link: function(scope, elem) {

@@ -13,3 +20,5 @@ var el = angular.element('<div ng-click="activate()" class="leonardo-activator"></div>');

'<li>LEONARDO</li>',
'<li>Scenarios</li>',
'<li ng-class="{ \'leo-selected-tab\': leonardo.activeTab === \'scenarios\' }" ng-click="leonardo.selectTab(\'scenarios\')">Scenarios</li>',
'<li ng-class="{ \'leo-selected-tab\': leonardo.activeTab === \'recorder\' }"ng-click="leonardo.selectTab(\'recorder\')">Recorder</li>',
'<li ng-class="{ \'leo-selected-tab\': leonardo.activeTab === \'export\' }"ng-click="leonardo.selectTab(\'export\')">Exported Code</li>',
'</ul>',

@@ -16,0 +25,0 @@ '</div>',

angular.module('leonardo').factory('leoConfiguration',
['leoStorage', '$httpBackend', function(leoStorage, $httpBackend) {
['leoStorage', '$httpBackend', '$rootScope', function(leoStorage, $httpBackend, $rootScope) {
var states = [],
_scenarios = {},
responseHandlers = {},
_requestsLog = [],
_savedStates = [],
// Core API

@@ -22,4 +24,9 @@ // ----------------

setActiveScenario: setActiveScenario,
getRecordedStates: getRecordedStates,
getRequestsLog: getRequestsLog,
loadSavedStates: loadSavedStates,
addSavedState: addSavedState,
//Private api for passing through unregistered urls to $htto
_requestSubmitted: requestSubmitted
_requestSubmitted: requestSubmitted,
_logRequest: logRequest
};

@@ -79,3 +86,3 @@ return api;

function sync(){
fetchStates().forEach(function (state) {
fetchStates().forEach(function (state, i) {
var option, responseHandler;

@@ -87,2 +94,3 @@ if (state.url) {

responseHandler.respond(function () {
console.log(i);
$httpBackend.setDelay(option.delay);

@@ -99,11 +107,16 @@ return [option.status, angular.isFunction(option.data) ? option.data() : option.data];

function getResponseHandler(state) {
if (!responseHandlers[state.url + '_' + state.verb]) {
var url = state.url;
var verb = state.verb === 'jsonp' ? state.verb : state.verb.toUpperCase();
var key = (url + '_' + verb).toUpperCase();
var escapedUrl = url.replace(/[?]/g, '\\?');
if (!responseHandlers[key]) {
if (state.verb === 'jsonp'){
responseHandlers[state.url + '_' + state.verb] = $httpBackend.whenJSONP(new RegExp(state.url));
responseHandlers[key] = $httpBackend.whenJSONP(new RegExp(escapedUrl));
}
else {
responseHandlers[state.url + '_' + state.verb] = $httpBackend.when(state.verb || 'GET', new RegExp(state.url));
responseHandlers[key] = $httpBackend.when(verb || 'GET', new RegExp(escapedUrl));
}
}
return responseHandlers[state.url + '_' + state.verb];
return responseHandlers[key];
}

@@ -128,8 +141,14 @@

});
$rootScope.$broadcast('leonardo:stateChanged', stateObj);
}
function addStates(statesArr) {
statesArr.forEach(function(stateObj) {
addState(stateObj);
});
if (angular.isArray(statesArr)) {
statesArr.forEach(function(stateObj) {
addState(stateObj);
});
} else {
console.warn('addStates should get an array');
}
}

@@ -143,3 +162,3 @@

status = stateObj.status || 200,
data = stateObj.data || {},
data = angular.isDefined(stateObj.data) ? stateObj.data : {},
delay = stateObj.delay || 0;

@@ -240,2 +259,57 @@ var defaultState = {};

}
function logRequest(method, url, data, status) {
if (method && url && !(url.indexOf(".html") > 0)) {
var req = {
verb: method,
data: data,
url: url.trim(),
status: status,
timestamp: new Date()
};
req.state = getStateByRequest(req);
_requestsLog.push(req);
}
}
function getStateByRequest(req) {
return fetchStates().filter(function(state) {
if (!state.url) return false;
return state.url === req.url && state.verb.toLowerCase() === req.verb.toLowerCase();
})[0];
}
function getRequestsLog() {
return _requestsLog;
}
function loadSavedStates() {
_savedStates = leoStorage.getSavedStates();
addStates(_savedStates);
}
function addSavedState(state) {
_savedStates.push(state);
leoStorage.setSavedStates(_savedStates);
addState(state);
}
function getRecordedStates() {
var requestsArr = _requestsLog
.map(function(req){
var state = getStateByRequest(req);
return {
name: state ? state.name : req.verb + " " + req.url,
verb: req.verb,
url: req.url,
options: [{
name: req.status >= 200 && req.status < 300 ? 'Success' : 'Failure',
status: req.status,
data: req.data
}]
}
});
console.log(angular.toJson(requestsArr, true));
return requestsArr;
}
}]);
angular.module('leonardo', ['leonardo.templates', 'ngMockE2E'])
/* wrap $httpbackend with a proxy in order to support delaying its responses
* we are using the approach described in Endless Indirection:
* https://endlessindirection.wordpress.com/2013/05/18/angularjs-delay-response-from-httpbackend/
*/
.config(['$provide', function($provide) {
$provide.decorator('$httpBackend', ['$delegate', function($delegate) {
.config(['$provide', '$httpProvider', function($provide, $httpProvider) {
$httpProvider.interceptors.push('leoHttpInterceptor');
$provide.decorator('$httpBackend', ['$delegate', '$timeout', function($delegate, $timeout) {
var proxy = function(method, url, data, callback, headers) {

@@ -12,3 +11,3 @@ var interceptor = function() {

_arguments = arguments;
setTimeout(function() {
$timeout(function() {
callback.apply(_this, _arguments);

@@ -75,3 +74,5 @@ }, proxy.delay || 0);

}]);
}]);
}])
.run(['leoConfiguration', function(leoConfiguration) {
leoConfiguration.loadSavedStates();
}]);

@@ -1,5 +0,7 @@

angular.module('leonardo').factory('leoStorage', ['$rootScope', function storageService($rootScope) {
var STATES_STORE_KEY = 'leonardo-states';
function getItem(key) {
var item = localStorage.getItem(key);
angular.module('leonardo').factory('leoStorage', ['$rootScope', '$window', '$leonardo', function storageService($rootScope, $window, $leonardo) {
var APP_PREFIX = $leonardo.getAppPrefix() + '_',
STATES_STORE_KEY = APP_PREFIX + 'leonardo-states',
SAVED_STATES_KEY = APP_PREFIX + 'leonardo-unregistered-states';
function _getItem(key) {
var item = $window.localStorage.getItem(key);
if (!item) {

@@ -11,21 +13,29 @@ return null;

function setItem(key, data) {
localStorage.setItem(key, angular.toJson(data));
function _setItem(key, data) {
$window.localStorage.setItem(key, angular.toJson(data));
}
function getStates() {
return getItem(STATES_STORE_KEY) || {};
return _getItem(STATES_STORE_KEY) || {};
}
function setStates(states) {
setItem(STATES_STORE_KEY, states);
_setItem(STATES_STORE_KEY, states);
$rootScope.$emit('leonardo:setStates');
}
function getSavedStates() {
return _getItem(SAVED_STATES_KEY) || [];
}
function setSavedStates(states) {
_setItem(SAVED_STATES_KEY, states);
}
return {
getItem: getItem,
setItem: setItem,
setStates: setStates,
getStates: getStates
getStates: getStates,
getSavedStates: getSavedStates,
setSavedStates: setSavedStates
};
}]);
angular.module('leonardo').directive('leoWindowBody',
['$http', 'leoConfiguration', function windowBodyDirective($http, leoConfiguration) {
['$http', 'leoConfiguration', '$timeout', function windowBodyDirective($http, leoConfiguration, $timeout) {
return {

@@ -8,14 +8,20 @@ restrict: 'E',

replace: true,
controller: ['$scope', function($scope){
$scope.selectedItem = 'activate';
$scope.NothasUrl = function(option){
require: '^leoActivator',
controller: ['$scope', function($scope) {
$scope.detail = {
option: 'success',
delay: 0,
status: 200
};
$scope.NothasUrl = function (option) {
return !option.url;
};
$scope.hasUrl = function(option){
$scope.hasUrl = function (option) {
return !!option.url;
};
$scope.deactivate = function() {
$scope.states.forEach(function(state){
state.active = false;
$scope.deactivate = function () {
$scope.states.forEach(function (state) {
state.active = false;
});

@@ -25,8 +31,8 @@ leoConfiguration.deactivateAllStates();

$scope.updateState = function(state){
$scope.updateState = function (state) {
if (state.active) {
console.log('activate state option:' + state.name + ': ' + state.activeOption.name);
console.log('activate state option:' + state.name + ': ' + state.activeOption.name);
leoConfiguration.activateStateOption(state.name, state.activeOption.name);
} else {
console.log('deactivating state: ' + state.name);
console.log('deactivating state: ' + state.name);
leoConfiguration.deactivateState(state.name);

@@ -40,3 +46,3 @@ }

$scope.activateScenario = function(scenario){
$scope.activateScenario = function (scenario) {
$scope.activeScenario = scenario;

@@ -46,4 +52,91 @@ leoConfiguration.setActiveScenario(scenario);

};
$scope.requests = leoConfiguration.getRequestsLog();
$scope.$watch('detail.value', function(value){
if (!value) {
return;
}
try {
$scope.detail.stringValue = value ? JSON.stringify(value, null, 4) : '';
$scope.detail.error = '';
}
catch (e) {
$scope.detail.error = e.message;
}
});
$scope.$watch('detail.stringValue', function(value){
try {
$scope.detail.value = value ? JSON.parse(value) : {};
$scope.detail.error = '';
}
catch(e) {
$scope.detail.error = e.message;
}
});
$scope.requestSelect = function (request) {
$scope.requests.forEach(function (request) {
request.active = false;
});
request.active = true;
if (request.state && request.state.name) {
var optionName = request.state.name + ' option ' + request.state.options.length;
}
angular.extend($scope.detail, {
state : (request.state && request.state.name) || '',
option: optionName || '',
delay: 0,
status: 200,
stateActive: !!request.state,
value: request.data || {}
});
$scope.detail._unregisteredState = request;
};
$scope.$on('leonardo:stateChanged', function(event, stateObj) {
$scope.states = leoConfiguration.getStates();
var state = $scope.states.filter(function(state){
return state.name === stateObj.name;
})[0];
if (state) {
state.highlight = true;
$timeout(function(){
state.highlight = false;
}, 3000);
}
});
$scope.getStatesForExport = function () {
$scope.exportStates = leoConfiguration.getStates();
}
}],
link: function(scope) {
link: function(scope, el, attr, leoActivator) {
scope.saveUnregisteredState = function () {
var stateName = scope.detail.state;
leoConfiguration.addSavedState({
name: stateName,
verb: scope.detail._unregisteredState.verb,
url: scope.detail._unregisteredState.url,
options: [
{
name: scope.detail.option,
status: scope.detail.status,
data: scope.detail.value
}
]
});
leoActivator.selectTab('scenarios');
};
scope.test = {

@@ -50,0 +143,0 @@ url: '',

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

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

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

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc