diff --git a/package.json b/package.json
index 645ee73e444b378561925b99898cd7313d5d7f29..3ed372dc9300a8f3793aeea43004b970897fe56a 100644
--- a/package.json
+++ b/package.json
@@ -42,11 +42,11 @@
     "copy-webpack-plugin": "^4.0.1",
     "css-loader": "^0.28.7",
     "enzyme": "^3.1.0",
-    "enzyme-adapter-react-16": "1.0.4",
+    "enzyme-adapter-react-16": "1.1.0",
     "eslint": "^4.7.1",
     "eslint-config-scratch": "^5.0.0",
     "eslint-plugin-import": "^2.7.0",
-    "eslint-plugin-react": "^7.2.1",
+    "eslint-plugin-react": "^7.5.1",
     "file-loader": "1.1.5",
     "get-float-time-domain-data": "0.1.0",
     "gh-pages": "github:rschamp/gh-pages#publish-branch-to-subfolder",
@@ -67,9 +67,9 @@
     "prop-types": "^15.5.10",
     "raf": "^3.4.0",
     "raw-loader": "0.5.1",
-    "react": "16.1.0",
+    "react": "16.1.1",
     "react-contextmenu": "2.8.0",
-    "react-dom": "16.1.0",
+    "react-dom": "16.1.1",
     "react-draggable": "3.0.3",
     "react-intl": "2.4.0",
     "react-intl-redux": "0.7.0",
@@ -77,7 +77,7 @@
     "react-redux": "5.0.6",
     "react-responsive": "3.0.0",
     "react-style-proptype": "3.1.0",
-    "react-tabs": "2.1.0",
+    "react-tabs": "2.1.1",
     "react-test-renderer": "16.1.1",
     "redux": "3.7.0",
     "redux-mock-store": "^1.2.3",
diff --git a/src/components/asset-panel/selector.css b/src/components/asset-panel/selector.css
index 2a4de1a252be6c1f4e70893f462493fc8fd18886..63e6868326617b20c9ae347b20a71f29400c195c 100644
--- a/src/components/asset-panel/selector.css
+++ b/src/components/asset-panel/selector.css
@@ -1,4 +1,5 @@
 @import "../../css/colors.css";
+@import "../../css/units.css";
 
 .wrapper {
     width: 150px;
@@ -51,3 +52,14 @@
     min-height: 5rem;
     margin: 1rem auto;
 }
+
+@media only screen and (max-width: $full-size-paint) {
+    .wrapper {
+        width: 80px;
+    }
+
+    .list-item {
+        width: 4rem;
+        min-height: 4rem;
+    }
+}
diff --git a/src/components/close-button/close-button.jsx b/src/components/close-button/close-button.jsx
index 416adec8e279b7c185468b376e10fb46bf729416..e90bd1d64b892306ecb613d15e6c2d891fc9d576 100644
--- a/src/components/close-button/close-button.jsx
+++ b/src/components/close-button/close-button.jsx
@@ -7,6 +7,7 @@ import closeIcon from './icon--close.svg';
 
 const CloseButton = props => (
     <div
+        aria-label="Close"
         className={classNames(
             styles.closeButton,
             props.className,
@@ -15,6 +16,7 @@ const CloseButton = props => (
                 [styles.large]: props.size === CloseButton.SIZE_LARGE
             }
         )}
+        role="button"
         onClick={props.onClick}
     >
         <img
diff --git a/src/components/icon-button/icon-button.jsx b/src/components/icon-button/icon-button.jsx
index 50d5557e508110531cb045556bb7ff7323eb02fd..c6f9ae3d03ccf48df55b83c7c58295354d3427dd 100644
--- a/src/components/icon-button/icon-button.jsx
+++ b/src/components/icon-button/icon-button.jsx
@@ -11,6 +11,7 @@ const IconButton = ({
 }) => (
     <div
         className={classNames(styles.container, className)}
+        role="button"
         onClick={onClick}
     >
         <img
diff --git a/src/components/language-selector/language-selector.css b/src/components/language-selector/language-selector.css
index 5e1a41aee1da7877f00d45d6f31487f91fdaa78f..a060131a8fc2d2c8aa6afa58629622e3a141320f 100644
--- a/src/components/language-selector/language-selector.css
+++ b/src/components/language-selector/language-selector.css
@@ -22,3 +22,7 @@
     color: #3373cc;
     font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
 }
+
+.language-select:focus {
+    border: 1px solid white;
+}
diff --git a/src/components/sprite-info/sprite-info.css b/src/components/sprite-info/sprite-info.css
index 200aedaf79f13627abf74a4c9378ccb0f60eb300..f018abe8e604bc3652de5431731b18ed42110998 100644
--- a/src/components/sprite-info/sprite-info.css
+++ b/src/components/sprite-info/sprite-info.css
@@ -62,6 +62,11 @@
     border-bottom-left-radius: $form-radius;
 }
 
