为什么点击处理程序在 Leadfoot 中不 运行?
Why does a click handler NOT run in Leadfoot?
我正在尝试使用 Intern framework which uses Leadfoot 库编写功能测试以实现 WebDriver API 因为我正在使用 Selenium Grid 设置在远程浏览器上测试我的 webapp。该应用程序已经启动 运行。
我使用的功能测试如下:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
var url = '...';
var server = '...';
tdd.suite("Init suite",function(){
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Checking servers', function () {
var that = this.remote;
return that
.setFindTimeout(15000)
.get(url)
.findById('linkservers')
.click()
.then(function(){
console.log("Click resolved");
})
.end()
.findDisplayedByClassName('server-name-span-text')
.getVisibleText()
.then(function(texts){
var t=0;
var tlen = 0;
if (Array.isArray(texts))
{
tlen = texts.length
for (t=0;t<tlen;t++)
console.log("server["+t+"]: "+texts[t]);
assert.strictEqual(texts[0],server,"server is: "+texts[0]);
} else {
assert.strictEqual(texts,server,"server is: "+texts[0]);
}
})
.end();
});
});
});
为了开始我的测试,我使用了实习生:./node_modules/.bin/intern-runner config=tests/intern.cfg -reporters=Runner
我的问题的本质是 findDisplayedByClassName('server-name-span-text')
找不到 class 名称,即使我正在使用等待元素显示的 findDisplayed
调用。该元素未显示,因为出于某种原因 click()
调用未正确触发事件(猜测)。我的意思是,webapp 代码中的点击处理程序不会执行,因此不会创建名称为 class server-name-span-text
的元素。由于超时,我最终得到的结果是失败 findDisplayedByClassName
。
因为我是 运行 这个本地人,所以我实际上可以观察并确认没有发生点击事件。所以我的 webapp 中没有发生预期的变化。
实习生的日志如下:
Listening on 0.0.0.0:9000
Tunnel started
‣ Created session firefox on LINUX (2d94ea44-dea8-411a-8ee5-a3d7b749cc7b)
Click resolved
× firefox on LINUX - Init suite - Checking servers (15.588s)
NoSuchElement: An element could not be located on the page using the given search parameters.
at <node_modules/intern/node_modules/leadfoot/lib/findDisplayed.js:37:21>
at <node_modules/intern/node_modules/dojo/Promise.ts:393:15>
at run <node_modules/intern/node_modules/dojo/Promise.ts:237:7>
at <node_modules/intern/node_modules/dojo/nextTick.ts:44:3>
at doNTCallback0 <node.js:417:9>
at process._tickCallback <node.js:346:13>
at Command.findDisplayed <node_modules/intern/node_modules/leadfoot/Command.js:23:10>
at Command.prototype.(anonymous function) [as findDisplayedByClassName] <node_modules/intern/node_modules/leadfoot/lib/strategies.js:28:16>
at Test.test <tests/functional/loadgui.js:36:6>
at <node_modules/intern/lib/Test.js:211:24>
at <node_modules/intern/node_modules/dojo/Promise.ts:393:15>
at runCallbacks <node_modules/intern/node_modules/dojo/Promise.ts:11:11>
at <node_modules/intern/node_modules/dojo/Promise.ts:317:4>
at run <node_modules/intern/node_modules/dojo/Promise.ts:237:7>
at <node_modules/intern/node_modules/dojo/nextTick.ts:44:3>
at doNTCallback0 <node.js:417:9>
No unit test coverage for firefox on LINUX
firefox on LINUX: 1/1 tests failed
TOTAL: tested 1 platforms, 1/1 tests failed
selenium 节点的日志没有显示问题,至少在 INFO 级别:
15:33:59.735 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Executing: [find element: By.id: linkservers])
15:33:59.742 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Done: [find element: By.id: linkservers]
15:33:59.750 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Executing: [click: 9 [[FirefoxDriver: firefox on LINUX (84846fb0-1467-45a9-bbfe-a6333ddef515)] -> id: linkservers]])
15:33:59.811 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Done: [click: 9 [[FirefoxDriver: firefox on LINUX (84846fb0-1467-45a9-bbfe-a6333ddef515)] -> id: linkservers]]
15:33:59.824 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Executing: [find elements: By.className: server-name-span-text])
15:34:14.844 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Done: [find elements: By.className: server-name-span-text]
15:34:14.957 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Executing: [execute script: return (function getCoverageData(coverageVariable) {
var coverageData = (function () { return this; })()[coverageVariable];
return coverageData && JSON.stringify(coverageData);
}).apply(this, arguments);, [__internCoverage]])
15:34:14.970 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Done: [execute script: return (function getCoverageData(coverageVariable) {
var coverageData = (function () { return this; })()[coverageVariable];
return coverageData && JSON.stringify(coverageData);
}).apply(this, arguments);, [__internCoverage]]
15:34:14.980 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Executing: [delete session: 2d94ea44-dea8-411a-8ee5-a3d7b749cc7b])
15:34:15.047 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Done: [delete session: 2d94ea44-dea8-411a-8ee5-a3d7b749cc7b]
如何解决这个问题?
注意:
实习生版本是“3.0.6”,leadfoot 是“1.6.4”。
我使用 Selenium IDE 尝试了 运行 相同的功能测试,它运行成功。
解决此问题的几个提示:
在使用 findDisplayedByClassName
之前,请确保您可以找到具有 findByClassName
的元素
如果找不到元素,请确保 .findById('linkservers')
正常工作。要检查您可以尝试在前后添加 .sleep()
以查看它是否确实有效并为您提供 'server-name-span-text'
class.
的元素
因为 click()
事件在附加处理程序之前由浏览器触发。
问题在 get()
调用和 click()
调用之间:
...
.get(url)
.findById('linkservers')
.click()
...
发生的事情是浏览器在附加处理程序之前触发了点击事件。处理程序在被测应用程序中实现。这意味着在触发点击事件时没有处理程序,因此未创建 server-name-span-text
元素,因此 findDisplayedByClassName
操作超时。请注意,我还尝试了 findByClassName
操作,因此出现异常 NoSuchElement。快速解决方法是在 get()
调用后添加一个 sleep()
。
解决方案 1:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
var url = '...';
var server = '...';
tdd.suite("Init suite",function(){
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Checking servers', function () {
var that = this.remote;
return that
.setFindTimeout(15000)
.get(url)
.sleep(1000) //#Fix-1
.findById('linkservers')
.click()
.then(function(){
console.log("Click resolved");
})
.end()
.findDisplayedByClassName('server-name-span-text')
.getVisibleText()
.then(function(texts){
var t=0;
var tlen = 0;
if (Array.isArray(texts))
{
tlen = texts.length
for (t=0;t<tlen;t++)
console.log("server["+t+"]: "+texts[t]);
assert.strictEqual(texts[0],server,"server is: "+texts[0]);
} else {
assert.strictEqual(texts,server,"server is: "+texts[0]);
}
})
.end();
});
});
更新:
如前所述,显式等待对于此类问题来说是一种糟糕的解决方案。下一个解决方案基于在应用程序端执行异步脚本 executeAsync()
调用。此脚本 return 是一个必须由应用程序解决的承诺,以结束对异步调用的等待。当然,应用程序必须与这个已实现的延迟对象合作,以便它确定应用程序加载的时间点。否则这样的方法是行不通的。优雅的方法如下。
解决方案 2:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
var url = '...';
var server = '...';
tdd.suite("Init suite",function(){
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Checking servers', function () {
var that = this.remote;
return that
.setFindTimeout(15000)
.get(url)
.executeAsync(function(done){
//application side.
application.loaded
.then(function(){
//at this moment the application has loaded
//so we resolve our intern side promise
done();
})
})
.findById('linkservers')
.click()
.then(function(){
console.log("Click resolved");
})
.end()
.findDisplayedByClassName('server-name-span-text')
.getVisibleText()
.then(function(texts){
var t=0;
var tlen = 0;
if (Array.isArray(texts))
{
tlen = texts.length
for (t=0;t<tlen;t++)
console.log("server["+t+"]: "+texts[t]);
assert.strictEqual(texts[0],server,"server is: "+texts[0]);
} else {
assert.strictEqual(texts,server,"server is: "+texts[0]);
}
})
.end();
});
});
如果您愿意,您还可以 return 一些在应用程序端解析的回调参数。有关这方面的更多信息,您可以查看 docs.
我正在尝试使用 Intern framework which uses Leadfoot 库编写功能测试以实现 WebDriver API 因为我正在使用 Selenium Grid 设置在远程浏览器上测试我的 webapp。该应用程序已经启动 运行。 我使用的功能测试如下:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
var url = '...';
var server = '...';
tdd.suite("Init suite",function(){
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Checking servers', function () {
var that = this.remote;
return that
.setFindTimeout(15000)
.get(url)
.findById('linkservers')
.click()
.then(function(){
console.log("Click resolved");
})
.end()
.findDisplayedByClassName('server-name-span-text')
.getVisibleText()
.then(function(texts){
var t=0;
var tlen = 0;
if (Array.isArray(texts))
{
tlen = texts.length
for (t=0;t<tlen;t++)
console.log("server["+t+"]: "+texts[t]);
assert.strictEqual(texts[0],server,"server is: "+texts[0]);
} else {
assert.strictEqual(texts,server,"server is: "+texts[0]);
}
})
.end();
});
});
});
为了开始我的测试,我使用了实习生:./node_modules/.bin/intern-runner config=tests/intern.cfg -reporters=Runner
我的问题的本质是 findDisplayedByClassName('server-name-span-text')
找不到 class 名称,即使我正在使用等待元素显示的 findDisplayed
调用。该元素未显示,因为出于某种原因 click()
调用未正确触发事件(猜测)。我的意思是,webapp 代码中的点击处理程序不会执行,因此不会创建名称为 class server-name-span-text
的元素。由于超时,我最终得到的结果是失败 findDisplayedByClassName
。
因为我是 运行 这个本地人,所以我实际上可以观察并确认没有发生点击事件。所以我的 webapp 中没有发生预期的变化。
实习生的日志如下:
Listening on 0.0.0.0:9000
Tunnel started
‣ Created session firefox on LINUX (2d94ea44-dea8-411a-8ee5-a3d7b749cc7b)
Click resolved
× firefox on LINUX - Init suite - Checking servers (15.588s)
NoSuchElement: An element could not be located on the page using the given search parameters.
at <node_modules/intern/node_modules/leadfoot/lib/findDisplayed.js:37:21>
at <node_modules/intern/node_modules/dojo/Promise.ts:393:15>
at run <node_modules/intern/node_modules/dojo/Promise.ts:237:7>
at <node_modules/intern/node_modules/dojo/nextTick.ts:44:3>
at doNTCallback0 <node.js:417:9>
at process._tickCallback <node.js:346:13>
at Command.findDisplayed <node_modules/intern/node_modules/leadfoot/Command.js:23:10>
at Command.prototype.(anonymous function) [as findDisplayedByClassName] <node_modules/intern/node_modules/leadfoot/lib/strategies.js:28:16>
at Test.test <tests/functional/loadgui.js:36:6>
at <node_modules/intern/lib/Test.js:211:24>
at <node_modules/intern/node_modules/dojo/Promise.ts:393:15>
at runCallbacks <node_modules/intern/node_modules/dojo/Promise.ts:11:11>
at <node_modules/intern/node_modules/dojo/Promise.ts:317:4>
at run <node_modules/intern/node_modules/dojo/Promise.ts:237:7>
at <node_modules/intern/node_modules/dojo/nextTick.ts:44:3>
at doNTCallback0 <node.js:417:9>
No unit test coverage for firefox on LINUX
firefox on LINUX: 1/1 tests failed
TOTAL: tested 1 platforms, 1/1 tests failed
selenium 节点的日志没有显示问题,至少在 INFO 级别:
15:33:59.735 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Executing: [find element: By.id: linkservers])
15:33:59.742 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Done: [find element: By.id: linkservers]
15:33:59.750 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Executing: [click: 9 [[FirefoxDriver: firefox on LINUX (84846fb0-1467-45a9-bbfe-a6333ddef515)] -> id: linkservers]])
15:33:59.811 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Done: [click: 9 [[FirefoxDriver: firefox on LINUX (84846fb0-1467-45a9-bbfe-a6333ddef515)] -> id: linkservers]]
15:33:59.824 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Executing: [find elements: By.className: server-name-span-text])
15:34:14.844 INFO [13] org.openqa.selenium.remote.server.DriverServlet - Done: [find elements: By.className: server-name-span-text]
15:34:14.957 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Executing: [execute script: return (function getCoverageData(coverageVariable) {
var coverageData = (function () { return this; })()[coverageVariable];
return coverageData && JSON.stringify(coverageData);
}).apply(this, arguments);, [__internCoverage]])
15:34:14.970 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Done: [execute script: return (function getCoverageData(coverageVariable) {
var coverageData = (function () { return this; })()[coverageVariable];
return coverageData && JSON.stringify(coverageData);
}).apply(this, arguments);, [__internCoverage]]
15:34:14.980 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Executing: [delete session: 2d94ea44-dea8-411a-8ee5-a3d7b749cc7b])
15:34:15.047 INFO [192] org.openqa.selenium.remote.server.DriverServlet - Done: [delete session: 2d94ea44-dea8-411a-8ee5-a3d7b749cc7b]
如何解决这个问题?
注意: 实习生版本是“3.0.6”,leadfoot 是“1.6.4”。 我使用 Selenium IDE 尝试了 运行 相同的功能测试,它运行成功。
解决此问题的几个提示:
在使用 findDisplayedByClassName
之前,请确保您可以找到具有 findByClassName
如果找不到元素,请确保 .findById('linkservers')
正常工作。要检查您可以尝试在前后添加 .sleep()
以查看它是否确实有效并为您提供 'server-name-span-text'
class.
因为 click()
事件在附加处理程序之前由浏览器触发。
问题在 get()
调用和 click()
调用之间:
...
.get(url)
.findById('linkservers')
.click()
...
发生的事情是浏览器在附加处理程序之前触发了点击事件。处理程序在被测应用程序中实现。这意味着在触发点击事件时没有处理程序,因此未创建 server-name-span-text
元素,因此 findDisplayedByClassName
操作超时。请注意,我还尝试了 findByClassName
操作,因此出现异常 NoSuchElement。快速解决方法是在 get()
调用后添加一个 sleep()
。
解决方案 1:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
var url = '...';
var server = '...';
tdd.suite("Init suite",function(){
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Checking servers', function () {
var that = this.remote;
return that
.setFindTimeout(15000)
.get(url)
.sleep(1000) //#Fix-1
.findById('linkservers')
.click()
.then(function(){
console.log("Click resolved");
})
.end()
.findDisplayedByClassName('server-name-span-text')
.getVisibleText()
.then(function(texts){
var t=0;
var tlen = 0;
if (Array.isArray(texts))
{
tlen = texts.length
for (t=0;t<tlen;t++)
console.log("server["+t+"]: "+texts[t]);
assert.strictEqual(texts[0],server,"server is: "+texts[0]);
} else {
assert.strictEqual(texts,server,"server is: "+texts[0]);
}
})
.end();
});
});
更新:
如前所述,显式等待对于此类问题来说是一种糟糕的解决方案。下一个解决方案基于在应用程序端执行异步脚本 executeAsync()
调用。此脚本 return 是一个必须由应用程序解决的承诺,以结束对异步调用的等待。当然,应用程序必须与这个已实现的延迟对象合作,以便它确定应用程序加载的时间点。否则这样的方法是行不通的。优雅的方法如下。
解决方案 2:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
var url = '...';
var server = '...';
tdd.suite("Init suite",function(){
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Checking servers', function () {
var that = this.remote;
return that
.setFindTimeout(15000)
.get(url)
.executeAsync(function(done){
//application side.
application.loaded
.then(function(){
//at this moment the application has loaded
//so we resolve our intern side promise
done();
})
})
.findById('linkservers')
.click()
.then(function(){
console.log("Click resolved");
})
.end()
.findDisplayedByClassName('server-name-span-text')
.getVisibleText()
.then(function(texts){
var t=0;
var tlen = 0;
if (Array.isArray(texts))
{
tlen = texts.length
for (t=0;t<tlen;t++)
console.log("server["+t+"]: "+texts[t]);
assert.strictEqual(texts[0],server,"server is: "+texts[0]);
} else {
assert.strictEqual(texts,server,"server is: "+texts[0]);
}
})
.end();
});
});
如果您愿意,您还可以 return 一些在应用程序端解析的回调参数。有关这方面的更多信息,您可以查看 docs.