Search code examples
javascriptclassobjectoopdependencies

JS: TypeError: Class extends value <ClassName> is not a constructor or null


I write UI tests using PageObject Pattern (NodeJS + Webdriverio) and I have a base class (BasePage), a page class(MyPage), a popup component class(PopupComponentClass) with multipurpose behaviour, a popup class with a specific implementation(SpecificPopupComponentClass). I need to extend SpecificPopupComponentClass from PopupComponentClass.

page.js:

export default class BasePage {


    get BASE_URL() {
        return "https://url.com";
    };

    ...some methods...
}

my.page.js:

import BasePage from "../page";

class MyPage extends BasePage {

    constructor() {
        super();
    };

    get URL() { return `${this.BASE_URL}/some/path` };
    get title() { return $("h1") };

    orderRandomTariff() {
        ...some actions...
    };

}

export default new MyPage ();

popup.component.page.js:

import BasePage from "../pages/page";

class PopupComponent extends BasePage{

    constructor() {
        super();
    };

    get title() { return $("h1") };
    

}

export default new PopupComponent();

specific.popup.component.js:

import PopupComponent from "./popupFragment";

class SpecificPopupComponent extends PopupComponent {

    constructor() {
        super();
    };

    get popupStreetInput() { return $(".//div[@class='checkAddress']//*[./*[contains(text(),'Street')]]//input") };

    fillStreet(street) {
        ...some actions with this.popupStreetInput...
    };

}

export default new SpecificPopupComponent();

...and trying to use it in test.js:

import MyPage from "../../../../pages/my.page";
import SpecificPopupComponent from "../../../../fragments/specific.popup.component";

const myPage= MyPage ;
const popup = SpecificPopupComponent ;

describe("Test", () => {

    before(() => {
        myPage.open();
    });

    it("Check", () => {
        popup.fillStreet("Street");
    });

});

but I'm getting an error: "TypeError: Class extends vlaue #PopupComponent is not a constructor or null". I suspect this is due to circular dependencies, but I can't understand, what I need to do to fix that.


Solution

  • It seems the issue here is how you're exporting the base class. You're instantiating it instead of just exporting the class you'll inherit from. It should be like this:

    export default class PopupComponent extends BasePage {
    
        constructor() {
            super();
        };
    
        get title() { return $("h1") };
        
    
    }
    

    And then create the instance when you're going to use it

    var myPage = new MyPage()
    var popup = new SpecificPopupComponent()
    
    myPage.open()
    popup.fillStreet('street')
    

    What you're doing there is equivalent to doing this:

    class SpecificPopupComponent extends new PopupComponent() {
       // ... what am I? 🤔
    }
    

    I suspect this is due to circular dependencies

    You can validate or reject your suspects by copying all the code into the test file in the correct order without using imports. But I don't think it's an circular dependency

    I created this Plunker to remove the usage of imports and prove this.