Protractor headless (headless)登录 gmail 失败,非 headless (headless)时可以正常登录

标签 protractor gmail headless

我有一个使用 Protractor 登录 gmail 的例程,它是从我的脚本中间调用的(这就是为什么有些东西看起来不必要的原因),但我已尽可能地将其隔离。当我运行它时,它不是 headless (headless)的,它会通过。当我 headless (headless)运行它时,它失败了。我查看了相关帖子,它们似乎不是特定于 Protractor 的,而且它们似乎确实与我的代码类似。

这是代码:

    const EC = ExpectedConditions;

beforeAll(function(){ 


});

beforeEach(function() {
  //because I am using gmail after sending an email from an angular app with a link to get back into one
  browser.waitForAngularEnabled(true);
  browser.ignoreSynchronization = false;

});

afterEach(function() {
  browser.waitForAngularEnabled(true);
  browser.ignoreSynchronization = false;
});


var gmailLogin = function(){
      browser.waitForAngularEnabled(false);//gmail screens not angular
      browser.ignoreSynchronization = true;
      browser.sleep(2000);//because ignore sync takes time to settle in
      browser.driver.manage().timeouts().implicitlyWait(10000);//set in config, but seems to work only if here
      browser.get("https://mail.google.com/mail");
      browser.wait(EC.titleContains("Gmail"), 10000, "wait for gmail page");
      $('[data-g-label="Sign in"]').click().then(
        //this sometimes appears and sometimes is skipped, so ignore result
        function(retval){},function(err){}
      )
      var variousInput = element(by.id('identifierId'));

      browser.wait(EC.presenceOf(variousInput), 10000, "wait for identier ID prompt").then(
      function(retVal){
      var variousInput2 = browser.driver.findElement(by.id('identifierId'));
      variousInput2.sendKeys("myemail here");
      variousInput2=browser.driver.findElement(by.id("identifierNext"));
      variousInput2.click(); 
      variousInput2 =  browser.driver.findElement(by.name('password'));
      variousInput2.sendKeys('my password here');
      variousInput2=browser.driver.findElement(by.id("passwordNext"));
      variousInput2.click();

      },

      function(err){}//assume not found because cookie still around, proceed to next step
      )
      browser.wait(EC.titleContains("Inbox"), 10000, "wait for inbox");
}


describe('runs gmail test for so', function() {
    it('tests gmail', function() {
        gmailLogin();
      expect(browser.getTitle()).toContain('Inbox');
    }, 2 * 60 * 1000); //should always come up within 2 minutes


}); //end of describe

这是标题配置文件:

    exports.config = {
  directConnect: true,
  allScriptsTimeout: 120000,
  getPageTimeout: 60000,

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome',

    chromeOptions: {
       //args: ["--headless","--disable-gpu","--no-sandbox"]
  },

  // Framework to use. Jasmine is recommended.
  framework: 'jasmine',

  // Spec patterns are relative to the current working directory when
  // protractor is called.
  specs: [
    './so.ts'
  ],

  // Options to be passed to Jasmine.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 180000
  },
  beforeLaunch: function() {

  },
  onPrepare() {
    browser.manage().window().setSize(1600, 1000);
    browser.driver.manage().timeouts().implicitlyWait(15000);
    }
}
}

这是 headless (headless)的(你可以看到我把厨房水槽扔到了选项中)。

exports.config = {
  directConnect: true,
  allScriptsTimeout: 60000,
  getPageTimeout: 30000,

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome',

    chromeOptions: {
       args: ["--headless","--disable-gpu","--window-size=1600,1000","--disable-infobars","--disable-extensions","--auth-server-whitelist","--remote-debugging-port=9222"]
  },

  // Framework to use. Jasmine is recommended.
  framework: 'jasmine',

  // Spec patterns are relative to the current working directory when
  // protractor is called.
  specs: [
    './so.ts'
  ],

  // Options to be passed to Jasmine.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 180000
  },
  beforeLaunch: function() {

  },
  onPrepare() {
    // screen size set in chrome options
      browser.driver.manage().timeouts().implicitlyWait(15000);

    }
}
}

