Merge pull request #970 from transloadit/feature/thumbnail-test

Add thumbnail generation integration test
This commit is contained in:
Renée Kooi 2018-10-01 15:44:36 +02:00 committed by GitHub
commit fc3dfcbcca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1545 additions and 385 deletions

View file

@ -1,6 +1,28 @@
language: node_js
node_js:
- 8.11.4
before_install:
- nvm install-latest-npm
install:
- npm install
- npm run bootstrap -- --no-ci
script:
- npm run build
- npm run test
- 'if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then npm run test:acceptance; fi'
- npm run uploadcdn
cache:
apt: true
directories:
- ~/.npm
services:
- docker
addons:
apt:
sources:
@ -12,19 +34,7 @@ addons:
secure: nAMJ/d1fm9urTYsQ+1uqj6Jjf71J8rzwYBSZbTDAeUEZzAdvGc0a9H3PYWM4pnUDPo5s1c9MMetXi2XNdUbXgMKHbEnePZ2mJamqFtXMmpG8pgFmMqj+btMd7Yybt070tRsn4Vy0uBSi2H/en7F3j+grABJV+SAXqWkSB7CU1fZaN/u0DpoGBNj1ZNwkYCIhpLueYJTPRWBOodMAarXuFv5+7KFOKuZM3tF/JjsMNSSaDgTkz13BZnbX6vNPxGJJNJcyJGSaXrVW8hh1Zmvnk/XdiLy+vt7Wz1wz3A9ebiFDuydo5AAkxrLFsCJ5nGEqLg3bkr6NaTRpbM84ZT3i1FQMTdKP6OHHqwAeBscB6BkyhZhzvsFtl2YRBNK9mA3OtOYvBmTkFkNqvrPQlfu7cFtyG5+AUfSCiTTgS/vWIwoqSVAXaOEqN8Fp54ecUdkzCTttl3gXteZzNLRYvyQcFpoJb6E+dS8qAW0OFOteiwKVuPCh3nGUzBP13bRo1i9UAX7ZCTlpjinkxE8ryzbToo6ZcVQMBAkKhaw/x8GzOtfm5rgYMeQzGEoBJNfr7qqfs7JMxAIEMYjrTL9PXVOp/R8F3FdsqbV70jSyfsxMSMkwSWFRmVslG8+Djy8P3LnckGy1FEbMHnH8GZHZg+hbBzN8Be1/1fV0oRRAr939WRc=
access_key:
secure: OY3oWwiJghfty9wSPVvlhirvFGxPHDdIRuVkzAv6j7C/hj2BWYAP/UHrwdQ9XiYisHi/B5mGeyRVlrAf0MNGrG84rTDUbTWZbmktfuxl7A+Y6c0czk+s4SdhOiANG5b3tFl5wKq8h7uhrWH5/jWoKQ2Fz1VDCqxTvvZQbo41jSBhi7TBia626hxEePzdaiuw6HhGFZtfaoVs/FX30ylz8WDNrBjwCynjxsT52BaQrVvgEhuyzlOpI69YkZBPOq4fc3KiZ2YR43gLTx8K+sYCE9yJxdg1xT/UAawEhmedU83nyBZVo4rr7+03AixIxtI28MUCfBMlcsGwBxcKEKY/IWcp9UkPCq6+zALQoncV478tP21eYvlmxSFhYCrv+WEQlN+BcNjr4OJlmmFDbCVaF7r9qLeQPImU0+9iJU3OjrW7lpfLxORpGDEr2Nx6awKkIJCxNyK9weefeNo6Fz3V1kkyZ/7yWFeniJnRUCbahrB2XgzxIE+W307s1Qs4fm6JK7hVLTtG4fBzjChmAyGIzu744ws9WqmjvkC9D7OfnuXqanv/VcBFqPiudInerv7NL8FketUC+fxe/7XJfcxdaDGBjk8Kq7zXDohGRGymUXEoMDNJsKkMMlaKzdf7tgqdhsRJoH9NCVqrDXuG5al0UtrDP5RS7qfoxUunJmNFhlg=
cache:
apt: true
directories:
- ~/.npm
before_install:
- nvm install-latest-npm
services:
- docker
script:
- npm run build
- npm run test
- '{ if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then npm run test:acceptance; fi } || true'
- npm run uploadcdn
env:
global:
- CXX=g++-4.8
@ -50,6 +60,7 @@ env:
- secure: V6qVB6vHAuSt1YPgzYpknLglnxbYJM5bsjAjQi78zZQSqrrWCMBgp5Q+Sq7Ad8nycgnPl8W8VpMnUIBqZcK4ciCW+vJBtZ7fBJLIEGMEk8+c8az8JePFcBRiaEicZPvZFuIHPteaAy6jK1GRVpjSjJi3NYEMpcDUs2aTM2bIpX0ks2WjUqTXiK8EvIaK2LTOgSBvyGUOiHwwTkom+PyD50t7jP98g+9Pn7GPwtWaUo1K8UpLArwR2fZ/nm0F2DU6ohz7o2t4LATFXuZhbOCj7O9vh+CmBf+/0C7giT3K23LbckDSK8CNTCDC2bsv8zDo5ZZtgdOvdatOD+VlsbAMkmUzzDgQ3410arZ8g1LVQw8eJwu1H+etcAinYf4r+Tr7s3dTBliMX70/IpjZrkHR9uXEi4LelBNYn6TKdLTW3lfVWkiFs/HPu4SoAmu1+sxSvwxVDDLeexQmb2fwp0r2tDKZ3eRfpQXLPACBaORnGW6ki9qXo8PBdaElxPbpzEWzAfT3F6zRjebpow+cdFBQrAga7/LrOrXerZxH2ekRWKgXzuhw7ERwVFrVN4/NlmDJXo+rm4na7n7CxY/QpZcdpthksDO9KYCqmn5dqMqFGislRvRe7PqIti8gC4pSdeUhDKsIh9OEgVNjCczvnA8rMRQ5aNmFx6wspmrBvO7qRLM=
- secure: rVsiFPA9TvH/d2wkP8+1i5QGUuYw0q2BUAUdxyxO9hQcG/nRiHXtQfLbTRZHKwvqf0vyV6J1pJqLlVN4JO/bPhAvk55KAQJWl8UqyaeZiEN9KMcTr3fJuNFlBj4ciYiZ3BWwakblsiaGCjKMRdjki58a9f8XL2rcM8R6ccndjkTMYnBKaopSsAgouI8D5n74wQz6lODUayGOlbwlGLfGtPYplUfSLK4wghC+jgWsNjJySqJhfgYS0JCZc10Qw+FI2BoU4SZ4+P0L0YPIC9zV/cUW4qDT11N/oUgwfjZbPWfM9A/xn/d7sgDH+SpeoGdYler/lvxojj6L2mD/wAh8/lg1E6nL2aKgExE3z+fd2XV8L0osB/sulB7/Exrezg/mVejAx2IkWVHi4VEJmcTV+3WeEvTFOM3fID8dOVf+GUv+hcHdZMxS/hfj3keKCYG1P5ameMJO8FehRqhetNYnr6FTyrK+S+xitaZ/nXrTbHItPS0pZ4XA6CFs5uzMBPeDnk5/D7paPyrE/k2HAc1WmA6g37OyzYIMEV1laBz8IG0qMqg6JJmr09P/Iwrim5Ex2fAssT9Yr1WuOE2gWoF0A3XuVXQHVf4tJT6x/WDKChmbX588a47AvBgkFyoXLRilUYlET2tWnEpVxUovsbJXqvHwTXWMLO9riRjjeInbpvA=
- secure: eq5hOqRBN2R7YO2dYdn5OjZc/zLLYYDZcCpCu/K/8fU4HYWTqxrBntjv8T0sZ5qdlAs3IniEfXxemz9V3zwvxR+vh2bGuYr2Xo7RRa2TIDuw+KUPZogrVxhXHPKfyJqstxy+dee2+pWhGkAP7caiu49eyqlboBMkzgpO/xcdehEWYRY5jPgvnlH+QRZ3GADKs1JEeltHDiZ6rYA7nj5Tyx9UoLgv4Av9UXdC29we7dLFTkVfCHE//7wfZW9+/IbxthA4qMjQOFaBrmagN5yweDg87iPTqNMth7FjzOavdUgQ2TW6d10VDEhLIZh36gLGreViKMDCEWKMQ8f/mv05Ao8+DXyXgxIn56II8lhUp5ukQ27ZWixfEKFx2lynJWRZE0pWwf8ec1+bXLQiBOE181Cl4nUT/TbFWzvV6yA+cMiQKe4y59bC4nhkK3IYgpR5kfCFOT+1tFknQ4hNJNacWwUmaDFMxYJaXEtRUn5jJa7eGRYSCrmnymbnzZ6w3Q3nQGNvNxpbBIXX/pzs0VDVTxSlgN4gA+n2jeCyjgVVrMQ/HoAS4uwm1cx89AttW+TANppg1PqWhhrJYuVEZSnvV8PM6R7rbvlS5tluezQj41YklgjsSopH7//+dbGGDNbrTTLic4J9PJR3yEtlAMdOCi53iT0R0Dt5X2WBv2QT5Eg=
notifications:
slack:
secure: L3iQQE8sZ0ik1Z26gPoNMiIam9EOEwYhraHCY60Jk/wmfH6SW/727yKXpgcb/yayx37rUZplvoO7H8e05ISxTJKSepEeqbBUIBQs48S8hr+FHk0VPtpP4HGxqaITRLm+mI1coPRvfISxzrB8d240oup6muhC9Ws4/LXi6v8miyIOs2zoYmGxd56TrUeON3UYlKt6dMava0V4bugARzrafN/tfyI9ccqbHzQLBspQvBI61DzZ5I2vnWpkjfWgIHz9Fl4VzXHqMXwjuTUEu8ibA12b3dHZiJEAoqeb9Oj9QcLPbstPLhlNTZZaOrfiFtwLctI2rFh37slDpAfk5idv3ycxcoG5rbCxgyg5i6dpQqrqHxnyglgHg2/nZ+YA5okeS7nJJNtU/4S6AFRWOUUWMVVY0VBEV+8w+uurl0PDy80RUY3uyK64qAgQ8U0M81/Ys1oyWyn78TqHcbby7V2Ws5I9Yakrq8D+mdfsWYCio8F6LXHSwJ0mt2FanJtdDvpPk9sAwsXZN0n8xhELt5TiRp3bzVIQ0IPUgF54dTG9/zWRvC1P4TFaFU/2fg73ZEUC5aWJoFMnLSZjbZvp5gwpCVd0MjSBk80nF9dHYcavIgJ0wMGI3BMb8Nn6+T11Gw/ycr7OGU4NMkj7i8vSFgKF74piWZyiNW8orkMN6XZgM+o=

