Posted on the jQuery forums http://forum.jquery.com/topic/how-do-i-test-for-web-sql-exceptions but thought I'd ask here. I'm trying to write unit tests against Web SQL api that I'm developing. The scenario I'm trying to account for is when parameters are not being supplied. Below is some sample code:
Web SQL helper object:
var sql = function () {
return {
getDb: function () {
return openDatabase("sampleDb", "1.0", "sampleDb", 5 * 1024 * 1024);
},
initDb: function () {
var db = this.getDb();
if (db) {
db.transaction(function (tx) {
tx.executeSql("CREATE TABLE IF NOT EXISTS SampleTable (Key TEXT UNIQUE NOT NULL,Value TEXT NOT NULL)");
});
}
},
insertRecord: function (key, value) {
var db = this.getDb();
if (db) {
db.transaction(function (tx) {
tx.executeSql("INSERT INTO SampleTable (Key, Value) VALUES (?, ?)", [key, value],
function () {
},
function (tx, error) {
throw (error.message);
});
});
}
}
}
}();
Below is my unit test:
asyncTest("test1", function () {
raises(function () {
sql.initDb();
sql.insertRecord(null, null);
start();
},
"exception expected");
});
I'm expecting an exception to be thrown because the key and value parameters are not being supplied; however, when the test is finished executing, it says that no exception is thrown. While I'm not explicitly throwing an exception, one is raised because the dynamically generated sql statement can not be executed without supplying the key and value parameters.
Is it possible to write tests to account for these types of scenarios?
Why not test async exception test first? As far I see, your test is nothing to do with WebSQL.
Also qunit async test may require expect() before calling start(). If not, all test are just passed, without waiting async workflow.
Related
I have the code bellow. when I run the code I get the data is undefined. I do need the before hook because I use async code and describe does not support async. I this case the before hook is not being ran and the execution goes directly to the test loop. Is there any way I can fix this problem by seeding my data inside the before hook prior to the test loop execution or making the describe function to execute async code ?
describe("some function", () => {
var users
data;
before(async () => {
users = await getAllUsers();
data = [
//seeding data
]
});
data.forEach(({fName, lName}) => {
it(`${fName}`, async function () {
//test execution
})
})
})
I just started learning Jasmine test cases for angularjs. I am unable to test below code.Kindly help
$scope.getConstants = function(lovName) {
ConstantService.getConstants(lovName).then(function(d) {
switch (lovName) {
case 'WORKFLOW':
$scope.workflowTypes = d;
$scope.loadCounterpartyTmp();
break;
--------Other Cases
}
My ConstantService is defined as
App.factory('ConstantService', [ '$http', '$q', function($http, $q) {
return {
getConstants : function(lovName) {
return $http.post('/sdwt/data/getConstants/', lovName).then(function(response) {
return response.data;
}, function(errResponse) {
return $q.reject(errResponse);
});
}
I want to test getConstants function.I need to create a mock of ConstantService and pass the data to it.
I have written below test case but the test case is not working.Please let me know how to test the above code
describe('getConstantsForMurexEntity', function() {
it('testing getConstantsForMurexEntity function', function() {
var d=[];
d.push(
{id:1,value:'ABC'},
{id:2,value:'DEF'},
{id:3,value:'IJK'},
{id:4,value:'XYZ'},
);
//defined controller
spyOn(ConstantService, 'getConstants').and.returnValue(d);
$scope.getConstants('WORKFLOW');
expect($scope.workflowTypes).toBe(d);
The above test case is not working as it is saying "ConstantService.getConstants(...).then is not a function".
Your ConstantService.getConstants() function returns a promise, which your actual code is using, with the .then() call. This means means that when you spy on it, you also need to return a promise, which you are not doing. Because you are not returning a promise, when your actual call tries to call .then(), it is undefined, which is the reason for the error message.
Also, you aren't using Array.push correctly.
Your test should probably look something like the following (note, this is untested):
describe('getConstantsForMurexEntity', function() {
it('should set workflowTypes to the resolved value when lovName is "WORKFLOW"', inject(function($q) {
var deferred = $q.defer();
spyOn(ConstantService, 'getConstants').and.returnValue(deferred.promise);
var d = [
{id:1,value:'ABC'},
{id:2,value:'DEF'},
{id:3,value:'IJK'},
{id:4,value:'XYZ'},
];
$scope.getConstants('WORKFLOW');
deferred.resolve(d);
$scope.$apply();
expect($scope.workflowTypes).toBe(d);
}));
});
http://hapijs.com/tutorials/validation
I'd like to pass a function in to my validation block that checks for the presence of v as a source and confirms that account, profile and ipAddress are present. The docs say this is possible but don't have an example of using a function var to do it.
When I start up my API I get: Error: Invalid schema content: (account)
How can I use a named function to do validation in Hapi?
Code:
var validateQueryString;
validateQueryString = function(value, options, next) {
console.dir({
value: value,
options: options
});
// do some validation here
return next(null, value);
};
routes.push({
method: 'POST',
path: '/export/{source}/{start}/{end?}',
config: {
validate: {
query: {
account: validateQueryString,
profile: validateQueryString,
ipAddress: validateQueryString
},
params: {
source: joi.string().valid(['a', 'v', 't']),
start: joi.string().regex(utcDateTimeRegex),
end: joi.string().regex(utcDateTimeRegex)
}
}
},
handler: function(apiRequest, apiReply) {}
});
Tried other ways of calling this like:
account: function(value, options, next) {
return validateQueryString(value, options, next); }
with no luck.
I don't think you can have a single function to handle both at the same time.
Typically, the method for the full 'list' of query parameter. Here is a bit of code to illustrate:
function validateQuery(value, options, next){
console.log( 'validating query elements');
for (var k in value) {
console.log( k, '=', value[k]);
}
next(new Error(null, value);
}
And you set it as follow:
routes.push({
...
validate: {
query: validateQuery,
params: ...
}
...
}
Now, let's assume you hit http://server/myroute?a=1&b=2&c=3, you will get the following output:
validating query elements
a = 1
b = 2
c = 3
If you want to throw an error, you have to call next() as follow:
next( new Error('some is wrong'), value );
So the 'proper' way is to have a method for query and params, it seems.
Hope this helps.
I would recommend what you are doing is out of bounds of Joi's intent. Joi is targetted for schema validation against a JS object. What you want is runtime validation against rules that exist outside of the schema itself. Hapi has something built for this called server method. Leveraging server methods, you can apply your business validations there while separating the concerns of input model and output model shape validation through Joi.
Here are 2 samples of the same test. The only difference is that first one uses a promise in beforeAll block to assign a value to the variable while the second one assigns the value directly.
I raised a similar question Running spec after promise has been resolved with one of the comments pointing to this issue https://github.com/jasmine/jasmine/issues/412 which says that this is not supported in Jasmine. Has somebody figured out any workaround?
This fails with TypeError: Cannot read property 'forEach' of undefined
describe('Async car test', function () {
var cars;
beforeAll(function (done) {
// getCars() is a promise which resolves to ['audi', 'bmw']
getCars().then(function (data) {
cars = data;
console.log(cars) // ['audi', 'bmw']
done();
});
});
cars.forEach(function (car) {
it('car ' + car, function () {
expect(car).toBe(car);
});
});
});
This works fine
describe('Car test', function () {
var cars = ['audi', 'bmw'];
cars.forEach(function (car) {
it('car ' + car, function () {
expect(car).toBe(car);
});
});
});
Posting it as an answer, because I can't see things properly in comments.
I'm actually generating tests in my spec as well, and I'm using https://www.npmjs.com/package/jasmine-data-provider , I think you probably cannot generate it directly from resolved promise. And wrapping in another it doesn't work for you. This should work:
var using = require('jasmine-data-provider');
using(cars.forEach, function (car) {
it(car + ' should be' + car, function () {
expect(car).toBe(car);
});
});
This is not an issue with jasmine, it is an issue with your code.
beforeAll does not block subsequent code below the statement. it blocks code that is defined in it('should ...', (done)=>{...});
it('should have cars', (done) => {
cars.forEach(function (car) {
expect(car).toBe(car);
});
});
Since Jasmine does not support adding tests at runtime, the trick is to request the asynchronous data before starting Jasmine, and then using the retrieved data during runtime instead. This can be achieved with a singleton and programmatically starting Jasmine.
See here for a working example.
// car-collection.js
class CarCollection {
static load() {
return this.request()
then((data) => this.cars = data);
}
static request() {
// in practice this function would do something cooler
return Promise.resolve(['audi', 'bmw']);
}
}
modules.export = CarCollection;
Since CarCollection has methods that are static they will be shared across imports and this.cars will persist.
// launcher.js
const Jasmine = require('jasmine');
const CarCollection = require('./car-collection');
CarCollection.load()
.then(() => {
console.log(`car count is ${CarCollection.cars.length}`); // prints: car count is 2
const jasmine = new Jasmine();
jasmine.loadConfigFile(...); // path to jasmine.json
jasmine.execute();
});
An important step here is configure jasmine to know where to look for the test files. Either by loading a config or passing specifics into the execute function.
// car.spec.js
const CarCollection = require('./car-collection');
describe('test', function () {
CarCollection.cars.forEach((car) => {
it('test' + car, () => {
expect(car).toBe(car);
});
});
});
Now run node ./launcher.js and the tests should run.
I created a custom validator that check if a username is used on a DB.
The whole process of validation works. What is not working is result.
function createExistingUsernameValidator() {
var name = 'existingUsernameValidator';
var ctx = { messageTemplate: 'Questa partita I.V.A. o codice fiscale sono giĆ stati inseriti.', displayName: "Partita IVA o Codice Fiscale" };
var val = new Validator(name, valFunction, ctx);
return val;
function valFunction(value, context) {
var result = ko.observable(true);
require('services/datacontext').getIsUserByUsername(value, result)
.then(function () {
debugger;
return !result();
});
}
}
The promise works: I know because it hits the debbugger line and the retunrnig value is correct.
But the validator always evaluate as false because I'm not returning anything when the validator is called. In other words: it won't wait for the promise.
Is it my bad javascript or something else?
Any help is welcome.
Thank you!
Edited after answer
I've come to a solution that involves Knockout Validation (very useful script).
function createIsExistingUserKoValidation() {
ko.validation.rules['existingUsername'] = {
async: true,
validator: function (val, params, callback) {
if (val) {
var result = ko.observable();
require('services/datacontext').getIsUserByUsername(val, result)
.then(function () {
callback(!result());
});
}
},
message: ' Existing username.'
};
ko.validation.registerExtenders();
}
In the entity creation:
var createDitta = function () {
var ditta = manager.createEntity(entityNames.ditta,
{
id: newGuid(),
legaleRappresentante: createPersona(),
isAttiva: true
});
ditta.pivaCodFiscale.extend({ existingUsername: { message: ' Existing username.', params: true } });
ditta.pivaCodFiscale.isValidating(false);
return ditta;
};
ditta.pivaCodFiscale.isValidating(false); this is needed because isValidating is initialized with true.
The problem is that your valFunction as written will ALWAYS return 'undefined'. ( which is 'falsy'.
The 'return !result()' expression is NOT the return value of 'valFunction', it is simply the result of an anonymous function that executes AFTER valFunction has already returned. This is the async nature of promises.
What you are trying is to write an 'asynchronous' validation which is NOT supported out of the box with Breeze, but the idea IS a good one.
I think that you might be able to accomplish what you want by having your async callback actually 'set' a value on the entity and have that set operation itself trigger a seperate 'synchronous' validation.
This IS a good idea for Breeze to support more naturally so please feel free to add a feature request to the Breeze User Voice for something like "asynchonous validation". We use this to gauge the communities interest in the various proposed features/extensions to Breeze.