如果关于哪些定位器可以 headless (headless)工作或不可以工作有某种潜在的、未记录的智慧,我很想知道。

谢谢, jk

小幅更新:我清理了代码,只使用显式等待和直接 Protractor (这就是我在阅读网上基于其他语言的文章之前最初的方式)。这是修改后的版本,它仍然通过 not headless 并失败 headless(我还删除了 OnPrepare() 中的隐式等待设置以及执行 headless 时除了前三个 chrome 选项之外的所有选项)。

var gmailLogin = function() {
browser.waitForAngularEnabled(false); //gmail screens not angular
browser.ignoreSynchronization = true;
browser.sleep(2000); //because ignore sync takes time to settle in
browser.get("https://mail.google.com/mail");
browser.wait(EC.titleContains("Gmail"), 10000, "wait for gmail page");
$('[data-g-label="Sign in"]').click().then(
    //this sometimes appears and sometimes is skipped, so ignore result
    function(retval) {},
    function(err) {}
);
var variousInput = element(by.id('identifierId'));

browser.wait(EC.presenceOf(variousInput), 10000, "wait for identifier ID prompt").then(
    function(retVal) {
        var variousInput2 = element(by.id('identifierId'));
        variousInput2.sendKeys("email address");
        variousInput2 = element(by.id("identifierNext"));
        variousInput2.click();
        variousInput2 = element(by.name('password'));
        browser.wait(EC.presenceOf(variousInput2), 10000, "wait for password prompt");
        browser.wait(EC.visibilityOf(variousInput2), 10000, "wait for password prompt");
        variousInput2.sendKeys('my password');
        variousInput2 = element(by.id("passwordNext"));
        variousInput2.click();

    },

    function(err) {} //assume not found because cookie still around, proceed to next step
    )
    browser.wait(EC.titleContains("Inbox"), 10000, "wait for inbox");
}

更大的更新:毕竟这可能是 headless (headless)的一些时髦的东西。我在等待标识符 ID element(by.tagName('html')).getText().then(function(text){console.log(text);}); 之前添加了以下几行 在非 headless (headless)模式下,产生的

    Sign in
to continue to Gmail
Email or phone
Forgot email?
Not your computer? Use Guest mode to sign in privately.
Learn more
NEXT
Create account
‪English (United States)‬
HelpPrivacyTerms

在 headless (headless)中,它给出了

One account. All of Google.
Sign in to continue to Gmail
Find my account
Create account
One Google Account for everything Google
About Google Privacy Terms Help

后面是一长串从南非荷兰语到繁体中的语言。因此,在 headless (headless)浏览器中,浏览器似乎已经忘记了它所在的位置(至少添加了所有 Google 和语言的 One 帐户,这表明它不是苹果对苹果)。这让我想知道在这种情况下 IdentifierId 是否也可能有不同的名称。 目前最后更新: 为了调试,我在加载第一页时添加了以下代码:

var inputs=element.all(by.tagName('input'));
  inputs.each(function(element,index){
  element.getAttribute("Id").then(function(text){console.log('input '+index+' '+text);})
  })

不是 headless (headless),我们得到:

input 0 identifierId
input 1 null
input 2 ca
input 3 ct
input 4 pstMsg
input 5 checkConnection
input 6 checkedDomains

但我们得到的是 headless (headless):

input 0 null
input 1 null
input 2 null
input 3 null
input 4 null
input 5 null
input 6 null
input 7 null
input 8 null
input 9 null
input 10 null
input 11 profile-information
input 12 session-state
input 13 null
input 14 _utf8
input 15 bgresponse
input 16 Email
input 17 Passwd-hidden
input 18 next

所以 Protractor 是对的,它无法通过 ID 标识符 ID 找到它。但怎么会这样呢?

