From e29184e1ce9c74676e391e43ed8b4dded412e0d9 Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Fri, 17 Nov 2017 15:09:57 -0500 Subject: [PATCH 1/3] Warn user before navigating away/unloading --- src/index.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/index.jsx b/src/index.jsx index 6d301f516..e55fc0ef4 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'); From 145ade6ffc98ba1ce378002b04cd197651134ded Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Fri, 17 Nov 2017 15:44:44 -0500 Subject: [PATCH 2/3] Fix integration tests by clearing reload warning --- test/integration/test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/integration/test.js b/test/integration/test.js index 86729cf27..8cb23329d 100644 --- a/test/integration/test.js +++ b/test/integration/test.js @@ -37,6 +37,7 @@ describe('costumes, sounds and variables', () => { test('Blocks report when clicked in the toolbox', async () => { await driver.get(`file://${uri}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await clickText('Blocks'); await clickText('Operators', blocksTabScope); await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation @@ -48,6 +49,7 @@ describe('costumes, sounds and variables', () => { test('Switching sprites updates the block menus', async () => { await driver.get(`file://${uri}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await clickText('Sound', blocksTabScope); await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation // "meow" sound block should be visible @@ -61,6 +63,7 @@ describe('costumes, sounds and variables', () => { test('Adding a costume', async () => { await driver.get(`file://${uri}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await clickText('Costumes'); await clickText('Add Costume'); const el = await findByXpath("//input[@placeholder='what are you looking for?']"); @@ -74,6 +77,7 @@ describe('costumes, sounds and variables', () => { test('Adding a sound', async () => { await driver.get(`file://${uri}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await clickText('Sounds'); await clickText('Add Sound'); const el = await findByXpath("//input[@placeholder='what are you looking for?']"); @@ -100,6 +104,7 @@ describe('costumes, sounds and variables', () => { test('Load a project by ID', async () => { const projectId = '96708228'; await driver.get(`file://${uri}#${projectId}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await new Promise(resolve => setTimeout(resolve, 2000)); await clickXpath('//img[@title="Go"]'); await new Promise(resolve => setTimeout(resolve, 2000)); @@ -110,6 +115,7 @@ describe('costumes, sounds and variables', () => { test('Creating variables', async () => { await driver.get(`file://${uri}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await clickText('Blocks'); await clickText('Data', blocksTabScope); await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation @@ -134,6 +140,7 @@ describe('costumes, sounds and variables', () => { test('Importing extensions', async () => { await driver.get(`file://${uri}`); + await driver.executeScript('window.onbeforeunload = undefined;'); await clickText('Blocks'); await clickText('Extensions'); await clickText('Pen', modalScope); // Modal closes From f3e76acd53e3a49f60a6b5938ba41f66a520cc44 Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Fri, 17 Nov 2017 16:18:16 -0500 Subject: [PATCH 3/3] Capture onbeforeunload unsetter in a helper --- test/helpers/selenium-helper.js | 11 ++++++++++- test/integration/examples.test.js | 9 +++++---- test/integration/test.js | 24 +++++++++--------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/test/helpers/selenium-helper.js b/test/helpers/selenium-helper.js index c4f36ca05..1021b48ec 100644 --- a/test/helpers/selenium-helper.js +++ b/test/helpers/selenium-helper.js @@ -15,7 +15,8 @@ class SeleniumHelper { 'findByText', 'findByXpath', 'getDriver', - 'getLogs' + 'getLogs', + 'loadUri' ]); } @@ -34,6 +35,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 7fffa903a..908dbfd36 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 8cb23329d..c792e80b0 100644 --- a/test/integration/test.js +++ b/test/integration/test.js @@ -8,7 +8,8 @@ const { findByText, findByXpath, getDriver, - getLogs + getLogs, + loadUri } = new SeleniumHelper(); const uri = path.resolve(__dirname, '../../build/index.html'); @@ -36,8 +37,7 @@ describe('costumes, sounds and variables', () => { test('Blocks report when clicked in the toolbox', async () => { - await driver.get(`file://${uri}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(uri); await clickText('Blocks'); await clickText('Operators', blocksTabScope); await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation @@ -48,8 +48,7 @@ describe('costumes, sounds and variables', () => { }); test('Switching sprites updates the block menus', async () => { - await driver.get(`file://${uri}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(uri); await clickText('Sound', blocksTabScope); await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation // "meow" sound block should be visible @@ -62,8 +61,7 @@ describe('costumes, sounds and variables', () => { }); test('Adding a costume', async () => { - await driver.get(`file://${uri}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(uri); await clickText('Costumes'); await clickText('Add Costume'); const el = await findByXpath("//input[@placeholder='what are you looking for?']"); @@ -76,8 +74,7 @@ describe('costumes, sounds and variables', () => { }); test('Adding a sound', async () => { - await driver.get(`file://${uri}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(uri); await clickText('Sounds'); await clickText('Add Sound'); const el = await findByXpath("//input[@placeholder='what are you looking for?']"); @@ -103,8 +100,7 @@ describe('costumes, sounds and variables', () => { test('Load a project by ID', async () => { const projectId = '96708228'; - await driver.get(`file://${uri}#${projectId}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(`${uri}#${projectId}`); await new Promise(resolve => setTimeout(resolve, 2000)); await clickXpath('//img[@title="Go"]'); await new Promise(resolve => setTimeout(resolve, 2000)); @@ -114,8 +110,7 @@ describe('costumes, sounds and variables', () => { }); test('Creating variables', async () => { - await driver.get(`file://${uri}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(uri); await clickText('Blocks'); await clickText('Data', blocksTabScope); await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation @@ -139,8 +134,7 @@ describe('costumes, sounds and variables', () => { }); test('Importing extensions', async () => { - await driver.get(`file://${uri}`); - await driver.executeScript('window.onbeforeunload = undefined;'); + await loadUri(uri); await clickText('Blocks'); await clickText('Extensions'); await clickText('Pen', modalScope); // Modal closes