автор Малаховская Екатерина
Playwright, cucumber, JS вопросы для собеседования

1. Можете объяснить структуру типичного теста Playwright?


Типичный тест Playwright состоит из следующих компонентов:

1. Импортирование модулей:
- Начинаете с импортирования необходимых модулей из Playwright или других библиотек, которые вам нужны.

import { test, expect } from '@playwright/test';
2. Определение тестового набора:
- Используйте функцию test.describe, чтобы сгруппировать связанные тесты вместе. Это необязательно, но полезно для организации тестов.

 test.describe('My Test Suite', () => {
      // Tests go here
  });
3. Настройка и завершение:
- Playwright предоставляет хуки, такие как beforeAll, beforeEach, afterAll и afterEach, для настройки и завершения тестовых сред.

test.beforeAll(async ({ browser }) => {
      // Code to run before all tests
  });

  test.afterAll(async ({ browser }) => {
      // Code to run after all tests
  });
4. Определение теста:
- Определите отдельные тесты, используя функцию test. Каждый тест состоит из описания и асинхронной функции, содержащей логику теста.

 test('should have the correct title', async ({ page }) => {
      await page.goto('https://example.com');
      const title = await page.title();
      expect(title).toBe('Example Domain');
  });
5. Утверждения:
- Используйте встроенную библиотеку утверждений Playwright для проверки ожидаемых результатов.
expect(someValue).toBe(expectedValue);
6. Взаимодействие со страницей:
- Выполняйте действия, такие как переход по URL, нажатие на элементы, ввод в поля и т.д.
await page.click('button#submit');
await page.fill('input#username', 'myUsername');
7. Локаторы:
- Используйте локаторы для поиска элементов на странице. Playwright предлагает мощные селекторные движки.
const submitButton = page.locator('button#submit');
await submitButton.click();

2. Как вы выполняете автоматизацию браузера в Playwright?


Автоматизация браузера в Playwright включает несколько ключевых шагов:

1. Запуск браузера:
- Начните с запуска экземпляра браузера. Playwright поддерживает несколько браузеров, таких как Chromium, Firefox и WebKit.
const browser = await playwright.chromium.launch();
2. Создание контекста браузера:
- Создайте новый контекст браузера. Это похоже на создание нового профиля браузера с отдельными куками, хранилищем и т.д. Это полезно для изоляции тестов.
const context = await browser.newContext();
3. Открытие новой страницы:
- Откройте новую страницу в контексте браузера. Это представляет собой одну вкладку.
const page = await context.newPage();
4. Переход к URL:
- Направьте браузер на переход к определенному URL.
await page.goto('https://example.com');
5. Взаимодействие со страницей:
- Выполняйте действия, такие как нажатие кнопок, заполнение форм и создание скриншотов.
  await page.click('button#login');
  await page.fill('input#username', 'testuser');
  await page.screenshot({ path: 'screenshot.png' });
6. Ожидание селекторов и событий:
- Playwright предоставляет встроенные механизмы для ожидания появления элементов или наступления определенных событий.
await page.waitForSelector('h1');
7. Утверждения (Assertions):
- Используйте утверждения Playwright для проверки ожидаемого состояния страницы.
 const header = await page.textContent('h1');
 expect(header).toBe('Welcome');
8. Закрытие браузера:
- После завершения тестов закройте страницу и контекст браузера.
 await page.close();
 await context.close();
 await browser.close();
9. Обработка нескольких страниц:
- Playwright поддерживает обработку нескольких страниц в одном контексте браузера, что полезно для сценариев с всплывающими окнами или новыми вкладками.
 const [newPage] = await Promise.all([
 context.waitForEvent('page'),
 page.click('a[target=_blank]') // Click opens a new tab
 ]);
 await newPage.waitForLoadState();
