9

I'm randomly getting the error:

Failed: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See https://github.com/angular/protractor/issues/2643 for details"

running

$ ng e2e --webdriverUpdate=false --devServerTarget=

In my spec.ts file I have the following 2 tests, the first one always work, the second randomly fail with the above error.

  beforeEach(async () => {
    myPage = new MyPage();
    browser.get('my-page');
  });

  it('should work', async () => {
    console.log('should work');
    expect(true).toBeTruthy();
  });

  it('should display the title', async () => {
    const title = await $('my-title-selector').getText();
    expect(title).toEqual('My-Title');
  });

Here is MyPage PageObject:

import { $, $$ } from 'protractor';

export class MyPage {
  title = $('my-title-selector');
}

Here is my protractor.conf.js

  // Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const { SpecReporter } = require('jasmine-spec-reporter');

exports.config = {
  allScriptsTimeout: 11000,
  specs: [
    './src/**/*.e2e-spec.ts'
  ],
  capabilities: {
    'browserName': 'chrome'
  },
  SELENIUM_PROMISE_MANAGER: false,
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  framework: 'jasmine',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function () { }
  },
  onPrepare() {
    require('ts-node').register({
      project: require('path').join(__dirname, './tsconfig.e2e.json')
    });
    jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
  },
};

Have you any ideas?

Zoe
  • 27,060
  • 21
  • 118
  • 148
user2010955
  • 3,871
  • 7
  • 34
  • 53

3 Answers3

2

If you are using async / await (which you are!) you will need to await all promises. So my guess is your beforeEach promise to load the page is not completed and you are looking for a web element that might not have been bootstrapped properly by Protractor.

beforeEach(async () => {
  myPage = new MyPage();
  await browser.get('my-page');   // browser.get returns a webdriver.promise.Promise
});

it('should work', async () => {
  console.log('should work');
  expect(true).toBeTruthy();
});

it('should display the title', async () => {
  const title = await $('my-title-selector').getText();  // <-- this is right, getText returns a webdriver.promise.Promise<string>
  expect(title).toEqual('My-Title');
});

If you are using Protractor 5.4, it is still using the selenium-webdriver control flow / promise library and not native Promises. So the webdriver.promise.Promise is from the selenium-webdriver typings, promise namespace, Promise object. In Protractor 6 (when it is out of beta), this will switch to native Promises.

Hope that helps.

cnishina
  • 5,016
  • 1
  • 23
  • 40
  • Hi, thanks, I've added SELENIUM_PROMISE_MANAGER: false in protractor.conf.js in order to disable the control flow / promise manager – user2010955 Jan 17 '19 at 10:29
  • 1
    Yup, it just appears you are missing a single await statement around the `browser.get` – cnishina Jan 17 '19 at 10:32
  • I tried, but it doesn't work, all the tests go in timeout after 11 seconds – user2010955 Jan 17 '19 at 10:35
  • Do you just have one spec? If so, what does your page object look like. – cnishina Jan 17 '19 at 10:41
  • yes I've only one spec, I edited my question adding the pageObject file – user2010955 Jan 17 '19 at 10:57
  • Maybe turn off wait for Angular with "await waitForAngularEnabled(false);". This will prevent bootstrapping and awaiting for testability. – cnishina Jan 17 '19 at 11:06
  • adding await browser.waitForAngularEnabled(false); it works all the time... But I'm not sure if that's the right solution, what you think ? It seems working even without waitForAngularEnabled(false) and removing the await from await $('my-title-selector').getText(); but I suppose this is not the right solution too – user2010955 Jan 17 '19 at 11:09
  • It depends. waitForAngular usually is a signal that your Angular application is in a "stable" state. Most times this is when the promise is awaited on the action; however, if you do notice some flakiness because your application is not in the right state, you could use a wait method `browser.wait( for some expected conditions, 5000);`. – cnishina Jan 17 '19 at 11:13
  • This answer helped solve my issue. Thanks. – Neyo Mar 22 '21 at 10:35
0

Your first test will pass always because it is not interacting with the application and therefore not checking the testability of the angular site. Your second test however does attempt to interact with the application but appears to be timing out because the page has not become testable at that stage. This is also why your tests are passing when waitForAngularEnabled(false) as they no longer check for testability.

There could an issue with your page settling if your the angular code is using $interval or $timeouts in a particular way. Checkout the updates to the main question in the link below and see if they could apply to your project.

How to debug timed out waiting for asynchronous Angular tasks? Failure to find elements on angular page occurring

DublinDev
  • 2,318
  • 2
  • 8
  • 31
0

You may be encountering a race condition bug in the Testabilities API outlined here: https://github.com/angular/angular/issues/15743

The TL/DR is that - if you have an APP_INITIALIZER injected that is asynchronous - say loading a config file - there's a chance that protractor will 'check for angular' before angular reports that it exists. The workaround is not to wait for angular, but instead wait for the existence of a DOM element that is rendered by the full angular application.

Here's some sample code:

await browser.wait(ExpectedConditions.urlContains(this.baseUrl));
await browser.waitForAngularEnabled(false);
await browser.wait(ExpectedConditions.visibilityOf($('.main-app-content'), 10000);
await browser.waitForAngularEnabled(true);
krotscheck
  • 91
  • 1
  • 6