Click() 函数在量角器脚本中不起作用

Posted

技术标签:

【中文标题】Click() 函数在量角器脚本中不起作用【英文标题】:Click() function isn't working in protractor scripts 【发布时间】:2016-08-20 15:27:50 【问题描述】:

我正在尝试使用 Protractor 和 Appium 对 iPad 模拟器中带有 jasmine 框架的 AngularJS 站点进行自动化测试,sendkeys() 函数适用于用户名和密码,但是当我点击登录按钮时,测试通过了,但是操作没有完成:没有重定向到主页,并且没有显示登录按钮的点击效果,我确定该元素的位置正确!因为当我期望 gettext() 等于“LOGIN”时,它通过但没有重定向,即使我输入browser.sleep(8000); 这是我的测试脚本:

    "use strict";
    require("jasmine-expect");
    var wd = require("wd");
    describe('my app', function() 
    it('should make the login test',function() 
   
//    browser.ignoresynchronization=true;
    browser.get("http://10.0.22.82:8080/jws/fetablet");
    expect(browser.getCurrentUrl()).toEqual(("http://10.0.22.82:8080/jws/fetablet/#/login"));

    element(by.model('credentials.username')).sendKeys('RET02').then(function()
    element(by.model('credentials.password')).sendKeys('RET02').then(function()
    element(by.css('.login-button')).click().then(function()
    browser.sleep(8000); expect(browser.getCurrentUrl()).not.toEqual("http://10.0.22.82:8080/jws/fetablet/#/login");
    );
    );
    );
);
);

还有其他方法可以正确定位点击按钮吗? 这是我的html代码:

​​<div class="lo​​gin_lang"> <md-button class="lang_button" ng-click="changeLang()">lang</md-button> </div> 
<div layout="column" flex layout-align="center center" class="md-padding splash-background"> <div class="login-logo"> <img src="logoSrc"> </div> <form class="login-form" name="loginForm" ng-submit="login()"> 
<fieldset> <md-input-container class="md-block"> 
<label translate="login.USERNAME" ng-class="'floating-label-rtl':dir==='rtl'" 

class="login-label">Username</label> 
<input required ng-model="credentials.username" ng-focus="onFocus()" type="text"> 

<div ng-messages="loginForm.credentials.username.$error" ng-show="loginForm.credentials.username.$dirty"> 
<div ng-message="required" trans
​​late="login.MESSAGE_REQUIRED">This is required.</div> </div> </md-input-container> <md-input-container class="md-block"> <label ​​translate="login.PASSWORD" ng-class="'floating-label-rtl':dir==='rtl'" 


class="login-label">Password</label> <input required ng-model="credentials.password" ng-focus="onFocus()" type="pa
​​ssword"> 
<div ng-messages="loginForm.credentials.password.$error" ng-show="loginForm.credentials.password.$dirty"> <div ng-message="required" translate="login.MESSAGE_REQUIRED">This is required.</div> </div> </md-input-container> 

<div layout-align="center center" layout="column" ng-if="oneTimePassword"> <p class="login-otp-message" translate="login.OTP_MESSAGE">Enter the code which you received by SMS</p> <md-button class="md-warn login-otp-retry" translate="login.OTP_RETRY" ng-click="retry()">Retry</md-button> </div> <md-input-container class="md-block" ng-if="oneTimePassword"> <label translate="login.SECURITY_CODE" class="login-label">Security code</label> <input required ng-model="credentials.securityCode" ng-focus="onFocus()" type="password"> <div ng-messages="loginForm.credentials.securityCode.$error" ng-show="loginForm.credentials.securityCode.$dirty"> <div ng-message="required" translate="login.MESSAGE_REQUIRED">This is required.</div> </div> </md-input-container> <div layout-align="center"> <section layout-align="center" layout="row" layout-sm="column"> <div id="login-error" md-caption class="msg-error" ng-show="error" class="label">error</div>
​​

 <md-button type="submit" class="md-raised login-button" ng-disabled="clicked" translate="login.LOGIN">Login</md-button> </section>
