1

I have two angular applications

  1. For Login

  2. For business Logic

I have tried to start automation testing for these applications by using protractor. But facing problem to get the element details from 2nd application after login (1st application).

The files are

specs: [
        'login.js',// 1st application 
        'navigatetoRegisterReport.js',// page loaded by menu navigation from 1st application
        'requestCreation.js',// 2nd application page loaded by `browser.get(2nd app Url)`
        'navigateToDcOtherInvoice.js'// navigation to another screen in my 2nd application 
    ],

I have done the logic for login by this below way and it is working very well

async first() {
        await browser.driver.get(browser.baseUrl).then(async () => {
            await browser.wait(ExpectedConditions.elementToBeClickable(element(by.linkText("Other User"))), 30000);
            await element(by.linkText("Other User")).click().then(() => {
                browser.wait(ExpectedConditions.elementToBeClickable(element(by.css('#username'))), 30000);
                element(by.css('#username')).sendKeys('XXXXX').then(() => {
                    browser.wait(ExpectedConditions.elementToBeClickable(element(by.id("password-field"))), 30000);
                    element(by.id("password-field")).sendKeys('XXXXX').then(() => {
                        browser.wait(ExpectedConditions.elementToBeClickable(element(by.id('login-submit'))), 30000);
                        element(by.id('login-submit')).click().then(async () => {
                            const dashboardImage = await element(by.css("app-dashboard .dashboard-image"));
                            browser.wait(ExpectedConditions.elementToBeClickable(dashboardImage), 30000);
                            dashboardImage.isDisplayed().then((value) => {
                                if (value == true) {
                                    console.log('dashborad image is displayed')
                                } else {
                                    console.log('dashborad image is not identified')
                                }
                            }).catch(error => console.error('caught error while login', error));;
                        }).catch(error => console.error('caught error 7', error));;
                    }).catch(error => console.error('caught error on password', error));;
                }).catch(error => console.error('caught error on user name', error));;
            }).catch(error => console.error('caught error tab click', error));;
        }).catch(error => console.error('caught error on load', error));
    }

But while getting the element value from 2nd application I am getting error

async requestCreation(date: string, report: string) {

        await browser.get('https://2ndapplication/xxx/xxxx').then(async () => {
            var selectDate = element(by.xpath("//input[@id='icon-right']"));
            var reportType = element(by.xpath("//input[@placeholder='Report Type']"));
            browser.wait(ExpectedConditions.elementToBeClickable(selectDate), 30000);
            selectDate.clear();
            selectDate.sendKeys(date)
            browser.wait(ExpectedConditions.elementToBeClickable(reportType), 30000);
            reportType.click();
            reportType.clear();
            reportType.sendKeys(report)
        }).catch(error => console.error('caught error on requestCreation', error));
    }

Error:

