Использование класса в тесте
Урок: Использование класса в тесте
Введение
На протяжении всего модуля мы постепенно строили одну важную идею:
- сначала научились создавать классы;
- затем добавили методы;
- потом превратили классы в Page Object;
- и сделали методы асинхронными.
Теперь осталось самое главное — научиться использовать всё это в реальных тестах.
Ниже в песочнице теории нет @playwright/test, поэтому мы имитируем минимальный test и page, чтобы код выполнялся и печатал шаги.
Как выглядел сценарий без Page Object
const page = {
goto: async (url) => console.log('goto', url),
fill: async (selector, value) => console.log('fill', selector, value),
click: async (selector) => console.log('click', selector),
};
(async () => {
await page.goto('https://example.com/login');
await page.fill('#login', 'user');
await page.fill('#password', '123');
await page.click('#submit');
})();
Когда тестов много, селекторы и шаги дублируются.
Page Object и «тест» в одном фрагменте
const page = {
goto: async (url) => console.log('goto', url),
fill: async (selector, value) => console.log('fill', selector, value),
click: async (selector) => console.log('click', selector),
};
class LoginPage {
constructor(page) {
this.page = page;
this.loginInput = '#login';
this.passwordInput = '#password';
this.submitButton = '#submit';
}
async login(login, password) {
await this.page.fill(this.loginInput, login);
await this.page.fill(this.passwordInput, password);
await this.page.click(this.submitButton);
}
}
async function test(name, fn) {
console.log('TEST:', name);
await fn({ page });
}
(async () => {
await test('логин пользователя', async ({ page }) => {
const loginPage = new LoginPage(page);
await page.goto('https://example.com/login');
await loginPage.login('user', '123');
});
})();
Создание объекта и вызов метода
const page = {
fill: async (s, v) => console.log('fill', s, v),
click: async (s) => console.log('click', s),
};
class LoginPage {
constructor(page) {
this.page = page;
this.loginInput = '#login';
this.passwordInput = '#password';
this.submitButton = '#submit';
}
async login(login, password) {
await this.page.fill(this.loginInput, login);
await this.page.fill(this.passwordInput, password);
await this.page.click(this.submitButton);
}
}
(async () => {
const loginPage = new LoginPage(page);
await loginPage.login('user', '123');
})();
Сравнение стиля
Низкоуровнево (всё на page):
const page = {
fill: async (s, v) => console.log('fill', s, v),
click: async (s) => console.log('click', s),
};
(async () => {
await page.fill('#login', 'user');
await page.fill('#password', '123');
await page.click('#submit');
})();
Через Page Object (смысл тот же, читается как сценарий):
const page = {
fill: async (s, v) => console.log('fill', s, v),
click: async (s) => console.log('click', s),
};
class LoginPage {
constructor(page) {
this.page = page;
this.loginInput = '#login';
this.passwordInput = '#password';
this.submitButton = '#submit';
}
async login(login, password) {
await this.page.fill(this.loginInput, login);
await this.page.fill(this.passwordInput, password);
await this.page.click(this.submitButton);
}
}
(async () => {
const loginPage = new LoginPage(page);
await loginPage.login('user', '123');
})();
Пример с проверкой (учебный expect)
const page = {
goto: async (url) => console.log('goto', url),
fill: async (s, v) => console.log('fill', s, v),
click: async (s) => console.log('click', s),
};
const expect = {
async toHaveURL(part) {
console.log('assert URL содержит', part);
},
};
class LoginPage {
constructor(page) {
this.page = page;
this.loginInput = '#login';
this.passwordInput = '#password';
this.submitButton = '#submit';
}
async login(login, password) {
await this.page.fill(this.loginInput, login);
await this.page.fill(this.passwordInput, password);
await this.page.click(this.submitButton);
}
}
(async () => {
const loginPage = new LoginPage(page);
await page.goto('https://example.com/login');
await loginPage.login('user', '123');
await expect.toHaveURL('/dashboard');
})();
Ошибка: забыли await у async-метода
const page = {
fill: async (s, v) => console.log('fill', s, v),
click: async (s) => console.log('click', s),
};
class LoginPage {
constructor(page) {
this.page = page;
this.loginInput = '#login';
this.passwordInput = '#password';
this.submitButton = '#submit';
}
async login(login, password) {
await this.page.fill(this.loginInput, login);
await this.page.fill(this.passwordInput, password);
await this.page.click(this.submitButton);
}
}
(async () => {
const loginPage = new LoginPage(page);
const p = loginPage.login('user', '123');
console.log('без await снаружи — это Promise?', p instanceof Promise);
await p;
})();
Правильно всегда писать await loginPage.login(...) при последовательном сценарии.
Импорт в реальном проекте
В Playwright-проекте класс обычно подключают из файла:
// В реальном репозитории:
// import { LoginPage } from '../pages/LoginPage';
console.log('Структура: pages/LoginPage + tests/*.spec.ts');
Итоговое понимание
Тест описывает сценарий, Page Object — как именно страница выполняет шаги.
Ты больше не думаешь только «как кликнуть», а «что делает пользователь» — и вызываешь методы страницы.
Именно так строятся реальные проекты на Playwright.