瀏覽代碼

Update webdriverio to v5 (#1675)

* build: update webdriverio to v5

* build: update wdio services config syntax

* e2e test updates for wdio 5

* Sync pinned versions between repo root and companion

* build: enable all e2e tests for this PR run

* waitForExist

* test: await browser.url() calls

* test: awaitify url-plugin test

* test: use sauceConnect

* test: upload files to sauce before using them

* fall back to fakechoosefile a lot?

* fall back to fakechoosefile more

* Disable file selection on saucelabs

* test: need to await this thing

* test: make more-sure that the input is visible

* test: use currently low load transloadit region so i dont have to wait

* test: update but disable xhr-limit

* test: change the order

* test: newer firefoxes

* test: change the order back

* kinda sucks that they only have super old browsers on linux

* ci: disable url-plugin and transloadit e2e tests again

* test: use local tus-node-server for integration tests

* test: use envify to check env variables and select appropriate URL

* test: use companion.test:1080 for tus uploads on Travis

* test: fix env vars in typescript and CRA tests

* test: use getBoundingClientRect, may work better in android

* test: try getSize AND getBoundingClientRect

* test: do not check image width in android

* test: allow retrying tests that are prone to flakiness

* test: be more verbose during e2e tests

* test: force <input> visibility in more tests

* test: warn if using test:endtoend not on CI
Renée Kooi 5 年之前
父節點
當前提交
0a40f2c444

+ 12 - 1
bin/endtoend-build-ci

@@ -3,7 +3,6 @@
 set -o pipefail
 set -o errexit
 set -o nounset
-set -o xtrace
 
 # Set magic variables for current file & dir
 __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -11,6 +10,18 @@ __file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
 __base="$(basename ${__file} .sh)"
 __root="$(cd "$(dirname "${__dir}")" && pwd)"
 
+if [ -z "${CI:-}" ]; then
+  echo "!! Running CI-style end-to-end tests but CI environment variable is not set"
+  echo "It is generally ill-advised to run the full end-to-end suite on your local machine."
+  echo "You are probably looking for this instead:"
+  echo "  npm run test:endtoend:local"
+  echo ""
+  echo "Hit Ctrl+C to stop or Enter if you REALLY DO want to run the full thing."
+  read
+fi
+
+set -o xtrace
+
 VERDACCIO_REGISTRY=http://localhost:4002
 CURRENT_COMMIT="$(git rev-parse HEAD)"
 

+ 3 - 2
bin/endtoend-build-tests

@@ -20,17 +20,18 @@ for t in $tests; do
   cp "${__root}/test/endtoend/$t/index.html" "${__root}/test/endtoend/$t/dist"
   browserify "${__root}/test/endtoend/$t/main.js" \
     -o "${__root}/test/endtoend/$t/dist/bundle.js" \
+    -t envify \
     -t babelify
 done
 
 # Speeecial tests that need custom builds.
 pushd "${__root}/test/endtoend/create-react-app"
   npm install
-  npm run build
+  REACT_APP_ON_TRAVIS="${TRAVIS:-}" npm run build
 popd
 pushd "${__root}/test/endtoend/typescript"
   mkdir -p dist
   cp "${__root}/packages/uppy/dist/uppy.min.css" dist/
   cp index.html dist/
-  browserify main.ts -p [ tsify --target ES3 ] -o dist/bundle.js
+  browserify main.ts -t envify -p [ tsify --target ES3 ] -o dist/bundle.js
 popd

File diff suppressed because it is too large
+ 812 - 677
package-lock.json


+ 9 - 4
package.json

@@ -20,6 +20,10 @@
     "@babel/register": "^7.4.4",
     "@octokit/rest": "^16.25.0",
     "@types/react": "^16.8.10",
+    "@wdio/cli": "^5.10.7",
+    "@wdio/local-runner": "^5.10.7",
+    "@wdio/mocha-framework": "^5.0.0",
+    "@wdio/sauce-service": "^5.0.0",
     "aliasify": "^2.1.0",
     "autoprefixer": "^9.5.1",
     "babel-eslint": "10.0.1",
@@ -33,6 +37,7 @@
     "chalk": "2.4.2",
     "cssnano": "^4.1.10",
     "disc": "^1.3.3",
+    "envify": "^4.1.0",
     "enzyme": "^3.9.0",
     "enzyme-adapter-react-16": "^1.11.2",
     "eslint": "^5.16.0",
@@ -48,6 +53,7 @@
     "eslint-plugin-standard": "^4.0.0",
     "events.once": "^2.0.2",
     "exorcist": "^1.0.1",
+    "express": "4.17.1",
     "fakefile": "0.0.9",
     "flat": "^4.1.0",
     "github-contributors-list": "1.2.3",
@@ -78,19 +84,18 @@
     "react-dom": "^16.8.6",
     "redux": "^4.0.1",
     "replace-x": "^1.5.0",
+    "rimraf": "^2.6.3",
     "stringify-object": "^3.3.0",
     "tar": "^4.4.8",
     "temp-write": "^3.4.0",
     "tinyify": "^2.5.0",
     "touch": "^3.1.0",
     "tsify": "^4.0.1",
+    "tus-node-server": "^0.3.2",
     "typescript": "^3.4.5",
     "verdaccio": "^4.0.0",
     "watchify": "^3.11.1",
-    "wdio-mocha-framework": "^0.6.4",
-    "wdio-sauce-service": "^0.4.14",
-    "wdio-static-server-service": "^1.0.1",
-    "webdriverio": "^4.14.4"
+    "webdriverio": "^5.0.0"
   },
   "scripts": {
     "bootstrap": "lerna bootstrap",

+ 1 - 1
packages/@uppy/companion/package.json

@@ -38,7 +38,7 @@
     "common-tags": "1.8.0",
     "connect-redis": "3.4.0",
     "cookie-parser": "1.4.3",
-    "express": "4.16.3",
+    "express": "4.17.1",
     "express-interceptor": "1.2.0",
     "express-prom-bundle": "3.3.0",
     "express-session": "1.15.6",

+ 5 - 2
test/endtoend/create-react-app/src/App.js

@@ -9,16 +9,19 @@ import '@uppy/dashboard/dist/style.css'
 // import '@uppy/drag-drop/dist/style.css'
 // import '@uppy/progress-bar/dist/style.css'
 
+const isOnTravis = process.env.REACT_APP_ON_TRAVIS
+const endpoint = isOnTravis ? 'http://companion.test:1080' : 'http://localhost:1080'
+
 class App extends Component {
   constructor (props) {
     super(props)
 
     this.uppy = new Uppy({ id: 'uppy1', autoProceed: true, debug: true })
-      .use(Tus, { endpoint: 'https://master.tus.io/files/' })
+      .use(Tus, { endpoint: `${endpoint}/files/` })
       .use(GoogleDrive, { companionUrl: 'https://companion.uppy.io' })
 
     this.uppy2 = new Uppy({ id: 'uppy2', autoProceed: false, debug: true })
-      .use(Tus, { endpoint: 'https://master.tus.io/files/' })
+      .use(Tus, { endpoint: `${endpoint}/files/` })
 
     this.state = {
       showInlineDashboard: true,

+ 52 - 43
test/endtoend/create-react-app/test.js

@@ -2,82 +2,91 @@
 const testURL = 'http://localhost:4567/create-react-app'
 
 describe('webpack build', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should include CSS', () => {
-    const el = $('#inline-dashboard .uppy-Dashboard-inner')
-    el.waitForExist()
-    const bgColor = el.getCssProperty('background-color').value
+  it('should include CSS', async () => {
+    const el = await $('#inline-dashboard .uppy-Dashboard-inner')
+    await el.waitForExist()
+    const bgColor = await el.getCSSProperty('background-color')
     // computed value is rgb() or rgba(), not hex (but listing it here to show the expected value too)
-    expect(/^rgba?\(250, ?250, ?250(?:, ?1)?\)$|^#fafafa$/.test(bgColor)).to.equal(true)
+    expect(/^rgba?\(250, ?250, ?250(?:, ?1)?\)$|^#fafafa$/.test(bgColor.value)).to.equal(true)
   })
 })
 
 describe('React: Dashboard', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should have Google Drive panel', () => {
-    const el = $('#inline-dashboard .uppy-Dashboard-inner')
-    el.waitForExist()
-
-    const tabs = $$('.uppy-DashboardTab-name')
-    expect(tabs.some(name => name.getText() === 'Google Drive')).to.equal(true)
+  it('should have Google Drive panel', async () => {
+    const el = await $('#inline-dashboard .uppy-Dashboard-inner')
+    await el.waitForExist()
+
+    const tabs = await $$('.uppy-DashboardTab-name')
+    let hasGDrive = false
+    for (const name of tabs) {
+      hasGDrive = (await name.getText()) === 'Google Drive'
+      if (hasGDrive) break
+    }
+    expect(hasGDrive).to.equal(true)
   })
 
-  it('should survive being mounted and unmounted', () => {
-    const el = $('#inline-dashboard .uppy-Dashboard-inner')
-    el.waitForExist()
+  it('should survive being mounted and unmounted', async () => {
+    const el = await $('#inline-dashboard .uppy-Dashboard-inner')
+    await el.waitForExist()
 
+    const toggle = await $('#inline-dashboard-toggle')
     // close
-    browser.click('#inline-dashboard-toggle')
-    browser.pause(250)
+    await toggle.click()
+    await browser.pause(250)
     // open
-    browser.click('#inline-dashboard-toggle')
-    browser.pause(250)
+    await toggle.click()
+    await browser.pause(250)
     // close
-    browser.click('#inline-dashboard-toggle')
-    browser.pause(250)
+    await toggle.click()
+    await browser.pause(250)
     // open
-    browser.click('#inline-dashboard-toggle')
-    browser.pause(250)
+    await toggle.click()
+    await browser.pause(250)
 
     // open GDrive panel
-    browser.click('.uppy-DashboardTab:nth-child(2) button')
-    browser.pause(500)
+    const gdriveButton = await $('.uppy-DashboardTab:nth-child(2) button')
+    await gdriveButton.click()
+    await browser.pause(500)
 
     // side effecting property access, not a function!
     // eslint-disable-next-line no-unused-expressions
-    expect($('.uppy-Provider-authBtn')).to.exist
+    expect(await $('.uppy-Provider-authBtn')).to.exist
   })
 })
 
 describe('React: DashboardModal', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should have controlled open and close', () => {
-    const modalToggle = $('#modal-dashboard-toggle')
-    const modalWrapper = $('#modal-dashboard .uppy-Dashboard--modal')
-    const modalClose = $('#modal-dashboard .uppy-Dashboard-close')
+  it('should have controlled open and close', async () => {
+    const modalToggle = await $('#modal-dashboard-toggle')
+    const modalWrapper = await $('#modal-dashboard .uppy-Dashboard--modal')
+    const modalClose = await $('#modal-dashboard .uppy-Dashboard-close')
+
+    await modalToggle.waitForExist()
 
-    expect(modalWrapper.getAttribute('aria-hidden')).to.equal('true')
+    expect(await modalWrapper.getAttribute('aria-hidden')).to.equal('true')
 
-    modalToggle.click()
-    browser.pause(50) // wait for the animation to start
+    await modalToggle.click()
+    await browser.pause(50) // wait for the animation to start
 
     // Edge appears to report empty string while others report null
-    expect(modalWrapper.getAttribute('aria-hidden')).to.be.oneOf([null, ''])
+    expect(await modalWrapper.getAttribute('aria-hidden')).to.be.oneOf([null, ''])
 
-    browser.pause(500) // wait for the animation to complete
+    await browser.pause(500) // wait for the animation to complete
 
-    modalClose.click()
-    browser.pause(500) // wait for the animation to complete
+    await modalClose.click()
+    await browser.pause(500) // wait for the animation to complete
 
-    expect(modalWrapper.getAttribute('aria-hidden')).to.equal('true')
+    expect(await modalWrapper.getAttribute('aria-hidden')).to.equal('true')
   })
 })

+ 18 - 11
test/endtoend/i18n-drag-drop/test.js

@@ -1,27 +1,34 @@
 /* global browser, expect, capabilities  */
 const path = require('path')
-const { selectFakeFile, supportsChooseFile } = require('../utils')
+const { selectFakeFile, supportsChooseFile, ensureInputVisible } = require('../utils')
 
 const testURL = 'http://localhost:4567/i18n-drag-drop'
 
-describe('File upload with DragDrop + XHRUpload, i18n translated string', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+describe('File upload with DragDrop + XHRUpload, i18n translated string', function () {
+  this.retries(2)
+
+  beforeEach(async () => {
+    await browser.url(testURL)
+    await browser.execute(ensureInputVisible, '#uppyi18n .uppy-DragDrop-input')
   })
 
-  it('should upload a file with XHRUpload and set progressbar to 100%', () => {
+  it('should upload a file with XHRUpload and set progressbar to 100%', async () => {
+    let testImage = path.join(__dirname, '../../resources/image.jpg')
     if (supportsChooseFile(capabilities)) {
-      browser.chooseFile('#uppyi18n .uppy-DragDrop-input', path.join(__dirname, '../../resources/image.jpg'))
+      const input = await browser.$('#uppyi18n .uppy-DragDrop-input')
+      await input.setValue(testImage)
     } else {
-      browser.execute(selectFakeFile, 'uppyi18n')
+      await browser.execute(selectFakeFile, 'uppyi18n')
     }
-    browser.pause(3000)
-    const html = browser.getHTML('#uppyi18n-progress .uppy-ProgressBar-percentage', false)
+    await browser.pause(3000)
+    const percent = await browser.$('#uppyi18n-progress .uppy-ProgressBar-percentage')
+    const html = await percent.getHTML(false)
     expect(parseInt(html)).to.be.equal(100)
   })
 
-  it('should translate text strings into Russian', () => {
-    const text = browser.getText('#uppyi18n .uppy-DragDrop-label')
+  it('should translate text strings into Russian', async () => {
+    const label = await browser.$('#uppyi18n .uppy-DragDrop-label')
+    const text = await label.getText()
     expect(text.trim()).to.be.equal('Перенесите файлы сюда или выберите')
   })
 })

+ 8 - 5
test/endtoend/providers/main.js

@@ -7,7 +7,10 @@ const Instagram = require('@uppy/instagram')
 const Dropbox = require('@uppy/dropbox')
 const Tus = require('@uppy/tus')
 
-Uppy({
+const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
+const companionUrl = isOnTravis ? 'http://companion.test:3030' : 'http://localhost:3030'
+
+window.uppy = Uppy({
   id: 'uppyProvider',
   debug: true,
   autoProceed: true
@@ -16,7 +19,7 @@ Uppy({
     target: '#uppyDashboard',
     inline: true
   })
-  .use(GoogleDrive, { target: Dashboard, companionUrl: 'http://localhost:3020' })
-  .use(Instagram, { target: Dashboard, companionUrl: 'http://localhost:3020' })
-  .use(Dropbox, { target: Dashboard, companionUrl: 'http://localhost:3020' })
-  .use(Tus, { endpoint: 'https://master.tus.io/files/' })
+  .use(GoogleDrive, { target: Dashboard, companionUrl })
+  .use(Instagram, { target: Dashboard, companionUrl })
+  .use(Dropbox, { target: Dashboard, companionUrl })
+  .use(Tus, { endpoint: 'http://localhost:1080/files/' })

+ 29 - 15
test/endtoend/thumbnails/test.js

@@ -16,35 +16,36 @@ const notImages = [
 ]
 
 describe('ThumbnailGenerator', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should generate thumbnails for images', function () {
+  it('should generate thumbnails for images', async function () {
     // Does not work on IE right now
     if (capabilities.browserName === 'internet explorer') {
       this.skip()
       return
     }
 
-    $('#uppyThumbnails .uppy-FileInput-input').waitForExist()
+    const input = await $('#uppyThumbnails .uppy-FileInput-input')
+    await input.waitForExist()
 
-    browser.execute(/* must be valid ES5 for IE */ function () {
+    await browser.execute(/* must be valid ES5 for IE */ function () {
       window.thumbnailsReady = new Promise(function (resolve) {
         window.uppyThumbnails.on('thumbnail:all-generated', resolve)
       })
     })
 
     if (supportsChooseFile()) {
-      for (const img of images) {
-        browser.chooseFile('#uppyThumbnails .uppy-FileInput-input', img)
+      for (const file of images) {
+        await input.setValue(file)
       }
       for (const { file } of notImages) {
-        browser.chooseFile('#uppyThumbnails .uppy-FileInput-input', file)
+        await input.setValue(file)
       }
     } else {
       for (const img of images) {
-        browser.execute(
+        await browser.execute(
           selectFakeFile,
           'uppyThumbnails',
           path.basename(img), // name
@@ -53,7 +54,7 @@ describe('ThumbnailGenerator', () => {
         )
       }
       for (const { type, file } of notImages) {
-        browser.execute(
+        await browser.execute(
           selectFakeFile,
           'uppyThumbnails',
           path.basename(file), // name
@@ -63,15 +64,15 @@ describe('ThumbnailGenerator', () => {
       }
     }
 
-    browser.executeAsync(/* must be valid ES5 for IE */ function (done) {
+    await browser.executeAsync(/* must be valid ES5 for IE */ function (done) {
       window.thumbnailsReady.then(done)
     })
 
     // const names = $$('p.file-name')
-    const previews = $$('img.file-preview')
+    const previews = await $$('img.file-preview')
 
     // Names should all be listed before previews--indicates that previews were generated asynchronously.
-    /* Nevermind this, chooseFile() doesn't accept multiple files so they are added one by one and the thumbnails
+    /* Nevermind this, setValue() doesn't accept multiple files so they are added one by one and the thumbnails
      * have finished generating by the time we add the next.
     const nys = names.map((el) => el.getLocation('y'))
     const pys = previews.map((el) => el.getLocation('y'))
@@ -84,8 +85,21 @@ describe('ThumbnailGenerator', () => {
 
     expect(previews).to.have.lengthOf(3) // ex. the invalid image
     for (const p of previews) {
-      expect(p.getAttribute('src')).to.match(/^blob:/)
-      expect(p.getElementSize('width')).to.equal(200)
+      expect(await p.getAttribute('src')).to.match(/^blob:/)
+      // Doesn't appear to work in Chrome 67 on Android 6.0
+      if (capabilities.platformName !== 'Android') {
+        expect(await getWidth(p)).to.equal(200)
+      }
     }
   })
 })
+
+async function getWidth (ref) {
+  try {
+    return await ref.getSize('width')
+  } catch (err) {
+    return browser.execute(function (el) {
+      return el.getBoundingClientRect().width
+    }, ref)
+  }
+}

+ 1 - 0
test/endtoend/transloadit/main.js

@@ -17,6 +17,7 @@ function initUppyTransloadit (transloaditKey) {
       inline: true
     })
     .use(Transloadit, {
+      service: 'https://api2-ap-southeast-1.transloadit.com',
       params: {
         auth: { key: transloaditKey },
         steps: {

+ 17 - 20
test/endtoend/transloadit/test.js

@@ -1,45 +1,42 @@
 /* global browser, expect, capabilities, $ */
 const path = require('path')
 const fs = require('fs')
-const { selectFakeFile, supportsChooseFile } = require('../utils')
+const { selectFakeFile, supportsChooseFile, ensureInputVisible } = require('../utils')
 
 const testURL = 'http://localhost:4567/transloadit'
 
-function unhideTheInput () {
-  var input = document.querySelector('#uppy-transloadit .uppy-Dashboard-input')
-  input.removeAttribute('hidden')
-  input.removeAttribute('aria-hidden')
-  input.removeAttribute('tabindex')
-}
-
 function setTransloaditKeyAndInit (transloaditKey) {
   window.initUppyTransloadit(transloaditKey)
 }
 
 describe('Transloadit file processing', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should upload a file to Transloadit and crop it', function () {
+  it('should upload a file to Transloadit and crop it', async function () {
     const transloaditKey = process.env.TRANSLOADIT_KEY
     if (transloaditKey === undefined) {
       console.log('skipping Transloadit integration test')
       return this.skip()
     }
-    browser.execute(setTransloaditKeyAndInit, transloaditKey)
 
-    const inputPath = '#uppy-transloadit .uppy-Dashboard-input'
-    const resultPath = '#uppy-result'
+    const wrapper = await $('#uppy-transloadit')
+    await wrapper.waitForExist()
+
+    await browser.execute(setTransloaditKeyAndInit, transloaditKey)
+
+    const input = await $('#uppy-transloadit .uppy-Dashboard-input')
+    const result = await $('#uppy-result')
 
-    $(inputPath).waitForExist()
+    await input.waitForExist()
+    await browser.execute(ensureInputVisible, '#uppy-transloadit .uppy-Dashboard-input')
 
     if (supportsChooseFile(capabilities)) {
-      browser.execute(unhideTheInput)
-      browser.chooseFile(inputPath, path.join(__dirname, '../../resources/image.jpg'))
+      await input.setValue(path.join(__dirname, '../../resources/image.jpg'))
     } else {
       const img = path.join(__dirname, '../../resources/image.jpg')
-      browser.execute(
+      await browser.execute(
         selectFakeFile,
         'uppyTransloadit',
         path.basename(img), // name
@@ -48,8 +45,8 @@ describe('Transloadit file processing', () => {
       )
       // browser.execute(selectFakeFile, 'uppyTransloadit')
     }
-    $(resultPath).waitForExist(25000)
-    const text = browser.getText(resultPath)
+    await result.waitForExist(25000)
+    const text = await result.getText()
     expect(text).to.be.equal('ok')
   })
 })

+ 4 - 1
test/endtoend/tus-dashboard/main.js

@@ -4,6 +4,9 @@ const Uppy = require('@uppy/core')
 const Dashboard = require('@uppy/dashboard')
 const Tus = require('@uppy/tus')
 
+const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
+const endpoint = isOnTravis ? 'http://companion.test:1080' : 'http://localhost:1080'
+
 const uppyDashboard = Uppy({
   id: 'uppyDashboard',
   debug: true
@@ -14,4 +17,4 @@ uppyDashboard
     target: '#uppyDashboard',
     inline: true
   })
-  .use(Tus, { endpoint: 'https://master.tus.io/files/' })
+  .use(Tus, { endpoint: `${endpoint}/files/` })

+ 4 - 1
test/endtoend/tus-drag-drop/main.js

@@ -5,6 +5,9 @@ const DragDrop = require('@uppy/drag-drop')
 const Tus = require('@uppy/tus')
 const ProgressBar = require('@uppy/progress-bar')
 
+const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
+const endpoint = isOnTravis ? 'http://companion.test:1080' : 'http://localhost:1080'
+
 // Initialise Uppy with Drag & Drop
 const uppyDragDrop = Uppy({
   id: 'uppyDragDrop',
@@ -17,4 +20,4 @@ uppyDragDrop
     target: '#uppyDragDrop'
   })
   .use(ProgressBar, { target: '#uppyDragDrop-progress' })
-  .use(Tus, { endpoint: 'https://master.tus.io/files/' })
+  .use(Tus, { endpoint: `${endpoint}/files/` })

+ 15 - 9
test/endtoend/tus-drag-drop/test.js

@@ -1,22 +1,28 @@
 /* global browser, expect  */
 const path = require('path')
-const { selectFakeFile, supportsChooseFile } = require('../utils')
+const { selectFakeFile, supportsChooseFile, ensureInputVisible } = require('../utils')
 
 const testURL = 'http://localhost:4567/tus-drag-drop'
 
-describe('File upload with DragDrop + Tus', () => {
-  beforeEach(() => {
-    browser.url(testURL)
+describe('File upload with DragDrop + Tus', function () {
+  this.retries(2)
+
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should upload a file with Tus and set progressbar to 100%', () => {
+  it('should upload a file with Tus and set progressbar to 100%', async () => {
+    await browser.execute(ensureInputVisible, '#uppyDragDrop .uppy-DragDrop-input')
+
     if (supportsChooseFile()) {
-      browser.chooseFile('#uppyDragDrop .uppy-DragDrop-input', path.join(__dirname, '../../resources/image.jpg'))
+      const input = await browser.$('#uppyDragDrop .uppy-DragDrop-input')
+      await input.setValue(path.join(__dirname, '../../resources/image.jpg'))
     } else {
-      browser.execute(selectFakeFile, 'uppyDragDrop')
+      await browser.execute(selectFakeFile, 'uppyDragDrop')
     }
-    browser.pause(3000)
-    const html = browser.getHTML('#uppyDragDrop-progress .uppy-ProgressBar-percentage', false)
+    await browser.pause(3000)
+    const percent = await browser.$('#uppyDragDrop-progress .uppy-ProgressBar-percentage')
+    const html = await percent.getHTML(false)
     expect(parseInt(html)).to.be.equal(100)
   })
 })

+ 3 - 1
test/endtoend/typescript/main.ts

@@ -12,7 +12,9 @@ import {
   Form
 } from 'uppy'
 
-const TUS_ENDPOINT = 'https://master.tus.io/files/'
+// @ts-ignore
+const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
+const TUS_ENDPOINT = `http://${isOnTravis ? 'companion.test' : 'localhost'}:1080/files/`
 
 const uppy = Core({
   debug: true,

+ 10 - 7
test/endtoend/typescript/test.js

@@ -1,18 +1,21 @@
 /* global browser, expect  */
 describe('Project compiled with Uppy\'s TypeScript typings', () => {
-  it('Should have correct imports (thus not crash)', () => {
-    browser.url('http://localhost:4567/typescript')
+  it('Should have correct imports (thus not crash)', async () => {
+    await browser.url('http://localhost:4567/typescript')
 
-    browser.waitForExist('.uppy-Root')
-    browser.click('#pick-files')
+    const root = await browser.$('.uppy-Root')
+    const trigger = await browser.$('#pick-files')
+    await root.waitForExist()
+    await trigger.click()
 
-    const typeofUppy = browser.execute(function () {
+    const typeofUppy = await browser.execute(function () {
       return typeof window.uppy
     })
     // It was initialized correctly
-    expect(typeofUppy.value).to.equal('object')
+    expect(typeofUppy).to.equal('object')
 
     // The dashboard is shown
-    expect(browser.isVisible(`.uppy-Dashboard`)).to.equal(true)
+    const dashboard = await browser.$('.uppy-Dashboard')
+    expect(await dashboard.isDisplayed()).to.equal(true)
   })
 })

+ 16 - 16
test/endtoend/url-plugin/main.js

@@ -5,20 +5,20 @@ const Dashboard = require('@uppy/dashboard')
 const Url = require('@uppy/url')
 const Tus = require('@uppy/tus')
 
-function initUrlPlugin (companionUrl) {
-  Uppy({
-    id: 'uppyProvider',
-    debug: true
-  })
-    .use(Dashboard, {
-      target: '#uppyDashboard',
-      inline: true
-    })
-    .use(Url, {
-      target: Dashboard,
-      companionUrl: companionUrl
-    })
-    .use(Tus, { endpoint: 'https://master.tus.io/files/' })
-}
+const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
+const companionUrl = isOnTravis ? 'http://companion.test:3030' : 'http://localhost:3030'
+const endpoint = isOnTravis ? 'http://companion.test:1080' : 'http://localhost:1080'
 
-window.initUrlPlugin = initUrlPlugin
+window.uppy = Uppy({
+  id: 'uppyProvider',
+  debug: true
+})
+  .use(Dashboard, {
+    target: '#uppyDashboard',
+    inline: true
+  })
+  .use(Url, {
+    target: Dashboard,
+    companionUrl: companionUrl
+  })
+  .use(Tus, { endpoint: `${endpoint}/files/` })

+ 17 - 15
test/endtoend/url-plugin/test.js

@@ -1,24 +1,26 @@
 /* global browser  */
 describe('File upload with URL plugin', () => {
-  it('should import  and upload a file completely with Url Plugin', () => {
-    browser.url('http://localhost:4567/url-plugin')
-
-    const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
-    const companionUrl = isOnTravis ? 'http://companion.test:3030' : 'http://localhost:3030'
-    browser.execute(function (companionUrl) {
-      window.initUrlPlugin(companionUrl)
-    }, companionUrl)
+  it('should import  and upload a file completely with Url Plugin', async () => {
+    await browser.url('http://localhost:4567/url-plugin')
 
     // select url plugin
-    browser.click(`.uppy-DashboardTab-btn[aria-controls=uppy-DashboardContent-panel--Url]`)
+    const urlButton = await browser.$('.uppy-DashboardTab-btn[aria-controls=uppy-DashboardContent-panel--Url]')
+    await urlButton.waitForDisplayed(10000)
+
+    await urlButton.click()
+    await browser.pause(500)
     // import set url value
-    browser.waitForVisible('input.uppy-Url-input', 3000)
-    browser.setValue('input.uppy-Url-input', 'https://github.com/transloadit/uppy/raw/master/assets/palette.png')
-    browser.click('button.uppy-Url-importButton')
+    const urlInput = await browser.$('input.uppy-Url-input')
+    await urlInput.waitForDisplayed(3000)
+    await urlInput.setValue('https://github.com/transloadit/uppy/raw/master/assets/palette.png')
+    const importButton = await browser.$('button.uppy-Url-importButton')
+    await importButton.click()
 
     // do the upload
-    browser.waitForVisible('.uppy-u-reset.uppy-c-btn.uppy-c-btn-primary.uppy-StatusBar-actionBtn--upload', 10000)
-    browser.click('.uppy-u-reset.uppy-c-btn.uppy-c-btn-primary.uppy-StatusBar-actionBtn--upload')
-    browser.waitForExist('.uppy-StatusBar.is-complete', 20000)
+    const uploadButton = await browser.$('.uppy-u-reset.uppy-c-btn.uppy-c-btn-primary.uppy-StatusBar-actionBtn--upload')
+    await uploadButton.waitForDisplayed(10000)
+    await uploadButton.click()
+    const completeStatusBar = await browser.$('.uppy-StatusBar.is-complete')
+    await completeStatusBar.waitForExist(20000)
   })
 })

+ 80 - 3
test/endtoend/utils.js

@@ -2,6 +2,7 @@
 /* global window, capabilities */
 const path = require('path')
 const { spawn } = require('child_process')
+const { promisify } = require('util')
 
 // This function must be valid ES5, because it is run in the browser
 // and IE10/IE11 do not support new syntax features
@@ -41,7 +42,18 @@ function selectFakeFile (uppyID, name, type, b64) {
   })
 }
 
+function ensureInputVisible (selector) {
+  var input = document.querySelector(selector)
+  input.style = 'width: auto; height: auto; opacity: 1; z-index: 199'
+  input.removeAttribute('hidden')
+  input.removeAttribute('aria-hidden')
+  input.removeAttribute('tabindex')
+}
+
 function supportsChooseFile () {
+  // no remote file uploads right now...
+  if (process.env.CI) return false
+
   // Webdriver for Safari and Edge doesn’t support .chooseFile
   return capabilities.browserName !== 'Safari' &&
          capabilities.browserName !== 'MicrosoftEdge' &&
@@ -58,7 +70,8 @@ class CompanionService {
       path.join(__dirname, '../../packages/@uppy/companion/lib/standalone/start-server')
     ], {
       stdio: 'pipe',
-      env: Object.assign({}, process.env, {
+      env: {
+        ...process.env,
         COMPANION_DATADIR: path.join(__dirname, '../../output'),
         COMPANION_DOMAIN: 'localhost:3030',
         COMPANION_PROTOCOL: 'http',
@@ -68,7 +81,7 @@ class CompanionService {
         COMPANION_DROPBOX_SECRET: process.env.TEST_COMPANION_DROPBOX_SECRET,
         COMPANION_GOOGLE_KEY: process.env.TEST_COMPANION_GOOGLE_KEY,
         COMPANION_GOOGLE_SECRET: process.env.TEST_COMPANION_GOOGLE_SECRET
-      })
+      }
     })
     return new Promise((resolve, reject) => {
       this.companion.on('error', reject)
@@ -93,8 +106,72 @@ class CompanionService {
   }
 }
 
+const express = require('express')
+class StaticServerService {
+  constructor ({ folders, staticServerPort = 4567 }) {
+    this.folders = folders
+    this.port = staticServerPort
+  }
+
+  async onPrepare () {
+    if (!this.folders) return
+
+    this.app = express()
+
+    for (const desc of this.folders) {
+      this.app.use(desc.mount, express.static(desc.path))
+    }
+
+    const listen = promisify(this.app.listen.bind(this.app))
+
+    this.server = await listen(this.port)
+  }
+
+  async onComplete () {
+    if (this.server) {
+      const close = promisify(this.server.close.bind(this.server))
+      await close()
+    }
+    this.app = null
+  }
+}
+
+const tus = require('tus-node-server')
+const os = require('os')
+const rimraf = promisify(require('rimraf'))
+const { randomBytes } = require('crypto')
+class TusService {
+  constructor ({ tusServerPort = 1080 }) {
+    this.port = tusServerPort
+    this.path = path.join(os.tmpdir(), `uppy-e2e-tus-node-server-${randomBytes(6).toString('hex')}`)
+  }
+
+  async onPrepare () {
+    this.tusServer = new tus.Server()
+    this.tusServer.datastore = new tus.FileStore({
+      path: '/files',
+      directory: this.path
+    })
+
+    const listen = promisify(this.tusServer.listen.bind(this.tusServer))
+    this.server = await listen({ host: '0.0.0.0', port: this.port })
+  }
+
+  async onComplete () {
+    if (this.server) {
+      const close = promisify(this.server.close.bind(this.server))
+      await close()
+    }
+    await rimraf(this.path)
+    this.tusServer = null
+  }
+}
+
 module.exports = {
   selectFakeFile,
+  ensureInputVisible,
   supportsChooseFile,
-  CompanionService
+  CompanionService,
+  StaticServerService,
+  TusService
 }

+ 17 - 14
test/endtoend/wdio.base.conf.js

@@ -1,5 +1,6 @@
 const glob = require('glob').sync
 const path = require('path')
+const { CompanionService, StaticServerService, TusService } = require('./utils')
 
 const suites = {}
 glob('test/endtoend/*/test.js').forEach((file) => {
@@ -22,8 +23,6 @@ exports.config = {
 
   // Patterns to exclude.
   exclude: [
-    'test/endtoend/url-plugin/*',
-    'test/endtoend/transloadit/*'
   ],
 
   // Suites allows you to do `wdio config.js --suite $name` to run a subset of tests.
@@ -86,18 +85,22 @@ exports.config = {
   // Services take over a specific job you don't want to take care of. They enhance
   // your test setup with almost no effort. Unlike plugins, they don't add new
   // commands. Instead, they hook themselves up into the test process.
-  services: ['static-server'],
-
-  staticServerFolders: [
-    { mount: '/i18n-drag-drop', path: './test/endtoend/i18n-drag-drop/dist' },
-    { mount: '/tus-drag-drop', path: './test/endtoend/tus-drag-drop/dist' },
-    { mount: '/xhr-limit', path: './test/endtoend/xhr-limit/dist' },
-    { mount: '/providers', path: './test/endtoend/providers/dist' },
-    { mount: '/thumbnails', path: './test/endtoend/thumbnails/dist' },
-    { mount: '/transloadit', path: './test/endtoend/transloadit/dist' },
-    { mount: '/typescript', path: './test/endtoend/typescript/dist' },
-    { mount: '/url-plugin', path: './test/endtoend/url-plugin/dist' },
-    { mount: '/create-react-app', path: './test/endtoend/create-react-app/build' }
+  services: [
+    [CompanionService],
+    [StaticServerService, {
+      folders: [
+        { mount: '/i18n-drag-drop', path: './test/endtoend/i18n-drag-drop/dist' },
+        { mount: '/tus-drag-drop', path: './test/endtoend/tus-drag-drop/dist' },
+        { mount: '/xhr-limit', path: './test/endtoend/xhr-limit/dist' },
+        { mount: '/providers', path: './test/endtoend/providers/dist' },
+        { mount: '/thumbnails', path: './test/endtoend/thumbnails/dist' },
+        { mount: '/transloadit', path: './test/endtoend/transloadit/dist' },
+        { mount: '/typescript', path: './test/endtoend/typescript/dist' },
+        { mount: '/url-plugin', path: './test/endtoend/url-plugin/dist' },
+        { mount: '/create-react-app', path: './test/endtoend/create-react-app/build' }
+      ]
+    }],
+    [TusService]
   ],
 
   // Framework you want to run your specs with.

+ 4 - 9
test/endtoend/wdio.local.conf.js

@@ -1,5 +1,4 @@
 const base = require('./wdio.base.conf')
-const { CompanionService } = require('./utils')
 
 // Use "npm run test:endtoend:local -- -b chrome" to test in chrome
 // "npm run test:endtoend:local -- -b firefox -b chrome" to test in FF and chrome
@@ -17,7 +16,9 @@ if (capabilities.length === 0) {
   capabilities.push({ browserName: 'firefox' })
 }
 
-exports.config = Object.assign(base.config, {
+exports.config = {
+  ...base.config,
+
   capabilities,
 
   // If you only want to run your tests until a specific amount of tests have failed use
@@ -28,12 +29,6 @@ exports.config = Object.assign(base.config, {
   // with "/", then the base url gets prepended.
   baseUrl: 'http://localhost',
 
-  // Test runner services
-  // Services take over a specific job you don't want to take care of. They enhance
-  // your test setup with almost no effort. Unlike plugins, they don't add new
-  // commands. Instead, they hook themselves up into the test process.
-  services: ['static-server', new CompanionService()],
-
   // Options to be passed to Mocha.
   // See the full list at http://mochajs.org/
   mochaOpts: {
@@ -41,4 +36,4 @@ exports.config = Object.assign(base.config, {
     reporter: 'dot',
     timeout: 60000
   }
-})
+}

+ 21 - 6
test/endtoend/wdio.remote.conf.js

@@ -1,5 +1,4 @@
 const base = require('./wdio.base.conf')
-const { CompanionService } = require('./utils')
 
 function createCapability (capability) {
   return {
@@ -10,10 +9,16 @@ function createCapability (capability) {
   }
 }
 
-exports.config = Object.assign(base.config, {
+exports.config = {
+  ...base.config,
+
+  logLevel: 'warn',
+
   capabilities: [
-    { browserName: 'firefox', version: '40.0', platform: 'Linux' },
-    { browserName: 'firefox', version: '61.0', platform: 'Windows 10' },
+    // Previous ESR
+    { browserName: 'firefox', version: '52.0', platform: 'Windows 7' },
+    // Current ESR
+    { browserName: 'firefox', version: '62.0', platform: 'Windows 10' },
     { browserName: 'internet explorer', version: '10.0', platform: 'Windows 8' },
     { browserName: 'internet explorer', version: '11.0', platform: 'Windows 10' },
     { browserName: 'chrome', version: '70.0', platform: 'Windows 10' },
@@ -24,6 +29,12 @@ exports.config = Object.assign(base.config, {
     { browserName: 'chrome', platformName: 'Android', platformVersion: '6.0', deviceOrientation: 'portrait', deviceName: 'Android Emulator' }
   ].map(createCapability),
 
+  // Patterns to exclude.
+  exclude: [
+    'test/endtoend/url-plugin/*',
+    'test/endtoend/transloadit/*'
+  ],
+
   // If you only want to run your tests until a specific amount of tests have failed use
   // bail (default is 0 - don't bail, run all tests).
   bail: 3,
@@ -36,7 +47,11 @@ exports.config = Object.assign(base.config, {
   // Services take over a specific job you don't want to take care of. They enhance
   // your test setup with almost no effort. Unlike plugins, they don't add new
   // commands. Instead, they hook themselves up into the test process.
-  services: ['static-server', 'sauce', new CompanionService()],
+  services: [
+    ...base.config.services,
+    'sauce'
+  ],
+  sauceConnect: true,
   user: process.env.SAUCE_USERNAME,
   key: process.env.SAUCE_ACCESS_KEY
-})
+}

+ 2 - 2
test/endtoend/xhr-limit/main.js

@@ -2,7 +2,7 @@ require('es6-promise/auto')
 require('whatwg-fetch')
 
 const Uppy = require('@uppy/core')
-const DragDrop = require('@uppy/drag-drop')
+const FileInput = require('@uppy/file-input')
 const XHRUpload = require('@uppy/xhr-upload')
 
 function startXHRLimitTest (endpoint) {
@@ -11,7 +11,7 @@ function startXHRLimitTest (endpoint) {
     debug: true,
     autoProceed: false
   })
-    .use(DragDrop, { target: '#uppyXhrLimit' })
+    .use(FileInput, { target: '#uppyXhrLimit', pretty: false })
     .use(XHRUpload, { endpoint, limit: 2 })
 
   uppy.uploadsStarted = 0

+ 19 - 21
test/endtoend/xhr-limit/test.js

@@ -2,6 +2,7 @@
 const http = require('http')
 const tempWrite = require('temp-write')
 const { Writable } = require('stream')
+const { supportsChooseFile } = require('../utils')
 
 const devNull = () => Writable({
   write (chunk, enc, cb) {
@@ -11,13 +12,6 @@ const devNull = () => Writable({
 
 const testURL = 'http://localhost:4567/xhr-limit'
 
-function browserSupportsChooseFile (capabilities) {
-  // Webdriver for Safari and Edge doesn’t support .chooseFile
-  return capabilities.browserName !== 'safari' &&
-         capabilities.browserName !== 'MicrosoftEdge' &&
-         capabilities.platformName !== 'Android'
-}
-
 describe.skip('XHRUpload with `limit`', () => {
   let server = null
   before(() => {
@@ -28,7 +22,9 @@ describe.skip('XHRUpload with `limit`', () => {
       })
       req.pipe(devNull())
       req.on('end', () => {
-        res.end('{"status":"ok"}')
+        setTimeout(() => {
+          res.end('{"status":"ok"}')
+        }, 3000)
       })
     }).listen()
   })
@@ -37,11 +33,11 @@ describe.skip('XHRUpload with `limit`', () => {
     server = null
   })
 
-  beforeEach(() => {
-    browser.url(testURL)
+  beforeEach(async () => {
+    await browser.url(testURL)
   })
 
-  it('should start counting progress for all files', () => {
+  it('should start counting progress for all files', async () => {
     const files = [
       makeFile(1000),
       makeFile(1000),
@@ -56,16 +52,17 @@ describe.skip('XHRUpload with `limit`', () => {
     ]
 
     const endpoint = `http://localhost:${server.address().port}`
-    browser.execute((endpoint) => {
+    await browser.execute((endpoint) => {
       window.startXHRLimitTest(endpoint)
     }, endpoint)
 
-    if (browserSupportsChooseFile(capabilities)) {
-      files.forEach((file) => {
-        browser.chooseFile('#uppyXhrLimit .uppy-DragDrop-input', file.path)
-      })
+    if (supportsChooseFile(capabilities)) {
+      const input = await browser.$('#uppyXhrLimit .uppy-FileInput-input')
+      for (const file of files) {
+        await input.setValue(file.path)
+      }
     } else {
-      browser.execute((files) => {
+      await browser.execute((files) => {
         files.forEach((data, i) => {
           window.uppyXhrLimit.addFile({
             source: 'test',
@@ -77,14 +74,15 @@ describe.skip('XHRUpload with `limit`', () => {
       }, files.map((file) => file.content.toString('hex')))
     }
 
-    browser.execute(() => {
+    await browser.execute(() => {
       window.uppyXhrLimit.upload()
     })
-    browser.pause(5000)
-    const status = browser.execute(() => ({
+    await browser.pause(5000)
+    const status = await browser.execute(() => ({
       started: window.uppyXhrLimit.uploadsStarted,
       complete: window.uppyXhrLimit.uploadsComplete
-    })).value
+    }))
+    console.log(status)
     expect(status.started).to.be.equal(files.length)
     expect(status.complete).to.be.equal(2)
   })

Some files were not shown because too many files changed in this diff