I am using JMeter Webdriver sampler for the application UI response time measurement. I am facing issue with the wait function. For example the login page loads between 10 to 120 secs. So I have the following code for the login page in Webdriver sampler for the page load check.
var ui=JavaImporter(org.openqa.selenium.support.ui)
var wait=new support_ui.WebDriverWait(WDS.browser,120)
wait.until(ui.ExpectedConditions.visibilityOfElementLocated(pkg.By.className('logout-btn-hover')))
The issue is even after the page load completely, JMeter is still waiting to perform the next action. This waiting time will reduce if I reduce the 120 secs.But sometimes the application will take 120 secs to load also so I need to keep 120 secs.
I am writing the time to a log file once the sampler completes its action. Because of the wait time issue I am not able to calculate time properly.
There are at least 2 errors in your script, it should look something like:
var ui=JavaImporter(org.openqa.selenium.support.ui)
var wait=new ui.WebDriverWait(WDS.browser,120)
wait.until(ui.ExpectedConditions.visibilityOfElementLocated(org.openqa.selenium.By.className('logout-btn-hover')))
Check out jmeter.log file for any suspicious entries, in particular for something like:
ERROR c.g.j.p.w.s.WebDriverSampler: Expected condition failed: waiting for visibility of element located by By.className: logout-btn-hover (tried for 120 second(s) with 500 milliseconds interval)
Double check your CSS selector
Consider refactoring your code to look for the logout button(?) in a loop with verbose logging for each step. Sample code:
var pkg = JavaImporter(org.openqa.selenium)
WDS.sampleResult.sampleStart()
WDS.browser.get('http://example.com')
var start = new Date().getTime()
var attempt = 1
while (new Date().getTime() - start < 5000) {
try {
var logout = WDS.browser.findElement(pkg.By.className('logout-btn-hover'))
WDS.log.info('Element found')
break
}
catch (err) {
WDS.log.info('Attempt # ' + attempt + ', Element not found')
java.lang.Thread.sleep(1000)
attempt++
}
}
WDS.sampleResult.sampleEnd()
Example output when the element is not found:
Example output when the element is found:
Check out The WebDriver Sampler: Your Top 10 Questions Answered article for more information on using WebDriver sampler in JMeter scripts.
Related
I used JMeter. Try to automate one site using JavaScript.
WDS.sampleResult.sampleStart()
var support_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait)
var wait = new support_ui.WebDriverWait(WDS.browser, 5000)
WDS.browser.get('http://mobile.yellow.com.au')
WDS.sampleResult.sampleEnd()
When execute then got the below error. How it is resolved? and also please let me know how implicit /explicit wait is used to locate all elements and not thows org.openqa.selenium.NoSuchElementException .
Error --> javax.script.ScriptException: TypeError: Can not create new object with constructor org.openqa.selenium.support.ui.WebDriverWait with the passed arguments; they do not match any of its method signatures. in <eval> at line number 3
(Build info: version: '3.14.0', revision: 'aacccce0', time: '2018-08-02T20:19:58.91Z')
Here is a working example from The WebDriver Sampler: Your Top 10 Questions Answered article:
var pkg = JavaImporter(org.openqa.selenium)
var support_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait)
var conditions = org.openqa.selenium.support.ui.ExpectedConditions
var wait=new support_ui.WebDriverWait(WDS.browser, 5000)
WDS.sampleResult.sampleStart()
WDS.browser.get('http://example.com')
wait.until(conditions.presenceOfElementLocated(pkg.By.linkText('More finformation...')))
var element=WDS.browser.findElement(pkg.By.linkText("More information..."))
element.click()
WDS.sampleResult.sampleEnd()
and official documentation on WebDriver Waits
Your how implicit /explicit wait is used to locate all elements and not thows org.openqa.selenium.NoSuchElementException stanza doesn't make any sense, you should either use explicit wait to "wait" for a specific element to appear/disappear/become clickable/whatever or just go for implicit wait so WebDriver will automatically will "wait" for the element for specified amount of time before failing.
"All elements" is not something you can get using selectors, you can have list of locators and verify their presence at the page but not more.
I'm executing JMeter task for a few hours on a server,
I want to be able to pause execution for a few seconds/minutes and resume when server finish restarted
Is there a way to signal JMeter to pause and resume its execution?
I saw similar question, but it doesn't fit my issue
As of current JMeter version 5.3 there is no way to accomplish your "issue" with built-in JMeter components.
The easiest solution I can think if is: given you're restarting your server it should be not available for some time and when it becomes available - it should respond with a HTML page containing some text.
So you can "wait" for the server to be up and running as follows:
Add JSR223 Sampler to the appropriate place in the Test Plan where you need to "wait' for the server to be up and running
Put the following code into "Script" area:
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.util.EntityUtils
SampleResult.setIgnore()
def retry = true
def requestConfig = RequestConfig.custom().setConnectTimeout(1000).setSocketTimeout(1000).build()
def httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build()
while (retry) {
def httpGet = new HttpGet('http://jmeter.apache.org')
try {
def entity = httpClient.execute(httpGet).getEntity()
if (EntityUtils.toString(entity).contains('Apache JMeter')) {
log.info('Application is up, proceeding')
retry = false
} else {
log.info('Application is still down, waiting for 5 seconds before retry')
sleep(5000)
}
}
catch (Throwable ex) {
sleep(5000)
ex.printStackTrace()
}
}
That's it, the code will try to open the web page and look for some text in it, if the page doesn't open and/or text is not present - it will wait for 5 seconds and retry
More information:
HttpClient Quick Start
Apache Groovy - Why and How You Should Use It
I would like to test my "waiting for server reply" UI behavior. How do I do that reliably without pausing my test for a hardcoded delay?
Say, I have a button that triggers an http request and has to show certain animation / actions until the response arrives.
A dumb working method is:
cy.route({
delay: 1000,
response: "blah blah",
})
// triggger submission
cy.get('#my-submit-button').click()
// will disappear upon receiving response
cy.contains('Waiting for response...')
I am pretty much sure that the "waiting" text will appear within a second while the response paused, but then I commit the sin of pausing the test for a whole second.
If I start to shorten or remove the delay then I am running a risk of creating flaky tests since there's a chance the response would be processed before I check for the existence of the "Waiting..." text, which would've been removed by that moment.
Is there a way to ensure the response is produced only after the check for the "Waiting..." text without a hard delay?
I naïvely tried to do a cypress assertion from the route's onResponse, but cypress wasn't happy about that:
cy.route({
onResponse: xfr => {
cy.contains('Waiting for response...')
return xfr
},
response: "blah blah",
})
cy.get('#my-submit-button').click()
producing the https://on.cypress.io/returning-promise-and-commands-in-another-command error:
Error: Uncaught CypressError: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
The command that returned the promise was:
> cy.click()
The cy command you invoked inside the promise was:
> cy.contains()
Because Cypress commands are already promise-like, you don't need to wrap them or return your own promise.
Cypress will resolve your command with whatever the final Cypress command yields.
The reason this is an error instead of a warning is because Cypress internally queues commands serially whereas Promises execute as soon as they are invoked. Attempting to reconcile this would prevent Cypress from ever resolving.
Could this work?
cy.route({
delay: 1000,
response: "blah blah",
}).as('getResponse')
cy.wait('getResponse')
https://docs.cypress.io/guides/guides/network-requests.html#Waiting
You could record the time these things happen using cy.moment(), then compare it afterwards using .isBefore() or one of the other moment functions.
I'm using onResponse here to record the time the response comes in.
let timeDisappeared;
let timeResponded;
cy.route({
delay: 1000,
response: "blah blah",
onResponse: () => {
timeResponded = Cypress.moment()
}
})
// triggger submission
cy.get('#my-submit-button').click()
// waits for the text to appear
cy.contains('Waiting for response...').should('exist')
// waits for the text to disappear
cy.contains('Waiting for response...').should('not.exist').then(() => {
timeDisappeared = Cypress.moment()
})
expect(timeResponded.isBefore(timeDisappeared))
After saw your comment and check the other answers
I think Bredan's answer is the best solution to do this. You can
stub a response with delay: x seconds
check the text to appear. Record the time: timeAppear
check the text to disappear. Record the time: timeDisappear
Check if timeDisappear - timeAppear > x seconds
or Check timeDisappear - timeAppear - x seconds > certain seconds(You can define the tolerance)
This proves the text shows in the given response time.
You can extend the response Delay to longer value.
I modified Bredan's answer a bit to reflect the steps above,
let timeAppear;
let timeDisappear;
//delay the response to come back after 20 seconds
cy.route({
delay: 20000,
response: "blah blah"
})
// triggger submission
cy.get('#my-submit-button').click()
// waits for the text to appear and record the time starts.
cy.contains('Waiting for response...').should('exist').then(() => {
timeAppear = Cypress.moment()
})
// waits for the text to disappear and record the time ends
// add timeouts option here to make sure it is longer than delay
cy.contains('Waiting for response...',{timeout:30000}).should('not.exist').then(() => {
timeDisappear = Cypress.moment();
//check the time is above the delay time 2000 ms
expect(timeDisappear - timeAppear).to.be.above(20000);
//or check the tolerance value e.g.5000 ms
expect(timeDisappear - timeAppear - 20000).to.be.below(5000);
})
I have a requirement where I need to verify that when I open a web page, there should less than 10 stylesheets and less than 20 .js are loading. Is there a way to do this in Jmeter?
It is, but you will need to do some scripting. Example solution:
Add Beanshell Assertion as a child of the HTTP Request you need to test.
Put the following code into the Beanshell Assertion "Script" area:
import org.apache.jmeter.samplers.SampleResult;
int js, css;
js = css = 0;
for (SampleResult subResult : SampleResult.getSubResults()) {
if (subResult.getUrlAsString().endsWith(".css")) {
css++;
} else if (subResult.getUrlAsString().endsWith(".js")) {
js++;
}
}
log.info("JS files: " + js); // you can comment or remove these lines
log.info("CSS files: " + css); // as they do nothing but print the numbers to jmeter.log
if (css > 10 || js > 20) {
Failure = true;
FailureMessage = "Exceeded maximum scripts/styles";
}
If any of the specified thresholds will be met, the sampler will get failed with the relevant message:
More information on conditionally failing JMeter tests: How to Use JMeter Assertions in Three Easy Steps
I have something like a microtime() function at the very start of my node.js / express app.
function microtime (get_as_float) {
// Returns either a string or a float containing the current time in seconds and microseconds
//
// version: 1109.2015
// discuss at: http://phpjs.org/functions/microtime
// + original by: Paulo Freitas
// * example 1: timeStamp = microtime(true);
// * results 1: timeStamp > 1000000000 && timeStamp < 2000000000
var now = new Date().getTime() / 1000;
var s = parseInt(now, 10);
return (get_as_float) ? now : (Math.round((now - s) * 1000) / 1000) + ' ' + s;
}
The code of the actual app looks something like this:
application.post('/', function(request, response) {
t1 = microtime(true);
//code
//code
response.send(something);
console.log("Time elapsed: " + (microtime(true) - t1));
}
Time elapsed: 0.00599980354309082
My question is, does this mean that from the time a POST request hits the server to the time a response is sent out is give or take ~0.005s?
I've measured it client-side but my internet is pretty slow so I think there's some lag that has nothing to do with the application itself. What's a quick and easy way to check how quickly the requests are being processed?
Shameless plug here. I've written an agent that tracks the time usage for every Express request.
http://blog.notifymode.com/blog/2012/07/17/profiling-express-web-framwork-with-notifymode/
In fact when I first started writing the agent, I took the same approach. But I soon realized that it is not accurate. My implementation tracks the time difference between request and the response by substituting the Express router. That allowed me to add tracker functions. Feel free to give it a try.