量角器:随机测试失败

时间:2018-12-15 08:38:26

标签: javascript angularjs protractor angularjs-e2e

因此,我刚开始进行量角器测试,并且面临以下问题-我的测试始终失败。有时,测试可能会通过,而下一次失败。失败的原因非常不同,可能是因为它未能在页面上找到元素,或者元素中没有文本(即使有)。

我正在Ubuntu 14.04上运行,这与Chrome Version 71.0.3578.80Firefox Version 60.0.2有关。 AngularJS Version 1.7.2Protractor Version 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');
    });
  });
});

这是驱动程序的一些功能,我在上面的测试中引用了

  // 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();
  };

我无法在此处上传整个代码,以使您更好地理解,因为到目前为止,我还有很多代码,但是上面提供的代码是我在各处使用的方法的准确示例,有人看到问题了吗在我的代码中?谢谢。

4 个答案:

答案 0 :(得分:1)

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

process.on("unhandledRejection", ({message}) => {
    console.log("\x1b[36m%s\x1b[0m", `Unhandled rejection: ${message}`);
});

如果您在任何地方错过了异步/等待,这基本上会以彩色方式登录到控制台,这将使您确信自己没有错过任何事情。

第二,我将安装“量角器控制台”插件,以确保浏览器控制台中没有错误/拒绝(即从应用程序侧排除问题的可能性)并添加到您的配置中

plugins: [{
    package: "protractor-console",
    logLevels: [ "severe" ]
}]

然后,我希望这些标志出现的下一个问题是等待功能不正确。理想情况下,在开发e2e项目时必须分别测试它们,但是由于已经全部编写完毕,因此我将告诉您如何调试它们。请注意,如果您的操作少于一秒(即您不会注意到它们),则这种方法可能对您没有帮助。否则,请遵循此链。

1)我在WebStorm中创建了运行配置,如我的评论所述(查找我的)How to debug angular protractor tests in WebStorm

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

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

当您开始调试过程时,webstorm将打开一个面板,其中包含三个部分:框架,控制台,变量。当变量部分显示消息connected to localhost且未列出任何变量时,表明您的步骤仍在执行。加载完成后,您可以看到所有变量,并且可以执行下一个命令。因此,这里的主要原理是单击“跳过”按钮,并注意变量部分。如果变量在加载应用程序之前出现(已执行等待方法,但应用程序仍在加载,这是错误的),那么您需要使用此方法。通过这种方式,我在自定义等待方法中发现了很多空白。

最后,如果这不起作用,请附上您的错误的堆栈跟踪信息并ping通我

答案 1 :(得分:1)

我担心此代码段

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>

您不应该依赖第一个it子句在其下面设置套件。您没有发布InsurerRefundDriver.getTitle()的代码,但是如果该代码未将浏览器发送到正确的URL,然后等待页面完成加载,则存在问题。您可能应该在await InsurerViewDriver.goToPage();子句中使用beforeEach

答案 2 :(得分:0)

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

browser.ignoreSynchronization = true;对您的所有测试都有全局影响。您可能必须将其设置回false,因此量角器等待angular完成页面渲染。例如在第二个beforeEach函数中或之前

答案 3 :(得分:0)

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

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

结果证明,browser.get方法是在url更改时解决的,但是现在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');
  };

在继续操作之前,应确保页面完成了所有编译工作。