10. Расширенные взаимодействия:
- Playwright также поддерживает расширенные взаимодействия, такие как загрузка файлов, перемещение мыши и ввод с клавиатуры.
 await page.setInputFiles('input[type="file"]', 'path/to/file.txt');
 await page.mouse.move(0, 0);
 await page.keyboard.type('Hello, world!');

3. Напишите функцию для переворота строки на JavaScript/TypeScript:

function reverseString(str: string): string { 
return str.split('').reverse().join(''); } 
console.log(reverseString("hello")); 
В целом, знание SQL является важным навыком для тестировщика, поскольку позволяет проводить более глубокое и эффективное тестирование приложений, особенно при работе с базами данных.

Хотите научиться работать с базами данных - пройдите курс Основы SQL!

4. Объясните разницу между let, var и const:

var переменная, объявленная с помощью var внутри функции, доступна в пределах всей этой функции. Если она объявлена вне какой-либо функции, она имеет глобальную область видимости. Переменные, объявленные с помощью var, могут быть переназначены.

let переменная доступна только в пределах блока ({}), где она объявлена. Может быть переназначена.

const имеет блочную область видимости, как и let. Не может быть переназначена. Должна быть инициализирована в момент объявления.

5. Как обрабатывать асинхронный код в JavaScript:


Обработка асинхронного кода в JavaScript может осуществляться несколькими способами, включая коллбэки, Промисы и async/await. Каждый из этих методов предоставляет способ управления задачами, которые выполняются в фоновом режиме, не блокируя основной поток. Это важно для поддержания отзывчивости приложений, особенно в браузерной среде.

Callbacks: Это функции, передаваемые в качестве аргументов другим функциям и вызываемые после завершения какой-либо операции. Это традиционный способ обработки асинхронных операций в JavaScript.
function fetchData(callback) { 
setTimeout(() => { 
const data = 'data from server'; 
callback(data); 
}, 1000); 
} 
fetchData((data) => { 
console.log(data); // "data from server" after 1 second 
});
Промисы (Promises): Это объекты, представляющие результат асинхронной операции. Они позволяют более удобно работать с асинхронными операциями, избегая "ад коллбэков".

async/await: Это синтаксический сахар для работы с промисами, который делает код асинхронных функций более понятным и читабельным.
async function fetchData() {
 return new Promise((resolve, reject) => {
   setTimeout(() => {
     const data = 'data from server';
     resolve(data);
   }, 1000);
 });
}

async function main() {
 try {
   const data = await fetchData();
   console.log(data); // "data from server" after 1 second
 } catch (error) {
   console.error(error);
 }
}
main();

6. Как управлять зависимостями в проекте Node.js?


С помощью файла package.json. Этот файл содержит метаданные о вашем проекте и записывает зависимости.
npm init
npm install express
npm install mocha --save-dev
package-lock.json автоматически генерируется и отслеживает точные версии зависимостей.

7. Какие общие модули Node.js вы использовали при тестировании?


  • Cucumber
  • Playwright
  • Eslint
  • Prettier
  • Cross-env
  • Allure reports

8. Как вы подходите к написанию тестовых случаев для новой функции?


  • Понять требования
  • Определить тестовые сценарии
  • Подумать о крайних случаях и о том, как функция должна вести себя в неожиданных ситуациях или с некорректным вводом.
  • Определить тестовые случаи
  • Категоризировать тестовые случаи (Smoke, Regression, Integration и т.д.)
  • Определить, какие тестовые случаи можно автоматизировать.
  • Выполнить тестовые случаи
  • Зарегистрировать дефекты
  • Просмотреть и рефакторить