View file

@ -39,15 +39,22 @@ npm run build
# https://github.com/facebook/create-react-app/pull/4626
(cd && npm-auth-to-token -u user -p password -e user@example.com -r "$VERDACCIO_REGISTRY")
git checkout -b endtoend-test-build
# HACK this thing changes all the time for some reason on CI
# so I'll just ignore it…
git checkout -- package-lock.json
# Simulate a publish of everything, to the local registry,
# without changing things in git
# Use --cd-version to skip version prompts
lerna publish --yes \
lerna version prerelease --yes \
--exact \
--force-publish \
--registry="$VERDACCIO_REGISTRY" \
--npm-client=npm \
--no-git-tag-version --no-push \
--canary
--no-push
lerna publish from-git --yes \
--registry="$VERDACCIO_REGISTRY" \
--no-verify-access \
--npm-client=npm
# revert version changes
git checkout -- packages/*/package.json packages/@uppy/*/package.json

View file

@ -11,7 +11,8 @@ __file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
__base="$(basename ${__file} .sh)"
__root="$(cd "$(dirname "${__dir}")" && pwd)"
tests="tus-drag-drop tus-dashboard i18n-drag-drop xhr-limit providers"
# Tests using a simple build setup.
tests="tus-drag-drop tus-dashboard i18n-drag-drop xhr-limit providers thumbnails"
for t in $tests; do
mkdir -p "${__root}/test/endtoend/$t/dist"
@ -22,4 +23,8 @@ for t in $tests; do
-t babelify
done
(cd "${__root}/test/endtoend/create-react-app" && npm install && npm run build > /dev/null)
# Speeecial tests that need custom builds.
pushd "${__root}/test/endtoend/create-react-app"
npm install
npm run build
popd

