0

I am trying playwright and try to automate login feature. I have page classes, test classes and separate action class to write common actions like click,enter inputs.

My common action class

import { expect, Locator, Page } from "@playwright/test"

export default class Actions {

page:Page;

constructor(page:Page) {
    this.page = page ;
}

public async enterInput(value:string,element:Locator) {
    element.fill(value);
    await this.page.waitForTimeout(5000);
}

public async clickButton(element:Locator) {
    element.click();
    await this.page.waitForTimeout(5000)
}

}

My login.page.ts class

import { Locator, Page, expect } from "@playwright/test";
import Actions from "../common/actions";
import * as path from "../xpaths/xpath.json"
import fs from 'fs';


export default class LoginPage {

page: Page;
action:Actions;

inputUsername:Locator;
inputPassword:Locator;
btnLogin:Locator;
errorText:Locator;

constructor(page:Page) {
    this.page = page ;
    this.action=new Actions(page);

    const pathsxData = fs.readFileSync("json path here", "utf-8");
    const pathsx = JSON.parse(pathsxData);

    this.inputUsername = this.page.locator(path.usernameInput);
    this.inputPassword = this.page.locator(path.passwordInput);
    this.btnLogin = this.page.locator(path.loginBtn);
    this.errorText=this.page.locator(path.loginError)
    }

    public async login(username:string,password:string)
   {
    this.action.enterInput(username,this.inputUsername);
    this.action.enterInput(password,this.inputPassword);
    await this.action.clickButton(this.btnLogin);
    }

    public async successLogin(username:string,password:string,title:string){
    this.login(username,password);
    await expect(this.page).toHaveTitle(title);
    }

    public async invalidLogin(username:string,password:string,error:string){
    this.login(username,password);
    await expect(this.errorText).toHaveText(error);
    }

    public async emptyLogin(username:string,password:string,error:string){
    this.login(username,password);
    await expect(this.errorText).toHaveText(error);
    }

    }

My logintest.spec.ts

import { test , expect} from "@playwright/test"
import LoginPage from "../pages/login.page"
import * as data from "../testdata/testdata.json"

test.describe('Login Test', () =>{
let login:LoginPage;

 test.beforeEach(async({page}) =>{
    await page.goto("My Url");
    await page.waitForTimeout(5000)
    login = new LoginPage(page);
 });

test('invalid login-username/password both incorrect', async () => {
    login.invalidLogin(data.invalid_username,data.invalid_password,data.invalid_error);
});

test('empty username/password login', async()=>{
    login.invalidLogin(data.invalid_username,data.invalid_password,data.invalid_error);
});
test('successfully login to the system' , async () => {    
    login.successLogin(data.username,data.password,data.dashboard_title);
 });
 });

Whenever I execute the code always getting Target Closed error.Below is the error

Error: locator.fill: Target closed
=========================== logs ===========================
waiting for locator('xpath=//input[contains(@id,\'outlined-basic\') and contains(@type,\'text\')]')
============================================================

   at ..\common\actions.ts:16

  14 |
  15 |     public async enterInput(value:string,element:Locator) {
> 16 |         element.fill(value);
     |                 ^
  17 |         await this.page.waitForTimeout(5000);
  18 |     }

But when I execute code without using action class like below code executes successfully.

import { test , expect} from "@playwright/test"
import LoginPage from "../pages/login.page"
import * as data from "../testdata/testdata.json"

test.describe('Login Test', () =>{
let login:LoginPage;

test.beforeEach(async({page}) =>{
    
    console.log(page.url)
   
    login = new LoginPage(page);
});

test('invalid login-username/password both incorrect', async ({page}) => {
    page.goto("http://192.168.0.127/ussd_qa/login");
    await page.waitForTimeout(5000);
    await login.inputUsername.fill(data.username);
    await page.waitForTimeout(5000);
    await login.inputPassword.fill(data.password);
    await page.waitForTimeout(5000);
    await login.btnLogin.click();
    await page.waitForTimeout(5000);
    await expect(login.errorText).toHaveText(data.invalid_error);
});
});

Can someone explain what is wrong here?

1 Answer 1

0

I was searching for another issue when I stumbled on your question. I think you're missing the awaits in your Actions class for the fill and click methods (which you add correctly in your "without class" version).

Thus, the fill/click may not happen when you think, hence the error if it happens after the page has been closed.

Hope this helps ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.