DRY Rest API testing - rest

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.

Related

SSR - Status code 301 is missing when the page comes from the cache ( Always returns 200 )

We currently have a problem with SSR optimized engine. The scenario is that a product has been removed or renamed on the catalog, and the user tends to access that old none existing URL directly. Then we have implemented a redirected behavior sending a status code of 301 so that the customer gets redirected to a relevant page where its URL is retrieved from BE. (Through a generic HTTP interceptor catchError)
catchError((error: any) => {
if (error instanceof HttpErrorResponse) {
...
this.response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
this.response.set('location',this.service.urlBuilder(redirectUrl));
return this.setMovedPermanentlyStatus();
}
}
However, we also have those pages cached, so the next time that the page comes from the cache, it returns 200 instead of 301, which we tried to implement in the first place. We tried to rule out those with 301 not to be treated like others, but it still returns with 200 when they're coming from the cache. ( By extending SSR optimized engine with an exception like )
protected fallbackToCsr(response: Response, filePath: string, callback: SsrCallbackFn): void {
if (response.statusCode !== HttpResponseStatus.MOVED_PERMANENTLY) {
response.set('Cache-Control', 'no-store');
callback(undefined, this.getDocument(filePath));
}
}
We're looking for a solution to ensure that all 'the redirected pages' will always respond with 301 and not 200, even if they come from the cache.
By extending SSR optimized engine
How did you extended (and used) optimized engine? I'm curious about this, because as I see it, the instance is hardcoded (and not injected), just like this:
// apply optimization wrapper if optimization options were defined
return optimizationOptions
? new OptimizedSsrEngine(engineInstance, optimizationOptions)
.engineInstance
: engineInstance;
If you actually managed to use your own instance of Optimized Engine, then you could do this:
Override renderResponse
protected renderResponse(
filePath: string,
options: any,
callback: (err?: Error | null, html?: string) => void
): void {
super.renderResponse(filePath, options, callback);
const response: Response = options.res || options.req.res;
if (response.statusCode === HttpResponseStatus.MOVED_PERMANENTLY) {
// remove the result from cache so that it's executed again
const request: Request = options.req;
const key = this.getRenderingKey(request);
this.renderingCache.clear(key);
}
}
However, this might not be too optimum. One way to improve: Use an additional internal Map<string,string> cache, and add code to store the renderingKey of the request and the Location value of the header inside the if above; so that, before calling super.renderResponse you will add code to check the map with the key; if present, then redirect to the result, and avoid the call to super.renderResponse.
Additionally, supposing that it's not possible to extend from OptimizedSsrEngine, the way to go would be to add a middleware on express server (see at server.ts file in your project), and make the implementation at low-level: the same approach, using a Map to store the redirects. You could add one middleware before the default to check that map, and calling next() only if the request key it's not in the map; and one after, to store the request key and the redirect if it's a redirect (ensure to add a call to next() from the default implementation).

Optional checkbox in Scala Play - form does not validate

I just started with Play and I'm trying to create a form with an "optional checkbox". The user must agree to the general terms (don't share your login credentials, ...). The second checkbox is optional and the user can decide whether this hint should be shown in the future again when he logs in the next time:
I created some form validation code in my Scala controller:
case class AbuseStatus(abuseHintAccepted: Boolean, dismissAbuseHintInFuture: Boolean)
val abuseHintForm = Form(
mapping(
"abuseHintAccepted" -> checked("Please accept the general terms."),
"dismissHintInFuture" -> boolean
)(AbuseStatus.apply)(AbuseStatus.unapply) verifying ("you must accept the general terms", result => result match {
case abuseStatus =>
{
abuseStatus.abuseHintAccepted.booleanValue()
}
})
)
I'm using the following method to handle the POST request when the form has been sent.
def sendAbuseHintForm = Action {implicit request =>
abuseHintForm.bindFromRequest.fold(
formWithErrors =>
{
Logger.info("Form did not validate")
formWithErrors.errors.map(error => Logger.info(error.messages.mkString(",")))
Ok(views.html.abuseHint(formWithErrors))
},
abuseStatus =>
{
if(abuseStatus.dismissAbuseHintInFuture)
{
Logger.info(">>>dismissHintInFuture = true")
Ok(views.html.home()).withCookies(showAbuseHintCookie)
}
else
Ok(views.html.home())
}
)
}
The form does not validate if both checkboxes are set to true. I would like it to validate when at least the first checkbox is set to true (the second is optional). How can I achieve this and what is the difference between
"abuseHintAccepted"->checked("...")
and
"dismissHintInFuture"->boolean
They both return a Mapping[Boolean].
I have tried your example using Play 2.3.8 and it does appear to validate correctly when passing these parameters:
abuseHintAccepted:true
dismissHintInFuture:true
It would be worth making sure the form field names and values (true/false) that are posted are actually correct in all of the scenarios you describe (you haven't supplied that part of the code).
The difference between boolean and checked(msg) is that checked(msg) has validation applied ensuring the value is true - it is equivalent to boolean verifying (msg, _ == true) - (see Play framework source).
Finally, the checked() validation you have for abuseHintAccepted means that the verifying check on the whole form is not needed, but this shouldn't affect the behaviour of the form (it is just duplicate validation).

How do I use findOrCreateEach in waterline/sailsjs?

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>
});