1541
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,7 @@
"isomorphic-fetch": "2.2.1",
"jest": "^23.5.0",
"json3": "^3.3.2",
"lerna": "^3.0.6",
"lerna": "^3.4.0",
"lint-staged": "^6.1.1",
"minify-stream": "^1.2.0",
"mkdirp": "0.5.1",
@ -126,7 +126,7 @@
"web:update:frontpage:code:sample": "cd website && ./node_modules/.bin/hexo generate && cp -f public/frontpage-code-sample.html ./themes/uppy/layout/partials/frontpage-code-sample.html",
"web": "npm-run-all web:clean web:build",
"uploadcdn": "bin/upload-to-cdn.sh",
"prepare": "lerna bootstrap --hoist",
"bootstrap": "lerna bootstrap --hoist",
"contributors": "githubcontrib --owner transloadit --repo uppy --cols 6 $([ \"${GITHUB_TOKEN:-}\" == \"\" ] && echo \"\" || echo \"--authToken ${GITHUB_TOKEN}\") --showlogin true --sortOrder desc",
"contributors:save": "replace-x -m '<!--contributors-->[\\s\\S]+<!--/contributors-->' \"<!--contributors-->\n## Contributors\n\n$(npm run --silent contributors)\n<!--/contributors-->\" README.md"
},

