-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuploadsDownloads.html
More file actions
194 lines (172 loc) · 9.64 KB
/
uploadsDownloads.html
File metadata and controls
194 lines (172 loc) · 9.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<link href='https://fonts.googleapis.com/css?family=Chivo:900' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/pygment_trac.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/highlight.min.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script>hljs.initHighlightingOnLoad();</script>
<title>Testing With Node by NickTulett</title>
</head>
<body>
<div id="container">
<div class="inner">
<header>
<h1>Uploads and Downloads</h1>
<h2></h2>
</header>
<!--
<section id="downloads" class="clearfix">
<a href="https://github.com/NickTulett/TestingWithNode/zipball/master" id="download-zip" class="button">
<span>Download .zip</span>
</a>
<a href="https://github.com/NickTulett/TestingWithNode/tarball/master" id="download-tar-gz" class="button">
<span>Download .tar.gz</span>
</a>
<a href="https://github.com/NickTulett/TestingWithNode" id="view-on-github" class="button">
<span>View on GitHub</span>
</a>
</section>
-->
<hr>
<section id="main_content">
<p>If you upload or download files to a website, you will typically see a file dialog appear to allow you to select the file location(s).</p>
<p>Neither webdriver nor node handle local system dialogs, so what can you do?</p>
<h2>
<a name="using-nodejs-a-an-automated-test-engine" class="anchor" href="#using-nodejs-a-an-automated-test-engine">
<span class="octicon octicon-link"></span>
</a>Handling Uploads</h2>
<p>A modern website should be handling uploads using the HTML5 file input element, such as:</p>
<pre><code class="html">
<input id="fileupload" class="fileupload" type="file" name="files[]" multiple=">
</code></pre>
<p>What this allows us to do is set the filepath directly on the element, so there is no need for any dialog handler. It really is this simple:</p>
<pre><code class="javascript">
$("#fileupload").set(filePath);
</code></pre>
<h2>Handling Downloads</h2>
<p>Assuming that you click some sort of element to initiate the download, I would suggest using the browser's default download folder and clearing out any matching files before you begin. Then you simply wait for the file to appear:</p>
<pre><code class="javascript">
//clear all csv files out of the download folder
try {
files.wipeFolder(downloadFolder, /\.csv$/);
} catch (e) {
}
//We recognise the download button from the tooltip in this AUT
$("//li[@tooltip='Export to CSV']/a/i").click();
//now poll the downloadFolder
var csvCount = false;
while (!csvCount) {
Delay(1e3);
//note the synchronous method - what else can you do here but wait?
fs.readdirSync(downloadFolder).forEach(function waitForCSVs(download) {
if (download.match(/\.csv$/)) {
csvCount = true;
}
});
}
//then do something with the file
</code></pre>
<h3>Firefox download confirmation</h3>
<p>By default, Firefox will annoyingly ask you to confirm the download location. You can suppress this behaviour when you instantiate the browser:</p>
<pre><code class="javascript">
var wd = require("webdriver-sync");
var profile = new FirefoxProfile();
profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "text/csv");
var driver = new wd["FirefoxDriver"](profile);
</code></pre>
<h3>Internet Explorer download confirmation</h3>
<p>This browser will pop up an out of process dialog every time you try to download something, so clicking on a link will freeze webdriver as it waits for the download to complete.</p>
<p>This annoyance can be circumvented by using keypresses to activate and confirm the download. Webdriver can handle a key press on an element, but we need another npm module, <a href="https://www.npmjs.com/package/robotjs">ROBOTJS</a> to send key presses to the download security theatre dialog.</p>
<pre><code class="javascript">
var KB = require("node_keyboard");
//these keypresses are handled by webdriver
$("a").sendKeys(PTL.WD.Keys.ENTER);
//sometimes the system gets confused and uses the Alt-S keyboard shortcut to open the start menu
//so tap the link again to maintain focus
Delay(1e3);
$("a").sendKeys(PTL.WD.Keys.ENTER);
Delay(5e3);
//robotjs handles the download bar
var robot = require("robotjs");
robot.keyToggle("s", "down", "alt");
robot.keyToggle("s", "up", "alt");
//depending on IE's settings, you may require an additional Alt-Q shortcut to close the dialog
</code></pre>
<h2>But what if there is no download button?</h2>
<p>Say you have a website that allows you to upload images. How can you check that the image you see on the site is the same one you uploaded?</p>
<h3>Compare an uploaded image to the original file</h3>
<p>Using the <a href="tips.html#sh">sh function</a> to run wget locally to download the image as a file.</p>
<p>Compare the downloaded file to the original that was uploaded earlier.</p>
<p>This is a good example of using the correct tool for the job:</p>
<ul>
<li>Webdriver to get the image properties and manage cookies.</li>
<li>wget to grab a file from the remote server.</li>
<li>node.js to handle the file locally.</li>
</ul>
<pre><code class="javascript">
function verifyImageUpload(img, original) {
var imgSrc = $(img).getAttribute("src");
// wget needs session cookie for authentication
var cookie = browser.manage().getCookies().toString().split(/;/)[0].split(/=/);
sh.run("wget -O " + testing.TEST_HOME + "topology/layout.png "
+ "--no-cookies --header \"Cookie: " + cookie[0] + "=" + cookie[1] + "\""
+ " " + imgSrc);
var original64 = fs.readFileSync(original).toString("base64");
var download64 = fs.readFileSync(testing.TEST_HOME + "topology/layout.png").toString("base64");
//delete the download to keep the folder clean
fs.unlinkSync(testing.TEST_HOME + "topology/layout.png");
return (original64 == download64);
}
</code></pre>
<h2>Zipped downloads</h2>
<p>Sometimes you are not downloading single files but .zip (or equivalent) archives.</p>
<p>The <a href='https://www.npmjs.com/package/adm-zip'>adm-zip</a> npm module will allow you to interrogate individual files in the archive.</p>
<p>You can check the integrity of the archive by checking the file names, sizes, CRC values, etc. of a known good archive and using these as a basis for comparison.</p>
<p>Then your test could do something like this:</p>
<pre><code class="javascript">
var AdmZip = require("adm-zip");
function checkDownloadedZip(expectedCRCs) {
files.wipeFolder(testing.DOWNLOADS, /\.zip$/);
$("'Download'").click();
Delay(25e3);//or run a specific loop to check the download is complete
var unzippedModel = new AdmZip(testing.DOWNLOADS + "Downloaded.zip");
var zipContents = unzippedModel.getEntries();
zipContents.forEach(function (zipFile, i) {
var expectedCRC = expectedCRCs[i];
console.log("CHECKING " + expectedCRC.name);
assert(expectedCRC.name === zipFile.entryName,
"File is missing from the downloaded zip");
assert(zipFile.header.size,
"file is empty when the zip is downloaded");
assert(zipFile.header.crc === expectedCRC.crc,
"CRC mismatch " + zipFile.header.crc);
});
}
checkDownloadedZip(
[
{"name": "input.xml", "crc": 1325479318},
{"name": "smLoad.csv", "crc": 197218698},
{"name": "smDraw.csv", "crc": 1454915604},
{"name": "utilityPower.csv", "crc": 2137376351},
{"name": "weather.csv", "crc": 3328012098}
]
);
</code></pre>
<a href="browserLogs.html">Next: Browser Logs</a>
</section>
<footer>
<a href="/TestingWithNode/">Testing With Node</a> is maintained by <a href="https://github.com/NickTulett">NickTulett</a>
<br>This page was generated by <a href="http://pages.github.com">GitHub Pages</a>. Tactile theme by <a href="https://twitter.com/jasonlong">Jason Long</a>.
</footer>
</div>
</div>
</body>
</html>