Skip to content

Commit

Permalink
feat: cy.selectFile() (#19332) (#19524)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blue F authored Jan 14, 2022
1 parent 29f5c64 commit 3809cd4
Show file tree
Hide file tree
Showing 20 changed files with 1,547 additions and 54 deletions.
3 changes: 2 additions & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"@types/sizzle": "^2.3.2",
"arch": "^2.2.0",
"blob-util": "^2.0.2",
"bluebird": "3.7.2",
"bluebird": "^3.7.2",
"buffer": "^5.6.0",
"cachedir": "^2.3.0",
"chalk": "^4.1.0",
"check-more-types": "^2.24.0",
Expand Down
4 changes: 4 additions & 0 deletions cli/types/cypress-eventemitter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ interface NodeEventEmitter {
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this
eventNames(): Array<string | symbol>
}

// We use the Buffer class for dealing with binary data, especially around the
// selectFile interface.
type BufferType = import("buffer/").Buffer
45 changes: 45 additions & 0 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,15 @@ declare namespace Cypress {
* Cypress.Blob.method()
*/
Blob: BlobUtil.BlobUtilStatic
/**
* Cypress automatically includes a Buffer library and exposes it as Cypress.Buffer.
*
* @see https://on.cypress.io/buffer
* @see https://github.com/feross/buffer
* @example
* Cypress.Buffer.method()
*/
Buffer: BufferType
/**
* Cypress automatically includes minimatch and exposes it as Cypress.minimatch.
*
Expand Down Expand Up @@ -662,6 +671,20 @@ declare namespace Cypress {
*/
as(alias: string): Chainable<Subject>

/**
* Select a file with the given <input> element, or drag and drop a file over any DOM subject.
*
* @param {FileReference} files - The file(s) to select or drag onto this element.
* @see https://on.cypress.io/selectfile
* @example
* cy.get('input[type=file]').selectFile(Cypress.Buffer.from('text'))
* cy.get('input[type=file]').selectFile({
* fileName: 'users.json',
* fileContents: [{name: 'John Doe'}]
* })
*/
selectFile(files: FileReference | FileReference[], options?: Partial<SelectFileOptions>): Chainable<Subject>

/**
* Blur a focused element. This element must currently be in focus.
* If you want to ensure an element is focused before blurring,
Expand Down Expand Up @@ -2466,6 +2489,17 @@ declare namespace Cypress {
scrollBehavior: scrollBehaviorOptions
}

interface SelectFileOptions extends Loggable, Timeoutable, ActionableOptions {
/**
* Which user action to perform. `select` matches selecting a file while
* `drag-drop` matches dragging files from the operating system into the
* document.
*
* @default 'select'
*/
action: 'select' | 'drag-drop'
}

interface BlurOptions extends Loggable, Forceable { }

interface CheckOptions extends Loggable, Timeoutable, ActionableOptions {
Expand Down Expand Up @@ -5641,6 +5675,17 @@ declare namespace Cypress {
stderr: string
}

type FileReference = string | BufferType | FileReferenceObject
interface FileReferenceObject {
/*
* Buffers will be used as-is, while strings will be interpreted as an alias or a file path.
* All other types will have `Buffer.from(JSON.stringify())` applied.
*/
contents: any
fileName?: string
lastModified?: number
}

interface LogAttrs {
url: string
consoleProps: ObjectLike
Expand Down
110 changes: 110 additions & 0 deletions packages/driver/cypress/fixtures/files-form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html>
<head>
<title>Generic File Inputs</title>
</head>
<script>
const template = document.createElement('template')
template.innerHTML = `
<label for="file-input">Shadow DOM</label>
<input name="file-input" id="file-input" type="file" />
`

class FileInput extends HTMLElement {
constructor() {
super()
this.root = this.attachShadow({ mode: 'open' })
}

connectedCallback() {
this.root.appendChild(template.content.cloneNode(true))
}
}

window.customElements.define('file-input', FileInput);
</script>
<body>
<style>
form {
position: relative;
min-height: 30px;
}

#hidden, #hidden-basic-label {
display: none;
}

#covered, #covering {
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 30px;
}
#covering {
background: black;
z-index: 1;
}

#scroll-form {
display: block;
width: 300px;
height: 50px;
overflow: auto;
}
#tall {
height: 80px;
background: black;
}
</style>

<form>
<label for="basic" id="basic-label">Basic Label</label>
<label for="basic" id="hidden-basic-label">Hidden Label</label>
<input id="basic" type="file" />
<label id="containing-label">
Containing Label
<input type="file" id="contained" />
</label>
</form>

<form>
<input id="multiple" type="file" multpile />
</form>

<form>
<label for="hidden" id="hidden-label">Label for Hidden</label>
<input id="hidden" type="file" />
</form>

<form>
<file-input id="shadow"></file-input>
</form>

<form>
<label for="text-input" id="text-label">Text label</label>
<input type="text" id="text-input" />

<label for="nonexistent" id="nonexistent-label">
Bad label
<input type="file" />
</label>
</form>

<form>
<div id="covering"></div>
<input id="covered" type="file" />
</form>

<form>
<label for="disabled" id="disabled-label">Disabled Label</label>
<input id="disabled" type="file" disabled />
</form>

<form id="scroll-form">
<div id="tall"></div>
<label for="scroll" id="scroll-label">Scroll Label</label>
<input id="scroll" type="file" />
</form>
</body>
</html>
Loading

0 comments on commit 3809cd4

Please sign in to comment.