Javascript 量角器:随机测试失败

Javascript 量角器:随机测试失败,javascript,angularjs,protractor,angularjs-e2e,Javascript,Angularjs,Protractor,Angularjs E2e,所以我刚刚开始量角器测试,我面临着以下问题——我的测试不一致地失败。有时,测试可能会通过,但下一次可能会失败。失败的原因非常不同,可能是因为在页面上找不到元素,或者元素中没有文本(即使有) 我运行的是Ubuntu 14.04,与Chrome 71.0.3578.80版和Firefox 60.0.2版同样的问题AngularJS 1.7.2版和量角器5.4.0版。我相信问题在我的代码中的某个地方,所以下面我提供了一个现有代码库的示例 这是我的量角器配置 exports.config = { r

所以我刚刚开始量角器测试,我面临着以下问题——我的测试不一致地失败。有时,测试可能会通过,但下一次可能会失败。失败的原因非常不同,可能是因为在页面上找不到元素,或者元素中没有文本(即使有)

我运行的是Ubuntu 14.04,与Chrome 71.0.3578.80版和Firefox 60.0.2版同样的问题<代码>AngularJS 1.7.2版和
量角器5.4.0版
。我相信问题在我的代码中的某个地方,所以下面我提供了一个现有代码库的示例

这是我的量角器配置

exports.config = {
  rootElement: '[ng-app="myapp"]',
  framework: 'jasmine',
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['./e2e/**/*protractor.js'],
  SELENIUM_PROMISE_MANAGER: false,
  baseUrl: 'https://localhost/',
  allScriptsTimeout: 20000,
  jasmineNodeOpts: {
    defaultTimeoutInterval: 100000,
  },
   capabilities: {
     browserName: 'firefox',
     marionette: true,
     acceptInsecureCerts: true,
     'moz:firefoxOptions': {
       args: ['--headless'],
     },
   },
}
这里是chrome浏览器的功能

  capabilities: {
    browserName: 'chrome',
     chromeOptions: {
       args: [ "--headless", "--disable-gpu", "--window-size=1920,1080" ]
     }
  },
最后,我的测试工具失败了几次

const InsurerViewDriver = require('./insurer-view.driver');
const InsurerRefundDriver = require('./insurer-refund.driver');
const { PageDriver } = require('@utils/page');
const { NotificationsDriver } = require('@utils/service');
const moment = require('moment');

describe(InsurerViewDriver.pageUrl, () => {
  beforeAll(async () => {
    await InsurerViewDriver.goToPage();
  });

  it('- should test "Delete" button', async () => {
    await InsurerViewDriver.clickDelete();

    await NotificationsDriver.toBeShown('success');
    await PageDriver.userToBeNavigated('#/setup/insurers');

    await InsurerViewDriver.goToPage();
  });

  describe('Should test Refunds section', () => {
    it('- should test refund list content', async () => {
      expect(await InsurerRefundDriver.getTitle()).toEqual('REFUNDS');

      const refunds = InsurerRefundDriver.getRefunds();
      expect(await refunds.count()).toBe(1);

      const firstRow = refunds.get(0);
      expect(await firstRow.element(by.binding('item.name')).getText()).toEqual('Direct');
      expect(await firstRow.element(by.binding('item.amount')).getText()).toEqual('$ 50.00');
      expect(await firstRow.element(by.binding('item.number')).getText()).toEqual('');
      expect(await firstRow.element(by.binding('item.date')).getText()).toEqual(moment().format('MMMM DD YYYY'));
    });

    it('- should test add refund action', async () => {
      await InsurerRefundDriver.openNewRefundForm();

      const NewRefundFormDriver = InsurerRefundDriver.getNewRefundForm();

      await NewRefundFormDriver.setPayment(`#555555, ${moment().format('MMMM DD YYYY')} (amount: $2,000, rest: $1,500)`);
      await NewRefundFormDriver.setPaymentMethod('Credit Card');

      expect(await NewRefundFormDriver.getAmount()).toEqual('0');
      await NewRefundFormDriver.setAmount(200.05);
      await NewRefundFormDriver.setAuthorization('qwerty');

      await NewRefundFormDriver.submit();
      await NotificationsDriver.toBeShown('success');

      const interactions = InsurerRefundDriver.getRefunds();
      expect(await interactions.count()).toBe(2);

      expect(await InsurerViewDriver.getInsurerTitleValue('Balance:')).toEqual('Balance: $ 2,200.05');
      expect(await InsurerViewDriver.getInsurerTitleValue('Wallet:')).toEqual('Wallet: $ 4,799.95');
    });
  });
});
这里是driver的一些函数,我在上面的测试中引用了这些函数

  // PageDriver.userToBeNavigated
  this.userToBeNavigated = async function(url) {
    return await browser.wait(
      protractor.ExpectedConditions.urlContains(url),
      5000,
      `Expectation failed - user to be navigated to "${url}"`
    );
  };

  this.pageUrl = '#/insurer/33';

  // InsurerViewDriver.goToPage
  this.goToPage = async () => {
    await browser.get(this.pageUrl);
  };

  // InsurerViewDriver.clickDelete()
  this.clickDelete = async () => {
    await $('[ng-click="$ctrl.removeInsurer()"]').click();
    await DialogDriver.toBeShown('Are you sure you want to remove this entry?');
    await DialogDriver.confirm();
  };

  // NotificationsDriver.toBeShown
  this.toBeShown = async (type, text) => {
    const awaitSeconds = 6;
    return await browser.wait(
      protractor.ExpectedConditions.presenceOf(
        text ? element(by.cssContainingText('.toast-message', text)) : $(`.toast-${type}`)
      ),
      awaitSeconds * 1000,
      `${type} notification should be shown within ${awaitSeconds} sec`
    );
  }

  // InsurerRefundDriver.getRefunds()
  this.getRefunds = () => $('list-refunds-component').all(by.repeater('item in $data'));

// InsurerViewDriver.getInsurerTitleValue
this.getInsurerTitleValue = async (text) => {
    return await element(by.cssContainingText('header-content p', text)).getText();
  };

我不能在这里上传整个代码来让您更好地理解,因为到目前为止我有很多代码,但上面提供的代码正是我在任何地方使用的方法的示例,有人看到我的代码中有问题吗?谢谢。

这似乎是由于异步javascript造成的


browser.ignoreSynchronization=true;对您的所有测试具有全局影响。您可能必须将其设置回false,以便量角器等待angular完成页面渲染。e、 g.在第二个beforeach函数中或之前

首先在导出配置之前添加此块

process.on("unhandledRejection", ({message}) => {
    console.log("\x1b[36m%s\x1b[0m", `Unhandled rejection: ${message}`);
});
如果您错过了async/Wait anywhere,这基本上会以彩色方式登录到控制台,这会让您确信您没有错过任何东西

其次,我会安装“Gragrator console”插件,以确保浏览器控制台中没有错误/拒绝(即排除应用程序端出现问题的可能性),并添加到配置中

plugins: [{
    package: "protractor-console",
    logLevels: [ "severe" ]
}]
那么,我认为这些标志的下一个问题是不正确的等待功能。理想情况下,在开发e2e项目时,您必须单独测试它们,但由于它们都已经编写好了,我将告诉您我是如何调试它们的。请注意,如果您的操作少于一秒(即,您无法注意到它们),这种方法可能对您没有帮助。否则,请遵循此链

1) 我在WebStorm中创建了运行配置,如我在这里的评论所述(查找我的)

