From 9ece2e6ea6a8787dab3b720b72907960b9e84b72 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 8 May 2018 16:19:56 -0400 Subject: [PATCH 01/32] Update selenium-webdriver and chromedriver versions to match gui. --- test/integration/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/package.json b/test/integration/package.json index 06fc0f859..f47f2496d 100644 --- a/test/integration/package.json +++ b/test/integration/package.json @@ -1,6 +1,6 @@ { "devDependencies": { - "selenium-webdriver": "2.45.0", - "chromedriver": "2.33.0" + "selenium-webdriver": "3.6.0", + "chromedriver": "2.37.0" } } From d0a2266c1005eeff3ac92a3a4f8e36270c761904 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 8 May 2018 16:20:57 -0400 Subject: [PATCH 02/32] Update gitignore to ignore node_modules in integration tests --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 90e261de2..1325f56fb 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ ENV /test/integration-cypress/cypress/screenshots /test/integration-cypress/cypress/videos /test/integration-cypress/package-lock.json +/test/integration/node_modules/* From cb52f679beadcab09a843aefc5fe4433fdbe19a1 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 8 May 2018 16:26:48 -0400 Subject: [PATCH 03/32] Move Selenium-Helpers file and point integration tests to it --- test/{helpers => integration}/selenium-helpers.js | 2 +- test/integration/smoke-testing/test_footer_links.js | 4 ++-- test/integration/smoke-testing/test_navbar_links.js | 4 ---- .../smoke-testing/test_signing_in_and_out_discuss.js | 2 +- .../smoke-testing/test_signing_in_and_out_homepage.js | 2 +- test/integration/smoke-testing/test_statistics_page.js | 2 +- 6 files changed, 6 insertions(+), 10 deletions(-) rename test/{helpers => integration}/selenium-helpers.js (97%) diff --git a/test/helpers/selenium-helpers.js b/test/integration/selenium-helpers.js similarity index 97% rename from test/helpers/selenium-helpers.js rename to test/integration/selenium-helpers.js index 2b55e2a4d..82a3abe58 100644 --- a/test/helpers/selenium-helpers.js +++ b/test/integration/selenium-helpers.js @@ -1,4 +1,4 @@ -const webdriver = require('selenium-webdriver'); +var webdriver = require('selenium-webdriver'); const driver = new webdriver.Builder() .forBrowser('chrome') diff --git a/test/integration/smoke-testing/test_footer_links.js b/test/integration/smoke-testing/test_footer_links.js index f2b0381e0..8cf84909a 100644 --- a/test/integration/smoke-testing/test_footer_links.js +++ b/test/integration/smoke-testing/test_footer_links.js @@ -3,13 +3,13 @@ * * Test cases: https://github.com/LLK/scratch-www/wiki/Most-Important-Workflows */ - + const tap = require('tap'); const { driver, webdriver -} = require('../../helpers/selenium-helpers.js'); +} = require('../selenium-helpers.js'); // Selenium's promise driver will be deprecated, so we should not rely on it webdriver.SELENIUM_PROMISE_MANAGER = 0; diff --git a/test/integration/smoke-testing/test_navbar_links.js b/test/integration/smoke-testing/test_navbar_links.js index efe5cf2ba..b23599a5a 100644 --- a/test/integration/smoke-testing/test_navbar_links.js +++ b/test/integration/smoke-testing/test_navbar_links.js @@ -14,10 +14,6 @@ seleniumWebdriver.SELENIUM_PROMISE_MANAGER = 0; // Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); - // number of tests in the plan tap.plan(7); diff --git a/test/integration/smoke-testing/test_signing_in_and_out_discuss.js b/test/integration/smoke-testing/test_signing_in_and_out_discuss.js index 030c12040..47abb9ea6 100644 --- a/test/integration/smoke-testing/test_signing_in_and_out_discuss.js +++ b/test/integration/smoke-testing/test_signing_in_and_out_discuss.js @@ -12,7 +12,7 @@ const { clickXpath, clickButton, driver -} = require('../../helpers/selenium-helpers.js'); +} = require('../selenium-helpers.js'); var username = process.env.SMOKE_USERNAME; var password = process.env.SMOKE_PASSWORD; diff --git a/test/integration/smoke-testing/test_signing_in_and_out_homepage.js b/test/integration/smoke-testing/test_signing_in_and_out_homepage.js index 29bdf5dae..e21fbc91e 100644 --- a/test/integration/smoke-testing/test_signing_in_and_out_homepage.js +++ b/test/integration/smoke-testing/test_signing_in_and_out_homepage.js @@ -11,7 +11,7 @@ const { findByXpath, clickXpath, driver -} = require('../../helpers/selenium-helpers.js'); +} = require('../selenium-helpers.js'); var username = process.env.SMOKE_USERNAME; var password = process.env.SMOKE_PASSWORD; diff --git a/test/integration/smoke-testing/test_statistics_page.js b/test/integration/smoke-testing/test_statistics_page.js index 15c044e27..223184b7e 100644 --- a/test/integration/smoke-testing/test_statistics_page.js +++ b/test/integration/smoke-testing/test_statistics_page.js @@ -10,7 +10,7 @@ const { findByXpath, findByCss, driver -} = require('../../helpers/selenium-helpers.js'); +} = require('../selenium-helpers.js'); var tap = require('tap'); const test = tap.test; From cb484da6b076a24c0aa895b3d42f74cbf993e8a1 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 8 May 2018 16:28:02 -0400 Subject: [PATCH 04/32] Update test_navbar_links integration test to use selenium_helpers --- .../smoke-testing/test_navbar_links.js | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/integration/smoke-testing/test_navbar_links.js b/test/integration/smoke-testing/test_navbar_links.js index b23599a5a..fbfd72291 100644 --- a/test/integration/smoke-testing/test_navbar_links.js +++ b/test/integration/smoke-testing/test_navbar_links.js @@ -5,11 +5,15 @@ */ require('chromedriver'); -var seleniumWebdriver = require('selenium-webdriver'); + +const { + driver, + webdriver +} = require('../selenium-helpers.js'); var tap = require('tap'); // Selenium's promise driver will be deprecated, so we should not rely on it -seleniumWebdriver.SELENIUM_PROMISE_MANAGER = 0; +webdriver.SELENIUM_PROMISE_MANAGER = 0; // Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; @@ -33,7 +37,7 @@ tap.beforeEach(function () { tap.test('checkCreateLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "create")]/a'; var expectedHref = '/projects/editor/?tip_bar=home'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { return element.getAttribute('href'); }) @@ -46,7 +50,7 @@ tap.test('checkCreateLinkWhenSignedOut', function (t) { tap.test('checkExploreLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "explore")]/a'; var expectedHref = '/explore/projects/all'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { return element.getAttribute('href'); }) @@ -59,7 +63,7 @@ tap.test('checkExploreLinkWhenSignedOut', function (t) { tap.test('checkTipsLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "tips")]/a'; var expectedHref = '/tips'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { return element.getAttribute('href'); }) @@ -72,7 +76,7 @@ tap.test('checkTipsLinkWhenSignedOut', function (t) { tap.test('checkAboutLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "about")]/a'; var expectedHref = '/about'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { return element.getAttribute('href'); }) @@ -87,7 +91,7 @@ tap.test('checkAboutLinkWhenSignedOut', function (t) { tap.test('checkSearchBar', function (t) { var xPathLink = '//input[@id="frc-q-1088"]'; // search bar should exist - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)).then(function (element) { + driver.findElement(webdriver.By.xpath(xPathLink)).then(function (element) { t.ok(element); t.end(); }); @@ -98,7 +102,7 @@ tap.test('checkSearchBar', function (t) { tap.test('checkJoinScratchLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "right") and contains(@class, "join")]/a'; var expectedText = 'Join Scratch'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { return element.getText('a'); }) @@ -111,7 +115,7 @@ tap.test('checkJoinScratchLinkWhenSignedOut', function (t) { tap.test('checkSignInLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "right") and contains(@class, "login-item")]/a'; var expectedText = 'Sign in'; - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) + driver.findElement(webdriver.By.xpath(xPathLink)) .then(function (element) { return element.getText('a'); }) From 93e483e6e992c0c71c86abdb4f1cd0c82e956fe3 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 8 May 2018 16:29:35 -0400 Subject: [PATCH 05/32] Split integration test test_signing_in_and_my_stuff into test-login-failures and test-my-stuff --- .../smoke-testing/test-login-failures.js | 130 ++++++++++++++++++ ...ng_in_and_my_stuff.js => test-my-stuff.js} | 112 +-------------- 2 files changed, 134 insertions(+), 108 deletions(-) create mode 100644 test/integration/smoke-testing/test-login-failures.js rename test/integration/smoke-testing/{test_signing_in_and_my_stuff.js => test-my-stuff.js} (54%) diff --git a/test/integration/smoke-testing/test-login-failures.js b/test/integration/smoke-testing/test-login-failures.js new file mode 100644 index 000000000..e57cc707f --- /dev/null +++ b/test/integration/smoke-testing/test-login-failures.js @@ -0,0 +1,130 @@ +const { + clickText, + findByXpath, + clickButton, + driver, + until, + By +} = require('../selenium-helpers.js'); + +var username = process.env.SMOKE_USERNAME; +var password = process.env.SMOKE_PASSWORD; + + +var tap = require('tap'); +const test = tap.test; + +var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; +var url = rootUrl + '/users/' + username; + +tap.plan(5); + +tap.tearDown(function () { + driver.quit(); +}); + +tap.beforeEach(function () { + return driver.get(url); +}); + +/* + * This test fails sometimes because blank username eventually + * triggers the captcha page, which is a bug: + * https://github.com/LLK/scratchr2/issues/4762 + */ +test('Trying to sign in with no username and no password using scratchr2 navbar', t => { + clickText('Sign in') + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) + ) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) + ) + .then(() => findByXpath('//form/div[@class="error"]')) + .then(element => element.getText()) + .then(text => t.match(text, 'This field is required.', + '"This field is required" error should be displayed')) + .then(() => t.end()); +}); + +/* + * This test fails sometimes because blank username eventually + * triggers the captcha page, which is a bug: + * https://github.com/LLK/scratchr2/issues/4762 + */ +test('Trying to sign in with no username using scratchr2 navbar', t => { + clickText('Sign in') + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) + ) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) + ) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'This field is required.', + '"This field is required" error should be displayed')) + .then(() => t.end()); +}); + +test('Trying to sign in with no password using scratchr2 navbar', t => { + var nonsenseusername = Math.random().toString(36) + .replace(/[^a-z]+/g, '') + .substr(0, 5); + clickText('Sign in') + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(nonsenseusername)) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'This field is required.', + '"This field is required" error should be displayed')) + .then(() => t.end()); +}); + +test('Trying to sign in with the wrong username using scratchr2 navbar', t => { + var nonsenseusername = Math.random().toString(36) + .replace(/[^a-z]+/g, '') + .substr(0, 5); + clickText('Sign in') + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(nonsenseusername)) + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'Incorrect username or password.', + '"Incorrect username or password" error should be displayed')) + .then(() => t.end()); +}); + +test('Trying to sign in with the wrong password using scratchr2 navbar', t => { + clickText('Sign in') + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(username)) + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys('nonsensepassword')) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'Incorrect username or password.', + '"Incorrect username or password" error should be displayed')) + .then(() => t.end()); +}); diff --git a/test/integration/smoke-testing/test_signing_in_and_my_stuff.js b/test/integration/smoke-testing/test-my-stuff.js similarity index 54% rename from test/integration/smoke-testing/test_signing_in_and_my_stuff.js rename to test/integration/smoke-testing/test-my-stuff.js index 68bed40b5..d6ea50285 100644 --- a/test/integration/smoke-testing/test_signing_in_and_my_stuff.js +++ b/test/integration/smoke-testing/test-my-stuff.js @@ -10,10 +10,8 @@ const { findByXpath, clickXpath, clickButton, - driver, - until, - By -} = require('../../helpers/selenium-helpers.js'); + driver +} = require('../selenium-helpers.js'); var username = process.env.SMOKE_USERNAME; var password = process.env.SMOKE_PASSWORD; @@ -23,9 +21,9 @@ var tap = require('tap'); const test = tap.test; var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; -var url = rootUrl + '/users/anyuser'; +var url = rootUrl + '/users/' + username; -tap.plan(12); +tap.plan(7); tap.tearDown(function () { driver.quit(); @@ -35,108 +33,6 @@ tap.beforeEach(function () { return driver.get(url); }); -/* - * This test fails sometimes because blank username eventually - * triggers the captcha page, which is a bug: - * https://github.com/LLK/scratchr2/issues/4762 - */ -test('Trying to sign in with no username and no password using scratchr2 navbar', t => { - clickText('Sign in') - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) - ) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) - ) - .then(() => findByXpath('//form/div[@class="error"]')) - .then(element => element.getText()) - .then(text => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); -}); - -/* - * This test fails sometimes because blank username eventually - * triggers the captcha page, which is a bug: - * https://github.com/LLK/scratchr2/issues/4762 - */ -test('Trying to sign in with no username using scratchr2 navbar', t => { - clickText('Sign in') - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) - ) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) - ) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); -}); - -test('Trying to sign in with no password using scratchr2 navbar', t => { - var nonsenseusername = Math.random().toString(36) - .replace(/[^a-z]+/g, '') - .substr(0, 5); - clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(nonsenseusername)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); -}); - -test('Trying to sign in with the wrong username using scratchr2 navbar', t => { - var nonsenseusername = Math.random().toString(36) - .replace(/[^a-z]+/g, '') - .substr(0, 5); - clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(nonsenseusername)) - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'Incorrect username or password.', - '"Incorrect username or password" error should be displayed')) - .then(() => t.end()); -}); - -test('Trying to sign in with the wrong password using scratchr2 navbar', t => { - clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(username)) - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys('nonsensepassword')) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'Incorrect username or password.', - '"Incorrect username or password" error should be displayed')) - .then(() => t.end()); -}); - test('Sign in to Scratch using scratchr2 navbar', t => { clickText('Sign in') .then(() => findByXpath('//input[@id="login_dropdown_username"]')) From e88d5f8745167952b1e5983903e6048391e6502f Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 8 May 2018 16:43:41 -0400 Subject: [PATCH 06/32] Add verbose method of running integration tests to output results of each test. --- Makefile | 3 +++ package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 65a57a3ac..6fe3eed4d 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,9 @@ integration: smoke: $(TAP) ./test/integration/smoke-testing/*.js --timeout=3600 + +smoke-verbose: + $(TAP) ./test/integration/smoke-testing/*.js --timeout=3600 -R spec localization: $(TAP) ./test/localization/*.js diff --git a/package.json b/package.json index 17e42e9c8..3ae61e8ca 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "stop": "make stop", "test": "make test", "smoke": "make smoke", + "smoke-verbose": "make smoke-verbose", "watch": "make watch", "build": "make build", "dev": "make watch && make start &" From 4e017d3ca71356a8a0d0542570da4ea5f0beb67c Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Tue, 15 May 2018 09:26:52 -0400 Subject: [PATCH 07/32] Remove Selenium smoke tests that sign in with no username since they break constantly. --- .../smoke-testing/test-login-failures.js | 46 +------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/test/integration/smoke-testing/test-login-failures.js b/test/integration/smoke-testing/test-login-failures.js index e57cc707f..ea7b9a78d 100644 --- a/test/integration/smoke-testing/test-login-failures.js +++ b/test/integration/smoke-testing/test-login-failures.js @@ -17,7 +17,7 @@ const test = tap.test; var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; var url = rootUrl + '/users/' + username; -tap.plan(5); +tap.plan(3); tap.tearDown(function () { driver.quit(); @@ -27,50 +27,6 @@ tap.beforeEach(function () { return driver.get(url); }); -/* - * This test fails sometimes because blank username eventually - * triggers the captcha page, which is a bug: - * https://github.com/LLK/scratchr2/issues/4762 - */ -test('Trying to sign in with no username and no password using scratchr2 navbar', t => { - clickText('Sign in') - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) - ) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) - ) - .then(() => findByXpath('//form/div[@class="error"]')) - .then(element => element.getText()) - .then(text => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); -}); - -/* - * This test fails sometimes because blank username eventually - * triggers the captcha page, which is a bug: - * https://github.com/LLK/scratchr2/issues/4762 - */ -test('Trying to sign in with no username using scratchr2 navbar', t => { - clickText('Sign in') - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) - ) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) - ) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); -}); - test('Trying to sign in with no password using scratchr2 navbar', t => { var nonsenseusername = Math.random().toString(36) .replace(/[^a-z]+/g, '') From a302d37eef96fe4837e98cd6c7852b3029cf86da Mon Sep 17 00:00:00 2001 From: Andrew Sliwinski Date: Tue, 15 May 2018 10:19:12 -0400 Subject: [PATCH 08/32] Remove references to Linux for the Scratch 2.0 offline editor. Resolves GH-1880 --- src/components/news/news.json | 2 +- src/views/download/download.jsx | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/components/news/news.json b/src/components/news/news.json index c708faf1c..af28dfb15 100644 --- a/src/components/news/news.json +++ b/src/components/news/news.json @@ -2,7 +2,7 @@ { "id": 128283902498, "headline": "Update to Scratch Offline Editor", - "copy": "We’ve released an update to Offline Editor which fixed bugs affecting Linux users.", + "copy": "We’ve released an update to Offline Editor which fixed bugs affecting Windows users.", "url": "https://scratch.mit.edu/news#128283902498", "image": "https://33.media.tumblr.com/695b93f4ab74c68feaef1fe03baebdd5/tumblr_inline_n0xubtT0vU1szpavb.png" }, diff --git a/src/views/download/download.jsx b/src/views/download/download.jsx index 1a9b905bd..e4a6bef7c 100644 --- a/src/views/download/download.jsx +++ b/src/views/download/download.jsx @@ -55,8 +55,7 @@ class Download extends React.Component { downloadUrls = { mac: `${downloadPath}${this.state.swfVersion}.dmg`, mac105: `${downloadPath}${this.state.swfVersion}.air`, - windows: `${downloadPath}${this.state.swfVersion}.exe`, - linux: `${downloadPath}${this.state.swfVersion}.air` + windows: `${downloadPath}${this.state.swfVersion}.exe` }; } @@ -143,12 +142,6 @@ class Download extends React.Component { -
  • - - - {' '} - - -
  • @@ -180,12 +173,6 @@ class Download extends React.Component { -
  • - - - {' '} - - -
  • ]} {this.state.swfVersion === -1 ? [ From 32fc959ed28e5a9d0ddcd24cac6d080d145275b4 Mon Sep 17 00:00:00 2001 From: Andrew Sliwinski Date: Wed, 16 May 2018 09:44:11 -0400 Subject: [PATCH 09/32] Remove references to Linux in download l10n strings --- src/views/download/l10n.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/views/download/l10n.json b/src/views/download/l10n.json index 48ecdd50c..3c5144115 100644 --- a/src/views/download/l10n.json +++ b/src/views/download/l10n.json @@ -1,6 +1,6 @@ { "download.title": "Scratch 2.0 Offline Editor", - "download.intro": "You can install the Scratch 2.0 editor to work on projects without an internet connection. This version will work on Mac, Windows, and some versions of Linux (32 bit).", + "download.intro": "You can install the Scratch 2.0 editor to work on projects without an internet connection. This version will work on Windows and MacOS.", "download.introMac": "Note for Mac Users: the latest version of Scratch 2.0 Offline requires Adobe AIR 20. To upgrade to Adobe AIR 20 manually, go here.", "download.installation": "Installation", "download.airTitle": "Adobe AIR", @@ -8,7 +8,6 @@ "download.macOSX": "Mac OS X", "download.macOlder": "Mac OS 10.5 & Older", "download.windows": "Windows", - "download.linux": "Linux", "download.download": "Download", "download.offlineEditorTitle": "Scratch Offline Editor", "download.offlineEditorBody": "Next download and install the Scratch 2.0 Offline Editor", From e7f57122c220e8422196006f09fda5ed5f710ba5 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Thu, 17 May 2018 11:33:21 -0400 Subject: [PATCH 10/32] Make Selenium Helper function to click element by CSS --- test/integration/selenium-helpers.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/integration/selenium-helpers.js b/test/integration/selenium-helpers.js index 82a3abe58..faf658ec9 100644 --- a/test/integration/selenium-helpers.js +++ b/test/integration/selenium-helpers.js @@ -30,6 +30,10 @@ const findByCss = (css) => { return driver.wait(until.elementLocated(By.css(css), 1000 * 5)); }; +const clickCss = (css) => { + return findByCss(css).then(el => el.click()); +}; + const getLogs = (whitelist) => { return driver.manage() .logs() @@ -65,5 +69,6 @@ module.exports = { findText, clickButton, findByCss, + clickCss, getLogs }; From 86e9549ceea51f9842515ec4283260b3c03e7669 Mon Sep 17 00:00:00 2001 From: BryceLTaylor Date: Thu, 17 May 2018 11:52:05 -0400 Subject: [PATCH 11/32] Make all Selenium tests of login-failures work and use css to select elements. --- .../smoke-testing/test-login-failures.js | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/test/integration/smoke-testing/test-login-failures.js b/test/integration/smoke-testing/test-login-failures.js index ea7b9a78d..fca6c9c01 100644 --- a/test/integration/smoke-testing/test-login-failures.js +++ b/test/integration/smoke-testing/test-login-failures.js @@ -1,10 +1,8 @@ const { - clickText, - findByXpath, - clickButton, driver, - until, - By + findByCss, + clickCss, + until } = require('../selenium-helpers.js'); var username = process.env.SMOKE_USERNAME; @@ -31,17 +29,17 @@ test('Trying to sign in with no password using scratchr2 navbar', t => { var nonsenseusername = Math.random().toString(36) .replace(/[^a-z]+/g, '') .substr(0, 5); - clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + clickCss('.dropdown-toggle') + .then(() => findByCss('form#login input#login_dropdown_username')) .then((element) => element.sendKeys(nonsenseusername)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) + .then(() => clickCss('form#login button')) + .then(() => findByCss('form#login .error')) + .then((element) => { + driver.wait(until.elementIsVisible(element)); + return element; + }) .then((element) => element.getText()) - .then((text) => t.match(text, 'This field is required.', + .then((text) => t.match(text, 'This field is required', '"This field is required" error should be displayed')) .then(() => t.end()); }); @@ -50,17 +48,17 @@ test('Trying to sign in with the wrong username using scratchr2 navbar', t => { var nonsenseusername = Math.random().toString(36) .replace(/[^a-z]+/g, '') .substr(0, 5); - clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + clickCss('.dropdown-toggle') + .then(() => findByCss('form#login input#login_dropdown_username')) .then((element) => element.sendKeys(nonsenseusername)) - .then(() => findByXpath('//input[@name="password"]')) + .then(() => findByCss('form#login input.wide.password')) .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) + .then(() => clickCss('form#login button')) + .then(() => findByCss('form#login .error')) + .then((element) => { + driver.wait(until.elementIsVisible(element)); + return element; + }) .then((element) => element.getText()) .then((text) => t.match(text, 'Incorrect username or password.', '"Incorrect username or password" error should be displayed')) @@ -68,17 +66,17 @@ test('Trying to sign in with the wrong username using scratchr2 navbar', t => { }); test('Trying to sign in with the wrong password using scratchr2 navbar', t => { - clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + clickCss('.dropdown-toggle') + .then(() => findByCss('form#login input#login_dropdown_username')) .then((element) => element.sendKeys(username)) - .then(() => findByXpath('//input[@name="password"]')) + .then(() => findByCss('form#login input.wide.password')) .then((element) => element.sendKeys('nonsensepassword')) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) + .then(() => clickCss('form#login button')) + .then(() => findByCss('form#login .error')) + .then((element) => { + driver.wait(until.elementIsVisible(element)); + return element; + }) .then((element) => element.getText()) .then((text) => t.match(text, 'Incorrect username or password.', '"Incorrect username or password" error should be displayed')) From 881c2affa462cad3c66bb238ccbcce579a8e4c4d Mon Sep 17 00:00:00 2001 From: Andrew Sliwinski Date: Mon, 21 May 2018 15:55:21 -0400 Subject: [PATCH 12/32] Update privacy policy --- src/views/privacypolicy/privacypolicy.jsx | 561 ++++++++++++++++------ 1 file changed, 406 insertions(+), 155 deletions(-) diff --git a/src/views/privacypolicy/privacypolicy.jsx b/src/views/privacypolicy/privacypolicy.jsx index ea988dda7..0db9ca512 100644 --- a/src/views/privacypolicy/privacypolicy.jsx +++ b/src/views/privacypolicy/privacypolicy.jsx @@ -9,213 +9,464 @@ const Privacypolicy = () => (
    +

    + + The Scratch Privacy Policy was last updated: May 23, 2018 + +

    - We made Scratch so people like you could create projects, - share ideas, and build a community. To make this happen, - we collect some information for our users. The Scratch Team - understands how important privacy is to our community, - especially kids and parents. We wrote this privacy policy - to explain what information we collect, how we use it, - and what we're doing to keep it safe. If you have any - questions regarding this privacy policy, you can{' '} - contact us. + Scratch understands how important privacy is to our + community, especially kids and parents. We wrote this + Privacy Policy to explain what information we collect + through our website (scratch.mit.edu) (the “Site”), how we + use, process, and share it, and what we're doing to keep it + safe. It also tells you about your rights and choices with + respect to your information, and how you can{' '} + contact us if you have any + questions or concerns.

    - Please do not share personal contact information, such as - your name, physical address, email address, phone number, - or anything else that can be used to make contact outside - of the Scratch website. Please report projects, comments, - or forum posts that contain this kind of information so - the Scratch team can remove it, and please remind the - author of our policy. + If you would like to build projects with Scratch without + submitting any Personal Information to us, you can download + the Scratch Offline Editor. Projects + created in the Scratch Offline Editor + {' '}are not accessible by the Scratch Team, and using the + offline editor does not disclose any personally identifying + information to Scratch unless you upload these projects to + the Scratch online community.

    -

    What information does the Scratch Team collect about me?

    -
    Account Information:
    +

    What personal information does the Scratch Team collect about me?

    +

    + For the purpose of this Privacy Policy, “Personal + Information” means any information relating to an + identified or identifiable individual. We obtain + Personal Information relating to you from various + sources described below. +

    +

    + Where applicable, we indicate whether and why you must + provide us with your Personal Information, as well as + the consequences of failing to do so. If you do not + provide Personal Information when requested, you may not + be able to benefit from our Site if that information is + necessary to provide you with the service or if we are + legally required to collect the information. +

    +
    Account Information
    - In order to build projects or comment on other users' projects, - you need to make an account. During account creation, we ask you - for a username, your country, birth month and year, gender, and - your email address (or your parent or guardian's email address if - you are under 13 years old). We ask that you select a user name - that does not disclose your real name or other information that - could identify you. Other users can see your username and country, - but not your age, gender, or email address. + In order to share projects, create studios, or post + comments, you need to make an account. During account + creation, we ask you for a username, your country, birth + month and year, gender, and your email address (or your + parent or guardian's email address if you are under 16 + years old). We ask that you select a username that does + not disclose your real name or other information that + could identify you. Other users can see your username + and country, but not your age, gender, or email address.
    -
    User-generated Content:
    +
    User-generated Content
    - All of your Scratch projects, comments, and forum posts are stored - on the Scratch servers. Other users can see your shared projects, - comments, and forum posts, along with your username. Because the - Scratch Team is responsible for moderation, we have access to all - content stored on the Scratch website, including unshared projects. - If you prefer to work on projects in complete privacy, you can use - either the Scratch 2{' '} - or Scratch 1.4 offline editor. + We collect any information that you provide to us when + you create Scratch projects (including unshared + projects), write comments, or post on our forums.
    -
    Usage Information:
    +
    Communications
    - When you use Scratch, our servers will automatically store a limited - amount of information about how you use the website. This information - includes a number that identifies your computer (the IP address), which - pages you visited, and what browser you are using. + If you contact us directly, we may receive additional + information about you. For example, when you contact our + Customer Support Team, we may receive your name, email + address, phone number, the contents of a message or + attachments that you may send to us, and other + information you choose to provide.
    -
    Google Analytics:
    +
    + Personal Information We Collect Automatically From Your + Use of the Site +
    - We also collect some data on where you click and which parts of the - site you visit using Google Analytics. This "click data" helps us figure - out ways to improve the website. Information collected and processed by - Google Analytics includes the user's IP address, network location, and - geographic location. Google Analytics acquires all its information - directly from the user, by installing a cookie (see below) on your - computer, if you have enabled JavaScript. Scratch does not share any - information it collects with Google, and Google does not collect any - personal identifying information about you. + When you use Scratch, we and our third-party service + providers collect information about you and your device + through automated means, such as cookies and web server + logs. By using Scratch, you consent to the placement of + cookies and similar technologies in your browser in + accordance with this Privacy Policy. The information + collected in this manner includes your IP address, + network location, what browser you are using, device IDs + and characteristics, operating system version, language + preferences, referring URLs, and information about the + usage of our site.
    -
    Cookies:
    - When you log in, the Scratch website asks your browser to put an http - "cookie" on your computer. The cookie is actually a small text file - that our site can send to your browser for storage on your computer. - This allows the website to remember that you are logged in when you - go to a different page. + We use this information, for example, to ensure that the + site functions properly, to determine how many users + have visited certain pages, or to prevent fraud. We use + IP address information to derive your approximate + location. We also work with analytics providers, such + as Google Analytics, which use cookies and similar + technologies to collect and analyze information about + use of the site and report on activities and trends. + These services may also collect information about the + use of other websites, apps, and online resources. You + can learn more about Google’s practices by going to{' '} + + https://www.google.com/policies/privacy/partners/. +
    +
    + If you do not want information collected through the use + of cookies, most browsers allow you to automatically + decline cookies or be given the choice of declining or + accepting the transfer to your computer of a particular + cookie (or cookies) from a particular site. You may also + wish to refer to{' '} + + http://www.allaboutcookies.org/manage-cookies/index.html. + If, however, you do not accept cookies, you may + experience some inconvenience in your use of Scratch.
    +
    + +

    How does the Scratch Team use my personal information?

    +

    +
    Internal and Service-Related Usage
    +
    + We use Personal Information for internal and Site-related + purposes, including to operate, provide, and maintain the + Site. +
    +
    Analytics and Improving the Site
    +
    + We and our service providers use Personal Information + that we collect on the Site, such as your location and + your activities on the Site, to monitor and analyze + usage of the Site and to improve and enhance the Site. +
    +
    Communications
    +
    + We may send emails to an email address you provide to us + for customer-service or technical-support purposes, to + send you information about topics or content that we + think may interest you, or updates about the latest + developments or features on the Site. We may also send a + newsletter to the email address you provide to us if you + subscribe to receive the newsletter. Parents and + guardians who register their under-16 year olds for + Scratch may also receive additional updates from the + Scratch Foundation, a non-profit that supports Scratch + educational initiatives. +
    +
    Aggregate Data
    +
    + We may de-identify and aggregate information collected + through the Site for statistical analysis and other + lawful purpose, including in research studies intended + to improve our understanding of how people learn with + Scratch. The results of this research are shared with + educators and researchers through conferences, journals, + and other publications. You can find out more on our{' '} + Research page. +
    +
    Legal
    +
    + We may use your Personal Information to enforce our{' '} + Terms of Use, to defend our + legal rights, and to comply with our legal obligations + and internal policies. We moderate all content posted to + Scratch, including unshared projects, comments, and + forum posts. +
    +
    + If you are located in the European Economic Area, we + only process your Personal Information based on a valid + legal ground, including when: +
    +
      +
    • + You have consented to the use of your Personal + Information, for example, to receive electronic + marketing communications; +
    • +
    • + We need your Personal Information to provide our + services, including for account registration, to + respond to your inquiries, or for customer support; +
    • +
    • + We have a legal obligation to use your Personal + Information; or +
    • +
    • + We or a third party have a legitimate interest in + using your Personal Information. In particular, we + have a legitimate interest in using your Personal + Information to personalize our services and provide + you with tailored content, conduct business + analytics, and otherwise improve the safety, + security, and performance of our Site. We only rely + on our or a third party’s legitimate interests to + process your Personal Information when these + interests are not overridden by your rights and + interests. +
    • +
    +
    +
    +
    -

    How does the Scratch Team use my information?

    +

    How Does Scratch Share my Personal Information?

    +

    + We disclose information that we collect through the Site to + third parties in the following circumstances: +

    • - We collect age and gender data so that we know who is using our - website. + To third-party service providers who provide services + such as website hosting, data analysis, information + technology and related infrastructure provisions, + customer service, email delivery, and other services.
    • - If you forget your password, we will ask you to disclose to us - your birth month and year so that we can verify your account, and - your email address so that we can send you a new password. + We may also disclose your Personal Information with your + permission. We may seek your permission in various ways. + For example, we may present you with an “opt-in” prompt + when you register to use the Site or access certain + content.
    • - We will use your email address to respond to messages you send us - or to communicate with you about the Scratch service or your account. + To a potential or actual acquirer, successor, or + assignee as part of any reorganization, merger, sale, + joint venture, assignment, transfer, or other + disposition of all or any portion of our organization or + assets. You will have the opportunity to opt out of any + such transfer if the new entity’s planned processing of + your information differs materially from that set forth + in this Privacy Policy.
    • - We send out occasional email updates about Scratch to the confirmed - email address on your account. Scratch will never sell or share your - email address without your permission. You can unsubscribe from these - updates by clicking the unsubscribe link found at the bottom of the - email. -
    • -
    • - Parents and guardians who register their under-13 year olds for - Scratch may also receive additional updates from the{' '} - Scratch Foundation, - a non-profit that supports Scratch educational initiatives. - The Scratch Foundation will never sell or share your email - address without your permission. You can unsubscribe from these - updates by clicking the unsubscribe link found at the bottom of - the email. -
    • -
    • - If we detect repeated abusive behavior from your account, IP address, - or email address, we may share your account name, IP address, and the - time and content of the abusive behavior with the IP address owner - (such as a school or internet service provider). -
    • -
    • - We may use de-identified location, age, gender, and usage data - in research studies intended to improve our understanding of - how people learn with Scratch. The results of this research are - shared with educators and researchers through conferences, - journals, and other publications. You can find out more on our{' '} - Research page. -
    • -
    • - We may disclose some of the information we collect to third-party - service providers that help us manage communications to and from - the Scratch website and improve website performance. We are - satisfied that these service providers have privacy policies that - restrict them from further disclosing any of your information. -
    • -
    • - Other than as described above, we will never share personally - identifiable information about you with any other person, - company, or organization, except: -
        -
      • - As required to comply with our obligations under the law. -
      • -
      • - For technical reasons, if we are required to transfer the - data on our servers to another location or organization. -
      • -
      -
    • -
    • - Scratch reserves the right to share user information with the - appropriate authorities (including schools, school districts, - and law enforcement, when necessary) for the purposes of protecting - the safety of users, other individuals, or the security of the site. + If required to do so by law or in the good faith belief + that such action is appropriate: (a) under applicable + law, including laws outside your country of residence; + (b) to comply with legal process; (c) to respond to + requests from public and government authorities, such + as school, school districts, and law enforcement, + including public and government authorities outside your + country of residence; (d) to enforce our terms and + conditions; (e) to protect our operations or those of + any of our affiliates; (f) to protect our rights, + privacy, safety, or property, and/or that of our + affiliates, you, or others; and (g) to allow us to + pursue available remedies or limit the damages that we + may sustain.
    -
    +
    -

    How can I update my personal information?

    +

    Third Party Services

    - You can update your password, email address, and country through - the Account Settings page. - You can also reset your password through the{' '} - Account Reset{' '} - page. You cannot change your username, but you can make a new - account and manually copy your projects to the new account. + This Privacy Policy applies only to the processing of your + Personal Information by Scratch. It does not address, and we + are not responsible for, the privacy, information, or other + practices of any third parties, including any third party + operating any site or service to which the Site links. The + inclusion of a link on the Site does not imply endorsement + of the linked site or service by us or by our affiliates.

    +
    +
    + +

    Your Rights and Choices

    +

    +
    +
    Updating Your Information
    +
    + You can update your password, email address, and country + through the Account + Settings page. You can also reset your password + through the Account + Reset page. You cannot change your username, but you + can make a new account and manually copy your projects + to the new account. +
    +
    + If you want to delete your account, login to Scratch, + and then click your username in the top right-hand + corner. Select "Account Settings," then click the "I + want to delete my account" link at the bottom of the + page. Deleting your account hides all information from + public view, but does not remove all of your information + from our servers. If you want to have all of your + information removed from our servers, please contact + help@scratch.mit.edu for assistance. +
    +
    Marketing Communications
    +
    + If you decide at any time that you no longer wish to + receive marketing communications from us, please follow + the unsubscribe instructions provided in any of the + communications. You may also opt out from receiving + email from us by sending your request to us by email at + help@scratch.mit.edu. Please be aware that, even after + you opt out from receiving marketing communications from + us, you may continue to receive administrative messages + from us regarding the Site. +
    +
    Your Data Protection Rights (EEA)
    +
    + In certain jurisdictions, you have the right to request + access and receive information about the Personal + Information we maintain about you, to update and correct + inaccuracies in your Personal Information, to restrict + or object to the processing of your Personal + Information, to have the information blocked, + anonymized, or deleted, as appropriate, or to exercise + your right to data portability to easily transfer your + Personal Information to another company. Those rights + may be limited in some circumstances by local law + requirements. In addition to the above-mentioned rights, + you also have the right to lodge a complaint with a + competent supervisory authority subject to applicable + law. +
    +
    + Where required by law, we obtain your consent for the + processing of certain Personal Information collected by + cookies or similar technologies, or used to send you + direct marketing communications, or when we carry out + other processing activities for which consent may be + required. If we rely on consent for the processing of + your Personal Information, you have the right to + withdraw it at any time and free of charge. When you do + so, this will not affect the lawfulness of the + processing before your consent withdrawal. +
    +
    + To update your preferences, ask us to remove your + information from our mailing lists, or submit a request + to exercise your rights under applicable law, please + contact us as specified in the “How to Contact Us” + section below. +
    +
    +
    +
    + +

    Data Retention

    - If you want to delete your account entirely, log in to Scratch, - and then click your username in the top right-hand corner. Select - "Account Settings," then click the "I want to delete my account" - link at the bottom of the page. + We take measures to delete your Personal Information or keep + it in a form that does not allow you to be identified when + this information is no longer necessary for the purposes for + which we process it, unless we are required by law to keep + this information for a longer period. When determining the + retention period, we take into account various criteria, + such as the type of services requested by or provided to + you, the nature and length of our relationship with you, + possible re-enrolment with our services, the impact on the + services we provide to you if we delete some information + from or about you, mandatory retention periods provided by + law and the statute of limitations.

    -

    How does the Scratch Team protect my information?

    +

    How does the Scratch Team protect my personal information?

    - The Scratch Team has in place physical and electronic procedures - to protect the information we collect on the Scratch website. We - strictly limit individual access to the Scratch servers and the - data we store on them. However, as effective as these measures - are, no security system is impenetrable. We cannot completely - guarantee the security of our database, nor can we guarantee that - the information you supply will not be intercepted while being - transmitted to us over the Internet. + The Scratch Team has in place administrative, physical, and + technical procedures that are intended to protect the + information we collect on the Scratch website against + accidental or unlawful destruction, accidental loss, + unauthorized alteration, unauthorized disclosure or access, + misuse, and any other unlawful form of processing of the + Personal Information in our possession. For example, we + strictly limit access to the Scratch servers and the data we + store on them. However, as effective as these measures are, + no security system is impenetrable. We cannot completely + guarantee the security of our databases, nor can we + guarantee that the information you supply will not be + intercepted while being transmitted to us over the Internet.

    -

    Notifications of Changes to the Privacy Policy

    +

    Notifications of changes to the Privacy Policy

    - We review our security measures and Privacy Policy on a periodic - basis, and we may modify our policies as appropriate. We may also - change or update our Privacy Policy if we add new services or - features. If we make any changes to our privacy practices, we will - amend this Privacy Policy accordingly and post the amended policy - on the Scratch website. We encourage you to review our Privacy - Policy on a regular basis. + We review our security measures and Privacy Policy on a + periodic basis, and we may modify our policies as + appropriate. If we make material changes, we will notify you + through the Site or by sending you an email or other + communication. We encourage you to review our Privacy Policy + on a regular basis. The “Last Updated” date at the top of + this page indicates when this Privacy Policy was last + revised. Your continued use of the Site following these + changes means that you accept the revised Privacy Policy. +

    +
    +
    + +

    International Cross-Border Data Transfer

    +

    + Scratch is based in the United States. Personal Information + that we collect may be transferred to, and stored at, any of + our affiliates, partners, or service providers which may be + inside or outside the European Economic Area, including the + United States. By submitting your personal data, you agree + to such transfers. +

    +
    +
    + +

    What can I do to help protect privacy on Scratch?

    +

    + Please do not share personal contact information (such as + your name, physical address, email address, or phone number) + in projects, comments, profiles, studios, or forum posts. + Please let us know if you see this kind of information by + using the “Report” link which appears on the page. It is + also important that you maintain the security and control + of your account credentials, and not share your password + with anyone. +

    +
    +
    + +

    Contact Us

    +

    + The Code-to-Learn Foundation d/b/a The Scratch Foundation is + the entity responsible for the processing of your Personal + Information. If you have any questions about this Privacy + Policy, or if you would like to exercise your rights to your + Personal Information, you may contact us at{' '} + help@scratch.mit.edu or + via mail at: +

    +

    + Scratch Foundation
    + ATTN: Privacy Policy
    + 7315 Wisconsin Ave.
    + 4th Floor West
    + Bethesda, MD 20814

    -

    The Scratch Privacy Policy was last updated: November 2016

    From d78d78e1fa9660b892b060cafb610c4be306df5e Mon Sep 17 00:00:00 2001 From: Andrew Sliwinski Date: Mon, 21 May 2018 15:55:42 -0400 Subject: [PATCH 13/32] Update default 'opt-in' state for teacher registration --- src/components/registration/steps.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/registration/steps.jsx b/src/components/registration/steps.jsx index b97960df6..4f090a8e0 100644 --- a/src/components/registration/steps.jsx +++ b/src/components/registration/steps.jsx @@ -1246,6 +1246,7 @@ class EmailStep extends React.Component { value help={null} name="subscribe" + value={false} valueLabel={ this.props.intl.formatMessage({id: 'registration.optIn'}) } From 88e99e655bb0bc0a0b503420601f8f4cf77e19d7 Mon Sep 17 00:00:00 2001 From: Andrew Sliwinski Date: Mon, 21 May 2018 17:04:50 -0400 Subject: [PATCH 14/32] Resolve lint issues --- src/components/registration/steps.jsx | 1 - src/views/privacypolicy/privacypolicy.jsx | 38 +++++++++++------------ 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/components/registration/steps.jsx b/src/components/registration/steps.jsx index 4f090a8e0..a1d752f99 100644 --- a/src/components/registration/steps.jsx +++ b/src/components/registration/steps.jsx @@ -1243,7 +1243,6 @@ class EmailStep extends React.Component { validations="equalsField:user.email" /> ( Scratch understands how important privacy is to our community, especially kids and parents. We wrote this Privacy Policy to explain what information we collect - through our website (scratch.mit.edu) (the “Site”), how we - use, process, and share it, and what we're doing to keep it - safe. It also tells you about your rights and choices with - respect to your information, and how you can{' '} + through our website (scratch.mit.edu) (the "Site"), + how we use, process, and share it, and what we're doing + to keep it safe. It also tells you about your rights and + choices with respect to your information, and how you can{' '} contact us if you have any questions or concerns.

    @@ -62,8 +62,8 @@ const Privacypolicy = () => ( comments, you need to make an account. During account creation, we ask you for a username, your country, birth month and year, gender, and your email address (or your - parent or guardian's email address if you are under 16 - years old). We ask that you select a username that does + parent or guardian's email address if you are under + 16 years old). We ask that you select a username that does not disclose your real name or other information that could identify you. Other users can see your username and country, but not your age, gender, or email address. @@ -133,7 +133,7 @@ const Privacypolicy = () => (

    How does the Scratch Team use my personal information?

    -

    +

    Internal and Service-Related Usage
    We use Personal Information for internal and Site-related @@ -282,7 +282,7 @@ const Privacypolicy = () => (

    Your Rights and Choices

    -

    +

    Updating Your Information
    @@ -297,13 +297,13 @@ const Privacypolicy = () => (
    If you want to delete your account, login to Scratch, and then click your username in the top right-hand - corner. Select "Account Settings," then click the "I - want to delete my account" link at the bottom of the - page. Deleting your account hides all information from - public view, but does not remove all of your information - from our servers. If you want to have all of your - information removed from our servers, please contact - help@scratch.mit.edu for assistance. + corner. Select "Account Settings," then click + the "I want to delete my account" link at the + bottom of the page. Deleting your account hides all + information from public view, but does not remove all of + your information from our servers. If you want to have + all of your information removed from our servers, please + contact help@scratch.mit.edu for assistance.
    Marketing Communications
    @@ -446,10 +446,10 @@ const Privacypolicy = () => ( via mail at:

    - Scratch Foundation
    - ATTN: Privacy Policy
    - 7315 Wisconsin Ave.
    - 4th Floor West
    + Scratch Foundation
    + ATTN: Privacy Policy
    + 7315 Wisconsin Ave.
    + 4th Floor West
    Bethesda, MD 20814

    From 495d9e117798ff314126db9c72fc9b43fdda4b69 Mon Sep 17 00:00:00 2001 From: Andrew Sliwinski Date: Tue, 22 May 2018 09:24:36 -0400 Subject: [PATCH 15/32] Fix typo --- src/views/privacypolicy/privacypolicy.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/privacypolicy/privacypolicy.jsx b/src/views/privacypolicy/privacypolicy.jsx index f65f16af1..6ae2cb680 100644 --- a/src/views/privacypolicy/privacypolicy.jsx +++ b/src/views/privacypolicy/privacypolicy.jsx @@ -456,7 +456,7 @@ const Privacypolicy = () => (