+.radio-left:focus {
+    border-color: #4c97ff;
+    box-shadow: inset 0 0 0 -2px rgba(0, 0, 0, 0.1);
+}
+
 .radio-right {
     border-bottom: 1px solid $form-border;
     border-top: 1px solid $form-border;
@@ -70,6 +75,11 @@
     border-bottom-right-radius: $form-radius;
 }
 
+.radio-right:focus {
+    border-color: #4c97ff;
+    box-shadow: inset 0 0 0 -2px rgba(0, 0, 0, 0.1);
+}
+
 .icon {
     width: 100%;
     height: 100%;
diff --git a/src/components/sprite-info/sprite-info.jsx b/src/components/sprite-info/sprite-info.jsx
index f9bbb64e32748af1f955db724d8dc113caea8648..9e1c8a4098d2aeae08e55cf9aa1d95ccedb5bbd9 100644
--- a/src/components/sprite-info/sprite-info.jsx
+++ b/src/components/sprite-info/sprite-info.jsx
@@ -54,6 +54,7 @@ class SpriteInfo extends React.Component {
                         <MediaQuery minWidth={layout.fullSizeMinWidth}>
                             <div className={styles.iconWrapper}>
                                 <img
+                                    aria-hidden="true"
                                     className={classNames(styles.xIcon, styles.icon)}
                                     src={xIcon}
                                 />
@@ -76,6 +77,7 @@ class SpriteInfo extends React.Component {
                         <MediaQuery minWidth={layout.fullSizeMinWidth}>
                             <div className={styles.iconWrapper}>
                                 <img
+                                    aria-hidden="true"
                                     className={classNames(styles.yIcon, styles.icon)}
                                     src={yIcon}
                                 />
@@ -116,6 +118,7 @@ class SpriteInfo extends React.Component {
                                 )}
                                 tabIndex="4"
                                 onClick={this.props.onClickVisible}
+                                onKeyPress={this.props.onPressVisible}
                             >
                                 <img
                                     className={styles.icon}
@@ -132,8 +135,9 @@ class SpriteInfo extends React.Component {
                                         [styles.isDisabled]: this.props.disabled
                                     }
                                 )}
-                                tabIndex="4"
+                                tabIndex="5"
                                 onClick={this.props.onClickNotVisible}
+                                onKeyPress={this.props.onPressNotVisible}
                             >
                                 <img
                                     className={styles.icon}
