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
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.
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:
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With