Загрузка данных


package ru.sber.qa.playwright.configuration.config.impl;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Playwright;
import ru.sber.qa.playwright.configuration.scope.PlaywrightConfigScope;
import ru.sber.qa.playwright.configuration.selenoid.SelenoidCapabilities;
import ru.sber.qa.playwright.services.PlaywrightServiceConfiguration;

import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

public class DefaultPlaywrightServiceConfiguration implements PlaywrightServiceConfiguration {
    private final Properties properties = new PlaywrightConfigScope().getProperties();

    public DefaultPlaywrightServiceConfiguration() {
    }

    /**
     * <p>Настройки запуска Playwright</p>
     */
    protected Properties getProperties() {
        return properties;
    }

    /**
     * <p>Настройки запуска Playwright</p>
     *
     * @return {@link Playwright.CreateOptions}
     */
    @Override
    public Playwright.CreateOptions createOptions() {
        Playwright.CreateOptions createOptions = new Playwright.CreateOptions();
        Map<String, String> env = new HashMap<>();

        // Включение отладки, но необходимо вручную задать путь до исходников через PLAYWRIGHT_JAVA_SRC
        // Например PLAYWRIGHT_JAVA_SRC=.../main/java:.../test/java разделяя пути двоеточием.
        if (Boolean.parseBoolean(properties.getProperty("web.playwright.debug"))) {
            env.put("PWDEBUG", "1");
        }

        // Ссылка на скачивание браузеров
        String downloadHost = properties.getProperty("web.playwright.download.host");
        if (isNotBlank(downloadHost)) {
            env.put("PLAYWRIGHT_DOWNLOAD_HOST", downloadHost);
        }

        // Отключение скачивание браузеров
        if (Boolean.parseBoolean(properties.getProperty("web.playwright.browser.download.skip"))) {
            env.put("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "1");
        } else {
            env.put("NODE_TLS_REJECT_UNAUTHORIZED", "0");
        }

        // Путь к установленному NodeJS, если есть
        String nodePath = properties.getProperty("web.playwright.nodejs.path");
        if (isNotBlank(nodePath)) {
            env.put("PLAYWRIGHT_NODEJS_PATH", nodePath);
        }

        // Путь к скачанным браузерам
        String browserDownloadPath = properties.getProperty("web.playwright.browser.download.path");
        if (isNotBlank(browserDownloadPath)) {
            env.put("PLAYWRIGHT_BROWSERS_PATH", browserDownloadPath);
        }

        createOptions.setEnv(env);
        return createOptions;
    }

    /**
     * <p>Настройки запуска Playwright на Selenoid.</p>
     */
    @Override
    public BrowserType.ConnectOverCDPOptions connectOverCDPOptions() {
        double timeout = Double.parseDouble(properties.getProperty("web.timeout"));
        double slowMo = Double.parseDouble(properties.getProperty("web.playwright.step.delay"));

        return new BrowserType.ConnectOverCDPOptions()
                .setTimeout(timeout)
                .setSlowMo(slowMo);
    }

    /**
     * <p>Опции для Selenoid.</p>
     */
    @Override
    public SelenoidCapabilities selenoidCapabilities() {
        // Для указания пути к бинарнику SberBrowser
        boolean isSber = false;
        // Во всех случаях, кроме edge результат будет chrome-о-подобный
        String browserName = switch (properties.getProperty("web.browser.type").toLowerCase()) {
            case "edge" -> "edge";
            case "sber" -> {
                isSber = true;
                yield "chrome";
            }
            default -> "chrome";
        };

        SelenoidCapabilities capabilities = new SelenoidCapabilities()
                .browserName(browserName)
                .browserVersion(properties.getProperty("web.browser.version"));

        if (isSber) {
            capabilities.binaryPath("/usr/bin/sberbrowser-browser");
        }

        return capabilities
                .enableVNC(Boolean.parseBoolean(properties.getProperty("web.enable.vnc")))
                .setArgs(args())
                .addPrefs(browserPreferences())
                .screenResolution(properties.getProperty("web.browser.size"))
                .setEnv(List.of(properties.getProperty("web.env.logs").split(";")))
                .sessionTimeout(properties.getProperty("web.session.timeout"))
                .downloadsEnabled(true);
    }

    /**
     * <p>Настройки запуска браузера</p>
     *
     * @return {@link BrowserType.LaunchOptions}
     */
    @Override
    public BrowserType.LaunchOptions launchOptions() {
        BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions();
        String downloadPath = properties.getProperty("web.playwright.download.path");
        if (isNotBlank(downloadPath)) {
            launchOptions.setDownloadsPath(Path.of(downloadPath));
        }

        double timeout = Double.parseDouble(properties.getProperty("web.timeout"));
        launchOptions.setTimeout(timeout);

        if (Boolean.parseBoolean(properties.getProperty("web.playwright.headless"))) {
            launchOptions.setHeadless(true);
        } else {
            launchOptions.setHeadless(false);
            double slowMo = Double.parseDouble(properties.getProperty("web.playwright.step.delay"));
            launchOptions.setSlowMo(slowMo);
        }

        String tracesPath = properties.getProperty("web.playwright.traces.path");
        if (isNotBlank(tracesPath)) {
            launchOptions.setTracesDir(Path.of(tracesPath));
        }

        // Chromium по умолчанию
        String browserProp = properties.getProperty("web.playwright.browser");
        Path executablePath = Path.of(browserProp);
        if (executablePath.toFile().exists()) {
            launchOptions.setExecutablePath(executablePath);
        }

        return launchOptions;
    }

    /**
     * <p>Настройки запуска браузера</p>
     *
     * @return {@link BrowserType.LaunchPersistentContextOptions}
     */
    @Override
    public BrowserType.LaunchPersistentContextOptions launchPersistentContextOptions() {
        BrowserType.LaunchPersistentContextOptions launchOptions = new BrowserType.LaunchPersistentContextOptions();
        launchOptions.setArgs(args());

        // Запись видео
        boolean recordVideo = Boolean.parseBoolean(properties.getProperty("web.playwright.video"));
        if (recordVideo) {
            String videoPath = properties.getProperty("web.playwright.video.path");
            if (isNotBlank(videoPath)) {
                launchOptions.setRecordVideoDir(Path.of(videoPath));
            }
        }

        String downloadPath = properties.getProperty("web.playwright.download.path");
        if (isNotBlank(downloadPath)) {
            launchOptions.setDownloadsPath(Path.of(downloadPath));
        }

        double timeout = Double.parseDouble(properties.getProperty("web.timeout"));
        launchOptions.setTimeout(timeout);

        if (Boolean.parseBoolean(properties.getProperty("web.playwright.headless"))) {
            launchOptions.setHeadless(true);
        } else {
            launchOptions.setHeadless(false);
            double slowMo = Double.parseDouble(properties.getProperty("web.playwright.step.delay"));
            launchOptions.setSlowMo(slowMo);
        }

        String tracesPath = properties.getProperty("web.playwright.traces.path");
        if (isNotBlank(tracesPath)) {
            launchOptions.setTracesDir(Path.of(tracesPath));
        }

        // Chromium по умолчанию
        String browserProp = properties.getProperty("web.playwright.browser");
        Path executablePath = Path.of(browserProp);
        if (executablePath.toFile().exists()) {
            launchOptions.setExecutablePath(executablePath);
        }

        String size = properties.getProperty("web.browser.size");
        if (isNotBlank(size)) {
            String[] viewportSize = size.split("[xX]");
            int width = Integer.parseInt(viewportSize[0]);
            int height = Integer.parseInt(viewportSize[1]);
            launchOptions.setViewportSize(width, height);
            if (recordVideo) {
                launchOptions.setRecordVideoSize(width, height);
            }
        }

        return launchOptions;
    }

    /**
     * <p>Определение типа браузера</p>
     *
     * @return функция, принимающая {@link Playwright} и возвращающая {@link BrowserType}
     */
    @Override
    public Function<Playwright, BrowserType> browserType() {
        // Chromium по умолчанию
        String browserProp = properties.getProperty("web.playwright.browser");
        if (Path.of(browserProp).toFile().exists()) {
            if (browserProp.contains("firefox")) {
                return Playwright::firefox;
            }
        } else {
            String browserTypeLower = browserProp.toLowerCase();
            return switch (browserTypeLower) {
                case "chromium" -> Playwright::chromium;
                case "firefox" -> Playwright::firefox;
                case "webkit" -> Playwright::webkit;
                default -> {
                    // Ищем совпадение в пути
                    if (browserTypeLower.contains("firefox")) {
                        yield Playwright::firefox;
                    } else {
                        yield Playwright::chromium;
                    }
                }
            };
        }

        return Playwright::chromium;
    }

    /**
     * <p>Настройки создания контекста</p>
     *
     * @return {@link Browser.NewContextOptions}}
     */
    @Override
    public Browser.NewContextOptions newContextOptions() {
        Browser.NewContextOptions contextOptions = new Browser.NewContextOptions();

        String viewport = properties.getProperty("web.browser.size");
        // viewportSize в конфиге заполняется в формате 1234x5678
        String[] viewportSize = viewport.split("[xX]");
        int width = Integer.parseInt(viewportSize[0]);
        int height = Integer.parseInt(viewportSize[1]);
        contextOptions.setViewportSize(width, height);

        // Запись видео
        boolean recordVideo = Boolean.parseBoolean(properties.getProperty("web.playwright.video"));
        if (recordVideo) {
            contextOptions.setRecordVideoSize(width, height);
            String videoPath = properties.getProperty("web.playwright.video.path");
            if (isNotBlank(videoPath)) {
                contextOptions.setRecordVideoDir(Path.of(videoPath));
            }
        }

        contextOptions.setAcceptDownloads(true);
        contextOptions.setIgnoreHTTPSErrors(true);

        return contextOptions;
    }

    /**
     * <p>Аргументы запуска браузера</p>
     *
     * @return список аргументов
     * @see <a href="https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md">
     * Chrome: Флаги запуска
     * </a>
     * @see <a href="https://peter.sh/experiments/chromium-command-line-switches/">
     * Chrome: Command Line Switches
     * </a>
     * @see <a href="https://chromium.googlesource.com/chromium/src/+/master/chrome/common/chrome_switches.cc">
     * Chrome: Switches
     * </a>
     */
    @Override
    public List<String> args() {
        // Самый минимум в случае SberBrowser
        return List.of("--disable-features=SberAuth");
    }

    /**
     * <p>Параметры конфигурации профиля (предпочтения браузера).</p>
     *
     * @see <a href="https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/common/pref_names.h">
     * Chrome: Полный список возможных значений.
     * </a>
     * @see <a href="https://kb.mozillazine.org/About:config_entries">
     * Firefox: Полный список возможных значений.
     * </a>
     */
    @Override
    public Map<String, Object> browserPreferences() {
        Map<String, Object> prefs = new HashMap<>(Map.of(
                "credentials_enable_service", false,
                "profile.password_manager_enabled", false,
                "browser.show_update_promotion_info_bar", false,
                "profile.default_content_setting_values.popups", 2,
                "plugins.always_open_pdf_externally", true,
                "plugins.plugins_disabled", List.of(
                        "Chrome PDF Viewer"
                )
        ));

        List<String> certSelectors = autoSelectCertificates();
        if (!certSelectors.isEmpty()) {
            prefs.put("profile.managed_auto_select_certificate_for_urls", certSelectors);
        }

        return prefs;
    }

    /**
     * <p>При потребности использовать -
     * расширить {@link DefaultPlaywrightServiceConfiguration} и переопределить этот метод.</p>
     * <p>Пример:</p>
     * <pre>{@code
     * @Override
     * public List<String> autoSelectCertificates() {
     *     return List.of(
     *             certificateSelector()
     *                 .pattern("https://auth-dbz.delta.sbrf.ru")
     *                 .issuer("SberCA Ext", "Sberbank of Russia")
     *                 .subject(personalLogin, "Sberbank")
     *                 .build()
     *     );
     * }
     * }</pre>
     */
    public List<String> autoSelectCertificates() {
        return List.of();
    }

    /**
     * <p>Запрашивается ли запуск через Selenoid</p>
     */
    @Override
    public boolean isRemote() {
        return Boolean.parseBoolean(properties.getProperty("web.playwright.remote"));
    }

    /**
     * <p>Базовый URL</p>
     */
    public String getBaseUrl() {
        return properties.getProperty("web.base.url");
    }
}