​​
 </div> </fieldset> </form> <md-divider></md-divider> <footer class="login-footer"> <div layout="row" layout-align="center center"> <md-button ng-click="goToCustomerCare()" class="login-footer-link" translate="login.CUSTOMER_CARE">Contact Customer Care</md-button> <div> | </div> <md-button ng-click="showDisclaimer()" class="login-footer-link" translate="login.DISCLAIMER">Disclaimer</md-button> </div> </footer> </div>

​​我把登录按钮的Appium记录器的细节放了

【问题讨论】:

尝试在不使用承诺链的情况下执行这些命令。这可能是上一条链中的问题。 @flaviomeira10:我使用的是 jasmine 框架,而不是 mocha (chai),你是这个意思吗? @Emna 你试过我在下面发布的答案吗? 是的,我已经尝试过了,但问题没有解决! 【参考方案1】:

这可能有多种原因,而且无论如何这将是一场猜谜游戏。

可能存在与.login-button 定位符匹配的另一个元素,而您正在单击另一个元素。让我们改进定位器

element(by.css(".login-form .login-button")).click();

wait for the element to be clickable

var EC = protractor.ExpectedConditions;
element(by.model('credentials.username')).sendKeys('RET02');
element(by.model('credentials.password')).sendKeys('RET02');

var loginButton = element(by.css('.login-form .login-button'));
browser.wait(EC.elementToBeClickable(loginButton), 5000);
loginButton.click();

在单击元素之前添加一个小延迟(很傻,但我认为这有时会有所帮助):

element(by.model('credentials.username')).sendKeys('RET02');
element(by.model('credentials.password')).sendKeys('RET02');
browser.sleep(500);
element(by.css('.login-form .login-button')).click();

又一次愚蠢的尝试,点击 2 次(我不敢相信我实际上是这样建议的):

var loginButton = element(by.css('.login-form .login-button'));
loginButton.click();
loginButton.click();

disable angular animations

通过browser.actions()点击按钮移动到点击前的元素:

var loginButton = element(by.css('.login-form .login-button'));
browser.actions().mouseMove(loginButton).click().perform();

是对前一种方法的一种扩展。移动到元素,休眠半秒然后点击:

browser.actions.mouseMove(loginButton).perform();
browser.sleep(500);
loginButton.click();

或者,如果你愿意introduce a custom sleep() action,你可以这样做:

browser.actions.mouseMove(loginButton).sleep(500).click().perform();

点击元素via javascript

var loginButton = element(by.css('.login-form .login-button'));
browser.executeScript("arguments[0].click();", loginButton);

并且,表单提交后,可以不用browser.sleep(),而是等待URL明确更改,请看:

Protractor- Generic wait for URL to change

附带说明,在 Protractor 中,您使用 $ and $$ shortcuts 作为 CSS 定位器:

var loginButton = $('.login-form .login-button');

【讨论】:

非常感谢@alecxe 的详细回答,我尝试使用第一个 :element(by.css(".login-form md-button.login-button")).click() ;但它告诉我 No element found using locator: By(css selector, .login-form md-button.login-button) @Emna 好的,element(by.css(".login-form .login-button")) 怎么样?另外,选项#2 - 等待 - 它是否很好地与等待一起玩?谢谢。 with element(by.css(".login-form .login-button")) 没关系,找到元素我什至得到文本并打印它等于“LOGIN”但是使用您向我提出的所有智能选项尚未解决 click() 的问题,该操作已执行但我们看不到它!并使用此选项: browser.actions.mouseMove(loginButton).click().perform();我收到此错误 browser.actions.mouseMove 未定义。否则我在所有脚本执行结束后收到此错误:错误:超时 - 在 jasmine.DEFAULT_TIMEOUT_INTERVAL 指定的超时内未调用异步回调 @Emna “浏览器操作”选项有问题 - 刚刚修复它:browser.actions().mouseMove(loginButton).click().perform() @Emna 是的,我看到你已经开始在这个问题上悬赏。以后有机会我会仔细看看。疯狂的日子..,谢谢。【参考方案2】:

尝试在不使用承诺链的情况下执行这些命令。这可能是上一条链中的问题。

