Trying to append timestamp to string but timestamp is undefined - node.js

I'm trying to build a test script using node.js. I am utilising assert and using the mocha testing framework for this. A feature of this is to be testing that registering a new user always returns 200. To do this, I've declared a timestamp using the following method:
var currentDate = new Date();
var timestamp = currentDate.getTime();
var testInvitee = {
"username": "name.lastname+11231232" + timestamp + "#company.com"
};
The idea is whenever I run the test the string should be different as the timestamp will change. When running mocha, however, I receive this response:
Testing registration
Register new user:
AssertionError [ERR_ASSERTION]: 403 === 400
+ expected - actual
-200
+400
at Context.it (test.js:596:28)
at <anonymous>
I've done a number of console.log() calls during the course of the script which revealed that the timestamp is undefined. See response body below:
Testing as System User.
undefined
Testing candidates
undefined
√ Get candidates (145ms)
//more code
Testing registration
undefined
13) Register new user
I'm not sure as to why the timestamp is undefined in this instance. I'm expecting it to be milliseconds since Jan 1, 1970 as it normally is. Is there anything I've missed out or done incorrectly? Perhaps there is a library I should be using? If it's not the timestamp causing the problem, I have to assume the problem is deeper in the API but I am certain this is not the case.
EDIT: Here is the code block from the describe it blocks in case I've caused a problem in here also:
describe('Testing registration', function () {
before(async () => {
await backend.authenticate();
});
it('Register new user', async () => {
const output = await backend.registerUser()
console.log("", backend.timestamp);
switch (userLevel) {
case "CLIENT_ADMIN":
assert.strictEqual(200, output.statusCode);
break;
case "ADMIN":
assert.strictEqual(200, output.statusCode);
break;
case "GROUP_ADMIN":
assert.strictEqual(200, output.statusCode);
break;
case "HR":
assert.strictEqual(200, output.statusCode);
break;
case "USER":
assert.strictEqual(200, output.statusCode);
break;
default:
console.log("No case match");
break;
}
});
})

The problem, most likely is in the scope.
Your code for declaring timestamp is correct. But the fact that on the tests the value is undefined tells us that the test scope does not have access to the scope where you defined the timestamp.
The easiest check for that would be too add the timestamp declaration right before it is used in the test.
Or just inline it:
var testInvitee = {
username: "name112233" + new Date().getTime() + "#company.com"
}
Other then that it is hard to tell without the full code. Plus why are you checking backend.timestamp with the console.log in the test?

Related

How to test correct data validation with Mocha using Loopback?

I'm setting up tests for already existing code. I want to test the creation of a database entry for an object, specifically how the create()-Method should behave when incorrect parameters are given. When trying to create the object with intentionally incorrect parameters, the Loopback upsert()-Method (which is used by our create()-Method) throws an error before I can assert the behaviour.
We're using Node, Express and Loopback for the Backend and Mocha with Chai as the testing suite. We're using the Loopback option "validateUpsert:true" in the Model of the object, which supposedly leads to throwing the aforementioned error.
The basic Model looks something like this:
{
"name": "Field",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"numberOfSpots": {
"type": "number",
"required": true
}
}
So my test case in Mocha looks like the code below. Note the comment next to numberOfSpots:
it('should return null upon entering false data', async() => {
// Given
const givenFieldData = {
numberOfSpots: 'two' // Using text instead of a number
}
// When
const newField = await Field.create(givenFieldData);
// Then
assert.isNull(newField);
});
Field.create(givenFieldData) basically calls this Loopback method after transforming givenFieldData into a Field-Object:
FieldModel.upsertWithWhere(where, Field)
.catch(error => logger.error(error))
.finally(return null);
Now I would expect that the assert runs but it is actually never executed. The finally block also does not seem to be executed. The console logs something like this:
ERROR (ValidationError/3844 on M): The instance `Field` is not valid. Details: `numberOfSpots` can't be blank (value: NaN).
Now the test fails although the behavior is correct, i.e. the object was not created. I need to find a way to check if the object was (correctly) not created and this should be reflected by a passing test. Thanks!
Field.create(givenFieldData) basically calls this Loopback method after transforming givenFieldData into a Field-Object:
FieldModel.upsertWithWhere(where, Field)
.catch(error => logger.error(error))
.finally(return null);
The first problem is in your Field.create method, it's effectively discarding errors and converting them to success result.
When an error occurs, your catch callback prints it to the console and implicitly returns undefined. As a result, the outer promise is eventually returned to undefined.
The value returned from finally callback is always ignored. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally.
Personally, I would not attempt to handle errors in your create method and leave error handling to callers.
class Field {
create() {
return FieldModel.upsertWithWhere(where, Field);
}
}
Then in the test, you should verify that create returns a promise that's eventually rejected with the expected error. For example, using should.js:
it('should return null upon entering false data', async() => {
// Given
const givenFieldData = {
numberOfSpots: 'two' // Using text instead of a number
}
Field.create(givenFieldData).should.be.rejectedWith(
/`numberOfSpots` can't be blank/
);
});
If you prefer to discard errors and return null, then you can implement Field.create as follows:
class Field {
async create() {
try {
return await FieldModel.upsertWithWhere(where, Field);
} catch(err) {
if (err.name !== 'ValidationError') {
// re-throw non-validation errors
// (e.g. cannot connect to the database)
throw err;
}
logger.error(error);
return null;
}
}
}

