# puppeteer 集成测试时所遇问题
# 问题 描述
我们很熟悉如下一种场景
<input type="file" name="uploadFile" id="uploadeFile" />上传文件
1
点击上传文件按钮时,浏览器会打开 你 系统里面的文件管理器,之后会让你选取你想 上传的文件。在你选取文件 ,点击确定按钮之后,浏览器会把你刚刚 选择的 相应文件上传到指定的服务器。
做前端开发的 大都使用很多框架或者小插件 来处理文件上传,很容易就可以搞定这件事。但这也往往造成了 前端开发人员 不太理解 前端文件上传的深层原理。这也引出 了 我下面的问题。
公司需要我使用 puppeteer 对公司的 的产品进行自动化集成测试。puppeteer 可以很容易 模拟人在真实浏览器中的 每一步操作,我 的思路也是按照现实的每一步动作进行 代码的书写。 总体步骤是:
- 获取元素 ①
- 元素点击、获取焦点 ②
- 输入数据 ③
可参考如下代码
//引入集成测试框架
var puppeteer = require('puppeteer');
//登录url
const loginUrl = 'URL';
puppeteer
.launch({
//false:在真实的浏览器中打开
headless: false,
//url不是https时需要设置
ignoreHTTPSErrors: true,
})
.then(async (browser) => {
var page = await browser.newPage();
//设置页面大小
page.setViewport({ width: 1920, height: 1080 });
//打开页面
try {
console.log('正在打开页面……');
await page.goto(loginUrl, { waitUntil: 'networkidle2' });
} catch (e) {
console.log('launch err:' + e);
}
/**1.登录 */
try {
console.log('正在登陆……');
//获取用户名输入框 ①
let userName = await page.$('#username');
//点击用户名输入框 ②
await userName.click();
//输入用户名 ③
await page.keyboard.type(account, { delay: 20 });
//获取密码输入框
let thePassword = await page.$('#password');
//点击密码输入框
await thePassword.click();
//输入密码
await page.keyboard.type(password, { delay: 20 });
//获取登录按钮节点
let loginBtn = await page.$('#login-button');
//点击登录按钮
await loginBtn.click();
await timeout(3000);
console.log('完成登录。');
} catch (e) {
console.log('login err:' + e);
}
//关闭browser
browser.close();
});
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
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
但是, 怎么模拟文件上传功能呢? 前端文件上传功能:
- 点击上传 input 标签;
- 在系统文件管理器中选取要上传的文件
- 确定, 上传。
那如何 来模拟这 几个操作呢? 难道也要这样一步一步来吗? 可是 puppeteer 里面并没有处理打开系统文件管理器--选取文件--确定这一系列操作的接口。 怎 样才能解决呢?
# 解决方法
可能好多一开始使用 puppeteer 做集成测试的人都会犯上面的错误。我搜索了几乎能找到的 blog 都没有解决我的问题。最终还是在官网 github api 中窥到了解决问题的方法---.uploadFile()
elementHandle.uploadFile(...filePaths)
...filePaths <...string> Sets the value of the file input these paths. If some of the filePaths are relative paths, then they are resolved relative to current working directory.
returns: <Promise>
This method expects elementHandle to point to an input element.
1
2
3
4
2
3
4
可是这真的是解决我们问题的 api 吗? 试了之后才发现,真是!可是表单中的文件上传这么重要的功能竟然也没有一个例子。我也真实服了。 最终 puppeteer 文件上传 功能实现如下
try {
console.log('文件上传中……');
//获取上传文件按钮
let uploadFile = await page.$('#uploadFile');
//文件上传fileToUpload是文件所在的地址--可以是相对也可以是绝对路径
await uploadFile.uploadFile(fileToUpload);
} catch (e) {
console.log('文件上传错误:' + e);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 忠告
- api 要写清楚功能,特别是重要的;
- 能 提供实例的最好 提供;
- English is REALLY important!