9. Как вы определяете приоритеты тестовых случаев?


  • Понимание бизнес-влияния.
  • Фокус на тестовых случаях, которые охватывают основные сценарии использования и рабочие процессы пользователей. Это пути, которые пользователи проходят наиболее часто.
  • Приоритизация тестирования областей с высоким риском отказов. Это может быть связано с сложностью, новым кодом или областями, которые исторически вызывали проблемы.
  • Определение потенциальной серьезности дефектов в каждой области.
  • Выравнивание приоритетов тестовых случаев с политиками и стандартами компании, такими как безопасность и производительность.
  • Тестовые случаи, требующие значительных ручных усилий и подверженные человеческим ошибкам, должны быть автоматизированы при возможности и соответственно приоритизированы.
  • Учитывать обратную связь от конечных пользователей.

10. Как вы подходите к отладке неудачного теста?


  • Понять причину сбоя. Определите, какой тест не прошел и характер сбоя (например, ошибка утверждения, тайм-аут, исключение).
  • Воспроизведите сбой локально. Запустите неудачный тест изолированно.
  • Проверьте изменения в коде. Если сбой произошел после недавнего изменения кода, проверьте изменения, внесенные в кодовую базу с момента последнего успешного запуска тестов.
  • Проверьте тестовое окружение. Убедитесь, что тестовая среда настроена правильно.
  • Проверьте тестовые данные. Оцените данные и вводные параметры, используемые неудачным тестом.
  • Используйте инструменты отладки, предоставляемые тестовым фреймворком.

11.Как вы интегрировали автоматизированные тесты в конвейер CI/CD?


Настройка GitLab CI/CD.
Создание файла YML.

12. Как вы обеспечиваете качество программного обеспечения в вашей команде?


  • Установите четкие стандарты качества и критерии для программного обеспечения.
  • Примените комплексную стратегию тестирования, которая включает модульное тестирование, интеграционное тестирование и тестирование end-to-end.
  • Регулярно проводите кодовые ревью.
  • Реализуйте конвейеры CI/CD для автоматизации процесса сборки, тестирования и развертывания.
  • Отслеживайте производительность вашего программного обеспечения в продакшн-среде для выявления узких мест.
  • Поддерживайте актуальную документацию для программного обеспечения.
  • Оценивайте риски на основе их влияния и вероятности, и реализуйте стратегии снижения рисков.

13. Какие существуют лучшие практики для написания поддерживаемых и масштабируемых тестов?


  • Сохраняйте тесты независимыми.
  • Пишите описательные и значимые названия тестов.
  • Следуйте шаблону Arrange-Act-Assert (AAA). Структурируйте ваши тесты, используя шаблон AAA, где вы устанавливаете предусловия (Arrange), выполняете действия (Act) над системой под тестирование и проверяете ожидаемые результаты (Assert).
  • Избегайте дублирования кода между тестами.
  • Используйте параметризованные тесты.
  • Сосредоточьтесь на тестировании критических путей и граничных случаев.
  • Регулярно рефакторите и поддерживайте ваш набор тестов в соответствии с изменениями в кодовой базе.
  • Мониторьте и анализируйте метрики тестирования.
  • Документируйте намерения за тестами. Это помогает новым членам команды понять цель тестов.

14. Как вы решаете проблему непостоянных (flaky) тестов?


  • Определите непостоянные тесты.
  • Выделите непостоянный тест и попытайтесь воспроизвести сбой локально.
  • Проверьте код и логику теста на наличие потенциальных причин непостоянства.
  • Устраните коренные причины непостоянства, внеся целевые изменения в код теста, код приложения или тестовую среду. Это может включать добавление явных ожиданий, улучшение синхронизации, стабилизацию внешних зависимостей.
  • Реализуйте механизм повтора (retry mechanism).
  • Улучшите отчетность и ведение журнала тестов для захвата дополнительной информации при сбое теста.
  • Пометьте непостоянные тесты.

15. Какие существуют типы данных в JavaScript?


Различные типы данных в JavaScript включают в себя семь примитивных типов: undefined, null, boolean, number, string, symbol и bigint. Также существует один не примитивный тип данных: object.

16. Что такое замыкание (closure) в JavaScript