Composing `Future` result in Play Framework with Scala

I am trying to write a Play Framework asynchronous Action for the following URL:
POST /users/:userId/items
My database calls all return Future[...], where ... is Option[A] for find methods and Option[Id] for create methods.
I would like to check for the existence of the userId before trying to create the new item. I have a method Users.findById(userId) that returns a Future[Option[User]]. The result is Some(User) if the user exists and None if not. Items.create() also returns a Future[Option[itemId]].
I am trying to compose something using for:
for {
user <- Users.findById(userId)
if user.isDefined
} yield {
Items.create(...) map { itemId => Ok(itemId) } getOrElse NotFound
}
I would like to return Ok(itemId) if the item is successfully created. I'm not sure how to handle the error case. I would like to return NotFound if either the userId is invalid or the item cannot be created (maybe a field conflicts with a unique value already in the database).
I'm not sure what to put after the for structure. I tried getOrElse, but that does not compile, since Future does not have a getOrElse method.
Ideally, I can handle URLs containing several ids to check, e.g.:
PUT /users/:userId/foo/:fooId/bar/:barId
and confirm that userId, fooId, and barId are all valid before doing the update. All of those calls (Users.findById, Foo.findById, and Bar.findById) will return Future[Option[A]].
It's that double-nesting (Future of Option) that seems to get people every time. Things become a lot easier if you can flatten stuff out first.
In this case, Future already has a way of representing an error condition, it can wrap an Exception as well as a success value, that's something you can use...
// making this a Singleton avoids the cost of building a stack trace,
// which only happens when an Exception is constructed (not when it's thrown)
object NotFoundException extends RuntimeException("Empty Option")
// The map operation will trap any thrown exception and fail the Future
def squish[T](x: Future[Option[T]]) =
x map { _.getOrElse(throw NotFoundException) }
It's now a lot easier to use those squished results in a comprehension:
val result = for {
user <- squish(Users findById userId)
itemId <- squish(Items.create(user, ...))
} yield {
Ok(itemId)
} recover {
case NotFoundException => NotFound
}
Which will, of course, evaluate to a Future. This is async programming, after all :)
Any exceptions other than NotFoundException will still be exposed.

Can I divide my tests into separate specs and then call them from another or is it better to use helper functions?

