diff --git a/.travis.yml b/.travis.yml
index 36e41544b0a54af7ff0ac476ca6426ee3057cedc..7e3b4f23a6f05a9b7ff3c3d246f57ce0df836a38 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -58,11 +58,6 @@ deploy:
     condition: $TRAVIS_EVENT_TYPE != cron
   skip_cleanup: true
   script: npm run deploy -- -x -e $TRAVIS_BRANCH -r https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git
-- provider: script
-  on:
-    all_branches: true
-    condition: $TRAVIS_EVENT_TYPE != cron
-  script: npm run prune -- https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git
 - provider: script
   on:
     branch: develop
diff --git a/package.json b/package.json
index b6fafe6186b3be993f34224e2c762e97f9d41be2..f83f826fe736b0b758daa025e018a9fda572dfd2 100644
--- a/package.json
+++ b/package.json
@@ -104,13 +104,13 @@
     "redux-throttle": "0.1.1",
     "rimraf": "^2.6.1",
     "scratch-audio": "0.1.0-prerelease.20190114210212",
-    "scratch-blocks": "0.1.0-prerelease.1549376808",
-    "scratch-l10n": "3.1.20190206143031",
+    "scratch-blocks": "0.1.0-prerelease.1549643185",
+    "scratch-l10n": "3.1.20190207224638",
     "scratch-paint": "0.2.0-prerelease.20190114205252",
-    "scratch-render": "0.1.0-prerelease.20190128154859",
+    "scratch-render": "0.1.0-prerelease.20190208165820",
     "scratch-storage": "1.2.2",
     "scratch-svg-renderer": "0.2.0-prerelease.20190125192231",
-    "scratch-vm": "0.2.0-prerelease.20190205221329",
+    "scratch-vm": "0.2.0-prerelease.20190207224121",
     "selenium-webdriver": "3.6.0",
     "startaudiocontext": "1.2.1",
     "style-loader": "^0.23.0",