View file

@ -20,7 +20,10 @@ module.exports = class ThumbnailGenerator extends Plugin {
thumbnailWidth: 200
}
this.opts = Object.assign({}, defaultOptions, opts)
this.opts = {
...defaultOptions,
...opts
}
this.addToQueue = this.addToQueue.bind(this)
this.onRestored = this.onRestored.bind(this)
@ -35,18 +38,18 @@ module.exports = class ThumbnailGenerator extends Plugin {
*/
createThumbnail (file, targetWidth) {
const originalUrl = URL.createObjectURL(file.data)
const onload = new Promise((resolve, reject) => {
const image = new Image()
image.src = originalUrl
image.onload = () => {
image.addEventListener('load', () => {
URL.revokeObjectURL(originalUrl)
resolve(image)
}
image.onerror = () => {
// The onerror event is totally useless unfortunately, as far as I know
})
image.addEventListener('error', (event) => {
URL.revokeObjectURL(originalUrl)
reject(new Error('Could not create thumbnail'))
}
reject(event.error || new Error('Could not create thumbnail'))
})
})
return onload
@ -154,9 +157,7 @@ module.exports = class ThumbnailGenerator extends Plugin {
* Set the preview URL for a file.
*/
setPreviewURL (fileID, preview) {
this.uppy.setFileState(fileID, {
preview: preview
})
this.uppy.setFileState(fileID, { preview })
}
addToQueue (item) {
@ -175,6 +176,8 @@ module.exports = class ThumbnailGenerator extends Plugin {
.then(() => this.processQueue())
} else {
this.queueProcessing = false
this.uppy.log('[ThumbnailGenerator] Emptied thumbnail queue')
this.uppy.emit('thumbnail:all-generated')
}
}
@ -183,9 +186,13 @@ module.exports = class ThumbnailGenerator extends Plugin {
return this.createThumbnail(file, this.opts.thumbnailWidth)
.then(preview => {
this.setPreviewURL(file.id, preview)
this.uppy.log(`[ThumbnailGenerator] Generated thumbnail for ${file.id}`)
this.uppy.emit('thumbnail:generated', this.uppy.getFile(file.id), preview)
})
.catch(err => {
console.warn(err.stack || err.message)
this.uppy.log(`[ThumbnailGenerator] Failed thumbnail for ${file.id}`)
this.uppy.log(err, 'warning')
this.uppy.emit('thumbnail:error', this.uppy.getFile(file.id), err)
})
}
return Promise.resolve()

View file

@ -4,25 +4,34 @@ const emitter = require('namespace-emitter')
const delay = duration => new Promise(resolve => setTimeout(resolve, duration))
function MockCore () {
const core = emitter()
const files = {}
core.mockFile = (id, f) => { files[id] = f }
core.getFile = (id) => files[id]
core.log = () => null
return core
}
describe('uploader/ThumbnailGeneratorPlugin', () => {
it('should initialise successfully', () => {
const plugin = new ThumbnailGeneratorPlugin(null, {})
const plugin = new ThumbnailGeneratorPlugin(new MockCore(), {})
expect(plugin instanceof Plugin).toEqual(true)
})
it('should accept the thumbnailWidth option and override the default', () => {
const plugin1 = new ThumbnailGeneratorPlugin(null) // eslint-disable-line no-new
const plugin1 = new ThumbnailGeneratorPlugin(new MockCore()) // eslint-disable-line no-new
expect(plugin1.opts.thumbnailWidth).toEqual(200)
const plugin2 = new ThumbnailGeneratorPlugin(null, { thumbnailWidth: 100 }) // eslint-disable-line no-new
const plugin2 = new ThumbnailGeneratorPlugin(new MockCore(), { thumbnailWidth: 100 }) // eslint-disable-line no-new
expect(plugin2.opts.thumbnailWidth).toEqual(100)
})
describe('install', () => {
it('should subscribe to uppy file-added event', () => {
const core = {
const core = Object.assign(new MockCore(), {
on: jest.fn()
}
})
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.addToQueue = jest.fn()
@ -35,10 +44,10 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
describe('uninstall', () => {
it('should unsubscribe from uppy file-added event', () => {
const core = {
const core = Object.assign(new MockCore(), {
on: jest.fn(),
off: jest.fn()
}
})
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.addToQueue = jest.fn()
@ -55,7 +64,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
describe('queue', () => {
it('should add a new file to the queue and start processing the queue when queueProcessing is false', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.processQueue = jest.fn()
@ -73,7 +82,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
it('should process items in the queue one by one', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.requestThumbnail = jest.fn(() => delay(100))
@ -106,9 +115,47 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
})
describe('events', () => {
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.createThumbnail = jest.fn((file) => delay(100).then(() => `blob:${file.id}.png`))
plugin.setPreviewURL = jest.fn()
function add (file) {
core.mockFile(file.id, file)
plugin.addToQueue(file)
}
it('should emit thumbnail:generated when a thumbnail was generated', () => new Promise((resolve, reject) => {
const expected = ['bar', 'bar2', 'bar3']
core.on('thumbnail:generated', (file, preview) => {
try {
expect(file.id).toBe(expected.shift())
expect(preview).toBe(`blob:${file.id}.png`)
} catch (err) {
return reject(err)
}
if (expected.length === 0) resolve()
})
add({ id: 'bar', type: 'image/png' })
add({ id: 'bar2', type: 'image/png' })
add({ id: 'bar3', type: 'image/png' })
}))
it('should emit thumbnail:all-generated when all thumbnails were generated', () => {
return new Promise((resolve) => {
core.on('thumbnail:all-generated', resolve)
add({ id: 'bar4', type: 'image/png' })
add({ id: 'bar5', type: 'image/png' })
}).then(() => {
expect(plugin.queue).toHaveLength(0)
})
})
})
describe('requestThumbnail', () => {
it('should call createThumbnail if it is a supported filetype', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.createThumbnail = jest
@ -127,7 +174,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
it('should not call createThumbnail if it is not a supported filetype', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.createThumbnail = jest
@ -142,7 +189,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
it('should not call createThumbnail if the file is remote', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.createThumbnail = jest
@ -157,7 +204,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
it('should call setPreviewURL with the thumbnail image', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
plugin.createThumbnail = jest
@ -199,7 +246,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
describe('getProportionalHeight', () => {
it('should calculate the resized height based on the specified width of the image whilst keeping aspect ratio', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
expect(
plugin.getProportionalHeight({ width: 200, height: 100 }, 50)
@ -215,7 +262,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
describe('canvasToBlob', () => {
it('should use canvas.toBlob if available', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
const canvas = {
toBlob: jest.fn()
@ -242,7 +289,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
xit('should scale down the image by the specified number of steps', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
const image = {
width: 1000,
@ -299,7 +346,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
describe('resizeImage', () => {
it('should return a canvas with the resized image on it', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
const image = {
width: 1000,
@ -324,7 +371,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
})
it('should upsize if original image is smaller than target size', () => {
const core = {}
const core = new MockCore()
const plugin = new ThumbnailGeneratorPlugin(core)
const image = {
width: 100,
@ -356,7 +403,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
b: { preview: 'blob:def' },
c: { preview: 'blob:xyz', isRestored: true }
}
const core = Object.assign(emitter(), {
const core = Object.assign(new MockCore(), {
getState () {
return { files }
},
@ -380,7 +427,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
const files = {
a: { preview: 'http://abc', isRestored: true }
}
const core = Object.assign(emitter(), {
const core = Object.assign(new MockCore(), {
getState () {
return { files }
},

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Uppy test page</title>
</head>
<body>
<style>
main {
max-width: 700px;
margin: auto;
}
</style>
<main>
<h2>Thumbnails</h2>
<div>
<div id="uppyThumbnails"></div>
</div>
</main>
<link href="uppy.min.css" rel="stylesheet">
<script src="bundle.js"></script>
</body>
</html>

View file

@ -0,0 +1,39 @@
/* eslint-disable */
require('es6-promise/auto')
require('whatwg-fetch')
const Uppy = require('@uppy/core')
const ThumbnailGenerator = require('@uppy/thumbnail-generator')
const FileInput = require('@uppy/file-input')
const uppyThumbnails = Uppy({
id: 'uppyThumbnails',
autoProceed: false,
debug: true
})
uppyThumbnails.use(ThumbnailGenerator, {})
uppyThumbnails.use(FileInput, { target: '#uppyThumbnails', pretty: false })
uppyThumbnails.on('file-added', (file) => {
const el = document.createElement('p')
el.className = 'file-name'
el.textContent = file.name
document.body.appendChild(el)
})
// Dump errors to the screen so saucelabs shows them in screenshots.
uppyThumbnails.on('thumbnail:error', (file, err) => {
const el = document.createElement('pre')
el.style = 'font: 14pt monospace; background: red; color: white'
el.textContent = `Error: ${err.stack}`
document.body.appendChild(el)
})
uppyThumbnails.on('thumbnail:generated', (file, preview) => {
const img = new Image()
img.src = file.preview
img.className = 'file-preview'
img.style.display = 'block'
document.body.appendChild(img)
})

View file

@ -0,0 +1,90 @@
/* global browser, expect, $, $$ */
const path = require('path')
const fs = require('fs')
const { selectFakeFile, supportsChooseFile } = require('../utils')
const testURL = 'http://localhost:4567/thumbnails'
const images = [
path.join(__dirname, '../../resources/image.jpg'),
path.join(__dirname, '../../resources/baboon.png'),
path.join(__dirname, '../../resources/kodim23.png'),
path.join(__dirname, '../../resources/invalid.png')
]
const notImages = [
{ type: 'text/javascript', file: __filename }
]
describe('ThumbnailGenerator', () => {
beforeEach(() => {
browser.url(testURL)
})
it('should generate thumbnails for images', function () {
// FIXME why isn't the selectFakeFile alternative below working?
if (!supportsChooseFile()) {
return this.skip()
}
$('#uppyThumbnails .uppy-FileInput-input').waitForExist()
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 notImages) {
browser.chooseFile('#uppyThumbnails .uppy-FileInput-input', file)
}
} else {
for (const img of images) {
browser.execute(
selectFakeFile,
'uppyThumbnails',
path.basename(img), // name
`image/${path.extname(img).slice(1)}`, // type
fs.readFileSync(img, 'base64') // b64
)
}
for (const { type, file } of notImages) {
browser.execute(
selectFakeFile,
'uppyThumbnails',
path.basename(file), // name
type, // type
fs.readFileSync(file, 'base64') // b64
)
}
}
browser.executeAsync(/* must be valid ES5 for IE */ function (done) {
window.thumbnailsReady.then(done)
})
// const names = $$('p.file-name')
const previews = $$('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
* 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'))
for (const ny of nys) {
for (const py of pys) {
expect(ny).to.be.below(py, 'names should be listed before previews')
}
}
*/
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)
}
})
})

View file

@ -2,14 +2,18 @@
const path = require('path')
const { spawn } = require('child_process')
function selectFakeFile (uppyID) {
// This function must be valid ES5, because it is run in the browser
// and IE10/IE11 do not support new syntax features
function selectFakeFile (uppyID, name, type, b64) {
if (!b64) b64 = 'PHN2ZyB2aWV3Qm94PSIwIDAgMTIwIDEyMCI+CiAgPGNpcmNsZSBjeD0iNjAiIGN5PSI2MCIgcj0iNTAiLz4KPC9zdmc+Cg=='
var blob = new Blob(
['data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTIwIDEyMCI+CiAgPGNpcmNsZSBjeD0iNjAiIGN5PSI2MCIgcj0iNTAiLz4KPC9zdmc+Cg=='],
{ type: 'image/svg+xml' }
['data:image/svg+xml;base64,' + b64],
{ type: type || 'image/svg+xml' }
)
window[uppyID].addFile({
source: 'test',
name: 'test-file',
name: name || 'test-file',
type: blob.type,
data: blob
})

View file

@ -92,6 +92,7 @@ exports.config = {
{ 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: '/create-react-app', path: './test/endtoend/create-react-app/build' }
],

View file

@ -1,12 +1,24 @@
const base = require('./wdio.base.conf')
const { CompanionService } = require('./utils')
// Use "npm run test:acceptance:local -- -b chrome" to test in chrome
// "npm run test:acceptance:local -- -b firefox -b chrome" to test in FF and chrome
let prevIsDashB = false
const capabilities = []
process.argv.forEach((arg) => {
if (prevIsDashB) {
capabilities.push({ browserName: arg })
}
prevIsDashB = arg === '-b'
})
// default to testing in firefox
if (capabilities.length === 0) {
capabilities.push({ browserName: 'firefox' })
}
exports.config = Object.assign(base.config, {
capabilities: [
{ browserName: 'firefox' }
// { browserName: 'MicrosoftEdge', version: '14.14393', platform: 'Windows 10' },
// { browserName: 'safari', version: '11.0', platform: 'macOS 10.12' }
],
capabilities,
// 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).

View file

@ -2,18 +2,24 @@ const base = require('./wdio.base.conf')
const { CompanionService } = require('./utils')
function createCapability (capability) {
return Object.assign({
return {
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
build: process.env.TRAVIS_BUILD_NUMBER
}, capability)
build: process.env.TRAVIS_BUILD_NUMBER,
extendedDebugging: true,
...capability
}
}
exports.config = Object.assign(base.config, {
capabilities: [
{ browserName: 'firefox', version: '38.0', platform: 'Linux' },
{ browserName: 'firefox', version: '61.0', platform: 'Windows 10' },
{ browserName: 'internet explorer', version: '10.0', platform: 'Windows 7' },
{ browserName: 'internet explorer', version: '11.0', platform: 'Windows 7' },
{ browserName: 'chrome', version: '50.0', platform: 'Windows 7' },
{ browserName: 'MicrosoftEdge', version: '14.14393', platform: 'Windows 10' },
{ browserName: 'chrome', version: '69.0', platform: 'Windows 10' },
{ browserName: 'MicrosoftEdge', version: '14', platform: 'Windows 10' },
{ browserName: 'MicrosoftEdge', version: '17', platform: 'Windows 10' },
// { browserName: 'safari', version: '11.0', platform: 'macOS 10.12' },
{ browserName: 'safari', version: '10.0', platformName: 'iOS', platformVersion: '10.0', deviceOrientation: 'portrait', deviceName: 'iPhone 6 Simulator', appiumVersion: '1.7.1' },
{ browserName: 'chrome', platformName: 'Android', platformVersion: '6.0', deviceOrientation: 'portrait', deviceName: 'Android Emulator', appiumVersion: '1.7.1' }

BIN
test/resources/baboon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 KiB

BIN
test/resources/invalid.png Normal file

Binary file not shown.

BIN
test/resources/kodim23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 KiB

View file

@ -14,8 +14,11 @@ After you have successfully forked the repo, clone and install the project:
git clone git@github.com:YOUR_USERNAME/uppy.git
cd uppy
npm install
npm run bootstrap
```
We use lerna to manage the many plugin packages Uppy has. You should always do `npm run bootstrap` after an `npm install` to make sure lerna has installed the dependencies of each package and that the `package-lock.json` in the repository root is up to date.
Our websites examples section is also our playground, please read the [Local Previews](#Local-Previews) section to get up and running.
## Tests