Проблема взаимодействия с ShadowDOM в HEADLESS режиме

Обнаружил проблему следующего характера:
Если запускать браузер в HEADLESS режиме, то возникает проблема следующая

  • shadowRoot не доступен

Пример следующий:
Я делаю загрузку файла и жду окончания его загрузки

  • через джаваскрипт я жду state.equals(“COMPLETE”)
((JavascriptExecutor) WebDriverRunner.getWebDriver()).executeScript("return document.querySelector('downloads-manager').shadowRoot.getElementById('downloadsList').items[0].state")

Если отключать HEADLESS режим, то все прекрасно отрабатывает.
Кто-то может уже сталкивался с такого рода сложностью и отыскал выход из ситуации?
Буду благодарен, если поможете отыскать ответ на данный вопрос

вам именно с download хочется или глобально ?

На данный момент, хочется решить на уровне download
На более глобальный уровень думаю, что это займет больше усилий

может попробуйте используйте браузер для этого вместо того чтобы подглядывать в шадодом ShadowDOM ?

Browser.setDownloadBehavior

Browser.downloadWillBegin
Browser.downloadProgress

и тд

а пример свой покажите интересно же всем как исчезает ShadowDOM в HEADLESS!

Сценарий для воспроизведения очень простой
Я тестировал на Chrome используя Selenide

  1. Можно скачать любой файлик (я для примера скачивал IDEA)
  • как раз можно подебажить, какие state возвращаются, пока скачивается файлик и когда он завершает скачивание
  1. Открыть страничку chrome://downloads/
  2. Настроить свою ожидалку через джаваскрипт, который я написал выше, где ты ждешь статус COMPLETE или IN_PROGRESS

Если браузер запускается в хедлесс, то джаваскрипт не исполнится, потому что нету shadowroot элементов и прокинится ошибка

you can’t get the shadowRoot property of null

Предварительно я искал ответ на вопрос, и вот аналогичный вопрос был задан на stackoverflow:

вам нужен пример ?
катси
свой горе кейс бросьте гистом пжта
какая версия селениума у вас

если 3 то одно ws:

если 4 то есть 2 легальных способа (один крутой):


private static String command = "Browser.setDownloadBehavior";
	@Before
	public void beforeTest() throws Exception {
		// Arrange
		params = new HashMap<>();
		params.put("behavior", "allow");
		// NOTE: the "allowAndName" will randomly name the downloaded file
		params.put("downloadPath", downloadPath);

		params.put("eventsEnabled", true);

		result = driver.executeCdpCommand(command, params);
		assertThat(result, notNullValue());

		new File(
				Paths.get(downloadPath).resolve(filename).toAbsolutePath().toString())
						.delete();
	}

	@After
	public void clearPage() {
		// Arrange
		params = new HashMap<>();
		params.put("behavior", "default");
		result = driver.executeCdpCommand(command, params);
		assertThat(result, notNullValue());
		driver.get("about:blank");
	}

	@Test
	public void test1() {
		try {
			// Act
			driver.get(url);
			Utils.sleep(3000);
			assertThat(new File(
					Paths.get(downloadPath).resolve(filename).toAbsolutePath().toString())
							.exists(),
					is(true));
		} catch (WebDriverException e) {
			System.err.println("Web Driver exception in " + command + " (ignored): "
					+ Utils.processExceptionMessage(e.getMessage()));
		} catch (Exception e) {
			System.err.println("Exception in " + command + "  " + e.toString());
			throw (new RuntimeException(e));
		}
	}

сейчас напишу еще -


	@Test
	public void test2() {
		List<DownloadProgress.State> states = new ArrayList<>();
		// Arrange
		chromeDevTools.send(
				Browser.setDownloadBehavior(Browser.SetDownloadBehaviorBehavior.ALLOW,
						Optional.empty(), Optional.of(downloadPath), Optional.of(true)));

		// Act
		try {
			chromeDevTools.addListener(Browser.downloadWillBegin(), o -> {
				System.err.println("in Browser.downloadWillBegin listener. url: "
						+ o.getUrl() + "\tfilename: " + o.getSuggestedFilename());
			});
			chromeDevTools.addListener(Browser.downloadProgress(), o -> {
				DownloadProgress.State state = o.getState();
				System.err.println(
						"in Browser.downloadProgress listener. state: " + state.toString());
				states.add(state);
			});
			driver.get(url);
			Utils.sleep(3000);
			assertThat(states.indexOf(DownloadProgress.State.COMPLETED),
					greaterThan(-1));

		} catch (WebDriverException e) {
			System.err.println("Web Driver exception (ignored): "
					+ Utils.processExceptionMessage(e.getMessage()));
		} catch (Exception e) {
			System.err.println("Exception: " + e.toString());
			throw (new RuntimeException(e));
		}
	}


свой горе кейс бросьте гистом пжта

мои примеры лежат на

и на

(3.x / ws:// ) - пример с download положу туда через 3 часа

Господь с вами, вовсе не нужно открывать вкладку “downloads” и отслеживать статусы. Всё гораздо проще.

В селениде это уже давно сделано за вас:

File idea = $("#download").download(with extension("exe"));

И селенид сам дождется окончания загрузки и вернёт вам готовый скачанный файл.

Проблема в том, что, к сожалению, на проекте кнопка не имеет @href и селенидовский метод download не отрабатывает, проксирование тоже ломает проект

Поэтому и было придумано именно такое решение

Так кроме href и прокси, в селениде есть третий метод FOLDER. Как раз то, что вам надо.

1 лайк

Это неверное решение. Костыльное.
Для таких вещей есть Proxy. Юзайте его.

“проксирование тоже ломает проект”

что именно ломает ?

1 лайк

Roma_RomanYaroslav Lazakovich вам все еще актуально ?
почему я спрашиваю ?
в примере на стаке похоже есть ошибка

… с другой стороны где их нет