Доступ к глобальным переменным

В Protractor глобальные переменные играют ключевую роль при организации тестов, особенно когда необходимо хранить данные, общие для нескольких сценариев. Понимание механизмов их объявления и области видимости обеспечивает более чистую архитектуру тестов и предотвращает неожиданные ошибки во время выполнения.

Глобальные переменные в Node.js и Protractor

Protractor работает на основе Node.js и Jasmine или Mocha как фреймворка для тестирования. В Node.js глобальные переменные можно объявлять с помощью объекта global. Любая переменная, добавленная к global, становится доступной во всех модулях и тестах без необходимости её повторного импорта. Пример:

// В файле конфигурации или отдельном helper.js
global.testUser = {
    username: 'admin',
    password: '12345'
};

После этого testUser доступен в любом тесте:

describe('Авторизация', function() {
    it('должна использовать глобальные данные пользователя', async function() {
        await browser.get('http://example.com/login');
        await element(by.id('username')).sendKeys(testUser.username);
        await element(by.id('password')).sendKeys(testUser.password);
        await element(by.id('loginBtn')).click();
    });
});

Важно: чрезмерное использование глобальных переменных может привести к трудностям с отладкой, особенно если несколько тестов изменяют одну и ту же глобальную структуру данных.

Использование browser.params для передачи данных

Protractor предоставляет встроенный объект browser.params, который позволяет хранить параметры конфигурации и использовать их как глобальные переменные без объявления через global. Доступ к ним осуществляется из любого тестового файла:

// В protractor.conf.js
exports.config = {
    params: {
        login: {
            username: 'admin',
            password: '12345'
        },
        apiUrl: 'http://api.example.com'
    }
};

В тесте:

it('должен авторизоваться через параметры конфигурации', async function() {
    await browser.get('http://example.com/login');
    await element(by.id('username')).sendKeys(browser.params.login.username);
    await element(by.id('password')).sendKeys(browser.params.login.password);
    await element(by.id('loginBtn')).click();
});

Использование browser.params считается более безопасным и структурированным подходом, так как параметры остаются неизменными для всех тестов, и их легко модифицировать через конфигурационный файл.

Передача данных между тестами

Protractor не рекомендует напрямую менять глобальные переменные между тестами из-за возможного влияния на независимость сценариев. Для передачи данных между тестами лучше использовать объекты или фабрики, возвращающие необходимые значения. Пример через фабрику:

// helpers/dataFactory.js
class DataFactory {
    constructor() {
        this.user = {
            username: 'admin',
            password: '12345'
        };
    }

    getUser() {
        return this.user;
    }

    setUser(username, password) {
        this.user.username = username;
        this.user.password = password;
    }
}

module.exports = new DataFactory();

В тестах:

const dataFactory = require('./helpers/dataFactory');

describe('Тест с фабрикой данных', function() {
    it('использует данные пользователя', async function() {
        const user = dataFactory.getUser();
        await browser.get('http://example.com/login');
        await element(by.id('username')).sendKeys(user.username);
        await element(by.id('password')).sendKeys(user.password);
        await element(by.id('loginBtn')).click();
    });
});

Такой подход позволяет сохранить чистоту тестов и избежать побочных эффектов при изменении глобальных состояний.

Проблемы синхронизации и области видимости

Когда глобальные переменные содержат асинхронные данные (например, результаты API-запросов), необходимо внимательно следить за их доступностью. Использование async/await обеспечивает корректное ожидание данных перед их применением в тестах. Пример:

global.apiToken = null;

beforeAll(async function() {
    const response = await fetch('http://api.example.com/auth', {
        method: 'POST',
        body: JSON.stringify({ user: 'admin', pass: '12345' }),
        headers: { 'Content-Type': 'application/json' }
    });
    const data = await response.json();
    global.apiToken = data.token;
});

it('должен использовать токен в запросе', async function() {
    await browser.get('http://example.com/dashboard');
    console.log(apiToken); // токен уже доступен
});

Без await тест может попытаться использовать переменную до её заполнения, что приведет к ошибкам.

Практические рекомендации

  • Использовать browser.params для конфигурационных данных.
  • Минимизировать использование global для изменяемых объектов.
  • Для передачи состояния между тестами применять фабрики или сервисы данных.
  • Всегда учитывать асинхронность при работе с глобальными переменными, чтобы избежать ошибок синхронизации.
  • Организовать глобальные переменные в отдельных модулях для лучшей читаемости и поддержки.

Грамотное управление глобальными переменными повышает стабильность тестов и облегчает масштабирование автоматизации, особенно в больших проектах с множеством сценариев и командной разработкой.