diff --git a/src/components/action-menu/action-menu.jsx b/src/components/action-menu/action-menu.jsx
index 36cf5d4449f7ddd1815cb5388d3784915a709a3e..f9e50f3ff667e02ff78cc5d345e761993e9b8709 100644
--- a/src/components/action-menu/action-menu.jsx
+++ b/src/components/action-menu/action-menu.jsx
@@ -142,7 +142,7 @@ class ActionMenu extends React.Component {
                 <div className={styles.moreButtonsOuter}>
                     <div className={styles.moreButtons}>
                         {(moreButtons || []).map(({img, title, onClick: handleClick,
-                            fileAccept, fileChange, fileInput}, keyId) => {
+                            fileAccept, fileChange, fileInput, fileMultiple}, keyId) => {
                             const isComingSoon = !handleClick;
                             const hasFileInput = fileInput;
                             const tooltipId = `${this.mainTooltipId}-${title}`;
@@ -166,6 +166,7 @@ class ActionMenu extends React.Component {
                                             <input
                                                 accept={fileAccept}
                                                 className={styles.fileInput}
+                                                multiple={fileMultiple}
                                                 ref={fileInput}
                                                 type="file"
                                                 onChange={fileChange}
@@ -198,7 +199,8 @@ ActionMenu.propTypes = {
         onClick: PropTypes.func, // Optional, "coming soon" if no callback provided
         fileAccept: PropTypes.string, // Optional, only for file upload
         fileChange: PropTypes.func, // Optional, only for file upload
-        fileInput: PropTypes.func // Optional, only for file upload
+        fileInput: PropTypes.func, // Optional, only for file upload
+        fileMultiple: PropTypes.bool // Optional, only for file upload
     })),
     onClick: PropTypes.func.isRequired,
     title: PropTypes.node.isRequired,
diff --git a/src/components/loader/loader.jsx b/src/components/loader/loader.jsx
index 6f4b9658a9ab90a2617b3b3f140010781a2c1ba9..c51621fc41ad8d52596284ace87bff81be1af8e2 100644
--- a/src/components/loader/loader.jsx
+++ b/src/components/loader/loader.jsx
@@ -120,15 +120,13 @@ class LoaderComponent extends React.Component {
     constructor (props) {
         super(props);
         this.state = {
-            messageNumber: 0
+            messageNumber: this.chooseRandomMessage()
         };
     }
     componentDidMount () {
-        this.chooseRandomMessage();
-
         // Start an interval to choose a new message every 5 seconds
         this.intervalId = setInterval(() => {
-            this.chooseRandomMessage();
+            this.setState({messageNumber: this.chooseRandomMessage()});
         }, 5000);
     }
     componentWillUnmount () {
@@ -145,7 +143,7 @@ class LoaderComponent extends React.Component {
                 break;
             }
         }
-        this.setState({messageNumber});
+        return messageNumber;
     }
     render () {
         return (
diff --git a/src/components/sprite-selector/sprite-selector.jsx b/src/components/sprite-selector/sprite-selector.jsx
index 115eaee955f25d6ccba82b86c7f8206cc0ee3719..d834f43b03bd44a23ce4fe6326543670439dbe27 100644
--- a/src/components/sprite-selector/sprite-selector.jsx
+++ b/src/components/sprite-selector/sprite-selector.jsx
@@ -122,7 +122,8 @@ const SpriteSelectorComponent = function (props) {
                         onClick: onFileUploadClick,
                         fileAccept: '.svg, .png, .jpg, .jpeg, .sprite2, .sprite3',
                         fileChange: onSpriteUpload,
-                        fileInput: spriteFileInput
+                        fileInput: spriteFileInput,
+                        fileMultiple: true
                     }, {
                         title: intl.formatMessage(messages.addSpriteFromSurprise),
                         img: surpriseIcon,
diff --git a/src/components/stage-selector/stage-selector.jsx b/src/components/stage-selector/stage-selector.jsx
index 64a1948a82670324221c5743f0657e9215d89677..db89a67c5a961a5419d7bf5cb850bd75ae504813 100644
--- a/src/components/stage-selector/stage-selector.jsx
+++ b/src/components/stage-selector/stage-selector.jsx
@@ -104,7 +104,8 @@ const StageSelector = props => {
                         onClick: onBackdropFileUploadClick,
                         fileAccept: '.svg, .png, .jpg, .jpeg', // Bitmap coming soon
                         fileChange: onBackdropFileUpload,
-                        fileInput: fileInputRef
+                        fileInput: fileInputRef,
+                        fileMultiple: true
                     }, {
                         title: intl.formatMessage(messages.addBackdropFromSurprise),
                         img: surpriseIcon,
diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx
index 83b27d4c3252cccd83c1f1567d73d486c4790b5d..3817c4f3c9fda0b4111194eaa95298bd5abe4285 100644
--- a/src/containers/costume-tab.jsx
+++ b/src/containers/costume-tab.jsx
@@ -13,7 +13,7 @@ import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import DragConstants from '../lib/drag-constants';
 import {emptyCostume} from '../lib/empty-assets';
 import sharedMessages from '../lib/shared-messages';
-import download from '../lib/download-url';
+import downloadBlob from '../lib/download-blob';
 
 import {
     closeCameraCapture,
@@ -154,7 +154,8 @@ class CostumeTab extends React.Component {
     }
     handleExportCostume (costumeIndex) {
         const item = this.props.vm.editingTarget.sprite.costumes[costumeIndex];
-        download(`${item.name}.${item.asset.dataFormat}`, item.asset.encodeDataURI());
+        const blob = new Blob([item.asset.data], {type: item.asset.assetType.contentType});
+        downloadBlob(`${item.name}.${item.asset.dataFormat}`, blob);
     }
     handleNewCostume (costume, fromCostumeLibrary) {
         if (fromCostumeLibrary) {
@@ -292,7 +293,8 @@ class CostumeTab extends React.Component {
                         onClick: this.handleFileUploadClick,
                         fileAccept: '.svg, .png, .jpg, .jpeg',
                         fileChange: this.handleCostumeUpload,
-                        fileInput: this.setFileInput
+                        fileInput: this.setFileInput,
+                        fileMultiple: true
                     },
                     {
                         title: intl.formatMessage(messages.addSurpriseCostumeMsg),
diff --git a/src/containers/monitor.jsx b/src/containers/monitor.jsx
index 039fa060d616d2df878f75eff8140fcbdcb51ecb..b35a04bb9c2056b74f276d213ac45fa42a2a343f 100644
--- a/src/containers/monitor.jsx
+++ b/src/containers/monitor.jsx
@@ -8,7 +8,7 @@ import MonitorComponent, {monitorModes} from '../components/monitor/monitor.jsx'
 import {addMonitorRect, getInitialPosition, resizeMonitorRect, removeMonitorRect} from '../reducers/monitor-layout';
 import {getVariable, setVariableValue} from '../lib/variable-utils';
 import importCSV from '../lib/import-csv';
-import download from '../lib/download-url';
+import downloadBlob from '../lib/download-blob';
 
 import {connect} from 'react-redux';
 import {Map} from 'immutable';
@@ -156,7 +156,8 @@ class Monitor extends React.Component {
         const {vm, targetId, id: variableId} = this.props;
         const variable = getVariable(vm, targetId, variableId);
         const text = variable.value.join('\r\n');
-        download(`${variable.name}.txt`, `data:text/plain;charset=utf-8,${encodeURIComponent(text)}`);
+        const blob = new Blob([text], {type: 'text/plain;charset=utf-8'});
+        downloadBlob(`${variable.name}.txt`, blob);
     }
     render () {
         const monitorProps = monitorAdapter(this.props);
diff --git a/src/containers/sb3-downloader.jsx b/src/containers/sb3-downloader.jsx
index 47df7bacaebe341abc571d3c9ca7e22e2d024e34..536934a270cfdbaace177fca5e4046a47b38f8ff 100644
--- a/src/containers/sb3-downloader.jsx
+++ b/src/containers/sb3-downloader.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import {connect} from 'react-redux';
 import {projectTitleInitialState} from '../reducers/project-title';
-
+import downloadBlob from '../lib/download-blob';
 /**
  * Project saver component passes a downloadProject function to its child.
  * It expects this child to be a function with the signature
@@ -26,25 +26,11 @@ class SB3Downloader extends React.Component {
         ]);
     }
     downloadProject () {
-        const downloadLink = document.createElement('a');
-        document.body.appendChild(downloadLink);
-
         this.props.saveProjectSb3().then(content => {
             if (this.props.onSaveFinished) {
                 this.props.onSaveFinished();
             }
-            // Use special ms version if available to get it working on Edge.
-            if (navigator.msSaveOrOpenBlob) {
-                navigator.msSaveOrOpenBlob(content, this.props.projectFilename);
-                return;
-            }
-
-            const url = window.URL.createObjectURL(content);
-            downloadLink.href = url;
-            downloadLink.download = this.props.projectFilename;
-            downloadLink.click();
-            window.URL.revokeObjectURL(url);
-            document.body.removeChild(downloadLink);
+            downloadBlob(this.props.projectFilename, content);
         });
     }
     render () {
diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx
index 40e08dfb737321de558b278c011c4a2e9e980142..9db3289d96d9eeb61b30a6d5fbe60244b5ec61a1 100644
--- a/src/containers/sound-tab.jsx
+++ b/src/containers/sound-tab.jsx
@@ -21,7 +21,7 @@ import soundLibraryContent from '../lib/libraries/sounds.json';
 import {handleFileUpload, soundUpload} from '../lib/file-uploader.js';
 import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import DragConstants from '../lib/drag-constants';
-import download from '../lib/download-url';
+import downloadBlob from '../lib/download-blob';
 
 import {connect} from 'react-redux';
 
@@ -90,8 +90,8 @@ class SoundTab extends React.Component {
 
     handleExportSound (soundIndex) {
         const item = this.props.vm.editingTarget.sprite.sounds[soundIndex];
-        const soundDataURL = item.asset.encodeDataURI();
-        download(`${item.name}.${item.asset.dataFormat}`, soundDataURL);
+        const blob = new Blob([item.asset.data], {type: item.asset.assetType.contentType});
+        downloadBlob(`${item.name}.${item.asset.dataFormat}`, blob);
     }
 
     handleDuplicateSound (soundIndex) {
@@ -223,7 +223,8 @@ class SoundTab extends React.Component {
                     onClick: this.handleFileUploadClick,
                     fileAccept: '.wav, .mp3',
                     fileChange: this.handleSoundUpload,
-                    fileInput: this.setFileInput
+                    fileInput: this.setFileInput,
+                    fileMultiple: true
                 }, {
                     title: intl.formatMessage(messages.surpriseSound),
                     img: surpriseIcon,
diff --git a/src/containers/target-pane.jsx b/src/containers/target-pane.jsx
index 16017423c903b881176569fc9255d13daea02d77..25382b9054c43de3e007be12fae4202c954b8860 100644
--- a/src/containers/target-pane.jsx
+++ b/src/containers/target-pane.jsx
@@ -21,6 +21,7 @@ import {emptySprite} from '../lib/empty-assets';
 import {highlightTarget} from '../reducers/targets';
 import {fetchSprite, fetchCode} from '../lib/backpack-api';
 import randomizeSpritePosition from '../lib/randomize-sprite-position';
+import downloadBlob from '../lib/download-blob';
 
 class TargetPane extends React.Component {
     constructor (props) {
@@ -94,20 +95,7 @@ class TargetPane extends React.Component {
         document.body.appendChild(saveLink);
 
         this.props.vm.exportSprite(id).then(content => {
-            const filename = `${spriteName}.sprite3`;
-
-            // Use special ms version if available to get it working on Edge.
-            if (navigator.msSaveOrOpenBlob) {
-                navigator.msSaveOrOpenBlob(content, filename);
-                return;
-            }
-
-            const url = window.URL.createObjectURL(content);
-            saveLink.href = url;
-            saveLink.download = filename;
-            saveLink.click();
-            window.URL.revokeObjectURL(url);
-            document.body.removeChild(saveLink);
+            downloadBlob(`${spriteName}.sprite3`, content);
         });
     }
     handleSelectSprite (id) {
diff --git a/src/lib/blocks.js b/src/lib/blocks.js
index eadf6d6fff6ec22e75f019178aef53e262bf4b9a..9ca3c6d7ed7b3a33cb83d65992f56f7e9f1cecfe 100644
--- a/src/lib/blocks.js
+++ b/src/lib/blocks.js
@@ -245,8 +245,15 @@ export default function (vm) {
                     // The block was in the flyout so look up future block info there.
                     lookupBlocks = vm.runtime.flyoutBlocks;
                 }
+                const sort = function (options) {
+                    options.sort((str1, str2) => str1.localeCompare(str2, [], {
+                        sensitivity: 'base',
+                        numeric: true
+                    }));
+                };
                 // Get all the stage variables (no lists) so we can add them to menu when the stage is selected.
                 const stageVariableOptions = vm.runtime.getTargetForStage().getAllVariableNamesInScopeByType('');
+                sort(stageVariableOptions);
                 const stageVariableMenuItems = stageVariableOptions.map(variable => [variable, variable]);
                 if (sensingOfBlock.inputs.OBJECT.shadow !== sensingOfBlock.inputs.OBJECT.block) {
                     // There's a block dropped on top of the menu. It'd be nice to evaluate it and
@@ -265,6 +272,7 @@ export default function (vm) {
                 // The target should exist, but there are ways for it not to (e.g. #4203).
                 if (target) {
                     spriteVariableOptions = target.getAllVariableNamesInScopeByType('', true);
+                    sort(spriteVariableOptions);
                 }
                 const spriteVariableMenuItems = spriteVariableOptions.map(variable => [variable, variable]);
                 return spriteOptions.concat(spriteVariableMenuItems);
diff --git a/src/lib/default-project/index.js b/src/lib/default-project/index.js
index df1154b6e8a7b34534c5370790164edcb375a408..92f01c908c1b3dfd05a71636fc71cd0eddfb3181 100644
--- a/src/lib/default-project/index.js
+++ b/src/lib/default-project/index.js
@@ -1,4 +1,3 @@
-import {TextEncoder} from 'text-encoding';
 import projectData from './project-data';
 
 /* eslint-disable import/no-unresolved */
@@ -9,8 +8,16 @@ import costume1 from '!raw-loader!./09dc888b0b7df19f70d81588ae73420e.svg';
 import costume2 from '!raw-loader!./3696356a03a8d938318876a593572843.svg';
 /* eslint-enable import/no-unresolved */
 
-const encoder = new TextEncoder();
 const defaultProject = translator => {
+    let _TextEncoder;
+    if (typeof TextEncoder === 'undefined') {
+        _TextEncoder = require('text-encoding').TextEncoder;
+    } else {
+        /* global TextEncoder */
+        _TextEncoder = TextEncoder;
+    }
+    const encoder = new _TextEncoder();
+
     const projectJson = projectData(translator);
     return [{
         id: 0,
diff --git a/src/lib/download-blob.js b/src/lib/download-blob.js
new file mode 100644
index 0000000000000000000000000000000000000000..13d53538c60107d59ce6be9de143ad5d5b5120e7
--- /dev/null
+++ b/src/lib/download-blob.js
@@ -0,0 +1,17 @@
+export default (filename, blob) => {
+    const downloadLink = document.createElement('a');
+    document.body.appendChild(downloadLink);
+
+    // Use special ms version if available to get it working on Edge.
+    if (navigator.msSaveOrOpenBlob) {
+        navigator.msSaveOrOpenBlob(blob, filename);
+        return;
+    }
+
+    const url = window.URL.createObjectURL(blob);
+    downloadLink.href = url;
+    downloadLink.download = filename;
+    downloadLink.click();
+    window.URL.revokeObjectURL(url);
+    document.body.removeChild(downloadLink);
+};
diff --git a/src/lib/download-url.js b/src/lib/download-url.js
deleted file mode 100644
index e01cb1f0890bf103d704c661b0795bce721418bd..0000000000000000000000000000000000000000
--- a/src/lib/download-url.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export default (filename, url) => {
-    const pom = document.createElement('a');
-    pom.setAttribute('href', url);
-    pom.setAttribute('download', filename);
-
-    if (document.createEvent) {
-        const event = document.createEvent('MouseEvents');
-        event.initEvent('click', true, true);
-        pom.dispatchEvent(event);
-    } else {
-        pom.click();
-    }
-};
diff --git a/src/lib/file-uploader.js b/src/lib/file-uploader.js
index 74f3c64a8625c05610c4e0d505484e56fc4a8600..483f31edf61c95a08d6aa38522df9eda52d0aac7 100644
--- a/src/lib/file-uploader.js
+++ b/src/lib/file-uploader.js
@@ -21,22 +21,25 @@ const extractFileName = function (nameExt) {
  * @param {Function} onload The function that handles loading the file
  */
 const handleFileUpload = function (fileInput, onload) {
-    let thisFile = null;
-    const reader = new FileReader();
-    reader.onload = () => {
-        // Reset the file input value now that we have everything we need
-        // so that the user can upload the same sound multiple times if
-        // they choose
-        fileInput.value = null;
-        const fileType = thisFile.type;
-        const fileName = extractFileName(thisFile.name);
-
-        onload(reader.result, fileType, fileName);
+    const readFile = (i, files) => {
+        if (i === files.length) {
+            // Reset the file input value now that we have everything we need
+            // so that the user can upload the same sound multiple times if
+            // they choose
+            fileInput.value = null;
+            return;
+        }
+        const file = files[i];
+        const reader = new FileReader();
+        reader.onload = () => {
+            const fileType = file.type;
+            const fileName = extractFileName(file.name);
+            onload(reader.result, fileType, fileName);
+            readFile(i + 1, files);
+        };
+        reader.readAsArrayBuffer(file);
     };
-    if (fileInput.files) {
-        thisFile = fileInput.files[0];
-        reader.readAsArrayBuffer(thisFile);
-    }
+    readFile(0, fileInput.files);
 };
 
 /**
diff --git a/test/fixtures/movie.wav b/test/fixtures/movie.wav
new file mode 100644
index 0000000000000000000000000000000000000000..79c10d2146204fa108038bc4a67c853ec81a4707
Binary files /dev/null and b/test/fixtures/movie.wav differ
diff --git a/test/fixtures/sneaker.wav b/test/fixtures/sneaker.wav
new file mode 100644
index 0000000000000000000000000000000000000000..01c4a17597b5e747368094e61c2e8d0d3414cc2b
Binary files /dev/null and b/test/fixtures/sneaker.wav differ
diff --git a/test/integration/backdrops.test.js b/test/integration/backdrops.test.js
index 09d398bd14a894322306151a4e56baecab1154a5..80a4a5650352a0710c2590cb0e31b4c5ae262e72 100644
--- a/test/integration/backdrops.test.js
+++ b/test/integration/backdrops.test.js
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
 const {
     clickText,
     clickXpath,
+    findByText,
     findByXpath,
     getDriver,
     getLogs,
@@ -48,4 +49,30 @@ describe('Working with backdrops', () => {
         const logs = await getLogs();
         await expect(logs).toEqual([]);
     });
+
+    test.only('Adding multiple backdrops at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
+            path.resolve(__dirname, '../fixtures/100-100.svg')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+
+        const buttonXpath = '//button[@aria-label="Choose a Backdrop"]';
+        const fileXpath = `${buttonXpath}/following-sibling::div//input[@type="file"]`;
+
+        const el = await findByXpath(buttonXpath);
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath(fileXpath);
+        await input.sendKeys(files.join('\n'));
+
+        await clickXpath('//span[text()="Stage"]');
+        await findByText('gh-3582-png', scope.costumesTab);
+        await findByText('100-100', scope.costumesTab);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
 });
diff --git a/test/integration/costumes.test.js b/test/integration/costumes.test.js
index 282ae3574bbc026d5b6e2b6f551b270c84a53a83..6095faf3b40ff7ee090e2baf67948bdffc7a1f9e 100644
--- a/test/integration/costumes.test.js
+++ b/test/integration/costumes.test.js
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
 const {
     clickText,
     clickXpath,
+    findByText,
     findByXpath,
     getDriver,
     getLogs,
@@ -175,4 +176,25 @@ describe('Working with costumes', () => {
         const logs = await getLogs();
         await expect(logs).toEqual([]);
     });
+
+    test.only('Adding multiple costumes at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
+            path.resolve(__dirname, '../fixtures/100-100.svg')
+        ];
+        await loadUri(uri);
+        await clickText('Costumes');
+        const el = await findByXpath('//button[@aria-label="Choose a Costume"]');
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath('//input[@type="file"]');
+        await input.sendKeys(files.join('\n'));
+
+        await findByText('gh-3582-png', scope.costumesTab);
+        await findByText('100-100', scope.costumesTab);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
 });
diff --git a/test/integration/sounds.test.js b/test/integration/sounds.test.js
index 09bfdc5f1d8300a8be2554b69b8818a94f60fa5b..4dc9fc55cc075149e96292460d4d108eb1c50b24 100644
--- a/test/integration/sounds.test.js
+++ b/test/integration/sounds.test.js
@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
 const {
     clickText,
     clickXpath,
+    findByText,
     findByXpath,
     getDriver,
     getLogs,
@@ -110,4 +111,26 @@ describe('Working with sounds', () => {
         const logs = await getLogs();
         await expect(logs).toEqual([]);
     });
+
+    test.only('Adding multiple sounds at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/movie.wav'),
+            path.resolve(__dirname, '../fixtures/sneaker.wav')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+        await clickText('Sounds');
+        const el = await findByXpath('//button[@aria-label="Choose a Sound"]');
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath('//input[@type="file"]');
+        await input.sendKeys(files.join('\n'));
+
+        await findByText('movie', scope.soundsTab);
+        await findByText('sneaker', scope.soundsTab);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
 });
diff --git a/test/integration/sprites.test.js b/test/integration/sprites.test.js
index 76cfae1213c3ce62e27891ff73847166a1ea7709..d70e75d2ccd74a5d02b600b698fd6d35d262f792 100644
--- a/test/integration/sprites.test.js
+++ b/test/integration/sprites.test.js
@@ -150,4 +150,25 @@ describe('Working with sprites', () => {
         await expect(logs).toEqual([]);
     });
 
+    test.only('Adding multiple sprites at the same time', async () => {
+        const files = [
+            path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
+            path.resolve(__dirname, '../fixtures/100-100.svg')
+        ];
+        await loadUri(uri);
+        await clickXpath('//button[@title="Try It"]');
+        const el = await findByXpath('//button[@aria-label="Choose a Sprite"]');
+        await driver.actions().mouseMove(el)
+            .perform();
+        await driver.sleep(500); // Wait for thermometer menu to come up
+        const input = await findByXpath('//input[@type="file"]');
+        await input.sendKeys(files.join('\n'));
+
+        await findByText('gh-3582-png', scope.spriteTile);
+        await findByText('100-100', scope.spriteTile);
+
+        const logs = await getLogs();
+        await expect(logs).toEqual([]);
+    });
+
 });