According to the release doc, Regula 1.3.0 should support async validation. It seems that compound constraints are able to take an option of async in some way. Does this hold true for custom validations as well? What would be the syntax for this?
I'm still working on finishing the documentation for 1.3 (what I have so far is available here).
Asynchronous support is available for both custom constraints and compound constraints (that contain at least one asynchronous constraint).
The syntax to define an asynchronous constraint is pretty simple:
regula.custom({
name: "MyAsyncContraint",
async: true,
defaultMessage: "The asynchronous constraint failed.",
validator: function(params, validator, callback) {
//Using jQuery as an example
jQuery.ajax({
url: myUrl,
dataType: "jsonp",
success: function(data) {
//Use the callback to pass the result of validation back to
//regula.
callback(data.pass)
}
});
}
});
There is no explicit syntax or call to make a compound constraint asynchronous. Any compound constraint that contains one or more asynchronous is implicitly asynchronous. To validate asynchronous constraints (or even a mix of synchronous and asynchronous constraints), you just pass a callback to .validate:
regula.validate(function(constraintViolations) {
...
});
You can use .validate with options and a callback as well:
regula.validate(options, function(constraintViolations) {
...
});
Related
I'm making unit tests on my rest api with mocha and chai. For the moment, for each request, (let's say a POST for example) I test the whole response body (excluding non static data like ids etc...). The problem is : if some day I decide to change the model of my resource, like maybe adding a new field. The actual tests won't check this new field. So I'll have to update every test related to this resource, which can be complicated as the number of tests increases.
So my question is : Am I doing it the right way ? If not, what should I test in my api responses and what should I not ?
The DRY (Don't repeat yourself) principle applies to testing as well, but don't overdo it. Tests should be "DAMP not DRY".
...if some day I decide to change the model of my resource, like maybe adding a new field. The actual tests won't check this new field. So I'll have to update every test related to this resource...
In this case what I usually do is create a Chai custom assertion that defines a set of assertions for a specific type, e.g a Todo.
This custom assertion is then (re)used in all relevant tests to verify that the returned object(s) actually pass the assertions for Todo, without having to repeat the same assertions in each and every test.
Here's an example:
const chai = require('chai')
const chaiHttp = require('chai-http')
const server = 'https://jsonplaceholder.typicode.com'
chai.should()
chai.use(chaiHttp)
// Define a custom assertion for 'Todo'. We expect that a Todo always
// has an `id` property of type `Number` and a `title` property of
// type `String`.
chai.use((chai, utils) => {
utils.addProperty(chai.Assertion.prototype, 'Todo', function () {
this._obj.should.have.property('id')
this._obj.should.have.property('title')
this._obj.id.should.be.a('Number')
this._obj.title.should.be.a('String')
})
})
// Begin Tests
describe('Retrieve a Todo', () => {
it('returns a single Todo by ID', () => {
return chai.request(server)
.get('/todos/1')
.then(res => {
res.should.have.status(200)
// Use the custom assertion to check if returned object
// passes the assertions for `Todo`.
res.body.should.be.a.Todo
})
})
})
describe('Retrieve all Todos', () => {
it('returns a list containing 200 Todos', () => {
return chai.request(server)
.get('/todos')
.then(res => {
res.should.have.status(200)
res.body.should.be.an('Array')
res.body.should.have.length(200)
// Reuse the custom assertion to check if all returned objects
// pass the assertions for `Todo`.
res.body.forEach(todo => todo.should.be.a.Todo)
})
})
})
If in the future I add a new field on Todo, i.e completed, all I need to do is modify the custom assertion like so:
chai.use((chai, utils) => {
utils.addProperty(chai.Assertion.prototype, 'Todo', function () {
this._obj.should.have.property('id')
this._obj.should.have.property('title')
this._obj.should.have.property('completed')
this._obj.id.should.be.a('Number')
this._obj.title.should.be.a('String')
this._obj.completed.should.be.a('Boolean')
})
})
... what should I test in my api responses and what should I not ?
As a minimum I would check if:
The response HTTP status is correct.
The response body has the appropriate properties and correct types for each property.
If the response is a list of items, I would check if the response body is indeed an Array, if it has the length I expect it to have and if each element in the Array has the correct properties and types.
There's no "rules" here. At the end it's a risk/time decision. Maintaining a test suite takes time. If I'm building a simple todo app for my own use, I won't concern myself too much with exhaustive testing. However if I'm building a public payment server, I'd definitely want my tests to be as exhaustive as possible.
I'm trying to get the semantic object and semantic action of my deployed SAPUI5 application. I tried looking into ushell services - URLParsing and LaunchPage but it does not seem to return my semantic objects and actions.
Have anybody tried this?
This worked for me so far:
sap.ui.require([ // modules lazily instead of accessing them with global names.
"sap/ushell/library", // Consider adding `"sap.ushell": { lazy: true }` to dependencies in manifest.json
"sap/ui/core/routing/HashChanger",
], async (sapUshellLib, HashChanger) => {
const fullHash = new HashChanger().getHash(); // returns e.g. "masterDetail-display?sap-ui-theme=sap_fiori_3&/product/HT-1000"
const urlParsing = await sapUshellLib.Container.getServiceAsync("URLParsing");
urlParsing.parseShellHash(fullHash); /** returns e.g. {
action: "display",
appSpecificRoute: "&/product/HT-1000",
contextRaw: undefined,
params: { "sap-ui-theme": "sap_fiori_3" },
semanticObject: "masterDetail"
} **/
});
You can always just use
window.location.hash
Which you can parse yourself pretty easily. If you really want launchpad code, you can often find it here:
sap.ushell.services.AppConfiguration.getCurrentApplication().sShellHash
I've noticed it's not always set though when you're looking at an embedded component
A simplistic way to do this would be:
var oHashObject = new sap.ui.core.routing.HashChanger();
oHashObject.getHash();
//this will return the semantic object and action alongwith the routing params
In our Node/MongoDB project we have a wrapper function we use for all findOne() operations in order to handle aspects like permissions centrally. The problem I'm running into involves Mongoose populate() functionality.
Because we're using a wrapper function on all our findOne()'s, I need to define the populate() logic at the wrapper function level. But because the number of populate()s I'll need varies from function to function, I have to end up writing conditional statements in our wrapper function, like this:
if (mongooseModelObject.modelName === "Staff" && this.parameters.populateArray) {
return await mongooseModelObject
.findOne(searchObject, options)
.setOptions({ authLevel: this.permissionString, permissions: true })
.populate(this.parameters.populateArray[0].targetId, this.parameters.populateArray[0].limit)
.populate(this.parameters.populateArray[1].targetId, this.parameters.populateArray[1].limit)
.populate(this.parameters.populateArray[2].targetId, this.parameters.populateArray[2].limit)
.populate(this.parameters.populateArray[3].targetId, this.parameters.populateArray[3].limit)
.populate(this.parameters.populateArray[4].targetId, this.parameters.populateArray[4].limit)
.populate(this.parameters.populateArray[5].targetId, this.parameters.populateArray[5].limit);
} else {
return await mongooseModelObject.findOne(searchObject, options).setOptions({ authLevel: this.permissionString, permissions: true });
}
What would make this much simpler is if I could pass an array to populate(). That way, whether I need to use populate() on one property or five, it will still work.
Is this something Mongoose allows for? Or do I have to chain populate() one by one like in my included code? if not, I'm open to other suggestions as well.
You could loop on the populateArray
await this.parameters.populateArray.reduce((tmp, {
targetId,
limit,
}) => tmp.populate(targetId, limit), mongooseModelObject
.findOne(searchObject, options)
.setOptions({
authLevel: this.permissionString,
permissions: true,
}));
According to populate documentation, you can't pass an array to it.
I been looking around on the sails site and was lead to the waterline page. I am curious to how I can use the findOrCreateEach method. Specifically, number of arguments, what it will return, and how it will benefit me using it? I been searching, around and going to have to dive into the source code. I figure I ask here while I look.
Method without bluebird promises
Model.findOrCreateEach(/* What Goes Here */).exec(/* What Returns Here */);
With bluebird promises
Model.findOrCreateEach(/* What Goes Here */).then(/* What Returns Here */);
findOrCreateEach is deprecated; that's why it's not in the documentation. The best way to replicate the functionality is by using .findOrCreate() in an asynchronous loop, for example with async.map:
// Example: find or create users with certain names
var names = ["scott", "mike", "cody"];
async.map(names, function(name, cb) {
// If there is a user with the specified name, return it,
// otherwise create one
User.findOrCreate({name: name}, {name: name}).exec(cb);
},
function done(err, users) {
if (err) { <handle error and return> }
<users now contains User instances with the specified names>
});
I am probably looking for something that is impossible, but anyway let's give it a try. Please consider the following pseudo code that is performing some conditional, remote operation, that executes callback upon completion. But the code in the callback needs to be executed even if remote operation was not neccessary:
if (needsToSave)
{
performRemoteOperation(operationParameters, function() {
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
});
}
else
{
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
}
I find this code particularly ugly and unmanageable. It is easy to omit a change done to callback block in relevant unconditional block. There is an obvious solution of wrapping code in some named function, but it isn't anonymous inline code anymore then. :-)
The best I can think of is to wrap whole code in some conditional caller:
function conditionalCall(condition, action, callback)
{
if (condition)
action(callback)
else
callback()
}
Then my code would fold to:
conditionalCall(needsToSave,
function(_callback) {
performRemoteOperation(operationParameters, _callback)
},
function()
{
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
}
);
...but I am not absolutely sure, whether this is more readable and manageable. Especially when lots of local/remote/callback parameters/closure variables get involved or one needs to "embed" one remote call within another call's callback. I hope there is some better syntax that could be used in such a scenario.
In can be simpified:
var finallyFunction = function {
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
}
if (needsToSave)
performRemoteOperation(operationParameters, finallyFunction);
else
finallyFunction();
This isn't really a closure problem. Assuming "remote operation" to mean "asynchronous operation", then it's to do with handling asynchronous responses.
For sure, anonymous function(s) can be (and typically will be) employed in this kind of situation, but remember that "anonymous function" is not a synonym for "closure". Forgegt (almost) everything you learned in PHP, which is not a great learning ground for lexical closures.
If my assumption is correct, and we are indeed talking about asynchronicity, then jQuery's Deferreds/promises make for a rather neat solution.
// First make sure performRemoteOperation() returns a promise,
function performRemoteOperation(operationParameters) {
...
return promise;//for example a jqXHR object, as generated by $.ajax() and its shorthand methods.
}
function myFunction(needsToSave) {
var p = needsToSave ? performRemoteOperation(operationParameters) : $.Deferred.resolve().promise();
//At this point `p` is either an unresolved promise returned by performRemoteOperation(), or a resolved promise generated in the line above.
p.done(function() {
//This function fires when the remote operation successfully completes, or immediately if `needsToSave` was false.
doSomeCleanup();
doSomeMoreCleanup();
setSomeStatus();
});
return p;//A promise is returned for good measure, in case further chaining is necessary where myFunction() is called.
}
//Sample calls
myFunction(false);
myFunction(true).then(function() {
alert("successfully saved");
}, function() {
alert("error: something went wrong");
});
Of course, you could refactor the code into a single function if you wished but it's arguably easier to understand as two functions, as indicated in the question.