简体   繁体   中英

Angular2+ e2e testing - Cannot use by.id

I'm new to Angular2 and haven't developed the Angular components to be tested. However, I'm supposed to write some some UI (e2e) tests but I'm not even able to input text in an input field.

My problem is that element(by.id('username')).sendKeys('test') is not working. (Same with Button elements and so on)

I'm sure that it is only a small thing but I'm not able to find out what it is.

I have the following configuration:

  • Proctractor : 5.1.2
  • chrome driver : 58.0.3029.110
  • OS : Windows NT 6.1.7601 SP1 x86_64

Spec file:

import { LoginPage } from './login.po';

describe('login tests', function() {
  let page: LoginPage;

  beforeEach(() => {
    page = new LoginPage();
  });

  it('Demo', () => {
    page.navigateTo();
    page.getUsernameInput().sendKeys('test');
  });
});

Page Object file:

import { browser, element, by } from 'protractor';

export class LoginPage {
  navigateTo() {
    return browser.get('/login');
  }

  getParagraphText() {
    return element(by.class('app-root h1')).getText();
  }

  getUsernameInput() {
    return element(by.id('username'));
  }
}

The HTML template:

....
<div>
  <input
    id="username" 
    name="username" 
    ngModel 
    type="text" 
    placeholder="{{something}}" 
    autocomplete="off" 
    class="input-text" 
    required>
</div>
...

Proctractor config

var SpecReporter = require('jasmine-spec-reporter');

exports.config = {
    allScriptsTimeout: 120000,
    getPageTimeout: 120000,
    specs: [
      './e2e/**/*.e2e-spec.ts'
    ],
    capabilities: {
      'browserName': 'chrome'
    },
    directConnect: true,
    seleniumAddress: 'http://localhost:4444/wd/hub',
    baseUrl: 'http://localhost:8001',
    framework: 'jasmine',
    jasmineNodeOpts: {
      showColors: true,
      defaultTimeoutInterval: 30000,
      print: function() {}
    },
    useAllAngular2AppRoots: true,
    beforeLaunch: function() {
      require('ts-node').register({
        project: 'e2e'
      });
    },
    onPrepare: function() {
      jasmine.getEnv().addReporter(new SpecReporter());
    }
};

Any help is highly appreciated.

EDIT: None of the solutions worked in my case. I ended up using browser.driver.findElement(by.id('username')); instead of element(by.id('username')); This is unsatisfying because I still don't understand why this doesn't work. I'd be thankful if someone could give me a hint or explanation.

I think your problem is timing.

What happens if you do:

it('Demo', () => {
    // wait for page to change to /login
    return page.navigateTo().then(() => {
        // then look for user input and write 'test' 
        return page.getUsernameInput().sendKeys('test');
    });    
});

Edit:

Sounds odd to me that browser.driver.findElement(by.id('username')) works since element(by.id('username')) should be equivalent.

I use a helper class for a lot of the browser interactions, perhaps worth a shot.

Snippets I use for finding element and sending keystrokes:

public static async getElement(locator: By | Function, waitMs?: number): Promise<ElementFinder | any> {

    await BrowserHelper.waitForVisibilityOf(locator, waitMs | 1000);

    return element(locator);
}

public static sendKeys(locator: By | Function, keys: string, clear?: boolean, waitMs?: number): Promise<void> {
    return BrowserHelper.getElement(locator, waitMs).then((element: ElementFinder) => {
        if (!clear) {
            return element;
        }

        return element.clear().then(() => element);
    }).then((element: ElementFinder) => {
        return element.sendKeys(keys)
    });
}

public static async waitForVisibilityOf(locator: By | Function, waitMs?: number): Promise<any> {
    await browser.wait(EC.presenceOf(element(locator)), waitMs || 5000).then(() => {
        // visible
    }, (error) => {
        console.error('timeout at waitForVisibilityOf', locator, error);
    });
}

I believe this is due to your getUsernameInput() method returning not the locator in this case. As per Protractor documentation,

The element() function returns an ElementFinder object. The ElementFinder knows how to locate the DOM element using the locator you passed in as a parameter, but it has not actually done so yet. It will not contact the browser until an action method has been called.

You can try this modified code

   getUsernameInput() {
      element(by.id('username')).sendKeys('text');
    }
   }

and then using

  it('Demo', () => {
      page.navigateTo();
      page.getUsernameInput();
  });
});

Also, I'm not sure your getText() would return the text, because getText() returns a Promise, which you would have to resolve. This has been explained here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM