简体   繁体   English

如何使用PhantomJS启动Angular摘要循环?

[英]How to start an Angular digest cycle using PhantomJS?

I'm using PhantomJs (virtual browser) and JQuery to automatically navigate a website. 我正在使用PhantomJs(虚拟浏览器)和JQuery来自动浏览网站。 But I'm stuck on the Login page - trying to submit username and password. 但我被困在登录页面 - 尝试提交用户名和密码。

This website is an angular app. 这个网站是一个有角度的应用 I use ng-click to call the login() function - which get's the user object. 我使用ng-click调用login()函数 - 获取用户对象。

Html: HTML:

<form>
    <label>Username:</label>
    <input type="text", ng-model="user.username" ><br>
    <label>Password:</label>
    <input type="text", ng-model="user.password" >
    <input type="button", ng-click="login(user)" value="Login">
</form>

LoginCtrl: LoginCtrl:

$scope.login = function(user){
   var route = Restangular.all("/auth/login");
   route.post(user)
        .then(function(response){
            console.log(response);
            $window.localStorage.token = response.token;
            $state.go('level1');
        }, function(err){
            console.log("ERROR in Logging in!");
        });
};

When I use the app from a normal browser - by typing on keyboard - the login functionality works. 当我从普通浏览器使用该应用程序时 - 通过在键盘上键入 - 登录功能可行。 But when I use PhantomJs and Jquery - to automate the login process - is not. 但是,当我使用PhantomJs和Jquery - 自动化登录过程时 - 不是。

PhantomJs renders the page like any other browser - and using the page.evaluate method with the following code it fills the username (123) and the password (123) and clicks on the Login Button. PhantomJs像任何其他浏览器一样呈现页面 - 并使用带有以下代码的page.evaluate方法填充用户名(123)和密码(123)并单击登录按钮。 This theoretically should login the user. 理论上这应该登录用户。 But practically is not. 但实际上并非如此。

page.evaluate(function() {
    $("form").find('input').eq(0).val("123"); // fill username
    $("form").find('input').eq(1).val("123"); // fill password
    setTimeout(function(){
        $("form").find('input').eq(2).click(); // click the Login Button.
    },100);
});

After little debugging I figured that data binding is the problem. 经过一点调试后,我认为数据绑定是个问题。 The above code does not trigger the angular digest cycle. 上面的代码不会触发角度摘要循环。

When the Login Button is clicked by jquery - the user.username and user.password even if they are filled, remain empty form the angular perspective. 当jquery单击登录按钮时 - 即使填充了user.username和user.password,也会从角度透视图保持为空。 ng-model it's not doing it's magic. ng-model它没有做它的魔力。 The user is empty, the controller submits empty data to the server - and that is why i get 401 Unauthorized! 用户为空,控制器将空数据提交给服务器 - 这就是我获得401 Unauthorized的原因!

I tried using this: 我试过用这个:

page.evaluate(function() {
    $("form").find('input').eq(0).val("123"); // fill username
    $("form").find('input').eq(1).val("123"); // fill password 

    // trying to start an angular digest cycle
    $myscope = angular.element(document.querySelector("body")).scope();
    $myscope.$apply(); 

    setTimeout(function(){
        $("form").find('input').eq(2).click();
    },100);
});

Basically nothing happens. 基本上没有任何反应。 What I'm doing wrong here? 我在这里做错了什么? I also think this is not an obscure issue. 我也认为这不是一个模糊的问题。 PhantomJs is used for unitTesting all day so how normal people - who test angular apps - do: automatic login, registration, navigation all that - how they start the digest cycle - from within the JQuery code placed inside the page.evaluate method? PhantomJs用于整天测试,所以普通人 - 测试角度应用程序的人 - 如何做:自动登录,注册,导航所有这些 - 他们如何开始摘要周期 - 来自放置在page.evaluate方法内的JQuery代码?

I found the answer. 我找到了答案。 Problem was angular binding as I expected. 问题是我预期的角度绑定。 In order to update the ng-model form outside of the angular world - ex JQuery - you need to use trigger("input") event. 为了在角度世界之外更新ng-model表单 - 从JQuery开始 - 你需要使用trigger(“input”)事件。

ng-model basically listens for this "input" events - and internally this will automatically trigger the digest loop. ng-model基本上监听这个“输入”事件 - 在内部这会自动触发摘要循环。 This input events are also sent all the time when typing on the keyboard. 在键盘上键入时,也会始终发送此输入事件。 ( I found this explanation here: How does AngularJS internally catch events like 'onclick', 'onchange'? ) (我在这里找到了这样的解释: AngularJS如何内部捕获'onclick','onchange'等事件?

The solution: 解决方案:

page.evaluate(function() {
    $("form").find('input').eq(0).val("123").trigger("input"); // fill username and update the ng-model
    $("form").find('input').eq(1).val("123").trigger("input"); // fill username and update the ng-model
    setTimeout(function(){
        $("form").find('input').eq(2).click(); // click on Login button -> this is picked up normally by angular.
    },100);
});

Solution Without JQuery 没有JQuery的解决方案

page.evaluate(function() {
    var emailInput = document.getElementById('emailField'),
        passwordInput = document.getElementById('passwordField'),
        loginButton = document.getElementById('loginButton');

    emailInput.value = 'email@domain.com';
    emailInput.dispatchEvent(new Event('input'));

    passwordInput.value = 'mypassword';
    passwordInput.dispatchEvent(new Event('input'));

    loginButton.click();
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM