I'm writing some tests on a game page for a couple of automated tests. I am using puppeteer and typescript. I have a problem in the function login()
because the instructions that are defined, when it reaches the login, are not yet defined
(node:16244) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'waitFor' of undefined
This is my index.ts
import CorePuppeteer from './core/puppeteer.core';
import { Credentials } from './interfaces/interface';
// Parámetros
const url = 'https://lobby.ogame.gameforge.com/es_ES/';
// Aquí se instancia un objeto, y el constructor se encarga de crear lo necesario para empezar a trabar
const core = new CorePuppeteer( url, false );
const credentials: Credentials = {
email: '[email protected]',
password: 'foobar'
};
// Invocación de funciones
( async () => {
// aquí salta el error
await core.login( credentials );
})();
This is the code for puppeteer.core.ts
import puppet from 'puppeteer';
import { Credentials } from '../interfaces/interface';
export default class CorePuppeteer {
// public browser: puppet.Browser;
// public page: puppet.Page;
public browser: any;
public page: any;
public delay = 100;
constructor( url: string, headless = true ) {
( async () => {
this.browser = await puppet.launch( { headless } );
this.page = await this.browser.newPage();
await this.page.setViewport({ width: 1366, height: 768});
await this.page.goto( url, { waitUntil: 'networkidle2' } );
})();
}
async login( credentials: Credentials ) {
const inputEmail = 'input[name="email"]';
const inputPass = 'input[name="password"]';
const button = 'button[type="submit"]';
await this.page.waitFor( inputEmail );
await this.page.type( inputEmail, credentials.email, { delay: this.delay } );
await this.page.type( inputPass, credentials.password, { delay: this.delay } );
await this.page.click( button );
}
}
What can I do to wait for the constructor to finish setting all the variables, before the next login function is called?
The problem is that a constructor cannot be async by definition. No matter how much you invoke an IIFE on itself, the instance is resolved (built) before
Promise
the IIFE's is resolved.That gives way to the error that you find, and that is that you have the instance of
CorePupeeter
before and its propertypage
is initialized after .Since the constructor is not asynchronous, we must create a method
async
that knows how to resolve instances ofCorePupeeter
asynchronously, leaving the constructor private (to avoid this error) and that method static.I'm going to simplify the class for the sake of example.
The asynchronous work is delegated to the same method
create
so that we can "wait" for the new instance toCorePupeeter
be ready and with all its properties initialized.We would use it as follows
I hope it works.