问题
I am trying to extend the ElementFinder of Protractor with a few additional methods. I am doing this exactly the same way I also extended other classes, where it works without any problem. In a separate file called 'protractor-extension.ts', both the module declaration and the method implementation is contained:
declare module 'protractor/built/element' {
export interface ElementFinder {
safeClick() : Promise<void>;
}
}
(protractor.ElementFinderas any).safeClick= function () {
const _self = this as protractor.ElementFinderas ;
return await browser.wait(ExpectedConditions.elementToBeClickable(self), 5000)
.then(function() {
return self.click(); //if found
}, function() {
console.error(`Element is not clickable`); //error
});
}
This file is then imported in the .spec file where the safeClick() is used, with "import './extensions/protractor-extension.ts';"
The function is recognized, and I immediately get it in code-completion when using it on any ElementFinder.
The problem: During runtime I always get "Failed: myButton.safeClick is not a function"
As I said, if I replace the whole example 1:1 with the moment.js example, it works. So it seems to be related to the ElementFinder in protractor? All existing posts related to this topic also suggest to do exactly what I have done, but most of them are outdated (<2 years old).
I appreciate any hint that leads me to the right solution.
EDIT: Here is how the extension methods are used:
1) In the page object, the elements are declared
export class AdminPage {
/* ELEMENTS */
public userTable = element(by.id('userTable'));
public unlockBtn = element(by.id('unlockBtn'));
}
2) In the test (.spec file), the extension method is used
it('unlock button should disappear after click', async () => {
await this.adminPage.unlockBtn.safeClick();
expect(this.unlockBtn.isPresent()).toBeFalsy();
});
-> .safeClick() is autocompleted when writing "this.adminPage.unlockBtn.." -> .safeClick() is not recognized during runtime and throws an error
回答1:
I guess you use element()
and element.all()
in your script to declare web element on page.
element
or all
is instance of class ElementFinder
, and both are created at very beginning of running test case.
If your above code executed behind of the creation of element
and all
, element
and all
won't includes the safeClick()
Following is protractor init procedure:
lib/cli.ts https://github.com/angular/protractor/blob/master/lib/cli.ts#L242
--> lib/launcher.ts initFn()
--> lib/launcher.ts createNextTaskRunner()
--> lib/taskRunner.ts run() https://github.com/angular/protractor/blob/master/lib/launcher.ts#L222
--> lib/runner.ts run() https://github.com/angular/protractor/blob/master/lib/runner.ts#L334
--> lib/runner.ts createBrowser() https://github.com/angular/protractor/blob/master/lib/browser.ts#L316
--> lib/brower.ts ProtractorBrowser() https://github.com/angular/protractor/blob/master/lib/runner.ts#L237
// element created in this method
--> lib/runner.ts setupGlobals_() https://github.com/angular/protractor/blob/master/lib/runner.ts#L335
// setup element, all, $$, browser in global space
As I learned, protractor did not provide something like hooks to enable user to do something prior to lib/runner.ts createBrowser()
. If have, you can add your code in the hook.
来源:https://stackoverflow.com/questions/59239852/protractor-extension-of-elementfinder