javascriptangularjsprotractorangularjs-e2e

protractor: random test fail


So I just started work on protractor tests and I'm facing the following problem - my tests fail inconsistently. Sometimes the test may pass and the next time it fails. Reasons to fail is very different, it may because it failed to find an element on a page or element does not have text in it (even if it has).

I'm running on Ubuntu 14.04, the same problem relevant for Chrome Version 71.0.3578.80 and Firefox Version 60.0.2. AngularJS Version 1.7.2 and Protractor Version 5.4.0. I believe the problem is somewhere in my code, so here below I provided an example of an existing code base.

Here is my protractor config

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'],
     },
   },
}

And here capabilities for chrome browser

  capabilities: {
    browserName: 'chrome',
     chromeOptions: {
       args: [ "--headless", "--disable-gpu", "--window-size=1920,1080" ]
     }
  },

And finally, my test kit that failed a few times

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');
    });
  });
});

And here some functions from driver's, that I'm referencing in the test above

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

I can't upload the whole code here to give you better understanding because I have a lot of code till this moment, but the code provided above is the exact sample of approach I'm using everywhere, does anyone see a problem in my code? Thanks.


Solution

  • After some time research I found what was the problem. The cause was the way I'm navigate through the app.

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

    Turns out, that browser.get method is being resolved when url changed, but now when angularjs done compile. I used the same approach in every test kit, that's why my tests were failing inconsistently, sometimes page was not fully loaded before test start.

    So here is an approach that did the trick

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

    You should ensure that page done all the compiling job before moving on.