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/test/helpers/selenium-helper.js b/test/helpers/selenium-helper.js
index 07002a94a7ba1a39cc64a14fe882db2d34140de1..ce3f04fbf2898469dd3b3774cd83ef2b79603e52 100644
--- a/test/helpers/selenium-helper.js
+++ b/test/helpers/selenium-helper.js
@@ -16,6 +16,7 @@ class SeleniumHelper {
             'findByXpath',
             'getDriver',
             'getLogs',
+            'loadUri',
             'rightClickText'
         ]);
     }
@@ -35,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());
     }
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 c2b5f2945d9610d7ea42efe6a58089be89d4da8b..cfea4e2176921c0d889e619500c50365197bc3eb 100644
--- a/test/integration/test.js
+++ b/test/integration/test.js
@@ -9,6 +9,7 @@ const {
     findByXpath,
     getDriver,
     getLogs,
+    loadUri,
     rightClickText
 } = new SeleniumHelper();
 
@@ -36,7 +37,7 @@ describe('costumes, sounds and variables', () => {
     });
 
     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,7 +74,7 @@ describe('costumes, sounds and variables', () => {
     });
 
     test('Adding a sound', async () => {
-        await driver.get(`file://${uri}`);
+        await loadUri(uri);
         await clickText('Sounds');
 
         // Delete the sound
@@ -104,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));
@@ -114,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
@@ -138,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