Hi all - I inherited a suite of Protractor tests that I’m trying to understand and do some refactoring on. It’s written in Typescript with ES6 syntax.
The test suite is using the Page Object Model and I noticed that elements and methods related to navigation currently live in a child page file called Landing Page. In essence:
// LandingPage.ts
import { ParentPage } from './parent-page.ts'
import { HomePage} from './home-page.ts'
import { AboutPage} from './about-page.ts'
export class LandingPage extends ParentPage {
homePageLink = element(by.id('home-page'))
aboutPageLink = element(by.id('about-page'))
navigateToHomePage: async (): Promise<HomePage> => {
await homePageLink.click()
return new HomePage();
}
navigateToAboutPage: async (): Promise<AboutPage> => {
await aboutPageLink.click()
return new AboutPage();
}
}
However - clicking navigation links and navigating to new pages is something that you can do from any page, not just the Landing, so it made sense to me to move these methods into the Parent Page Object itself. But when I do, I get this error:
Error: TypeError: Class extends value undefined is not a constructor or null
I learned that this is because I created a circular dependency from this Stackoverflow article and the ones linked in the answers: javascript - TypeError: Class extends value undefined is not a function or null - Stack Overflow
Essentially:
// ParentPage Object
import {HomePage} from './home-page'
export class ParentPage {
navigateToHomePage() {
// do some stuff
return new HomePage();
}
}
// Home Page Object
import {ParentPage} from './parent-page'
export class HomePage extends ParentPage {}
I have a method in my Parent Page object that returns an instance of a class that extends the Parent itself, which seems to be the crux of the problem. And also why all these navigation methods are in a child page class and not the parent.
But, how do I get around this while still using the page object model? All I can think of is not returning a Home Page object from the navigateToHomePage()
method, just going through the steps and making it a void return type like so:
// ParentPage Object
import {HomePage} from './home-page'
export class ParentPage {
navigateToHomePage() {
// do some stuff
}
}
// a test file
import {HomePage} from './home-page'
it('tests I can get to the home page', async() => {
await landingPage.navigateToHomePage();
let homePage = new HomePage();
})
This test would have to import all of the pages it would navigate to in the course of the test - not sure if that is an anti-pattern or not.
Anyone have thoughts on how to best handle this?