selectFile
选择 HTML5 input 元素中的文件或模拟将文件拖拽到浏览器中。
在 .selectFile()
之后继续链式调用依赖该主题的命令是不安全的。
语法
.selectFile(file)
.selectFile(file, options)
.selectFile([file1, file2, ...])
.selectFile([file1, file2, ...], options)
用法
正确用法
cy.get('input[type=file]').selectFile('file.json')
cy.get('input[type=file]').selectFile(['file.json', 'file2.json'])
cy.get('input[type=file]').selectFile({
contents: Cypress.Buffer.from('file contents'),
fileName: 'file.txt',
mimeType: 'text/plain',
lastModified: Date.now(),
})
cy.get('input[type=file]').selectFile('file.json', { action: 'drag-drop' })
cy.document().selectFile('file.json', { action: 'drag-drop' })
错误用法
// 错误,不能从 'cy' 链式调用
cy.selectFile('file.json')
// 会尝试在磁盘上查找名为 'file contents' 的文件
// 可能不是你想要的效果
cy.get('input[type=file]').selectFile('file contents')
参数
file (String, Array, Object 或 Cypress.Buffer)
可以是一个文件或文件数组。文件可以是:
- 项目根目录(包含默认 Cypress 配置文件的目录)中的文件路径。例如:
'path/to/file.json'
@alias
- 任何类型的别名,之前使用.as()
存储。例如:'@alias'
- 包含二进制数据的
TypedArray
, 例如Uint8Array.from('123')
。Cypress.Buffer
实例,例如由cy.readFile('file.json', null)
返回或由Cypress.Buffer.from('foo')
创建的实例,都是TypedArray
实例。 - 具有非空
contents
属性的对象,指定文件的详细信息。例如:{contents: '@alias', fileName: 'file.json'}
如果提供对象,可以包含以下属性。
选项 | 描述 |
---|---|
contents | 文件内容。可以是如上所述的字符串简写,包含二进制数据的 TypedArray 实例(如 Cypress.Buffer 实例)或非 TypedArray 对象,后者将通过 JSON.stringify() 和 utf8 编码转换为字符串。 |
fileName | 文件名。如果 contents 是磁盘上的路径或来自 cy.readFile() 或 cy.fixture() 的别名,则默认为实际文件名。其他情况下默认为空字符串。 |
mimeType | 文件的 mimeType。如果省略,将根据文件扩展名推断。如果无法推断,则默认为空字符串。 |
lastModified | 文件的最后修改时间戳,单位为自 UNIX 纪元以来的毫秒数(例如 Date.prototype.getTime() )。默认为 Date.now() 。 |
options (Object)
传入选项对象以更改 .selectFile()
的默认行为。
选项 | 默认值 | 描述 |
---|---|---|
action | 'select' | 切换模式。有效值为 select 和 drag-drop 。详见 Action 部分。 |
animationDistanceThreshold | animationDistanceThreshold | 元素随时间移动超过的像素距离,以被视为动画。 |
force | false | 强制执行操作,禁用等待可操作性。 |
log | true | 在命令日志中显示命令。 |
timeout | defaultCommandTimeout | 等待 .selectFile() 解析的超时时间。 |
waitForAnimations | waitForAnimations | 是否等待元素完成动画后再执行命令。 |
生成结果
.selectFile()
返回与给定主题相同的主题。- 在
.selectFile()
之后继续链式调用依赖该主题的命令是不安全的。
Action
根据 options
参数中的 action
设置,.selectFile()
可以模拟两种不同的用户行为:
select
(默认)
默认情况下,.selectFile()
以 'select' 模式运行,模拟用户在 HTML5 input 元素中选择一个或多个文件。在此模式下,主题必须是单个 type="file"
的 input
元素,或连接到 input 的 label
元素(通过 for
属性或包含 input)。
drag-drop
将 action 设置为 drag-drop
会将命令的行为更改为模拟用户从操作系统拖拽文件到浏览器中,并将其放置在所选主题上。在此模式下,主题可以是任何 DOM 元素或整个 document
。
示例
从磁盘文件
cy.get('input[type=file]').selectFile('path/to/file.json')
cy.get('input[type=file]').selectFile('path/to/file.png')
如果给定路径,.selectFile()
将相对于项目根目录查找文件,并附加磁盘上完全相同的文件。这是处理磁盘上文件的首选方法,避免了许多编码相关的问题。
在隐藏的 input 上
cy.get('input[type=file]').selectFile('file.json', { force: true })
在现代应用程序的许多情况下,底层的文件 input 是隐藏的,并通过用户点击按钮激活。在这些情况下,你需要告诉 Cypress 忽略其可操作性检查,即使用户无法直接激活文件 input,也要选择文件。
从 fixture
cy.fixture('file.json', null).as('myFixture')
cy.get('input[type=file]').selectFile('@myFixture')
注意使用 null
编码。默认情况下,cy.fixture()
和 cy.readFile()
会尝试解释从磁盘读取的文件,这将导致 JSON 文件被解码并重新编码为 utf-8 字符串 - 内容将被保留,但格式可能不会保留,编码可能会改变。有关文件编码的更多详情,请参阅 cy.fixture
或 cy.readFile
。
从 API 响应
cy.request('http://localhost:8888/users/827').its('body').as('responseBody')
cy.get('input[type=file]').selectFile('@responseBody')
在测试中处理数据
cy.readFile('users.json')
.then((users) => {
users[0].username = 'JohnCena'
})
.as('myFile')
cy.get('input[type=file]').selectFile('@myFile')
选择多个文件
cy.get('input[type=file]').selectFile([
'file1.json',
'file2.json',
'file3.json',
])
除非文件 input 具有 multiple
属性,否则这将失败。
自定义 fileName、mimeType 和 lastModified
cy.get('input[type=file][multiple]')
.selectFile([
{
contents: 'cypress/fixtures/example.json',
},
{
contents: 'cypress/fixtures/example.json',
fileName: 'file.png',
},
{
contents: 'cypress/fixtures/example.json',
fileName: 'file.png',
mimeType: 'text/plain',
lastModified: new Date('Feb 18 1989').valueOf(),
},
])
.then(($input) => {
const files = $input[0].files
// 如果未指定任何内容,fileName 和 MIME 类型将从磁盘上的路径推断:
expect(files[0].name).to.eq('example.json')
expect(files[0].type).to.eq('application/json')
// 如果给出了 fileName,MIME 类型将基于此推断。
expect(files[1].name).to.eq('file.png')
expect(files[1].type).to.eq('image/png')
// 但显式指定的 MIME 类型始终被使用。
expect(files[2].name).to.eq('file.png')
expect(files[2].type).to.eq('text/plain')
// lastModified 默认为当前时间,但可以覆盖。
expect(files[0].lastModified).to.be.closeTo(Date.now(), 1000)
expect(files[1].lastModified).to.be.closeTo(Date.now(), 1000)
expect(files[2].lastModified).to.eql(new Date('Feb 18 1989').valueOf())
})
在 document 上拖放文件
cy.document().selectFile('file.json', { action: 'drag-drop' })
注意事项
存在性
默认文件存在断言
每当解析文件路径时,.selectFile()
会断言文件存在,如果文件不存在则会失败。如果文件最初不存在,它将重试读取文件,直到文件存在或命令超时。
// 在达到 defaultCommandTimeout 后会失败
cy.get('input[type=file]').selectFile('does-not-exist.yaml')
可操作性
元素必须首先达到可操作状态
.selectFile()
是一个“操作命令”,遵循所有可操作性的规则。
规则
要求
.selectFile()
需要链式调用产生 DOM 元素的命令。使用input
操作(默认)时,还需要一个type="file"
的单个input
元素,或连接到 input 的label
元素。- 如果给定路径,
.selectFile()
要求文件必须存在。 - 如果给定别名,
.selectFile()
要求别名的主题不能为null
或undefined
。
断言
.selectFile()
会自动等待元素达到可操作状态。
超时设置
.selectFile()
可能会因等待元素达到可操作状态而超时。.selectFile()
可能会因等待文件存在于磁盘上或别名解析而超时。
命令日志
为 input 选择文件
cy.get('.file-input').selectFile(Cypress.Buffer.from('Hello world'))
上述命令将在命令日志中显示为:

当点击命令日志中的 selectFile
时,控制台输出如下:

历史
版本 | 变更 |
---|---|
9.3.0 | 添加了 .selectFile() 命令 |
9.4.0 | 添加了对 TypedArray 和 mimeType 属性的支持。使用别名时不再丢失默认 fileName 名称。 |
社区认可
.selectFile()
命令深受现已弃用的 Cypress File Upload 插件的启发。它由 @abramenal 和 cypress-file-upload 仓库的贡献者实现。