How to verify results of spied function (callThrough)

I want to verify/assert the results of spied function. I'm using nestjs framework with jasmine. I create a jasmine spy on a method i want to "spy" on, that is, eavesdrop args and response/exception. However, I can't access return value of spied method.
Let's say I have an emitter and listener and I want to assert that my listener throws an exception when a DB operation fails.
Listener:
onModuleInit() {
this.emitter.on('documentDeleted', d => this.onDocumentDeleted(d));
}
#CatchAndLogAnyException()
private async onDocumentDeleted(dto: DocumentDeletedEventDTO) {
this.logger.log(`Deleting document with id '${dto.id}'...`);
const result = await this.ResearchHearingTestModel.deleteOne({ _id: dto.id });
if (!result.ok) {
throw new DataAccessException(
`Deleting document with id '${dto.id}' failed. Model.deleteOne(id) result: ${result}`,
);
}
if (result.n < 1) {
throw new DocumentNotFoundException(`Deleting document with id '${dto.id}' failed.`);
}
this.logger.log(`Deleted document with id '${dto.id}.`);
}
Test:
const mockId = 123;
const spyDelete = spyOn(model, 'deleteOne').and.returnValue({ ok: 1, n: 0 });
const spyOnDeleted = spyOn(listener, 'onDocumentDeleted');
spyOnDeleted.and.callThrough();
await emitter.emit('documentDeleted', new DocumentDeletedEventDTO(mockId));
expect(spyOnDeleted).toHaveBeenCalledTimes(1);
expect(spyDelete).toHaveBeenCalledTimes(1);
expect(spyDelete).toHaveBeenCalledWith(expect.objectContaining({ _id: mockId }));
expect(spyOnDeleted).toThrow(DocumentNotFoundException);
So when debugging, I can see spyOnDeleted["[[Scopes]]"][0].spy.calls.mostRecent["[[Scopes]]"][0].calls[0].returnValue is a promise i'm probably looking for, but I can't access it or verify on it.
And when I run the test, this is the output:
expect(received).toThrow(expected)
Expected name: "DocumentNotFoundException"
Received function did not throw
95 | expect(spyDelete).toHaveBeenCalledTimes(1);
96 | expect(spyDelete).toHaveBeenCalledWith(expect.objectContaining({ _id: mockId }));
> 97 | expect(spyOnDeleted).toThrow(DocumentNotFoundException);
| ^
98 | });
99 | });
100 | });
I've seen CallThrough injected spy and several other questions that are similar, but I'm still hoping it's possible to spy on callThrough methods and eavesdrop on in/out of it. Any suggestions?
toThrow cannot be used on spies. You can use spies to mock behavior or use the actual behavior with callThrough and then make sure the method was called with specific parameters. But a spy will not have information about the result it produced (value or error) so you cannot set expectations on it.
If you want to test the behavior of onDocumentDeleted you have to either test it indirectly by observing the effects of the method. In your case (with #CatchAndLogAnyException), it seems to write to the log!? So you can spy on the log and expect it to be called with the error message. Or alternatively, you test the method directly by making it public.

Running Mocha multiple times with the same data produces different results

I have been noticing. With no discernible pattern, that sometimes I run my mocha tests and get a failed assertion. then I run it again immediately. Without making any changes and the assertions all pass. Is there something that I'm doing wrong. Is there test data that is cached?
I, unfortunately don't know what to post, since I can't seem to pin this down to any one thing but here is one function I've seen it happen to
mysqltest.js
describe('get_tablet_station_name', function() {
it ('isSuccessful', function() {
mysqlDao.init();
var callback = sinon.spy();
mysqlDao.get_tablet_station_name(state.TABLET_NAME, function(err, result) {
assert(err == undefined)
});
});
it ('isUnsuccessful', function() {
mysqlDao.init();
var callback = sinon.spy();
mysqlDao.get_tablet_station_name("'''%\0", function(err, result) {
assert(err != undefined);
});
});
});
When the assertions fail it is
assert(err != undefined);
err is returning null despite the bad SQL statement.
You should share the error you are getting when test case is getting failed.
But from you code and problem described, I can guess that your mysql calls must be taking time greater than the default timeout of mocha test cases. And while running your test case for the second time mysql must be returning data from cache hence preventing timeout.
To debug try increasing the default timeout of your test case, and for that use inside you describe call ->
describe('get_tablet_station_name', function() {
this.timeout(10000);
......//rest of the code
Please note this could not be the solution,please provide why assertion is getting failed if above mentioned thing do not work.

casperJS - grunt-casper: Running multiple Test-Suites in a loop

Preparation
Hi i am using CasperJS in combination with grunt-casper (github.com/iamchrismiller/grunt-casper) for running automated functional and regression tests in our GUI Development process for verification.
We use it like this, casper runner in gruntfile.js:
casper: {
componentTests: {
options: {
args: ['--ssl-protocol=any', '--ignore-ssl-errors=true', '--web-security=no'],
test: true,
includes: ['tests/testutils/testutils.js']
},
files: {
'tests/testruns/logfiles/<%= grunt.template.today("yyyy-mm-dd-hhMMss") %>/componenttests/concat-testresults.xml': [
'tests/functionaltests/componenttests/componentTestController.js']
}
},
so as it can be seen here we just normally run casper tests with SSL params and calling only ONE Controllerclass here instead of listing the single tests (this is one of the roots of my problem). grunt-casper delivers the object which is in charge for testing and inside every single Controllerclass the tests are included and concatenated....
...now the componentTestController.js looks like the following:
var config = require('../../../testconfiguration');
var urls = config.test_styleguide_components.urls;
var viewportSizes = config.test_styleguide_components.viewportSizes;
var testfiles = config.test_styleguide_components.testfiles;
var tempCaptureFolder = 'tests/testruns/temprun/';
var testutils = new testutils();
var x = require('casper').selectXPath;
casper.test.begin('COMPONENT TEST CONTROLLER', function(test) {
casper.start();
/* Run tests for all given URLs */
casper.each(urls, function(self, url, i) {
casper.thenOpen(url, function() {
/* Test different viewport resolutions for every URL */
casper.each(viewportSizes, function(self, actViewport, j) {
/* Reset the viewport */
casper.then(function() {
casper.viewport(actViewport[0], actViewport[1]);
});
/* Run the respective tests */
casper.then(function() {
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
});
});
});
});
casper.run(function() {
test.done();
});
});
Here you can see that we running a 3 level loop for testing
ALL URLs given in a JSON config file which are contained in an ARRAY of String ["url1.com","url2.com"....."urln.com"]
ALL VIEWPORT SIZES so that every URL is tested in our desired Viewport resolutions to test the correct Responsibility behaviour of the components
ALL TESTFILES, all testfiles only include a TEST STUB what means, no start, begin or something else, its all in a large Testsourrounding.
MAYBE this is already mocky and can be done in a bette way, so if this is the case i would glad if someone has proposals here, but don't forget that grunt-casper is involved as runner.
Question
So far, so good, the tool in general works fine and the construction we built works as we desired. But the problem is, because all testfiles are ran in a large single context, one failing component fails the whole suite.
In normal cases this is a behaviour i would support, but in our circumstances i do not see any proper solution than log the error / fail the single testcomponent and run on.
Example:
I run a test, which is setUp like described above and in this part:
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
we include 2 testfiles looking like the following:
Included testfile1.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Atoms']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
casper.click(x("//a[normalize-space(text())='Atoms']"));
},
function fail() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
});
});
Included testfile2.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Buttons']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
casper.click(x("//a[normalize-space(text())='Buttons']"));
},
function fail() {
testutils.createErrorScreenshot('#menu > li.active > ul > li:nth-child(7)', tempCaptureFolder, casper, 'BUTTONGROUPS#2-buttons-menu-does-not-exist.png');
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
});
});
So if the assert in testfile1.js fails, everthing failes. So how can i move on to testfile2.js, even if the first fails? Is this possible to configure? Can it be encapsulated somehow?
FYI, this did not work:
https://groups.google.com/d/msg/casperjs/3jlBIx96Tb8/RRPA9X8v6w4J
Almost similar problems
My problem is almost the same like this here:
https://stackoverflow.com/a/27755205/4353553
And this guy here has almost another approach i tried but got his problems too because multiple testsuites ran in a loop occuring problems:
groups.google.com/forum/#!topic/casperjs/VrtkdGQl3FA
MUCH THANKS IN ADVICE
Hopefully I understood what you ware asking - is there a way to suppress the failed assertion's exception throwing behavior?
The Tester's assert method actually allows for overriding the default behavior of throwing an exception on a failed assertion:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
test.assert(false, message, { doThrow: false });
Not all assert helpers have this option though and the only other solution I can think of is catching the exception:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
try {
test.assertEquals(true, false, message);
} catch (e) { /* Ignore thrown exception. */ }
Both of these approaches are far from ideal since the requirement in our cases is to not throw for all assertions.
Another short term solution that requires overriding the Tester instance's core assert method is (but is still quite hacky):
// Override the default assert method. Hopefully the test
// casper property doesn't change between running suites.
casper.test.assert =
casper.test.assertTrue = (function () {
// Save original assert.
var __assert = casper.test.assert;
return function (subject, message, context) {
casper.log('Custom assert called!', 'debug');
try {
return __assert.apply(casper.test, arguments);
}
catch (error) {
casper.test.processAssertionResult(error.result);
return false;
}
};
})();
That said, I'm currently looking for a non-intrusive solution to this "issue" (not being able to set a default value for doThrow) as well. The above is relative to Casper JS 1.1-beta3 which I'm currently using.