Замыкание (closure) в JavaScript — это функция, которая имеет доступ к своему собственному окружению, окружению внешней функции и глобальному окружению.
function createCounter() {
 let count = 0; 

 return function() {
   count++; 
   console.log(count);
 };
}

const counter = createCounter();

counter(); // Output: 1
counter(); // Output: 2
counter(); // Output: 3

17. Объясните концепцию "this" в JavaScript.


"this" в JavaScript — это специальное ключевое слово, которое ссылается на текущий контекст выполнения кода. Значение "this" зависит от того, как вызывается функция:
  • В глобальном контексте: В строгом режиме "this" будет undefined, в нестрогом режиме "this" ссылается на глобальный объект (например, window в браузере или global в Node.js).
  • В методе объекта: "this" ссылается на объект, к которому принадлежит метод.
  • В конструкторе: "this" ссылается на новый созданный объект.
  • С помощью call(), apply() или bind(): Эти методы позволяют явно указать значение "this".
Конкретное значение "this" определяется в момент выполнения кода и может изменяться в зависимости от контекста вызова функции.

18. Что такое цикл событий (loop) в JavaScript?


Цикл событий — это механизм, который позволяет JavaScript выполнять неблокирующие асинхронные операции. Он постоянно проверяет очередь сообщений и стек вызовов, выполняя задачи из очереди, когда стек пуст.

for (let i = 1; i <= 5; i++) { 
console.log(i); }
/////////////////////////////////
let i = 1; 
while (i <= 5) { 
console.log(i); 
i++; }
/////////////////////////////////
let j = 1; 
do { 
console.log(j);
 j++; 
} while (j <= 5);

19. Объясните разницу между == и ===


Оператор === сравнивает два значения без приведения типов. Он считает равными только те значения, которые имеют одинаковый тип и значение.

console.log(5 === ’5’) // false, потому что число 5 не равно строке "5"
Оператор == сравнивает два значения, выполняя приведение типов, если это необходимо. Это означает, что он может считать равными значения разного типа, если они могут быть приведены к одному и тому же типу.
console.log(5 == ’5’) // true, потому что число 5 равно строке "5"

20. Что такое Promises и как они работают?


Promise (обещание) — это объект, представляющий окончание или неудачу асинхронной операции. Он может находиться в одном из трех состояний: ожидание (pending), выполнено (fulfilled) или отклонено (rejected). Promises позволяют создавать цепочки через методы .then() и .catch(), что облегчает работу с асинхронными операциями.

// Пример функции, возвращающей promise для имитации асинхронной операции
function fetchData() {
 return new Promise((resolve, reject) => {
   // Имитация асинхронной операции с использованием setTimeout
   setTimeout(() => {
     const success = true; // Имитируем успех или неудачу

     if (success) {
       resolve('Data fetched successfully!');
     } else {
       reject('Error fetching data.');
     }
   }, 2000); // Имитируем задержку в 2 секунды
 });
}

// Использование promise
fetchData()
 .then((data) => {
   console.log(data); // Это выполнится, если promise выполнен успешно
 })
 .catch((error) => {
   console.error(error); // Это выполнится, если promise был отклонен
 });

21. Что такое async/await и чем он отличается от Promises


async/await — это синтаксический сахар поверх Promises. Асинхронная функция (async function) возвращает Promise, а await приостанавливает выполнение асинхронной функции, ожидая, пока Promise выполнится. Это позволяет писать асинхронный код, который выглядит и ведет себя больше как синхронный код.

Скачать шпаргалку с вопросами и ответами можно здесь:

Хотите узнать больше об автоматизированном тестировании?
Записывайтесь на наш курс по Автоматизации!
Учимся отличать тест-план, тест-кейсы и чек-листы на примерах.
Полезные ресурсы и советы для поиска работы
Выпускник школы QaLearning рассказывает про свой путь обучения, поиска работы и прохождения собеседований. Вы получите много дельных советов!