2) 在要调试的测试的第一行设置断点

3) 然后使用创建的运行配置逐行执行测试

当您开始调试过程时,webstorm会打开一个包含三个部分的面板:框架、控制台和变量。当variables(变量)部分有一条连接到localhost(本地主机)的消息
,并且没有列出任何变量时,这意味着您的步骤仍在执行中。加载完成后,您可以查看所有变量,并可以执行下一个命令。所以这里的主要原则是你们点击单步跳过按钮,然后观察变量部分。如果变量出现在应用程序加载完成之前(等待方法已执行,但应用程序仍在加载,这是错误的),则需要使用此方法。通过这种方式,我在自定义等待方法中发现了很多漏洞


最后,如果这不起作用,请附加错误的堆栈跟踪并ping我

我很关心这个代码片段

describe(InsurerViewDriver.pageUrl, () => {
  beforeAll(async () => {
    await InsurerViewDriver.goToPage();
  });

  it('- should test "Delete" button', async () => {
    await InsurerViewDriver.clickDelete();

    await NotificationsDriver.toBeShown('success');
    await PageDriver.userToBeNavigated('#/setup/insurers');

    await InsurerViewDriver.goToPage(); // WHY IS THIS HERE?
  });

  describe('Should test Refunds section', () => {
    it('- should test refund list content', async () => {
      // DOESN'T THIS NEED SOME SETUP?
      expect(await InsurerRefundDriver.getTitle()).toEqual('REFUNDS');
// <truncated>
description(insureervewdriver.pageUrl,()=>{
之前(异步()=>{
等待保险公司的批准。goToPage();
});
它('-应该测试“删除”按钮),异步()=>{
等待保险服务驱动。单击删除();
等待托贝镇驾驶员的通知(“成功”);
等待PageDriver.userToEnabled(“#/setup/insurers”);
等待保险公司的消息。goToPage();//这是为什么?
});
描述('应测试退款部分',()=>{
它('-应该测试退款列表内容',异步()=>{
//这不需要一些设置吗?
expect(等待被保险人refunddriver.getTitle()).toEqual(“退款”);
// 

您不应该依赖第一个
it
子句来设置它下面的套件。您没有发布
InsurerRefundDriver.getTitle()的代码
但如果该代码没有将浏览器发送到正确的URL,然后等待页面完成加载,则这是一个问题。您可能需要
等待InsurageWdriver.goToPage()
在每个
之前的
条款中。

经过一段时间的研究,我发现了问题所在。原因是我在应用程序中的导航方式

  this.goToPage = async () => {
    await browser.get(this.pageUrl);
  };
原来,当url更改时,
browser.get
方法正在解决,但现在angularjs完成编译时。我在每个测试工具包中都使用了相同的方法,这就是为什么我的测试不一致地失败,有时在测试开始之前页面没有完全加载

因此,这里有一个方法,做到了这一点

  this.goToPage = async () => {
    await browser.get(this.pageUrl);
    await browser.wait(EC.presenceOf(`some important element`), 5000, 'Element did not appear after route change');
  };

在继续之前,您应该确保page完成了所有的编译工作。

您有动画吗?如果有,请尝试禁用所有动画的测试。我禁用了所有动画,感谢您的建议。失败是否发生在同一个
it
?我想可能的原因之一是,您在某个代码行中错过了
等待
。您可以运行一个测试文件多次,如果它总是可以通过,然后运行另一个测试文件,直到找到不稳定的测试文件,然后在不稳定的文件中运行它块来缩小不稳定的it块,用同样的方法缩小不稳定的代码行,然后你会得到错过的代码行,这是非常好的一点!虽然这是我的第一个想法,但我怀疑e检查代码,没有发现缺少的
wait
。它很可能在不同的it块上失败,不一致,因此我找不到原因,让我发疯。我正在使用最新版本的量角器,其中
ignoreSynchronization
很久以前就被弃用了。如果这有助于您找到问题所在,请接受正确的答案。否则,请确定您关心的问题。谢谢。
browser.get
只等待