ScriptTimeoutError: script timeout
  (Session info: chrome=88.0.4324.190)
  (Driver info: chromedriver=88.0.4324.96 (68dba2d8a0b149a1d3afac56fa74648032bcf46b-refs/branch-heads/4324@{#1784}),platform=Windows NT 10.0.18363 x86_64)
    at Object.checkLegacyResponse (E:\updatedCode\backup\node_modules\selenium-webdriver\lib\error.js:546:15)
    at parseHttpResponse (E:\updatedCode\backup\node_modules\selenium-webdriver\lib\http.js:509:13)
    at doSend.then.response (E:\updatedCode\backup\node_modules\selenium-webdriver\lib\http.js:441:30)
    at process._tickCallback (internal/process/next_tick.js:68:7)
From: Task: Protractor.waitForAngular() **- Locator: By(xpath, //input[@id='icon-right'])

I can see the element in browser and it is visible. But protractor throwing the error as it is not there. I know it will be solved if I providing false for WaitForAngularDisabled(false). But the both applications are implemented by Angular only. So I don't want to loose any protractor features by disable angular. So how to test two angular applications by protractor?

Versions:

  • Protector: 7.0.0
  • Angular: 7.3.9
Ramesh Rajendran
  • 37,412
  • 45
  • 153
  • 234
  • 1
    why are you messing your code so much with so much chaining !!!! can't you directly use await instead of chaining. The code becomes really a maintenance headache with such promise chainning – PDHide Feb 27 '21 at 22:09
  • https://stackoverflow.com/a/66072132/6793637 – PDHide Feb 27 '21 at 22:11
  • @PDHide Thanks for your reply. Actually It is working for my 1st application, the problem is my 2nd application throwing unable to find the element error . – Ramesh Rajendran Feb 28 '21 at 15:52
  • 1
    it surely will work , but the problem is when something breaks and you have to debug , change the chaining and make it await instead – PDHide Feb 28 '21 at 15:53
  • OK, I'll try and let you know :) – Ramesh Rajendran Feb 28 '21 at 15:54
  • I have tried and also I have removed await in find element.But still I am getting element is not found error message. But it is working fine if I am providing AngularEnabled is false :( @PDHide – Ramesh Rajendran Mar 01 '21 at 08:37
  • Please add the updated code it will be easy to look into – PDHide Mar 01 '21 at 09:08
  • Some times if the page is not purely angular then you need to disable waotforangular – PDHide Mar 01 '21 at 09:10
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/229337/discussion-between-ramesh-rajendran-and-pdhide). – Ramesh Rajendran Mar 01 '21 at 09:13
  • 1
    not all angular applications can be tested with protractor with waitForAngularEnabled(true) which is default. See here how to check if your app will work https://stackoverflow.com/a/66111219/9150146 let me know what getAllAngularTestabilities return on each of your pages – Sergey Pleshakov Mar 02 '21 at 15:23
  • @SergeyPleshakov Good Info. All of the screens are showing haspendingmacrotasks are showing true. Do u know why it is true for some pages even with implemented by same versiona and concepts? – Ramesh Rajendran Mar 03 '21 at 04:21

2 Answers2

1

As I mentioned in the comments, your problem is because your angular application is constantly polling something in the background, even though visually it may look like the page is ready. You can read more about it in protractors page and here. Unfortunately, I only do test automation, and never tried to solve the problem on application side. However, I always tend to disable protractor's waiting for angular in any case, so it never really bothered me much


I understand you already read my answer in another post, I just want to recite some of it here for everyone's reference

  1. Find out if your page is Angular: open dev console in the browser and inside of 'console' tab run command
getAllAngularTestabilities()

If the output is getAllAngularTestabilities is not defined, then your page is not angular, go to the step #3 to disable built-in waiting

  1. If your page is angular, it's too early to celebrate, since Protractor still may not be working natively. Run these commands in the console to check if it does
getAllAngularTestabilities()[0]._ngZone.hasPendingMacrotasks
getAllAngularTestabilities()[0]._ngZone.hasPendingMicrotasks

If any of these return true (if there are micro or macro tasks pending), then go to the last step. If all are false, congrats, you can use the builtin protractor's waiting for angular. But if you don't like it as I don't, then read the last step to find out how to disable it

  1. Run the above mentioned command. BUT! It returns a promise, which needs to be handled, preferably using await keyword
await browser.waitForAngularEnabled(false)

Full answer here

Sergey Pleshakov
  • 7,964
  • 2
  • 17
  • 40
  • I found the problem in application side, We are calling one common package in all the component's. inside the common service, we have defined three BehaviorSubject properties globally, So whenever I am calling the common service class in component constructor I am getting the error. If I removed that common service from constructor it will be working fine. Now my Question is **How to write the BehaviorSubject property declarations in outside of angular?** too critical :( – Ramesh Rajendran Mar 04 '21 at 04:48
  • 1
    **Found the root cause :** The Application insights is a cuprite. After removing the load event in application insight macro task is false. But how to handle it in real application instead of removing? Any idea? – Ramesh Rajendran Mar 04 '21 at 13:24
0

I have found the root cause from Application insights causing protractor timeout, So I have moved the code outside of angular. Now the protractor is working very well.

this.ngZone.runOutsideAngular(() => {
      this.appInsightSvc.onPageLoad();
    });

And ngb-carousel also throwing the same error, So for that also I have fixed by the same

Add [interval]='0' in carousel control

<ngb-carousel *ngIf="images" [interval]='0' style="position: fixed;" [showNavigationArrows]="showNavigationArrows"
     [showNavigationIndicators]="showNavigationIndicators">
     <ng-template ngbSlide *ngFor="let image of images">
          <img [src]="image" class="img-slide" alt="Random slide">
     </ng-template>
</ngb-carousel>

Add this code in componenet.ts

import { NgbCarousel } from '@ng-bootstrap/ng-bootstrap';

 @ViewChild(NgbCarousel)
 private carousel: NgbCarousel;

Define NgZone in constructor

private ngZone: NgZone

add this below line in ngOninit hook

this.ngZone.runOutsideAngular(() => {
            setInterval(() => {
                this.ngZone.run(() => {
                    this.carousel.next();
                });
            }, 3000);
        });
Ramesh Rajendran
  • 37,412
  • 45
  • 153
  • 234