Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protractor e2e test written in typescript with page object

I'm trying to write some e2e tests in typescript using Protractor and Jasmine syntax using a Page Object to abstract the DOM structure from the tests.

When running protractor I get an error telling me that my my page object is not a function.

Here is the page object as a typescript class: home.po.spec.ts

module Tests.e2e.Home {
    export class HomePage {
        emailInput;

        constructor() {
            this.emailInput = element(by.model('email'));
        }

        get(): void {
            browser.get('https://localhost:44300');
        }

        get email(): string {
            return this.emailInput.getText();
        }

        set email(value: string) {
            this.emailInput.sendKeys(value);
        }
    }
}

This is my test: home.e2e.spec.ts

///<reference path="home.po.spec.ts"/>
module Tests.e2e.Home {
    describe('home view', () => {
        it('should mark invalid email in field', () => {
            // arrange
            var homePage = new HomePage();
            homePage.get();
            var emailField = homePage.emailInput;

            // act
            homePage.email = 'some invalid email';

            // assert
            expect(emailField.getAttribute('class')).toMatch('ng-invalid');
        });
    });
}

I'm writing the tests in Visual Studio 2013 and running protractor with a gulp task on nodejs.

Here is the error message:

Starting selenium standalone server...
[launcher] Running 1 instances of WebDriver
Selenium standalone server started at http://192.168.5.153:23704/wd/hub
F

Failures:

1) home view should mark invalid email in field
Message:
TypeError: Home.HomePage is not a function
    Stacktrace:
    TypeError: Home.HomePage is not a function
    at [object Object].<anonymous>(C:\Users\BSO\Documents\Git repos\app\Prese
    ntation.Web\Tests\home.e2e.spec.ts:5:28)
at C: \Users\BSO\AppData\Roaming\npm\node_modules\protractor\node_modules\jas
minewd\index.js:94:14
at goog.async.run.processWorkQueue(C:\Users\BSO\AppData\Roaming\npm\node_mo
    dules\protractor\node_modules\selenium - webdriver\lib\goog\async\run.js:130:15)
From: Task: Asynchronous test function: it()
at[object Object].<anonymous> (C:\Users\BSO\AppData\Roaming\npm\node_module
s\protractor\node_modules\jasminewd\index.js:93:33)
at[object Object].<anonymous> (C:\Users\BSO\AppData\Roaming\npm\node_module
s\protractor\node_modules\minijasminenode\lib\async - callback.js:45:37)
at[object Object].jasmine.Block.execute(C:\Users\BSO\AppData\Roaming\npm\n
    ode_modules\protractor\node_modules\minijasminenode\lib\jasmine - 1.3.1.js:1174:17
    )
at[object Object].jasmine.Queue.next_(C:\Users\BSO\AppData\Roaming\npm\nod
    e_modules\protractor\node_modules\minijasminenode\lib\jasmine - 1.3.1.js:2209:31)
at[object Object]._onTimeout(C:\Users\BSO\AppData\Roaming\npm\node_modules
    \protractor\node_modules\minijasminenode\lib\jasmine - 1.3.1.js:2199:18)
Error
at[object Object].<anonymous> (C:\Users\BSO\Documents\Git repos\app\Prese
ntation.Web\Tests\home.e2e.spec.ts:3:9)
at[object Object].jasmine.Env.describe_(C:\Users\BSO\AppData\Roaming\npm\n
    ode_modules\protractor\node_modules\minijasminenode\lib\jasmine - 1.3.1.js:913:21)

at[object Object].jasmine.Env.describe(C:\Users\BSO\AppData\Roaming\npm\no
    de_modules\protractor\node_modules\minijasminenode\lib\jasmine - 1.3.1.js:898:15)
at describe (C:\Users\BSO\AppData\Roaming\npm\node_modules\protractor\node_m
    odules\minijasminenode\lib\jasmine - 1.3.1.js:658:27)
at e2e.Home.e2e.Home(C:\Users\BSO\Documents\Git repos\app\Presentation.We
    b\Tests\home.e2e.spec.ts:2:5)
at Tests.e2e.Tests.e2e(C:\Users\BSO\Documents\Git repos\app\Presentation.
    Web\Tests\home.e2e.spec.ts:16:2)
at Tests (C:\Users\BSO\Documents\Git repos\app\Presentation.Web\Tests\home
    .e2e.spec.ts:16:2)
at Object.<anonymous>(C:\Users\BSO\Documents\Git repos\app\Presentation.W
    eb\Tests\home.e2e.spec.ts:16:2)

Finished in 0.031 seconds
1 test, 1 assertion, 1 failure

Shutting down selenium standalone server.
    [launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 failed 1 test(s)
[launcher] overall: 1 failed spec(s)
[launcher] Process exited with error code 1

Can anyone help me with this? How can I make the test file reference

Solution

The solution is to not use internal modules in TypeScript for this. By changing to commonjs module system and use typescripts import something = require('path to someting') it works as expected.

Here is a sample of the setup. The page object home.po.spec.ts:

class HomePage {

    getPage(): void {
        browser.get('https://localhost:44300/');
    }

    nameElement = element(by.id('name'));
    get nameInput(): string {
        var value: string;
        this.nameElement.getAttribute('value').then(v => value = v);
        return value;
    }

    set nameInput(value: string) {
        this.nameElement.sendKeys(value);
    }
}

export = HomePage;

And the test spec home.e2e.spec.ts:

import HomePo = require('./home.po.spec');

describe('home view', () => {
    it('name input should be writeable', () => {
        // arrange
        var pageObject: HomePo = new ItProjectEditPo();
        pageObject.getPage();

        // act
        pageObject.nameInput = 'SomeName';

        // assert
        expect(pageObject.nameInput).toBe('SomeName');
    });
});

Some notes on the solution. The page object needs to resolve the element getAttribute promise when using TypeScript properties, getAttribute returns a promise but sendKeys takes a string.

TypeScript modules documentation is here. It took me some time to understand it, but it makes good sense now. By using this module structure it is also possible to import nodejs packages.

like image 855
Bjørn Sørensen Avatar asked Nov 13 '15 13:11

Bjørn Sørensen


1 Answers

You probably told protractor to include all your *.spec.ts files, so protractor will include them by the order of the abc. This means that the file home.e2e.spec.ts will be included before the home.po.spec.ts file.

You have two options:

  1. Change the order of the files (Bad idea).
  2. Tell TypeScript to export into commonjs module format, so it will be possible to do import to the page object (Instead of reference files)

There's another issue that you didn't see: You initialized the emailInput in the constructor but called get after it was initialized...

like image 152
gilamran Avatar answered Oct 21 '22 10:10

gilamran