Implementation of the process of uploading a file from a container with a browser to a test framework

Automation of End-2-End testing of an integrated information system
Part 2-2. Implementing the process of uploading a file from a container with a browser to a test framework. Search for the name of the file downloaded by the browser


Author: habr.com/en/users/anrad
Hubs:
Tags: #autotest, #selenium, #selenoid, #headlessbrowser, #download


When we were developing End-2-End autotests for UI, we were faced with the question “How to get the name of the last loaded file browser from WebDriver? ”, Google didn’t get anything quickly. Therefore, I wrote this article, which at the same time told what exactly we had a problem and how we solved it.

With this article, we continue a series of publications on how we automated the process of manual testing (hereinafter referred to as self-tests) of a large information system (hereinafter referred to as Systems) in one of the large LANIT projects and what came of it.

image
source


The article itself completes the cycle, below is a link to all the previous parts:
Part 1. Organizational and managerial. Why did we need automation. Organization of the development and management process. Organization of use
Part 2. Technical. Architecture and technical stack. Implementation Details and Technical Surprises
Part 2-1. Base class implementation for all tests and JUnit RuleChain.

That was a year ago. So today it may not be relevant. Write in the comments if you know what an efficient way to process files with multiple selenoid grid servers.

During the development of “autotests” we had the task of downloading (downloading) files from the system with subsequent analysis of their contents. To “upload” files from the tested system, we use the following solutions:
  • for the "local" launch mode (launch directly on the working PC) - when the "local" browser is initialized, the name of the temporary local folder is passed to it as a parameter. Next, the file is read directly from the local folder for subsequent analysis;
  • for "remote" mode (via Bamboo) - the file was "taken" from the container with the browser through the Solenoid server feature: selenoid-host.example.com : 4444 / download / {SESSION_ID} / {FILE_NAME}


Details are described in the documentation.

For both modes, to access the file, you had to know its name. This was a surprise. The problem of lack of data on the name of the “download” file was as follows:
  • after “clicking” the “download file” button, the browser downloaded the file to the appropriate local folder in the container;
  • in this case, the file name was formed dynamically and, how to determine it in advance, we could not find. This was a feature of our test system;
  • Further, this file should be “pulled out” from the container and business verification of its contents should be carried out;
  • in order to “pull out” the file, you should know its name, but we did not know the name, since the name was generated dynamically and there was no value in the link.


In addition, the situation was aggravated by the fact that due to the great complexity of some tests, several files could be unloaded during the test as part of different independent test scripts from the composition of the test itself.
The best solution for us was the method in which we determined the last downloaded file. There were several ways to do this:
  • . . , ;
  • Google Chrome javascript chrome://downloads/, html-. .




Analyzing the composition of the browser-loaded files for local mode is a trivial task.
For remote mode, you need to use the “undocumented” feature of the server selenoid: selenoid-host.example.com : 4444 / download / {SESSION_ID} displays a list of all successfully downloaded files, where SESSION_ID is a selenoid session ID
In general, the scheme works fine with one exception: we You need to wait a while until the file is downloaded and appears in the list. The wait can be set through a timeout cycle, however, this way we can not get information about a possible file upload error. We can only determine that the file did not load in this circuit. Therefore, in the end, we settled on the method of determining the file name through the chrome: // downloads / page.

Getting the file name through the chrome: // downloads / page


This method works equally well in both local and remote mode. The scheme of work is quite simple:
  • run java script to open the chrome window: // downloads /;
  • process data in the window in the usual way. Wait until the first file in the list is loaded and determine its name;
  • close the chrome: // downloads / window and return the name of the file you are looking for.


We googled the idea of ​​using chrome: // downloads / and, unfortunately, I can’t provide a link to the source, since it has not been preserved corny. The actual implementation of the class for obtaining the file name is given below.

Class to get the name of the downloaded file via chrome: // downloads /
	private static final long DOWNLOADS_PAGE_LOAD_TIMEOUT = 5_000;
	private static final long MAX_GET_FILE_NAME_ATTEMPT = 5;
 
	public static String getLastDownloadedFilename() throws DownloaderException {
        String[] filename = new String[1];
        Exception[] ex = new Exception[1];
        WebDriver driver = WebDriverRunner.getWebDriver();
        JavascriptExecutor executor = (JavascriptExecutor) driver;
        Utils.driver.openNewTabCheckAndClose(
                () -> {
                    executor.executeScript("window.open('','_blank');");
                },
                () -> {
                    driver.get("chrome://downloads/");
 
                    for (int i = 0; i < MAX_GET_FILE_NAME_ATTEMPT; i++) {
                    	ex[0] = null;
                        sleep();
                    	try {
                        	WebElement element = (WebElement) executor.executeScript(
                                    "return document.querySelector('downloads-manager').shadowRoot.querySelector('downloads-item').shadowRoot.getElementById('file-link')");
                        	filename[0] = element.getText();
                            LOGGER.info("Attempt get file name " + i + ". Name = '" + filename[0] + "'");
                    	} catch (WebDriverException e) {
                        	ex[0] = e;
                            LOGGER.info("Failed attempt "+ i + " to get filename text: " + e.getMessage());
                        	continue;
                    	}
                    	if (filename[0] != null && !filename[0].isEmpty()) {
                        	 //             
                         	executor.executeScript(
                                    "document.querySelector('downloads-manager').shadowRoot.querySelector('downloads-item').shadowRoot.getElementById('remove').click()");
                        	break;
                    	}
                    }
                }
    	);
 
    	if (filename[0] != null && !filename[0].isEmpty()) {
            return filename[0];
    	}
 
    	String message = "Timeout. Can not get last downloaded file name from chrome://downloads/. File name is '" + filename[0] + "'. Exception: " + ex[0].getMessage();
        LOGGER.warning(message);
    	throw new DownloaderException(message, ex[0]);
	}

All Articles