I am adding some qunit test cases for a module. Few of the test cases have sync processes which I am using the standard stop() and start() as per docs.
My questions is, isn't the fact that the extra 1 second from setTimeout(function () { start();}, 1000); is added to the runtime of the test run, making the results in accurate?
I am a little not satisfied that +1000ms is added to the runtime as outside of the testsuite, inside the real app that uses that module that process completes without the 1000ms added here to carry out the test.
So when I pass this interface to less technical tester I have to explain in the title of the test to subtract that 1000 from that test before adding them up or whatever to calculate overall speed etc. [I basically want a way to have that extra timeout removed from the results automatically]
Module code below:
define("tests/admin.connections.tests", ["mods/admin.connections", "datacontext"], function (connections, datacontext) {
module("ADMIN PAGE CONNECTION LIST MODULE", {
setup: function () {
//ok(true, "once extra assert per test for Search Modules");
}
});
test('Module is available?', function () {
equal(_.isUndefined(connections), false, "connections js module exists");
equal(_.isObject(connections), true, "connections js module is valid object");
});
test('HTML and CSS loading correctly? [Subtract 1 second from time to get the real time lapsed]', function () {
function testHtml(html) {
var d = document.createElement('htmlTestDiv');
d.innerHTML = html;
return d.innerHTML.replace(/\s+/g, ' ');;
}
stop();
$.get('http://media.concepglobal.com/cbaddons/templates/connections.html', function (data) {
equal(testHtml(connections.html), data.replace(/\s+/g, ' '), 'Html of the module was correctly loaded');
});
$.get('http://media.concepglobal.com/cbaddons/styles/connections.css', function (data) {
equal(testHtml(connections.css), data.replace(/\s+/g, ' '), 'CSS of the module was correctly loaded');
});
setTimeout(function () { start();}, 1000);
});
test('getConnectionsByUserId Async Method [Subtract 1 second from time to get the real time lapsed]', function () {
function getConnectionsByUserId(successCallback) {
amplify.request("getConnectionsByUserId", { uid: '0' }, function (data) {
connections.userConnectionsCallback(data);
successCallback();
});
}
stop();
getConnectionsByUserId(function () {
var connectionsReturnedData = connections.connectionListViewModel.connections();
expect(2);
ok(_.isArray(connectionsReturnedData), 'Valid array has been returned for connections: ' + connectionsReturnedData);
equal(connectionsReturnedData[0].type(), "sitecore", 'First returned object has a type property of "' + connectionsReturnedData[0].type() + '" and we expected it to be "sitecore"');
});
setTimeout(function () { start(); }, 1000);
});
});
QUnit saves the currently running test in QUnit.config.current, this allows you to change the test during it's execution.
What you probably want is to reset the timer of the test after the timeout.
I created a little example to show what I mean (see on jsFiddle):
asyncTest("Long running test with 2s timeout", function () {
expect(1);
ok(true);
setTimeout(function () {
QUnit.config.current.started = +new Date();
start();
}, 2000);
});
Like that the timer is reset once the timeout is over. This results in more accurate runtime in terms of what is executed. Now only the total time shows how much time was actually used to run all tests.
Related
I have a page that has an element where if you scroll down, it loads new data.
This takes about 10 seconds.
I have written the following test:
it('Should display at least one facility in booking panel', (done) => {
function recursivelyScroll() {
cy.get(element)
.scrollTo('bottom');
cy.get(element)
.then($el => {
// If the element contains a loading class, we wait one second and scroll down again
if ($el.find(Loading).length > 0) {
setTimeout(recursivelyScroll, 1000);
} else {
// We are done waiting, no more loading is needed
// write test here
done();
}
});
}
recursivelyScroll();
});
CypressError
Timed out after 4000ms. The done() callback was never invoked!
The done() method is not called fast enough according to Cypress, but they have no documentation on how to extend the done time period. Also, there might be a better way that I'm unaware of to create this scrollbehaviour in Cypress. Is there an easy fix?
Have you tried using the recursion plugin in cypress?
It would look something like this:
cy.get(element).scrollTo('bottom');
recurse(
() => cy.contains('element', 'Loading').should(() => {}),
($quote) => $quote.length > 0 ,
{
limit: 300,
log: false,
post(){
setTimeout(recursivelyScroll, 1000);
}
},
)
The idea was taken here: https://www.youtube.com/watch?v=KHn7647xOz8
Here example how to use and install https://github.com/bahmutov/cypress-recurse
Try to switch to When assertion and declare that function outside the execution:
When('Should display at least one facility in booking panel', (done) => {
recursivelyScroll(done)
}
function recursivelyScroll(done){
//see implementation below
}
Not sure how about which "Loading" is, maybe you have to put into double quotes?
Moreover please note that cypress is asynchronous, then the scrollTo and the then code sections are executed at same time in your code, just use then after the scroll.
And I will change the setTimeout into cy wait function before executing recursion, give a try to below code:
function recursivelyScroll(done) {
cy.get(element)
.scrollTo('bottom')
.then($el => {
// If the element contains a loading class, we wait one second and scroll down again
if ($el.find(".Loading").length > 0) {
cy.wait(1000).then(()=>{
recursivelyScroll(done);
})
} else {
// We are done waiting, no more loading is needed
// write test here
done();
}
});
}
I am running a HTTP Request to a file and depending on the response whether it be "200" or another response a success or error function is ran. This request takes place every second.
The problem I am facing is when I get lots of error responses they all run together and the last one doesn't stop e.g. End the interval to start a new one.
The red light begins to flash way too fast. Can anyone help me out. My code is below and I have been playing with it for a few hours now but can't seem to get to the bottom of it.
var requestResponses = {
greenLight: $('.cp_trafficLight_Light--greenDimmed'),
redLight: $('.cp_trafficLight_Light--redDimmed'),
greenBright: 'cp_trafficLight_Light--greenBright',
redBright: 'cp_trafficLight_Light--redBright',
init: function (url) {
setInterval(function () {
requestResponses.getResponse(url);
}, 1000);
},
successResponse: function () {
var redBright = requestResponses.redBright,
greenBright = requestResponses.greenBright;
requestResponses.errorCode = false;
requestResponses.redLight.removeClass(redBright);
requestResponses.greenLight.addClass(greenBright);
},
errorResponse: function () {
requestResponses.runOnInterval();
},
runOnInterval: function () {
// clearInterval(runInterval);
var redBright = requestResponses.redBright,
greenBright = requestResponses.greenBright,
redLight = requestResponses.redLight;
requestResponses.greenLight.removeClass(greenBright);
var runInterval = setInterval(function () {
if (requestResponses.errorCode === true) {
redLight.toggleClass(redBright);
}
}, 400);
},
getResponse: function (serverURL) {
$.ajax(serverURL, {
success: function () {
requestResponses.errorCode = false;
requestResponses.successResponse();
},
error: function () {
requestResponses.errorCode = true;
requestResponses.errorResponse();
},
});
},
errorCode: false
}
requestResponses.init('/status');
Appreciate the help.
Javascript is an event driven language. Do not loop inifinitely to check things periodically. There are places to do so but most of the time either calling a delay function (setTimeout) repeatedly when needed or using a callback would be better method.
Using setInterval with request, think what happens if requests start taking longer than your interval.
In your case, you have two loops created with setInterval. First one is the request which will run every 1 sec. Instead of using setInterval, you can modify your code to run setTimeout only after a request finishes and do other tasks just before re-running the next request :
function runRequest(...) {
$.ajax(serverURL, {
...
complete: function () {
setTimeout(runRequest, 1000);
}
...
});
}
function lightsOnOff() {
var redBright = requestResponses.redBright,
greenBright = requestResponses.greenBright,
redLight = requestResponses.redLight;
requestResponses.greenLight.removeClass(greenBright);
if (requestResponses.errorCode === true) {
redLight.toggleClass(redBright);
}
}
setInterval(lightsOnOff, 400);
The setInterval() method repeats itself over and over, not just one time. Your error response handler is then invoking the routine that creates another setInterval(), and so on. Until you have so many processes running that you get the flashing red light issue.
The solution is to only invoke the logic where the setInterval() call is made once. Or, even better, use setTimeout() to call the routine. It is run one-time and likely better for your use.
I am trying to control the inflow for a slow subscriber. Tried the below in NodeJS
var xmlNodeStream = Rx.Observable.from([1,2,3,4,5,6,7,8,9,10,11]);
var commJson = xmlNodeStream.bufferWithCount(2).publish();
var FastSubscriber = commJson.subscribe(
function (x) { console.log('----------\nFastSub: onNext: %s', x); },
function (e) { console.log('FastSub: onError: %s', e); },
function () { console.log('FastSub: onCompleted'); });
var slowSubscriber = commJson.subscribe(function (x) {
setTimeout(function () { console.log("============\nSlowsub called: ", x); }, 5000);
});
commJson.connect();
When I run the above code, I would expect the slow subscriber to pause for 5 seconds everytime before next data-batch is received.
But that is not happening. After an initial 5 second delay, all data is flooded to slowSubscriber in batches of 2.
What is the right way to control the inflow so that slow subscibers can take their time (and preferably fast ones can wait for the slow ones to complete) ?
It isn't pausing because setTimeout will not block execution it just schedules work to be done at a later time, i.e. after 2 seconds, then more data comes in and it gets scheduled for 2 seconds + some tiny delta from now. The result being that the fast and slow subscriber will finish at the same time, but the results of slow subscriber won't be visualized until 2 seconds later.
If the slow subscriber in your actual use case is really non-blocking then you have two options for controlling the flow of the events, either you need to control the flow from the source of the messages, where ever that may be. Or you need to use one of the back pressure operators like controlled()
var xmlNodeStream = Rx.Observable.from([1,2,3,4,5,6,7,8,9,10,11]);
var controller = xmlNodeStream.bufferWithCount(2).controlled();
var commJson = controller.publish().refCount();
var FastSubscriber = commJson.subscribe(
function (x) { console.log('----------\nFastSub: onNext: %s', x); },
function (e) { console.log('FastSub: onError: %s', e); },
function () { console.log('FastSub: onCompleted'); });
var slowSubscriber = commJson.subscribe(function (x) {
setTimeout(function () {
console.log("============\nSlowsub called: ", x);
controller.request(1);
}, 5000);
});
commJson.request(1);
I'm trying to use selenium-webdriver in Node to crawl Google finance pages. The driver.wait function does not appear to work as expected. I have set my mocha timeout to be 10 seconds and the driver.wait timeout be 9 seconds. The test passes about half of the time, but when it fails, it doesn't take anywhere near 9 seconds to fail - it actually fails in about 1 second and then takes another 8 before closing the test. I'm obviously missing something, but I've included the commented-out iterations of different things I've tried in order to make this work (including setTimeout). If anyone can help me see the error in my thinking, I would be much obliged. Here's the code:
(function () {
var assert = require("chai").assert;
var webdriver = require("selenium-webdriver");
var urlGoogleFinanceRoot = "https://www.google.com/finance";
describe("Selenium", function () {
it("should fetch a couple of pages and keep all of the content", function (done) {
var driver = new webdriver.Builder().withCapabilities(webdriver.Capabilities.chrome()).build();
webdriver.promise.controlFlow().on("uncaughtException", function (e) {
console.error("Error1: " + e);
});
// driver.get(urlGoogleFinanceRoot + "?q=BAC").then(function () {
// return setTimeout(function () {
// return driver.findElement(webdriver.By.xpath("//table[#class='snap-data']")).isDisplayed();
// }, 9000).then(function (isDisplayed) {
// assert.isTrue(isDisplayed);
// driver.quit();
// done();
// });
// });
// driver.wait(function () {
// return driver.get(urlGoogleFinanceRoot + "?q=BAC").then(function () {
// return driver.wait(function () {
// return driver.findElement(webdriver.By.xpath("//table[#class='snap-data']")).isDisplayed();
// }, 9000);
// });
// }, 9000).then(function (isDisplayed) {
// assert.isTrue(isDisplayed);
// driver.quit();
// done();
// });
// driver.wait(function(){
// return driver.get(urlGoogleFinanceRoot + "?q=BAC").then(function(){
// return driver.findElement(webdriver.By.xpath("//table[#class='snap-data']")).isDisplayed();
// });
// },5000).then(function(isDisplayed){
// assert.isTrue(isDisplayed);
// driver.quit();
// done();
// });
driver.get(urlGoogleFinanceRoot + "?q=BAC").then(function () {
driver.wait(function () {
return driver.findElement(webdriver.By.xpath("//table[#class='snap-data']")).isDisplayed();
}, 9000).then(function (isReady) {
assert.isTrue(isReady);
driver.quit();
done();
});
});
});
});
})();
and here's the output:
Selenium
Error1: NoSuchElementError: no such element
(Session info: chrome=44.0.2403.107)
(Driver info: chromedriver=2.16.333243 (0bfa1d3575fc1044244f21ddb82bf870944ef961),platform=Linux 3.16.0-4-amd64 x86_64)
1) should fetch a couple of pages and keep all of the content
0 passing (10s)
1 failing
1) Selenium should fetch a couple of pages and keep all of the content:
Error: timeout of 10000ms exceeded. Ensure the done() callback is being called in this test.
from this doc I understand that when you provide a function, it waits until the promise is resolved, but guessing that it is run only once, so you gotto try something like:
driver.get(urlGoogleFinanceRoot + "?q=BAC").then(function () {
driver.wait(webdriver.until.elementLocated(webdriver.By.xpath("//table[#class='snap-data']")), 9000)
.then(...
I am developing a web interface for Arduino, using Python. For automatic updates and display, I use JSON. I have a very interesting problem.
The following code sends the command to a python function, if a command exists. Then, whether a command was sent to the function or not, the function checks for updates from the Arduino by calling another function.
Here is what I can't find any explanation to: in the first and only condition of the update() function, if I remove the line that says alert('hey'); the python function is not called anymore. But if I do write alert('hey'); after the JSON request, it works fine, the function is called and the arduino gets the message.
Anyone has an idea why?
function update(command=0) {
// if a command is passed, send it
if (command!=0) {
$.getJSON('/action?command='+command);
alert('hey'); // if I remove this, the action function is not called. Why?
}
// read from the read function, no matter what
$.getJSON('/read', {}, function(data) {
if (data.state != 'failure' && data.content != '') {
$('.notice').text(data.content);
$('.notice').hide().fadeIn('slow');
setTimeout(function () { $('.notice').fadeOut(1000); }, 1500);
}
setTimeout(update, 5000); // next update in 5 secs
});
}
update(); // for the first call on page load
Are you checking for the results of the first command with the second? If so, I suspect the alert('hey') is pausing execution long enough for the first to finish. Can you try making your read a callback function of the first getJSON?
function update(command=0) {
if (command!=0) {
$.getJSON('/action?command='+command, function() {
read();
});
} else {
read();
}
}
function read() {
$.getJSON('/read', {}, function(data) {
if (data.state != 'failure' && data.content != '') {
$('.notice').text(data.content);
$('.notice').hide().fadeIn('slow');
setTimeout(function () { $('.notice').fadeOut(1000); }, 1500);
}
setTimeout(update, 5000); // next update in 5 secs
});
}
update(); // for the first call on page load
Here's a fiddle