如何在AngularJS E2E Protractor测试中上传文件

92

我想通过 AngularJS 的端到端(e2e)测试来测试文件上传。在 e2e 测试中如何实现这一操作?我通过 Grunt Karma 运行我的测试脚本。


https://dev59.com/RWYr5IYBdhLWcg3w499- - DimaOverflow
10个回答

145

这是我的做法:

var path = require('path');

it('should upload a file', function() {
  var fileToUpload = '../some/path/foo.txt',
      absolutePath = path.resolve(__dirname, fileToUpload);

  element(by.css('input[type="file"]')).sendKeys(absolutePath);    
  element(by.id('uploadButton')).click();
});
  1. 使用path模块来解析您想要上传的文件的完整路径。
  2. 将路径设置为input type="file"元素。
  3. 单击上传按钮。

这在火狐浏览器上不起作用。Protractor会抱怨因为该元素不可见。要在火狐浏览器中上传,您需要使输入框可见。这是我所做的:

browser.executeAsyncScript(function(callback) {
  // You can use any other selector
  document.querySelectorAll('#input-file-element')[0]
      .style.display = 'inline';
  callback();
});

// Now you can upload.
$('input[type="file"]').sendKeys(absolutePath);    
$('#uploadButton').click();

+1 这个可行。Andres,你应该向 OP 请求反馈,因为这个可能会被接受为正确答案。 - coma
1
也使用过 Protractor。 - Ilia Barahovsky
7
有时候,__dirname 可能指向临时目录(可能是测试运行程序复制测试的地方)。如果是这种情况,你可以使用 process.cwd() 替换 __dirname - BorisOkunskiy
这在我的Chrome浏览器上可以工作,但是对于其他浏览器,Protractor会抱怨该元素不可见...有什么想法吗? - Omid Ahourai
你无法使用 Firefox 上传,因为该元素不可见。你需要使该元素可见以设置路径值。请参见更新后的答案。 - Andres D
显示剩余3条评论

16

直接操作是不可能的。

出于安全原因,在类似ngScenario这样的功能测试套件中,您无法模拟选择系统上文件的用户。

使用Protractor,由于其基于WebDriver,应该可以使用这个技巧

Q:WebDriver支持文件上传吗? A:是的。

您无法直接与本机操作系统文件浏览器对话框交互,但我们会进行一些操作,以便如果您在文件上传元素上调用WebElement#sendKeys(“/path/to/file”),它会执行正确的操作。 确保您不要单击文件上传元素的WebElement#click(),否则浏览器可能会挂起。

这很好地解决了问题:

$('input[type="file"]').sendKeys("/file/path")

这似乎没有回答问题,并链接到另一个网站。 - activedecay

4
这里是Andres D和davidb583的建议结合,这将帮助我解决问题...
我试图执行针对flowjs控件的protractor测试。
    // requires an absolute path
    var fileToUpload = './testPackages/' + packageName + '/' + fileName;
    var absolutePath = path.resolve(__dirname, fileToUpload);

    // Find the file input element
    var fileElem = element(by.css('input[type="file"]'));

    // Need to unhide flowjs's secret file uploader
    browser.executeScript(
      "arguments[0].style.visibility = 'visible'; arguments[0].style.height = '1px'; arguments[0].style.width = '1px'; arguments[0].style.opacity = 1",
      fileElem.getWebElement());

    // Sending the keystrokes will ultimately submit the request.  No need to simulate the click
    fileElem.sendKeys(absolutePath);

    // Not sure how to wait for the upload and response to return first
    // I need this since I have a test that looks at the results after upload
    //  ...  there is probably a better way to do this, but I punted
    browser.sleep(1000);

2
var imagePath = 'http://placehold.it/120x120&text=image1';
element(by.id('fileUpload')).sendKeys(imagePath);

这对我有效。


1

这是我在Firefox上上传文件的方法,这个脚本使元素可见以设置路径值:

   browser.executeScript("$('input[type=\"file\"]').parent().css('visibility', 'visible').css('height', 1).css('width', 1).css('overflow', 'visible')");

1

如果以上解决方法无效,请阅读以下内容

首先,为了上传文件,应该有一个input元素,用于输入文件路径。通常,它紧挨着“上传”按钮... 但是我见过这种情况,当按钮周围没有一个输入框时可能会让人感到困惑。保持冷静,输入框必须存在于页面上!尝试在DOM中查找具有类似“上传”或“文件”之类的输入元素,只需记住它可以出现在任何地方。

当您找到它后,获取其选择器,并键入文件路径。请记住,它必须是绝对路径,从您的根目录开始(对于MAC用户为/something/like/this,对于Windows用户为C:/some/file

await $('input[type="file"]').sendKeys("/file/path")

这可能无法正常工作,如果……

Protractor的sendKeys只能在可见的输入框中输入文字。通常,输入框可能会被隐藏或大小为0像素。你也可以解决这个问题。

let $input = $('input[type="file"]');
await browser.executeScript(
    "arguments[0].style.visibility = 'visible'; arguments[0].style.height = '1px'; arguments[0].style.width = '1px'; arguments[0].style.opacity = 1",
    $input.getWebElement()
);

0

// 从 C:\ 目录上传文件

{

var path = require('path');
var dirname = 'C:/';
var fileToUpload = '../filename.txt';
var absolutePath = path.resolve('C:\filename.txt');
var fileElem = ptor.element.all(protractor.By.css('input[type="file"]'));

fileElem.sendKeys(absolutePath);
cb();

};

那么变量 fileToUpload 是用来做什么的? - user6749601

0
我意识到在我正在测试的Web应用程序中,文件输入只有在使用JavaScript滚动到视图中时才在Firefox中可见,因此我在Andres D的代码中添加了scrollIntoView()以使其适用于我的应用程序:
  browser.executeAsyncScript(function (callback) {
        document.querySelectorAll('input')[2]
     .style = '';
        document.querySelectorAll('input')[2].scrollIntoView();

        callback();
    });

(我还删除了文件输入元素的所有样式)


0
如果你想在不打开弹出窗口的情况下选择文件,以下是答案:
var path = require('path'); 
var remote = require('../../node_modules/selenium-webdriver/remote'); 
browser.setFileDetector(new remote.FileDetector()); 
var fileToUpload = './resume.docx';
var absolutePath = path.resolve(process.cwd() + fileToUpload); 
element(by.css('input[type="file"]')).sendKeys(absolutePath);

-3

当前记录的解决方案仅在用户加载jQuery时有效。在所有不同的情况下,用户都会收到一个错误,如:Failed: $未定义

我建议记录一种使用本地angularjs代码的解决方案。

例如,我建议不是建议:

    $('input[type="file"]') .....

建议:

    angular.element(document.querySelector('input[type="file"]')) .....

后者更标准,在 Angular 的基础上,更重要的是不需要 jQuery。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接