"use strict";
require("jasmine-expect");
var wd = require("wd");
describe('my app', function() 
it('should make the login test',function() 
  browser.get("http://10.0.22.82:8080/jws/fetablet");
  expect(browser.getCurrentUrl()).toEqual(("http://10.0.22.82:8080/jws/fetablet/#/login"));
  element(by.model('credentials.username')).sendKeys('RET02');
  element(by.model('credentials.password')).sendKeys('RET02');
  element(by.css('.login-button')).click();
  browser.sleep(8000);   
  expect(browser.getCurrentUrl()).not.toEqual("http://10.0.22.82:8080/jws/fetablet/#/login");
);

PS:当你不需要使用方法的结果时,可以避免使用'then'函数。由控制流控制

【讨论】:

是的,我已经尝试过了,但没有,所以我然后看看它是否被执行,我发现一切都被执行了!但我有点怀疑可能有另一种方法来定位元素? 是的,您可以使用 xpath 定位器(不推荐)。您的按钮是默认启用还是您必须填写某些字段才能启用它?您可以在单击命令之前插入browser.sleep(10000); 并检查单击它的按钮吗?它有效吗? PS:尝试使用 '.md-raised login-button' 来查找元素。 是的,我尝试过使用 appium 生成的 xpath,但找不到它!我将 appium 记录器的详细信息放在问题中,因为我正在使用 appium 和量角器进行测试 @Emna:您的按钮是默认启用还是由事件启用?填写密码字段后尝试手动触发 mouseUp 事件:element(by.model('credentials.password')).sendKeys('RET02'); browser.actions().mouseDown().mouseUp().perform(); element(by.css('.login-button')).click(); 感谢您的评论,是的,默认情况下已启用。现在它可以与类似这样的东西一起使用 browser.actions().mouseMove(loginButton).click().perform();但我不知道这是否是端到端测试的最佳解决方案,还是我应该再找一个?【参考方案3】:

点击后添加 browser.sleep 对我有用:

it('Some test', function () 

    element(by.css("button[type='submit']")).click();
    browser.sleep(1000);
);

【讨论】:

【参考方案4】:

我还有一个建议,您可以期望显示特定元素并清除文本框。你实际上可以在 promise 中写,这是最好的方式。

  var loginButton = element(by.css('.md-raised.login-button'));
  var userName = element(by.model('credentials.username'));
  var password = element(by.model('credentials.password'));

  this.username = function(sendUserName) 
      expect(userName.isDisplayed()).toBeTruthy();
      userName.clear().then(function()
          userName.sendKeys(sendUserName).then(function()
              expect(password.isDisplayed()).toBeTruthy();
          );
      );
  ;

  this.password = function(password) 
      expect(password.isDisplayed()).toBeTruthy();
      password.clear().then(function()
          password.sendKeys(password).then(function()
              browser.wait(EC.elementToBeClickable(loginButton), 10000);
          );
      );
  ;

  this.clickloginbutton = function() 
    expect(loginButton.isDisplayed()).toBeTruthy();
    loginButton.click().then(function()
      expect('something').not.toBeNull();
    );
 

【讨论】:

投了反对票的人,请告诉我原因。这样下次我可以更正。 这是其他答案中独一无二的答案,请有人告诉我为什么这被否决。 正如我之前提到的,当您不需要驱动程序命令的结果时,您可以避免承诺链接。您的代码不是很可读。看看控制流解释(spin.atomicobject.com/2014/12/17/…)。 嗨@Nick,感谢您尝试回答我的问题 Nick,但是方法等待(EC.elementToBeClickable () .. 已经由 Alecxe 提出,它对我不起作用。 @Nick,我说的不是用户名或密码字段,而是登录按钮。现在问题解决了! ;)【参考方案5】:

尝试单击该按钮两次,并且在功能方面它有效,但第二次单击时抛出 NoSuchElementError。

进行了以下调整,它对我有用

    await browser.wait(EC.elementToBeClickable(element(by.css('selector')), 5000);
    await $('selector').click();
         if(await $(selector).isDisplayed())
           await $(selector).click();

【讨论】:

以上是关于Click() 函数在量角器脚本中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

为啥 button.click() 在我的脚本中不起作用?

为啥 hotkeys.trigger 在 Mac 中不起作用?

Angular Ng-click 功能在按钮中不起作用

ng-click 在指令中不起作用

.click 事件在 Safari 中不起作用

jQuery .click(function() 在 Firefox 中不起作用