Merge pull request #584 from paulkaplan/selenium-with-jest

Add end-to-end testing using selenium-webdriver
This commit is contained in:
Paul Kaplan authored and GitHub committed 2017-08-11 10:27:49 -04:00
commit d0fc523f6b
7 files changed
+170 -8

No files matched your search

+1
View File
@@ -1,6 +1,7 @@
{
"plugins": [
"syntax-dynamic-import",
"transform-async-to-generator",
"transform-object-rest-spread",
["react-intl", {
"messagesDir": "./translations/messages/"
+5
View File
@@ -1,6 +1,11 @@
language: node_js
sudo: false
dist: trusty
addons:
chrome: stable
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
node_js:
- 6
cache:
+6 -1
View File
@@ -31,7 +31,7 @@ Then go to [http://localhost:8601/](http://localhost:8601/) - the playground out
## Testing
NOTE: If you're a windows user, please run these scripts in Windows `cmd.exe` instead of Git Bash/MINGW64.
Run linter, unit tests, and build.
Run linter, unit tests, build, and integration tests.
```bash
npm test
```
@@ -46,6 +46,11 @@ Run unit tests in watch mode (watches for code changes and continuously runs tes
npm run unit-test -- --watch
```
Run integration tests in isolation.
```bash
npm run integration-test
```
You may want to review the documentation for [Jest](https://facebook.github.io/jest/docs/en/api.html) and [Enzyme](http://airbnb.io/enzyme/docs/api/) as you write your tests.
## Publishing to GitHub Pages
+6 -2
View File
@@ -11,8 +11,9 @@
"i18n:src": "babel src > tmp.js && rimraf tmp.js && ./scripts/build-i18n-source.js ./translations/messages/ ./translations/",
"lint": "eslint . --ext .js,.jsx",
"start": "npm run i18n:msgs && webpack-dev-server",
"unit-test": "jest",
"test": "npm run lint && npm run unit-test && npm run build",
"unit-test": "jest test/unit",
"integration-test": "npm run build && jest test/integration",
"test": "npm run lint && npm run unit-test && npm run integration-test",
"watch": "webpack --progress --colors --watch"
},
"author": "Massachusetts Institute of Technology",
@@ -34,9 +35,11 @@
"babel-loader": "^7.0.0",
"babel-plugin-react-intl": "2.3.1",
"babel-plugin-syntax-dynamic-import": "6.18.0",
"babel-plugin-transform-async-to-generator": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.22.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"chromedriver": "^2.31.0",
"classnames": "2.2.5",
"copy-webpack-plugin": "4.0.1",
"css-loader": "0.28.3",
@@ -83,6 +86,7 @@
"scratch-render": "latest",
"scratch-storage": "^0.2.0",
"scratch-vm": "latest",
"selenium-webdriver": "^3.5.0",
"style-loader": "^0.18.0",
"svg-to-image": "1.1.3",
"svg-url-loader": "2.1.0",
+5 -5
View File
@@ -7717,7 +7717,7 @@
109,
32
],
"md5": "4cddf35440090d30d4de188625d609c9.svg",
"md5": "0a54c19714962c197532f68c56fde123.svg",
"type": "costume",
"name": "text awesome",
"tags": [
@@ -7731,7 +7731,7 @@
135,
24
],
"md5": "6f54c5de1985d7f23a24341e1688c4b0.svg",
"md5": "97c9e6ef78d4f1987fd8c6e5042963cb.svg",
"type": "costume",
"name": "text keep scratching",
"tags": [
@@ -7745,7 +7745,7 @@
172,
30
],
"md5": "e634628e4b948573710f7e4a4f50659b.svg",
"md5": "9fde2e190a9d01c08737dff291bdd4a8.svg",
"type": "costume",
"name": "text valentine's day",
"tags": [
@@ -7759,7 +7759,7 @@
165,
34
],
"md5": "7ebe62c6f2b7c8b644d2abe036b8f69e.svg",
"md5": "0176a402a133f7b833da61b890e0d73e.svg",
"type": "costume",
"name": "text Halloween",
"tags": [
@@ -10629,4 +10629,4 @@
"vector"
]
}
]
]
+58
View File
@@ -0,0 +1,58 @@
/* eslint-env jest */
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; // eslint-disable-line no-undef
import webdriver from 'selenium-webdriver';
const {By, until} = webdriver;
const driver = new webdriver.Builder()
.forBrowser('chrome')
.build();
const findByXpath = (xpath) => {
return driver.wait(until.elementLocated(By.xpath(xpath), 5 * 1000));
};
const clickXpath = (xpath) => {
return findByXpath(xpath).then(el => el.click());
};
const clickText = (text) => {
return clickXpath(`//*[contains(text(), '${text}')]`);
};
const clickButton = (text) => {
return clickXpath(`//button[contains(text(), '${text}')]`);
};
const getLogs = (whitelist) => {
return driver.manage()
.logs()
.get('browser')
.then((entries) => {
return entries.filter((entry) => {
const message = entry.message;
for (let i = 0; i < whitelist.length; i++) {
if (message.indexOf(whitelist[i]) !== -1) {
// eslint-disable-next-line no-console
console.warn('Ignoring whitelisted error: ' + whitelist[i]);
return false;
} else if (entry.level !== 'SEVERE') {
// eslint-disable-next-line no-console
console.warn('Ignoring non-SEVERE entry: ' + message);
return false;
}
return true;
}
});
});
};
export {
clickText,
clickButton,
clickXpath,
driver,
findByXpath,
getLogs
};
+89
View File
@@ -0,0 +1,89 @@
/* eslint-env jest */
/* globals Promise */
import path from 'path';
import {
clickText,
clickButton,
clickXpath,
driver,
findByXpath,
getLogs
} from '../helpers/selenium-helpers';
const uri = path.resolve(__dirname, '../../build/index.html');
const errorWhitelist = [
'The play() request was interrupted by a call to pause()'
];
describe('costumes, sounds and variables', () => {
afterAll(async () => {
await driver.quit();
});
test('Adding a costume', async () => {
await driver.get('file://' + uri);
await clickText('Costumes');
await clickText('Add Costume');
const el = await findByXpath("//input[@placeholder='what are you looking for?']");
await el.sendKeys('abb');
await clickText('abby-a'); // Should close the modal, then click the costumes in the selector
await clickText('costume1');
await clickText('abby-a');
const logs = await getLogs(errorWhitelist);
await expect(logs).toEqual([]);
});
test('Adding a sound', async () => {
await driver.get('file://' + uri);
await clickText('Sounds');
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');
await clickText('chomp');
await clickXpath('//button[@title="Play"]');
await clickText('meow');
await clickXpath('//button[@title="Play"]');
await clickText('Louder');
await clickText('Softer');
await clickText('Faster');
await clickText('Slower');
await clickText('Robot');
await clickText('Echo');
await clickText('Reverse');
const logs = await getLogs(errorWhitelist);
await expect(logs).toEqual([]);
});
test('Load a project by ID', async () => {
const projectId = '96708228';
await driver.get('file://' + uri + '#' + projectId);
await new Promise(resolve => setTimeout(resolve, 2000));
await clickXpath('//img[@title="Go"]');
await new Promise(resolve => setTimeout(resolve, 2000));
await clickXpath('//img[@title="Stop"]');
const logs = await getLogs(errorWhitelist);
await expect(logs).toEqual([]);
});
test('Creating variables', async () => {
await driver.get('file://' + uri);
await clickText('Blocks');
await clickText('Data');
await clickText('Create variable...');
let el = await findByXpath("//input[@placeholder='']");
await el.sendKeys('score');
await clickButton('OK');
await clickText('Create variable...');
el = await findByXpath("//input[@placeholder='']");
await el.sendKeys('second variable');
await clickButton('OK');
const logs = await getLogs(errorWhitelist);
await expect(logs).toEqual([]);
});
});