How to automate file upload testing with Autoit and Protractor
Tags: testing, testautomation, protractor, autoit
Published: 2019-08-27 16:05:45

#Introduction

In the most of web applications file uploading is not only web-based feature and requires system window activity like 
opening of system dialog "Open"  where you choose file(s) to upload them to web site. This window based activity is not handled by test automation frameworks and instruments.

**Is it possible to handle Windows system dialog in my automated tests of web application?**
Yes. It is possible using compiled Autoit scripts.

In the article we will  try to automate interaction with Windows upload dialog and will learn: 
 * What is Autoit
 * How to use Autoit
 * How to write and compile Autoit script
 * How to use compiled Autoit script in E2E tests

## 1. What is Autoit

Autoit is a freeware tool that can be used to automate interaction with Windows desktop applications, dialogs and processes like running, closing, deleting application. In general Autoit can be used in automating Windows GUI.

To automate Windows GUI Autoit v3 scripting language uses.
Autoit v3 is BASIC-like scripting language. So, be ready to be involved into learning BASIC-like syntax in this tutorial.
 
More information about Autoit and Autoit v3 you can find on [Autoit official site](https://www.autoitscript.com/site/).

##2. How to use Autoit

First of all let's go to [AutoIt downloads](https://www.autoitscript.com/site/autoit/downloads/) and download Autoit full installation.

 ![Autoit full installation](https://thepracticaldev.s3.amazonaws.com/i/7vrn5ss7x3f0jax1mhjs.PNG)

Pass all installation steps, open Autoit3 folder and run Au3Info.exe.
This app is used for getting info about a window that will be used in programming.

![Window info app](https://thepracticaldev.s3.amazonaws.com/i/tf4owqssgb9trvihxebp.PNG)

Basic information about system dialog that is needed for programming  of interaction with dialog is **Class**, **Title** and **Instance**.

![Winfow info](https://thepracticaldev.s3.amazonaws.com/i/ymdikzrckgiffianlzte.PNG)

To get an information about a element or a window hold on Finder Tool and move mouse to an element or a window.

![Finder tool](https://thepracticaldev.s3.amazonaws.com/i/w6wnrry6h31hgwu83lgf.png)

Well, how to use Autoit tool is pretty clear. Let's go to the programming part.

## 3. Autoit scripting

The article is about automating testing of file uploading. 
So, the goal is to automate interaction with "Open" Windows system dialog. Let's do it in a few steps.

**Step 1**

The first step is to open Notepad or your a code editor you prefer.
Start writing a script with  importing necessary dependencies.
<pre> 
;Constants to be userd in an AutoIt v3 script.
#include &lt;AutoItConstants.au3&gt
</pre>

**Step 2**

Define variable <code>$hWnd</code> - the handle of the window you will interact with.

<pre>
#include &lt;AutoItConstants.au3&gt;
Local $hWnd
</pre>

**Step 3**

We need to wait for the system dialog.
Use <code>WinWait(WINDOW_CLASS, TITLE, TIMEOUT)</code> function.
Let's get <code>WINDOW_CLASS</code> and <code>TITLE</code> with use of **Au3Info.exe** (find it in Autoit installation folder).

![Get Window class](https://thepracticaldev.s3.amazonaws.com/i/fbdac8k4gxum5l0w1g8x.jpg)

<pre>
#include &lt;AutoItConstants.au3&gt;
Local $hWnd

;Wait 15sec for file dialog (Class #32770) with title 'Open'
$hWnd = WinWait("[CLASS:#32770]","Open",15)
</pre>

**Step 4**

We need a mechanism to put file path to the file path field of the system window. Let's get <code>CLASS</code> and <code>INSTANCE</code> of the file path field.

![File path field](https://thepracticaldev.s3.amazonaws.com/i/mh5plojdxazaznkhuw20.jpg)

Set focus to the field and put a file path.

<pre>
#include &lt;AutoItConstants.au3&gt;
Local $hWnd

;Wait 15sec for file dialog (Class #32770) with title 'Open'
$hWnd = WinWait("[CLASS:#32770]","Open",15)

;Second parameter can be empty string, because of you use class and instance to define the element
;More information about Autoit functions see here 
https://www.autoitscript.com/autoit3/docs/functions/

ControlFocus($hWnd, "", "[CLASS:Edit; INSTANCE:1]")
ControlSetText($hWnd, "", "[CLASS:Edit; INSTANCE:1]", $CmdLine[1])
</pre>

<code>$CmdLine[1]</code> - the parameter will be passed to the function as a path of a file we want to upload to a web site.
You can hardcode this parameter by absolute file path (ex. "c:\upload_me.txt");

**Step 5**

Click by **Open** button. 
First get <code>CLASS</code> and <code>INSTANCE</code> of **Open** button.

![Open button](https://thepracticaldev.s3.amazonaws.com/i/5487yag3nteqr7mbkslx.jpg)

When we know <code>CLASS</code> and <code>INSTANCE</code> of **Open** button we are ready to click by it.

There are 2 ways to click by the element.

*Way 1.*

Just use <code>ControlClick()</code> method.

<pre>
ControlClick($hWnd, "", "[CLASS:Button; INSTANCE:1])
</pre>

My experience has shown that <code>ControlClick()</code> works unstable. From time to time a button is not clicked by unknown reason.

I have solved this problem by using mouse actions such as mouse move and mouse click. Let's programming it.

*Way 2.*

Describe variables for *x*, *y* coordinates and array with size 2 for storing **Open** button position.

<pre>
Local $pos[2]
Local $x
Local $y
</pre>

Get **Open** button position.

<pre>
;ControlGetPosition returs x and y coordinates of high left corner of the button.
$pos = ControlGetPos($hWnd, "", "[CLASS:Button; INSTANCE:1]")
</pre>

Set the way coords will be  used in the mouse functions, either absolute coords or coords relative to the current active window

<pre>
;2 = relative coords to the client area of the active window
AutoItSetOption("MouseCoordMode", 2)
</pre>

Define <code>$x</code> and <code>$y</code> variables. To prevent some random failures move the mouse from high left corner to another button space by adding 10px to <code>$x</code> and <code>$y</code>. Feel free in playing with coordinate values!

<pre>
$x=$pos[0] + 10
$y=$pos[1] + 10
</pre>

And finally perform mouse left click action.

<pre>
MouseClick($MOUSE_CLICK_LEFT, $x, $y, 1);
</pre>

Nice! You have finished scripting. Let's see the whole script.

<pre>
#include <AutoItConstants.au3>

Local $hWnd
Local $pos[2]
Local $x
Local $y

$hWnd = WinWait("[CLASS:#32770]","Open",15)

ControlFocus($hWnd, "", "[CLASS:Edit; INSTANCE:1]")
ControlSetText($hWnd, "", "[CLASS:Edit; INSTANCE:1]", $CmdLine[1])

AutoItSetOption("MouseCoordMode", 2)
$pos = ControlGetPos($hWnd, "", "[CLASS:Button; INSTANCE:1]")
$x=$pos[0]+10
$y=$pos[1]+10

MouseClick($MOUSE_CLICK_LEFT, $x, $y, 1);
</pre>

Save the script with **.au3** extension.

# 3. Compile Autoit script

To use the script in automated E2E tests you need to compile the script to executable file:

1. Run **Autoit2Exe.exe** app.
2. Import saved script and click by **Convert** button. 

![Convert to exe](https://thepracticaldev.s3.amazonaws.com/i/9sradm0m0u9npbw5an4z.PNG)

Perfect, now you have executable file which can be used in E2E tests. 

#4. Test compiled Autoit script

Before using compiled script in E2E tests we should be sure that it works.

To test it, pass the following steps:

*1.Trigger upload file dialog.*

*2. Run compiled script with a file path argument.*

![File uploading](https://thepracticaldev.s3.amazonaws.com/i/i92ki3r4k9monr54cy7m.gif)

If you didn't mistakes during scripting the file should be uploaded.

#5. Use the script in E2E tests.

You can extremely easy use compiled script in E2E tests.

Below you can see an example of Protractor tests.

*Page object example*

```typescript
import { by, element, $ } from 'protractor';
import * as cp from 'child_process';

export class FileUploadingPage {
  uploadButton = $('.mat-raised-button');
  addFilesButton = element(by.xpath('//button[contains(@class, "add-files-btn")]'));

  uploadFile(filePath) {
    console.log('File path: ', filePath);
    //UploadFile.exe - compiled Autoit script
    cp.execSync('uploadFile.exe' + ' ' + filePath);
    return Promise.resolve();
  }
}
```

*E2E test example*

```typescript
import { FileUploadingPage } from './file-uploading-page';
import { browser, ExpectedConditions, element, by } from 'protractor';
import { win32 } from 'path';

const path = win32;
const EC = ExpectedConditions;
const TIMEOUT = 30000;

let fileUploadingPage: FileUploadingPage;
fileUploadingPage = new FileUploadingPage();

describe('File uploading, () => {
  before((done) =>
    browser.get(browser.baseUrl)
      .then(() => done())
      .catch(done)
  );

  it('Upload file', (done) => {
    browser.wait(EC.visibilityOf(fileUploadingPage.uploadButton), TIMEOUT)
      .then(() => fileUploadingPage.uploadButton.click())
      .then(() => browser.wait(EC.visibilityOf(fileUploadingPage.addFilesButton), TIMEOUT))
      .then(() => fileUploadingPage.addFilesButton.click())
      .then(() => {
        const filePath = path.resolve(__dirname + '/test_file.txt');
        return fileUploadingPage.uploadFile(filePath);
      })
      .then(() => done())
      .catch(done);
  });
});
```

#Conclusion

From this article you have learned:

1. What is Autoit and how to use it.
2. How to automate interaction with Windows system dialog.
4. How to use compiled Autoit script in E2E tests.


Thanks and enjoy automation!:rainbow::rainbow::rainbow:
Don't forget to tap &#x1f497;