Загрузка файлов в Selenium (Windows вариант)

Загрузить файл довольно просто если у вас есть обычное HTML поле для загрузки файла, вам просто нужно выполнить .find_element_by_id('id_photo').send_keys(<full path to file>). Но часто для красоты это поле заменяется на что-то другое и прячется, в таком случае мы не можем выполнять send_keys к спрятанным элементам и этот способ больше не работает. Но если доступно диалоговое окно открытия файла и тест работает в Windows тогда можно подключит pywinauto или другую утилиту с помощью которой можно управлять окнами и загрузить файл.

С помощью pywinauto можно вставить путь к файлу в поле редактирования и нажать кнопку “Открыть”. Для подключения pywinauto к браузеру нужен его process id, для Firefox pid можно найти прямо в инстансе драйвера, если же используется Chrome то нужен process id вкладки, в моем примере у меня всего одна вкладка поэтому я просто беру первый дочерний процесс. Так же перед тем как использовать диалог нужно проверить что он открылся или же просто “спать” что бы дать открыться диалогу.

Дальше есть небольшой пример кода по загрузке файла.

#!/usr/bin/python
import psutil
from unittest import TestCase
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from pywinauto.application import Application


class UploadTestCase(TestCase):
    def setUp(self):
        self.browser = webdriver.Chrome()
        self.wait = WebDriverWait(self.browser, 10)

    def tearDown(self):
        self.browser.close()

    def get_pid(self):
        if isinstance(self.browser, webdriver.Chrome):
            process = psutil.Process(self.browser.service.process.pid)
            return process.children()[0].pid              # process id of browser tab
        if isinstance(self.browser, webdriver.Firefox):
            return self.browser.service.process.pid       # process id of browser

        assert Exception('driver does not supported')

    def upload_file(self, filename):
        path = os.path.join(
            os.path.realpath('.'),
            'fixtures',
            filename
        )
        assert os.path.exists(path)

        for i in range(10):
            app = Application()
            app.connect(process=self.get_pid())  # connect to browser
            dialog = app.top_window_()           # get active top window (Open dialog)
            if not dialog.Edit.Exists():         # check if Edit field is exists
                time.sleep(1)                    # if no do again in 1 second (waiting for dialog after click)
                continue
            dialog.Edit.TypeKeys('"{}"'.format(path))   # put file path
            dialog['&OpenButton'].Click()               # click Open button

            return

        raise Exception('"Open File" dialog not found')

    def test_upload_small_logo(self):
        el_logo_upload = self.wait.until(
            EC.presence_of_element_located(
                (By.NAME, upload-logo')
            )
        )

        el_logo_upload.click()
        self.upload_file('logo_small.png')

        # checking