Skip to main content
Cypress应用

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'切换模式。有效值为 selectdrag-drop。详见 Action 部分。
animationDistanceThresholdanimationDistanceThreshold元素随时间移动超过的像素距离,以被视为动画
forcefalse强制执行操作,禁用等待可操作性
logtrue命令日志中显示命令。
timeoutdefaultCommandTimeout等待 .selectFile() 解析的超时时间
waitForAnimationswaitForAnimations是否等待元素完成动画后再执行命令。

生成结果 了解主题管理

  • .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.fixturecy.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',
])
caution

除非文件 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() 要求别名的主题不能为 nullundefined

断言 了解断言

超时设置 了解超时机制

  • .selectFile() 可能会因等待元素达到可操作状态而超时。
  • .selectFile() 可能会因等待文件存在于磁盘上或别名解析而超时。

命令日志

为 input 选择文件

cy.get('.file-input').selectFile(Cypress.Buffer.from('Hello world'))

上述命令将在命令日志中显示为:

selectFile 的命令日志

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

selectFile 的 console.log

历史

版本变更
9.3.0添加了 .selectFile() 命令
9.4.0添加了对 TypedArraymimeType 属性的支持。使用别名时不再丢失默认 fileName 名称。

社区认可

.selectFile() 命令深受现已弃用的 Cypress File Upload 插件的启发。它由 @abramenalcypress-file-upload 仓库的贡献者实现。

另请参阅