Node.js Cron Job Messing with Date Object

I'm trying to schedule several cron jobs to generate serial numbers for different entities within my web app. However I am running into this problem, when I'm looping each table, it says it has something to do with date.js. I'm not doing anything with a date object ? Not at this stage anyway. A couple of guesses is that the cron object is doing a date thing in its code and is referencing date.js. I'm using date.js to get access to things like ISO date.
for (t in config.generatorTables) {
console.log("t = " + config.generatorTables[t] + "\n\n");
var ts3 = azure.createTableService();
var jobSerialNumbers = new cronJob({
//cronTime: '*/' + rndNumber + ' * * * * *',
cronTime: '*/1 * * * * *',
onTick: function () {
//console.log(new Date() + " calling topUpSerialNumbers \n\n");
manageSerialNumbers.topUpSerialNumbers(config.generatorTables[t], function () { });
},
start: false,
timeZone: "America/Los_Angeles"
});
ts3.createTableIfNotExists(config.generatorTables[t], function (error) {
if (error === null) {
var query = azure.TableQuery
.select()
.from(config.generatorTables[t])
.where('PartitionKey eq ?', '0')
ts3.queryEntities(query, function (error, serialNumberEntities) {
if (error === null && serialNumberEntities.length == 0) {
manageSerialNumbers.generateNewNumbers(config.maxNumber, config.serialNumberSize, config.generatorTables[t], function () {
jobSerialNumbers.start();
});
}
else jobSerialNumbers.start();
});
}
});
}
And this is the error message I'm getting when I examine the server.js.logs\0.txt file:
C:\node\w\WebRole1\public\javascripts\date.js:56
onsole.log('isDST'); return this.toString().match(/(E|C|M|P)(S|D)T/)[2] == "D"
^
TypeError: Cannot read property '2' of null
at Date.isDST (C:\node\w\WebRole1\public\javascripts\date.js:56:110)
at Date.getTimezone (C:\node\w\WebRole1\public\javascripts\date.js:56:228)
at Object._getNextDateFrom (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:88:30)
at Object.sendAt (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:51:17)
at Object.getTimeout (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:58:30)
at Object.start (C:\node\w\WebRole1\node_modules\cron\lib\cron.js:279:33)
at C:\node\w\WebRole1\server.js:169:46
at Object.generateNewNumbers (C:\node\w\WebRole1\utils\manageSerialNumbers.js:106:5)
at C:\node\w\WebRole1\server.js:168:45
at C:\node\w\WebRole1\node_modules\azure\lib\services\table\tableservice.js:485:7
I am using this line in my database.js file:
require('../public/javascripts/date');
is that correct that I only have to do this once, because date.js is global? I.e. it has a bunch of prototypes (extensions) for the inbuilt date object.
Within manageSerialNumbers.js I am just doing a callback, their is no code executing as I've commented it all out, but still receiving this error.
Any help or advice would be appreciated.
Ok I've commented out the date.js module and now I'm getting this error:
You specified a Timezone but have not included the time module. Timezone functionality is disabled. Please install the time module to use Timezones in your application.
When I examine the cron.js module it has this statement at the top:
var CronDate = Date;
try {
CronDate = require("time").Date;
} catch(e) {
//no time module...leave CronDate alone. :)
}
So this would conclude then that it does have something to do with the date.js module ?
Anyone see whats wrong.
cheers
I was using date.js for a while, and then realized that the Date object in Node.js/V8 already had ISO support, input and output, and Date.js only added a very specific edge case. What exactly do you need date.js for?
If you do need date.js...
is that correct that I only have to do this once, because date.js is global?
That's true as long as the code is running in the same process. I'm not familiar Node.js on Azure, or the library providing the cronJob method you're using, but perhaps it spawns a new process, which has its own V8 instance, and then you lose the Date object changes? (So require it again in that code.)

Resources