最终: 因此,根据是否 headless (headless),谷歌会重定向到两个不同的网址,其中包含两组不同的 ID 和名称。我在我的答案中发布了处理这两个问题的修改后的代码。

谢谢大家的指导。

最佳答案

事实证明,Google 会将邮件服务请求重定向到其界面的两个不同版本,具体取决于是否进入 headless (headless)状态。我重写了代码来处理其中任何一个。我还尝试尽可能地简化,包括不再隐式等待并添加更多链接(在 Oleksii 评论的鼓励下,我也尝试了 ES6)。

    const EC = ExpectedConditions;

beforeAll(function(){ 
});

beforeEach(function() {
  //because I am using gmail after sending an email from an angular app with a link to get back into one
  browser.waitForAngularEnabled(true);
  browser.ignoreSynchronization = false;
});

afterEach(function() {
  browser.waitForAngularEnabled(true);
  browser.ignoreSynchronization = false;
});

var waitForIds = (id1,id2)=>{//waits for one of two ids, assumes they must exist or else it is an error
  var elm = element.all(by.xpath("//*[@id = '"+id1+"' or @id = '"+id2+"']")).first();
  browser.wait(EC.presenceOf(elm), 30000, "wait for "+id1+" or "+ id2);
  return elm;
}

var gmailLogin = () => {
browser.waitForAngularEnabled(false); //gmail screens not angular
browser.ignoreSynchronization = true;
browser.sleep(2000); //because ignore sync takes time to settle in
browser.get("https://accounts.google.com/ServiceLogin?service=mail");
browser.sleep(2000);


element(by.id('gbqfq')).isPresent().then((present) => {
    //if present, we are already on the inbox screen, because we found the search pane
    if (!present) { //still work to do to get there
        browser.wait(EC.titleContains("Gmail"), 10000, "wait for a gmail page");

        $('[data-g-label="Sign in"]').click().then(
            //this sometimes appears and sometimes is skipped, so ignore result
            (retval) => {}, (err) => {}
        );
        waitForIds('Email', 'identifierId').sendKeys("my email here");
        waitForIds("identifierNext", "next").click();
        waitForIds('Passwd', 'password').getAttribute('id').then((text) => {
            element(by.name(text)).sendKeys('my password here');
            waitForIds("signIn", "passwordNext").click();
        })
    }
})




browser.wait(EC.titleContains("Inbox"), 10000, "wait for inbox");
}


    describe('runs gmail test for so', function() {
        it('tests gmail', function() {
            gmailLogin();
            expect(browser.getTitle()).toContain('Inbox');
        }, 2 * 60 * 1000); //should always come up within 2 minutes 
    }); //end of describe

更新:我接受这一点,因为它直接解决了我的问题:发生了什么、为什么以及如何解决。我完全接受,尽管回答了这个问题,但有更好的方法来完成我真正想做的事情(从电子邮件中获取 href),可以通过捕获电子邮件或使用 gmail api。

关于Protractor headless (headless)登录 gmail 失败,非 headless (headless)时可以正常登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50918799/

相关文章:

typescript - 使用 Protractor 和 TypeScript,如何从 URL 返回当前页面名称作为字符串?

php - Docx 到 pdf 使用 openoffice headless 方式太慢

c# - 采用 ASP .NET Core 的 headless (headless) Umbraco CMS

gmail - 网站上的 php 联系表格和回复电子邮件

java - 如何防止 Java 中的 headless (headless)异常?

javascript - 如何从 Protractor 中使用 browser.executeScript 执行的 js 获取返回值?

javascript - 如何在 Protractor 测试中选择 Kendo MultiselectTextBox 的值

javascript - 如何使用 Protractor 验证 URL?

gmail - 解码 Gmail API 下载的附件数据

node.js - Nodemailer 与 Gmail 发生环回错误 - 对象 #<Object> 没有方法 'getToken'