Just got started with Protractor for E2E testing and I am having a bit of trouble with the test case structure.
Not sure if can I divide my tests into separate specs and then call them from another or how can I make nice helper functions to handle this.
I am finding elements by a repeater and then I would like to make tests for each of the operation for each of the element in the repeater. Sort of like this:
describe('tasty', function () {
'use strict';
var ptor;
beforeEach(function () {
ptor = protractor.getInstance();
ptor.get('http://localhost:8000/');
});
it('Should sample three tasty fruits of every kind on my shopping list.', function () {
ptor.findElement(protractor.By.className('fruitstore')).click();
var fruitshelves = ptor.findElements(protractor.By.repeater('fruit in fruits').column('header'));
fruitshelves.then(function(arr) {
for (var i=0;i<arr.length; i++) {
// Pick up three fruits of this kind from the shelf and put in shopping cart
// Should be listed on my shopping list
// Open the wallet
// Should have money
// Pay for the fruits and put it in your shopping bag
// Should be able to complete the transaction
// For each one of the fruits in your shopping bag
// Take a bite
// Should be tasty
}
});
});
});
Based on the #langliman answer, I've managed to achieve the desired behaviour.
Note login.spec.js and Login.page.js should be located in the same folder.
Login.page.js file:
var LoginPage = function (ptor) {
//following PageObject pattern define the functions here.
}
module.exports.getLoginPage = function (ptor) {
return new LoginPage(ptor);
};
login.spec.js file:
(function () {
'use strict';
describe('login page', function () {
var ptor = protractor.getInstance();
var loginPageBuilder = require('./Login.page.js');
var loginPage = loginPageBuilder.getLoginPage(ptor);
it('should login as admin', function () {
loginPage.visit();
loginPage.enterUsername('user');
loginPage.enterPassword('password');
loginPage.login();
});
});
}());
I came to this question looking for a way to have helper functions shared between spec files in Protractor. In case others are looking for the same, turns out since Protractor is just running in Node, all you need to do is var helpers = require('./your-helper-file').
In case you want shared setup and before/after functions as well as helper methods, one solution is to require the tests from your spec helper instead of requiring your spec helper from the tests.
conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['e2e/spec.js']
}
e2e/spec.js
var chai = require('chai'),
homepage = require('./homepage.js'),
signin = require('./signin.js');
chai.should()
browser.baseUrl = 'http://localhost:3000'
homepage.test()
signin.test()
e2e/homepage.js
exports.test = function() {
describe('homepage', function() {
it('should have the right title', function() {
browser.get('/')
browser.getTitle().then(function(title){
title.should.eq('Home')
})
});
});
}
e2e/signin.js
exports.test = function() {
describe('signin', function() {
it('should have the right title', function() {
browser.get('/signin')
browser.getTitle().then(function(title){
title.should.eq('Sign in')
})
});
});
}
I'm looking at the same thing myself, and to some extent I had hoped that you would have an answer for me on this question. :-)
Having said that, it appears that protractor is new enough that nobody really knows the answer, and I guess that makes my answer as good as the next persons.
Firstly, I'm using the page object notation that is described on the protractor getting started page, towards the bottom: https://github.com/angular/protractor/blob/master/docs/getting-started.md
This gives an element of modularity, my view here is that I end up with a set of classes, one per page, that abstract away some of the detail. So, for example, I might have a "foo" class, which includes in it abstractions like "foo.get" and "foo.validate(id, name, otherData)". This would be a way to pull out repeated code.
The bit that I haven't worked out is how to create a library of modules and then assemble those into a single set of scenarios. I have a few thoughts though:
The underlying problem is the ability to include javascript files in each other - which really doesn't exist as a capability. There are third party libraries, which I'd prefer not to use, and I haven't seen a way to use Angular's module capability to do this.
End 2 end testing can be very dependent on the order of the tests. So one test may create data, another test may then use that data. As an example, if you want a test that logs people on, you may need a test that registers people first. You probably don't want to put registration on the front of every test that you run. As such, you probably need a lot of control over the order of your test scenarios anyway
As such, one option is to just put everything in one really big file. Which goes against everything we all learned in school, but I haven't really come up with a reason that wouldn't work. Then you can write functions and abstractions to your hearts content.
If you follow that to the next stage, another option is to write a series of javascript files with strict naming conventions, then use grunt to concatenate them for you before executing them. So, for example:
A set of files named xxxx.page.scenario.js, which contain the "page object" definitions - basically helper methods for each page
A set of files named xxxx.functions.scenario.js, which contain common components of your scenarios - so maybe you have a register and logon set of actions, and you make that into a library function
A set of files named nnxx.scenarios.scenario.js, which contain the actual scripts themselves. These are numbered at the start (the nn), so we can concatenate them in a reliable sequence and thereby control which order our scripts run
I'm not yet saying this is a good idea, just that it at least superficially looks like it could work, and would give the desired result. My main concern is that it feels fragile - so as the test suite grows in size it would perhaps become very difficult to maintain. Perhaps another way to do this would be, instead of numbering the scenarios, to instead define them as dependencies, and have something that makes sure that any given script runs after any script it declares itself to be dependent on. That would maybe allow for subsetting of the scripts as well - so you could say "run the bar script" and the framework would know that the bar script needs the foo script run first, and maybe the login script. But it's OK to leave all the other scripts out.
EDIT: I see astrolabe as potentially a good answer here, it looks like it explicitly allows you to modularise your tests. https://github.com/stuplum/astrolabe. I've just completed a proof of concept with it, and it seems to do everything I might hope. The code for it ends up something like:
clubs.part.scenario.js:
/**
* Partial for the page objects associated with clubs
*/
var Page = require('astrolabe').Page;
module.exports = Page.create({
url: { value: 'UI/index.html#clubs' },
title: { get: function() { return this.findElement(this.by.id('title')); } },
description: { get: function() { return this.findElement(this.by.id('description')); } },
clubTableElement: { value: function(rowNum, columnBinding) {
return this.findElement(this.by.repeater('club in clubs').row(rowNum).column(columnBinding)); } }
}
);
clubs.scenario.js:
/**
* End to end tests for the club functionality
*/
var homePage = require('../home/home.part.scenario.js');
var clubsPage = require('./clubs.part.scenario.js');
describe( 'Navigate to club list page', function() {
it ( 'should allow navigation to the club list page', function() {
homePage.go();
expect(homePage.clubsLink.getText()).toEqual('Clubs');
homePage.clubsLink.click();
expect(clubsPage.title.getText()).toEqual('Club functions');
expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server');
expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');
expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');
expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');
expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');
});
it ( 'should allow us to go directly to the club list page', function() {
clubsPage.go();
expect(clubsPage.title.getText()).toEqual('Club functions');
expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server');
expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');
expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');
expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');
expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');
});
});
I'm pretty happy with this structure, it doesn't do everything but it does most things. The sample code I've provided is from the tutorial that I've been working on for a while with angularjs, which I'm updating for e2e testing and Rails 4 at the moment, if you want the context that goes with that: http://technpol.wordpress.com/2013/11/16/5-end-to-end-testing/