mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-23 15:39:28 -05:00
feat(launchpad): Directory Upload in Global Mode (#18165)
* small html tweaks * add basic implementation of vue3-file-selector * add test for file upload * update readme to reflect latest * Update packages/launchpad/src/global/GlobalEmpty.vue Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com> * HTML tweaks * add cypress-file-upload types Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { Component, computed, watch, defineComponent, h } from 'vue'
|
||||
import { ClientTestContext } from '../../src/graphql/ClientTestContext'
|
||||
import type { TestSourceTypeLookup } from '@packages/graphql/src/testing/testUnionType'
|
||||
import { createI18n } from '@packages/launchpad/src/locales/i18n'
|
||||
import 'cypress-file-upload'
|
||||
|
||||
/**
|
||||
* This variable is mimicing ipc provided by electron.
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": ["../driver/src"], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [] /* List of folders to include type definitions from. */
|
||||
"types": ["chrome", "./vue-shims", "./vite-env", "vite-plugin-icons", "@intlify/vite-plugin-vue-i18n/client", "@testing-library/cypress"], /* Type declaration files to be included in compilation. */
|
||||
"types": ["chrome", "./vue-shims", "./vite-env", "vite-plugin-icons", "@intlify/vite-plugin-vue-i18n/client", "@testing-library/cypress", "cypress-file-upload"], /* Type declaration files to be included in compilation. */
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
|
||||
@@ -36,21 +36,13 @@ yarn workspace @packages/launchpad build
|
||||
|
||||
For the best development experience, you will want to use VS Code with the [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) extension. This will give you type completion inside `vue` files.
|
||||
|
||||
You probably want to start Vite in watch mode:
|
||||
|
||||
```bash
|
||||
## from repo root
|
||||
yarn workspace @packages/launchpad watch
|
||||
yarn dev
|
||||
```
|
||||
|
||||
The start the application:
|
||||
|
||||
```bash
|
||||
## from repo root
|
||||
yarn workspace @packages/launchpad dev
|
||||
```
|
||||
|
||||
This also starts the GraphQL Server. You can access it on `http://localhost:52159/graphql`.
|
||||
This starts Vite in watch mode. It also starts the GraphQL Server. You can access it on `http://localhost:52159/graphql`.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"baseUrl": "http://localhost:5555",
|
||||
"viewportWidth": 800,
|
||||
"viewportHeight": 850,
|
||||
"fixturesFolder": false,
|
||||
"video": false,
|
||||
"retries": {
|
||||
"runMode": 2,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"purpose": "This is a file to test a file input."
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
"classnames": "2.3.1",
|
||||
"concurrently": "^6.2.0",
|
||||
"cross-env": "6.0.3",
|
||||
"cypress-file-upload": "^5.0.8",
|
||||
"graphql": "^15.5.1",
|
||||
"graphql-tag": "^2.12.5",
|
||||
"javascript-time-ago": "2.3.8",
|
||||
@@ -52,6 +53,7 @@
|
||||
"vue-prism-component": "2.0.0",
|
||||
"vue-prism-editor": "^2.0.0-alpha.2",
|
||||
"vue-tsc": "^0.3.0",
|
||||
"vue3-file-selector": "^1.0.1",
|
||||
"windicss": "3.1.4",
|
||||
"wonka": "^4.0.15"
|
||||
},
|
||||
|
||||
@@ -4,19 +4,27 @@ import GlobalEmpty from './GlobalEmpty.vue'
|
||||
const emptyText = defaultMessages.globalPage.empty
|
||||
|
||||
describe('<GlobalEmpty />', () => {
|
||||
it('renders the empty state', () => {
|
||||
beforeEach(() => {
|
||||
cy.mount(() => (<div
|
||||
class="p-12 min-w-280px max-w-650px overflow-auto resize-x">
|
||||
<GlobalEmpty />
|
||||
</div>))
|
||||
})
|
||||
|
||||
it('renders the empty state', () => {
|
||||
cy.contains(emptyText.title)
|
||||
cy.contains(emptyText.helper)
|
||||
|
||||
const parts = emptyText.dropText.split('{0}')
|
||||
|
||||
cy.contains(parts[0])
|
||||
|
||||
cy.contains(emptyText.browseManually)
|
||||
|
||||
cy.get('input[type=file]').should('have.length', 1)
|
||||
})
|
||||
|
||||
it('handles a file upload', () => {
|
||||
cy.get('input[type=file]').attachFile('project-upload.json')
|
||||
cy.get('[data-testid=upload-name]').should('have.text', 'project-upload.json')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,29 +1,56 @@
|
||||
<template>
|
||||
<main class="text-center">
|
||||
<main class="text-center" ref="projectUpload">
|
||||
<h1 class="text-2rem mb-2">{{ t('globalPage.empty.title') }}</h1>
|
||||
<p class="text-lg font-light text-gray-600 mb-6">{{ t('globalPage.empty.helper') }}</p>
|
||||
<button
|
||||
type="button"
|
||||
@click="selectProject"
|
||||
class="min-w-220px relative block w-full border-2 bg-gray-50 border-gray-300 border-dashed rounded-lg p-12 text-center hover:border-gray-400 text-center"
|
||||
>
|
||||
<IconPlaceholder
|
||||
class="-mb-8px mx-auto max-w-65px h-full relative justify-center w-full text-indigo-600"
|
||||
/>
|
||||
<span class="mt-13px block text-lg font-medium text-gray-700 font-light">
|
||||
<i18n-t keypath="globalPage.empty.dropText">
|
||||
<a class="font-normal" @click="selectProject">{{ t('globalPage.empty.browseManually') }}</a>
|
||||
</i18n-t>
|
||||
</span>
|
||||
</button>
|
||||
<FileSelector v-model="files" v-slot="{ openDialog }" allow-multiple >
|
||||
<Dropzone v-slot="{ hovered }" @click="openDialog">
|
||||
<div
|
||||
class="min-w-220px relative block w-full border-2 bg-gray-50 border-gray-300 border-dashed rounded-lg p-12 text-center hover:border-gray-400 text-center"
|
||||
:class="{ 'border-blue-200': hovered }"
|
||||
>
|
||||
<IconPlaceholder
|
||||
class="mx-auto max-w-65px h-full relative justify-center w-full text-indigo-600"
|
||||
/>
|
||||
<i18n-t keypath="globalPage.empty.dropText">
|
||||
<button
|
||||
class="text-indigo-600 hover:underline"
|
||||
>
|
||||
<!--
|
||||
This button allows keyboard users to fire a click event with the Enter or Space keys,
|
||||
which will be handled by the dropzone's existing click handler.
|
||||
-->
|
||||
{{ t('globalPage.empty.browseManually') }}</button>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</Dropzone>
|
||||
</FileSelector>
|
||||
<div data-testid="upload-name" class="hidden">{{uploadName}}</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "../composables"
|
||||
import IconPlaceholder from 'virtual:vite-icons/icons8/circle-thin'
|
||||
import { FileSelector, Dropzone } from 'vue3-file-selector'
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const files = ref<File[]>([])
|
||||
const uploadName = ref('')
|
||||
const projectUpload = ref<HTMLDivElement>()
|
||||
|
||||
const selectProject = (file: File) => { uploadName.value = file.name}
|
||||
|
||||
watch(files, (newVal) => {
|
||||
const uploadLength = newVal.length;
|
||||
const latestUpload = newVal[uploadLength - 1]
|
||||
selectProject(latestUpload)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// TODO: remove this when vue3-file-selector supports setting this attribute
|
||||
projectUpload.value?.querySelector('input[type=file]')?.setAttribute('webkitdirectory', 'webkitdirectory')
|
||||
})
|
||||
|
||||
|
||||
const selectProject = () => { }
|
||||
</script>
|
||||
|
||||
@@ -16747,6 +16747,11 @@ cypress-expect@2.0.0:
|
||||
arg "4.1.3"
|
||||
debug "4.2.0"
|
||||
|
||||
cypress-file-upload@^5.0.8:
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1"
|
||||
integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==
|
||||
|
||||
cypress-image-snapshot@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/cypress-image-snapshot/-/cypress-image-snapshot-3.1.1.tgz#cb7242d8086e0d4cbb7f333f927f71cdb5ff9971"
|
||||
@@ -41372,6 +41377,11 @@ vue-tsc@^0.3.0:
|
||||
dependencies:
|
||||
vscode-vue-languageservice "^0.27.0"
|
||||
|
||||
vue3-file-selector@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vue3-file-selector/-/vue3-file-selector-1.0.1.tgz#bcae2f5ab44c406c1d72a60885990883051b688b"
|
||||
integrity sha512-popFgEvLrkRFo9MWs8mzlb4HH+Mg2+5DhJF7MzKmUrE9179rtVt4Wf7/w+0FvhDRVELQ6f8Z9BhF+SDSUSpRVw==
|
||||
|
||||
vue@3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.6.tgz#c71445078751f458648fd8fb3a2da975507d03d2"
|
||||
|
||||
Reference in New Issue
Block a user