@@ -151,7 +155,7 @@ class SpriteInfo extends React.Component {
                                 small
                                 disabled={this.props.disabled}
                                 label="Direction"
-                                tabIndex="5"
+                                tabIndex="6"
                                 type="text"
                                 value={this.props.disabled ? '' : this.props.direction}
                                 onSubmit={this.props.onChangeDirection}
@@ -200,6 +204,8 @@ SpriteInfo.propTypes = {
     onChangeY: PropTypes.func,
     onClickNotVisible: PropTypes.func,
     onClickVisible: PropTypes.func,
+    onPressNotVisible: PropTypes.func,
+    onPressVisible: PropTypes.func,
     rotationStyle: PropTypes.oneOf(ROTATION_STYLES),
     visible: PropTypes.bool,
     x: PropTypes.oneOfType([
diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index 471dc6cd08643341c290f66227b723ef28dbffb1..f3e46dfaf2bd9f88496cbaed2a29e9ce1ae62061 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -172,6 +172,11 @@ class Blocks extends React.Component {
         this.workspace.reportValue(data.id, data.value);
     }
     onWorkspaceUpdate (data) {
+        // When we change sprites, update the toolbox to have the new sprite's blocks
+        if (this.props.vm.editingTarget) {
+            this.props.updateToolboxState(makeToolboxXML(this.props.vm.editingTarget.id));
+        }
+
         if (this.props.vm.editingTarget && !this.state.workspaceMetrics[this.props.vm.editingTarget.id]) {
             this.onWorkspaceMetricsChange();
         }
@@ -179,6 +184,8 @@ class Blocks extends React.Component {
         // Remove and reattach the workspace listener (but allow flyout events)
         this.workspace.removeChangeListener(this.props.vm.blockListener);
         const dom = this.ScratchBlocks.Xml.textToDom(data.xml);
+        // @todo This line rerenders toolbox, and the change in the toolbox XML also rerenders the toolbox.
+        // We should only rerender the toolbox once. See https://github.com/LLK/scratch-gui/issues/901
         this.ScratchBlocks.Xml.clearWorkspaceAndLoadFromXml(dom, this.workspace);
         this.workspace.addChangeListener(this.props.vm.blockListener);
 
@@ -193,8 +200,8 @@ class Blocks extends React.Component {
     handleExtensionAdded (blocksInfo) {
         this.ScratchBlocks.defineBlocksWithJsonArray(blocksInfo.map(blockInfo => blockInfo.json));
         const dynamicBlocksXML = this.props.vm.runtime.getBlocksXML();
-        const toolboxXML = makeToolboxXML(dynamicBlocksXML);
-        this.props.onExtensionAdded(toolboxXML);
+        const toolboxXML = makeToolboxXML(this.props.vm.editingTarget.id, dynamicBlocksXML);
+        this.props.updateToolboxState(toolboxXML);
     }
     handleCategorySelected (categoryName) {
         this.workspace.toolbox_.setSelectedCategoryByName(categoryName);
@@ -220,7 +227,7 @@ class Blocks extends React.Component {
             vm,
             isVisible,
             onActivateColorPicker,
-            onExtensionAdded,
+            updateToolboxState,
             onRequestCloseExtensionLibrary,
             toolboxXML,
             ...props
@@ -257,7 +264,6 @@ Blocks.propTypes = {
     extensionLibraryVisible: PropTypes.bool,
     isVisible: PropTypes.bool,
     onActivateColorPicker: PropTypes.func,
-    onExtensionAdded: PropTypes.func,
     onRequestCloseExtensionLibrary: PropTypes.func,
     options: PropTypes.shape({
         media: PropTypes.string,
@@ -281,6 +287,7 @@ Blocks.propTypes = {
         comments: PropTypes.bool
     }),
     toolboxXML: PropTypes.string,
+    updateToolboxState: PropTypes.func,
     vm: PropTypes.instanceOf(VM).isRequired
 };
 
@@ -322,11 +329,11 @@ const mapStateToProps = state => ({
 
 const mapDispatchToProps = dispatch => ({
     onActivateColorPicker: callback => dispatch(activateColorPicker(callback)),
-    onExtensionAdded: toolboxXML => {
-        dispatch(updateToolbox(toolboxXML));
-    },
     onRequestCloseExtensionLibrary: () => {
         dispatch(closeExtensionLibrary());
+    },
+    updateToolboxState: toolboxXML => {
+        dispatch(updateToolbox(toolboxXML));
     }
 });
 
diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx
index 1984923d541427b16a82980d1c6bc627f4541413..6143175ddace4a3755d81c743bc8c81192cd23ad 100644
--- a/src/containers/sound-tab.jsx
+++ b/src/containers/sound-tab.jsx
@@ -52,20 +52,18 @@ class SoundTab extends React.Component {
 
     render () {
         const {
-            editingTarget,
-            sprites,
-            stage,
+            vm,
             onNewSoundFromLibraryClick,
             onNewSoundFromRecordingClick
         } = this.props;
 
-        const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage;
-
-        if (!target) {
+        if (!vm.editingTarget) {
             return null;
         }
 
-        const sounds = target.sounds ? target.sounds.map(sound => (
+        const sprite = vm.editingTarget.sprite;
+
+        const sounds = sprite.sounds ? sprite.sounds.map(sound => (
             {
                 url: soundIcon,
                 name: sound.name
@@ -106,7 +104,7 @@ class SoundTab extends React.Component {
                 onDeleteClick={this.handleDeleteSound}
                 onItemClick={this.handleSelectSound}
             >
-                {editingTarget && target.sounds && target.sounds.length > 0 ? (
+                {sprite.sounds && sprite.sounds.length > 0 ? (
                     <SoundEditor soundIndex={this.state.selectedSoundIndex} />
                 ) : null}
                 {this.props.soundRecorderVisible ? (
diff --git a/src/containers/sprite-info.jsx b/src/containers/sprite-info.jsx
index 532fb37e5fdb8c9af94602ef825257b7bb1d64a9..f4b5ca696d2118898bdbd73c87b30173f8acf52d 100644
--- a/src/containers/sprite-info.jsx
+++ b/src/containers/sprite-info.jsx
@@ -10,7 +10,9 @@ class SpriteInfo extends React.Component {
         bindAll(this, [
             'handleChangeRotationStyle',
             'handleClickVisible',
-            'handleClickNotVisible'
+            'handleClickNotVisible',
+            'handlePressVisible',
+            'handlePressNotVisible'
         ]);
     }
     handleChangeRotationStyle (e) {
@@ -24,6 +26,18 @@ class SpriteInfo extends React.Component {
         e.preventDefault();
         this.props.onChangeVisibility(false);
     }
+    handlePressVisible (e) {
+        if (e.key === ' ' || e.key === 'Enter') {
+            e.preventDefault();
+            this.props.onChangeVisibility(true);
+        }
+    }
+    handlePressNotVisible (e) {
+        if (e.key === ' ' || e.key === 'Enter') {
+            e.preventDefault();
+            this.props.onChangeVisibility(false);
+        }
+    }
     render () {
         return (
             <SpriteInfoComponent
@@ -31,6 +45,8 @@ class SpriteInfo extends React.Component {
                 onChangeRotationStyle={this.handleChangeRotationStyle}
                 onClickNotVisible={this.handleClickNotVisible}
                 onClickVisible={this.handleClickVisible}
+                onPressNotVisible={this.handlePressNotVisible}
+                onPressVisible={this.handlePressVisible}
             />
         );
     }
diff --git a/src/css/units.css b/src/css/units.css
index 3de6174a2fe38b65148f7d99a5e459950e37160a..3e7f73f36d327fa55f464c4b49577661f58b4799 100644
--- a/src/css/units.css
+++ b/src/css/units.css
@@ -9,3 +9,7 @@ $stage-menu-height: 2.75rem;
 $library-header-height: 4.375rem;
 
 $form-radius: calc($space / 2);
+
+/* layout contants from `layout-constants.js` */
+$full-size: 1095px;
+$full-size-paint: 1249px;
diff --git a/src/index.jsx b/src/index.jsx
index 6d301f5168501f6b20252a6d0e034f509c5eea77..e55fc0ef4d29ef81ff2e8f970b9e932a6412a967 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -7,6 +7,11 @@ import ProjectLoaderHOC from './lib/project-loader-hoc.jsx';
 
 import styles from './index.css';
 
+if (process.env.NODE_ENV === 'production' && typeof window === 'object') {
+    // Warn before navigating away
+    window.onbeforeunload = () => true;
+}
+
 const App = AppStateHOC(ProjectLoaderHOC(GUI));
 
 const appTarget = document.createElement('div');
diff --git a/src/lib/layout-constants.js b/src/lib/layout-constants.js
index 672c8013f58d477ae767a159a3d2af28784d7139..67c2ae44cc0ecc3c8b979626d4ba51e85a176b63 100644
--- a/src/lib/layout-constants.js
+++ b/src/lib/layout-constants.js
@@ -3,5 +3,6 @@ export default {
     fullStageHeight: 360,
     smallerStageWidth: 480 * 0.85,
     smallerStageHeight: 360 * 0.85,
-    fullSizeMinWidth: 1096
+    fullSizeMinWidth: 1096,
+    fullSizePaintMinWidth: 1250
 };
diff --git a/src/lib/make-toolbox-xml.js b/src/lib/make-toolbox-xml.js
index 315e1388c51656e87be18924c559fb506322dc6c..608cf92b3c307efd54e34ae6aa2d26a19e747f6c 100644
--- a/src/lib/make-toolbox-xml.js
+++ b/src/lib/make-toolbox-xml.js
@@ -2,7 +2,8 @@ const categorySeparator = '<sep gap="36"/>';
 
 const blockSeparator = '<sep gap="36"/>'; // At default scale, about 28px
 
-const motion = `
+const motion = function (targetId) {
+    return `
     <category name="Motion" colour="#4C97FF" secondaryColour="#3373CC">
         <block type="motion_movesteps">
             <value name="STEPS">
@@ -120,14 +121,16 @@ const motion = `
         ${blockSeparator}
         <block type="motion_setrotationstyle"/>
         ${blockSeparator}
-        <block id="xposition" type="motion_xposition"/>
-        <block id="yposition" type="motion_yposition"/>
-        <block id="direction" type="motion_direction"/>
+        <block id="${targetId}_xposition" type="motion_xposition"/>
+        <block id="${targetId}_yposition" type="motion_yposition"/>
+        <block id="${targetId}_direction" type="motion_direction"/>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const looks = `
+const looks = function (targetId) {
+    return `
     <category name="Looks" colour="#9966FF" secondaryColour="#774DCB">
         <block type="looks_sayforsecs">
             <value name="MESSAGE">
@@ -229,15 +232,17 @@ const looks = `
             </value>
         </block>
         ${blockSeparator}
-        <block id="costumeorder" type="looks_costumeorder"/>
+        <block id="${targetId}_costumeorder" type="looks_costumeorder"/>
         <block id="backdroporder" type="looks_backdroporder"/>
         <block id="backdropname" type="looks_backdropname"/>
-        <block id="size" type="looks_size"/>
+        <block id="${targetId}_size" type="looks_size"/>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const sound = `
+const sound = function () {
+    return `
     <category name="Sound" colour="#D65CD6" secondaryColour="#BD42BD">
         <block type="sound_play">
             <value name="SOUND_MENU">
@@ -284,9 +289,11 @@ const sound = `
         <block id="volume" type="sound_volume"/>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const events = `
+const events = function () {
+    return `
     <category name="Events" colour="#FFD500" secondaryColour="#CC9900">
         <block type="event_whenflagclicked"/>
         <block type="event_whenkeypressed">
@@ -317,9 +324,11 @@ const events = `
         </block>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const control = `
+const control = function () {
+    return `
     <category name="Control" colour="#FFAB19" secondaryColour="#CF8B17">
         <block type="control_wait">
             <value name="DURATION">
@@ -354,9 +363,11 @@ const control = `
         <block type="control_delete_this_clone"/>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const sensing = `
+const sensing = function () {
+    return `
     <category name="Sensing" colour="#4CBFE6" secondaryColour="#2E8EB8">
         <block type="sensing_touchingobject">
             <value name="TOUCHINGOBJECTMENU">
@@ -422,9 +433,11 @@ const sensing = `
         <block type="sensing_dayssince2000"/>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const operators = `
+const operators = function () {
+    return `
     <category name="Operators" colour="#40BF4A" secondaryColour="#389438">
         <block type="operator_add">
             <value name="NUM1">
@@ -602,33 +615,37 @@ const operators = `
         </block>
         ${categorySeparator}
     </category>
-`;
+    `;
+};
 
-const data = `
+const data = function () {
+    return `
     <category name="Data" colour="#FF8C1A" secondaryColour="#DB6E00" custom="VARIABLE">
     </category>
-`;
+    `;
+};
 
 const xmlOpen = '<xml style="display: none">';
 const xmlClose = '</xml>';
 
 /**
+ * @param {!string} targetId - The current editing target
  * @param {string?} categoriesXML - null for default toolbox, or an XML string with <category> elements.
  * @returns {string} - a ScratchBlocks-style XML document for the contents of the toolbox.
  */
-const makeToolboxXML = function (categoriesXML) {
+const makeToolboxXML = function (targetId, categoriesXML) {
     const gap = [categorySeparator];
 
     const everything = [
         xmlOpen,
-        motion, gap,
-        looks, gap,
-        sound, gap,
-        events, gap,
-        control, gap,
-        sensing, gap,
-        operators, gap,
-        data
+        motion(targetId), gap,
+        looks(targetId), gap,
+        sound(targetId), gap,
+        events(targetId), gap,
+        control(targetId), gap,
+        sensing(targetId), gap,
+        operators(targetId), gap,
+        data(targetId)
     ];
 
     if (categoriesXML) {
diff --git a/src/reducers/toolbox.js b/src/reducers/toolbox.js
index 4b06a807cac5e10ebb0d643ab06eea39e5b56b77..3f559884f0771545acc67eacf867adcc0274f994 100644
--- a/src/reducers/toolbox.js
+++ b/src/reducers/toolbox.js
@@ -1,9 +1,9 @@
 const UPDATE_TOOLBOX = 'scratch-gui/toolbox/UPDATE_TOOLBOX';
-
 import makeToolboxXML from '../lib/make-toolbox-xml';
 
 const initialState = {
-    toolboxXML: makeToolboxXML()
+    // @todo switch this to make the stage's XML
+    toolboxXML: makeToolboxXML('')
 };
 
 const reducer = function (state, action) {
diff --git a/test/helpers/selenium-helper.js b/test/helpers/selenium-helper.js
index c4f36ca05b712e36c30246c269d47c6c1afa78ce..ce3f04fbf2898469dd3b3774cd83ef2b79603e52 100644
--- a/test/helpers/selenium-helper.js
+++ b/test/helpers/selenium-helper.js
@@ -4,7 +4,7 @@ import bindAll from 'lodash.bindall';
 import 'chromedriver'; // register path
 import webdriver from 'selenium-webdriver';
 
-const {By, until} = webdriver;
+const {By, until, Button} = webdriver;
 
 class SeleniumHelper {
     constructor () {
@@ -15,7 +15,9 @@ class SeleniumHelper {
             'findByText',
             'findByXpath',
             'getDriver',
-            'getLogs'
+            'getLogs',
+            'loadUri',
+            'rightClickText'
         ]);
     }
 
@@ -34,6 +36,14 @@ class SeleniumHelper {
         return this.findByXpath(`//body//${scope || '*'}//*[contains(text(), '${text}')]`);
     }
 
+    loadUri (uri) {
+        return this.driver
+            .get(`file://${uri}`)
+            .then(() => (
+                this.driver.executeScript('window.onbeforeunload = undefined;')
+            ));
+    }
+
     clickXpath (xpath) {
         return this.findByXpath(xpath).then(el => el.click());
     }
@@ -42,6 +52,12 @@ class SeleniumHelper {
         return this.findByText(text, scope).then(el => el.click());
     }
 
+    rightClickText (text, scope) {
+        return this.findByText(text, scope).then(el => this.driver.actions()
+            .click(el, Button.RIGHT)
+            .perform());
+    }
+
     clickButton (text) {
         return this.clickXpath(`//button[contains(text(), '${text}')]`);
     }
diff --git a/test/integration/examples.test.js b/test/integration/examples.test.js
index 7fffa903a4bb6f99f08ab18285869ce7bbd05f17..908dbfd36a3ec145bc79b42eb0ad464190959180 100644
--- a/test/integration/examples.test.js
+++ b/test/integration/examples.test.js
@@ -9,7 +9,8 @@ const {
     clickXpath,
     findByXpath,
     getDriver,
-    getLogs
+    getLogs,
+    loadUri
 } = new SeleniumHelper();
 
 const errorWhitelist = [
@@ -31,7 +32,7 @@ describe('player example', () => {
 
     test('Load a project by ID', async () => {
         const projectId = '96708228';
-        await driver.get(`file://${uri}#${projectId}`);
+        await loadUri(`${uri}#${projectId}`);
         await new Promise(resolve => setTimeout(resolve, 2000));
         await clickXpath('//img[@title="Go"]');
         await new Promise(resolve => setTimeout(resolve, 2000));
@@ -54,7 +55,7 @@ describe('blocks example', () => {
 
     test('Load a project by ID', async () => {
         const projectId = '96708228';
-        await driver.get(`file://${uri}#${projectId}`);
+        await loadUri(`${uri}#${projectId}`);
         await new Promise(resolve => setTimeout(resolve, 2000));
         await clickXpath('//img[@title="Go"]');
         await new Promise(resolve => setTimeout(resolve, 2000));
@@ -64,7 +65,7 @@ describe('blocks example', () => {
     });
 
     test('Change categories', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(`${uri}`);
         await clickText('Looks');
         await clickText('Sound');
         await clickText('Events');
diff --git a/test/integration/test.js b/test/integration/test.js
index 86729cf277017b5cb99f9b858514633583564d47..cfea4e2176921c0d889e619500c50365197bc3eb 100644
--- a/test/integration/test.js
+++ b/test/integration/test.js
@@ -8,7 +8,9 @@ const {
     findByText,
     findByXpath,
     getDriver,
-    getLogs
+    getLogs,
+    loadUri,
+    rightClickText
 } = new SeleniumHelper();
 
 const uri = path.resolve(__dirname, '../../build/index.html');
@@ -34,9 +36,8 @@ describe('costumes, sounds and variables', () => {
         await driver.quit();
     });
 
-
     test('Blocks report when clicked in the toolbox', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Blocks');
         await clickText('Operators', blocksTabScope);
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
@@ -47,7 +48,7 @@ describe('costumes, sounds and variables', () => {
     });
 
     test('Switching sprites updates the block menus', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Sound', blocksTabScope);
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
         // "meow" sound block should be visible
@@ -60,7 +61,7 @@ describe('costumes, sounds and variables', () => {
     });
 
     test('Adding a costume', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Costumes');
         await clickText('Add Costume');
         const el = await findByXpath("//input[@placeholder='what are you looking for?']");
@@ -73,17 +74,22 @@ describe('costumes, sounds and variables', () => {
     });
 
     test('Adding a sound', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Sounds');
+
+        // Delete the sound
+        await rightClickText('meow', soundsTabScope);
+        await clickText('delete', soundsTabScope);
+        await driver.switchTo().alert()
+            .accept();
+
+        // Add a sound
         await clickText('Add Sound');
         const el = await findByXpath("//input[@placeholder='what are you looking for?']");
         await el.sendKeys('chom');
         await clickText('chomp'); // Should close the modal, then click the sounds in the selector
-        await clickText('meow', soundsTabScope);
         await clickText('chomp', soundsTabScope);
         await clickXpath('//button[@title="Play"]');
-        await clickText('meow', soundsTabScope);
-        await clickXpath('//button[@title="Play"]');
 
         await clickText('Louder');
         await clickText('Softer');
@@ -99,7 +105,7 @@ describe('costumes, sounds and variables', () => {
 
     test('Load a project by ID', async () => {
         const projectId = '96708228';
-        await driver.get(`file://${uri}#${projectId}`);
+        await loadUri(`${uri}#${projectId}`);
         await new Promise(resolve => setTimeout(resolve, 2000));
         await clickXpath('//img[@title="Go"]');
         await new Promise(resolve => setTimeout(resolve, 2000));
@@ -109,7 +115,7 @@ describe('costumes, sounds and variables', () => {
     });
 
     test('Creating variables', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Blocks');
         await clickText('Data', blocksTabScope);
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
@@ -133,7 +139,7 @@ describe('costumes, sounds and variables', () => {
     });
 
     test('Importing extensions', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Blocks');
         await clickText('Extensions');
         await clickText('Pen', modalScope); // Modal closes
diff --git a/test/unit/components/__snapshots__/icon-button.test.jsx.snap b/test/unit/components/__snapshots__/icon-button.test.jsx.snap
index 3a26f0acf165ca366275b154a43c236ff45ec7d3..b5f3e7a1090bae6573458341790daeeba665566d 100644
--- a/test/unit/components/__snapshots__/icon-button.test.jsx.snap
+++ b/test/unit/components/__snapshots__/icon-button.test.jsx.snap
@@ -4,6 +4,7 @@ exports[`IconButtonComponent matches snapshot 1`] = `
 <div
   className="custom-class-name"
   onClick={[Function]}
+  role="button"
 >
   <img
     className={undefined}
diff --git a/test/unit/components/__snapshots__/sound-editor.test.jsx.snap b/test/unit/components/__snapshots__/sound-editor.test.jsx.snap
index 6e863223f1d8753ce674382f29db0153edf82b65..693cf59cf31bcc3271be429d4976f391cec1a1f8 100644
--- a/test/unit/components/__snapshots__/sound-editor.test.jsx.snap
+++ b/test/unit/components/__snapshots__/sound-editor.test.jsx.snap
@@ -341,6 +341,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
@@ -357,6 +358,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
@@ -373,6 +375,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
@@ -389,6 +392,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
@@ -405,6 +409,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
@@ -421,6 +426,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
@@ -437,6 +443,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
     <div
       className=""
       onClick={[Function]}
+      role="button"
     >
       <img
         className={undefined}
diff --git a/test/unit/components/__snapshots__/sprite-selector-item.test.jsx.snap b/test/unit/components/__snapshots__/sprite-selector-item.test.jsx.snap
index d30617f9aa25d3bcec9972f271d2cf7d76aeaf7d..22b12a467fe94868401db9c26d292214f153f259 100644
--- a/test/unit/components/__snapshots__/sprite-selector-item.test.jsx.snap
+++ b/test/unit/components/__snapshots__/sprite-selector-item.test.jsx.snap
@@ -12,8 +12,10 @@ exports[`SpriteSelectorItemComponent matches snapshot when selected 1`] = `
   onTouchStart={[Function]}
 >
   <div
+    aria-label="Close"
     className=""
     onClick={[Function]}
+    role="button"
   >
     <img
       className={undefined}