mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-24 06:22:45 +08:00
feat(e2e-tests) simplify e2e test structure
This commit is contained in:
@ -25,7 +25,7 @@
|
||||
"scripts": {
|
||||
"build": "stencil build",
|
||||
"dev": "sd concurrent \"stencil build --dev --watch\" \"stencil-dev-server\"",
|
||||
"e2e": "node ./scripts/e2e.js",
|
||||
"e2e": "node ./scripts/run-e2e.js",
|
||||
"snapshot": "node ./scripts/e2e.js --snapshot",
|
||||
"test": "jest --no-cache",
|
||||
"test.watch": "jest --watch --no-cache",
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
The end-to-end testing scripts consist of the following modules:
|
||||
|
||||
1. `e2e` - the script that npm uses to kick this stuff off
|
||||
1. `e2e-test-runner` - the test controller and test utilities
|
||||
1. `e2e` - the test controller and test utilities
|
||||
1. `run-e2e` - the script that npm uses to kick this stuff off
|
||||
1. `E2ETestPage` - a base class for end-to-end tests
|
||||
1. `Snapshot` - the snapshot tool, copied from the `index.js` file in the [Snapshot Repo](https://github.com/ionic-team/snapshot) (private)
|
||||
|
||||
@ -13,21 +13,18 @@ Each end-to-end test file is NodeJS ES2015 script that contains at least one `de
|
||||
|
||||
In general, writing an end-to-end tests consists of the following steps:
|
||||
|
||||
1. create a `filename.e2e-spec.js` file
|
||||
1. extend the E2ETestPage class to perform the extra actions a page needs to do (if any)
|
||||
1. register each test you would like to run using the `register` method from the `e2e-test-runner` module, the `register` method takes two parameters: a test description and a callback function that contains the test, the callback is passed the selenium driver that is in use for the test
|
||||
1. create a `e2e.js` file
|
||||
1. extend the `Page` class to perform the extra actions a page needs to do (if any)
|
||||
1. register each test you would like to run using the `register` method from the `e2e` module, the `register` method takes two parameters: a test description and a callback function that contains the test, the callback is passed the selenium driver that is in use for the test
|
||||
|
||||
The most basic end-to-end test just navigates to the page in order to verify that it draws properly. In this case, it is not necessary to extend the E2ETestPage class. The base class contains a navigate method that goes to the page and waits for it to load. The test just needs to instantiate the page with the proper URL and call the navigate. Such a test looks like this:
|
||||
|
||||
```ts
|
||||
'use strict';
|
||||
|
||||
const register = require('../../../../scripts/e2e-test-runner').register;
|
||||
const E2ETestPage = require('../../../../scripts/E2ETestPage');
|
||||
const { register, Page } = require('../../../../scripts/e2e');
|
||||
|
||||
describe('button: basic', () => {
|
||||
register('navigates', driver => {
|
||||
const page = new E2ETestPage(driver, 'http://localhost:3333/src/components/button/test/basic.html');
|
||||
const page = new Page(driver, 'http://localhost:3333/src/components/button/test/basic/index.html');
|
||||
return page.navigate();
|
||||
});
|
||||
});
|
||||
@ -36,18 +33,12 @@ describe('button: basic', () => {
|
||||
For more complicated tests, it may be necessary to extend the base E2ETestPage class to add perform more actions that can then be used in the tests. Such a test may look like this:
|
||||
|
||||
```ts
|
||||
'use strict';
|
||||
const { By, until } = require('selenium-webdriver');
|
||||
const { register, Page } = require('../../../../scripts/e2e');;
|
||||
|
||||
const webdriver = require('selenium-webdriver');
|
||||
const By = webdriver.By;
|
||||
const until = webdriver.until;
|
||||
|
||||
const register = require('../../../../scripts/e2e-test-runner').register;
|
||||
const E2ETestPage = require('../../../../scripts/E2ETestPage');
|
||||
|
||||
class ActionSheetE2ETestPage extends E2ETestPage {
|
||||
class ActionSheetE2ETestPage extends Page {
|
||||
constructor(driver) {
|
||||
super(driver, 'http://localhost:3333/src/components/action-sheet/test/basic.html');
|
||||
super(driver, 'http://localhost:3333/src/components/action-sheet/test/basic/index.html');
|
||||
}
|
||||
|
||||
present(buttonId) {
|
||||
|
@ -1,129 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const glob = require('glob');
|
||||
const Mocha = require('mocha');
|
||||
const path = require('path');
|
||||
const webdriver = require('selenium-webdriver');
|
||||
|
||||
const Snapshot = require('./Snapshot');
|
||||
|
||||
let driver;
|
||||
let snapshot;
|
||||
let specIndex = 0;
|
||||
let takeScreenshots = false;
|
||||
|
||||
function startDevServer() {
|
||||
const server = require('@stencil/dev-server/dist'); // TODO: fix after stencil-dev-server PR #16 is merged
|
||||
const cmdArgs = ['--config', path.join(__dirname, '../stencil.config.js'), '--no-open'];
|
||||
|
||||
return server.run(cmdArgs);
|
||||
}
|
||||
|
||||
function generateTestId() {
|
||||
let chars = 'abcdefghjkmnpqrstuvwxyz';
|
||||
let id = chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
chars += '0123456789';
|
||||
while (id.length < 3) {
|
||||
id += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function getTestFiles() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const src = path.join(__dirname, '../src/**/*.e2e-spec.js');
|
||||
glob(src, (err, files) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(files);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function processCommandLine() {
|
||||
process.argv.forEach(arg => {
|
||||
if (arg === '--snapshot') {
|
||||
takeScreenshots = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function registerE2ETest(desc, tst) {
|
||||
// NOTE: Do not use an arrow function here because: https://mochajs.org/#arrow-functions
|
||||
it(desc, async function() {
|
||||
await tst(driver);
|
||||
if (takeScreenshots) {
|
||||
await snapshot.takeScreenshot(driver, {
|
||||
name: this.test.fullTitle(),
|
||||
specIndex: specIndex++
|
||||
});
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
function getTotalTests(suite) {
|
||||
let ttl = suite.tests.length;
|
||||
suite.suites.forEach(s => (ttl += getTotalTests(s)));
|
||||
return ttl;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const mocha = new Mocha({
|
||||
timeout: 5000,
|
||||
slow: 2000
|
||||
});
|
||||
|
||||
driver = new webdriver.Builder().forBrowser('chrome').build();
|
||||
|
||||
processCommandLine();
|
||||
|
||||
const devServer = await startDevServer();
|
||||
|
||||
const files = await getTestFiles();
|
||||
files.forEach(f => mocha.addFile(f));
|
||||
mocha.loadFiles(() => {
|
||||
specIndex = 0;
|
||||
|
||||
snapshot = new Snapshot({
|
||||
groupId: 'ionic-core',
|
||||
appId: 'snapshots',
|
||||
testId: generateTestId(),
|
||||
domain: 'ionic-snapshot-go.appspot.com',
|
||||
// domain: 'localhost:8080',
|
||||
sleepBetweenSpecs: 750,
|
||||
totalSpecs: getTotalTests(mocha.suite),
|
||||
platformDefaults: {
|
||||
browser: 'chrome',
|
||||
platform: 'linux',
|
||||
params: {
|
||||
platform_id: 'chrome_400x800',
|
||||
platform_index: 0,
|
||||
platform_count: 1,
|
||||
width: 400,
|
||||
height: 800
|
||||
}
|
||||
},
|
||||
accessKey: process.env.IONIC_SNAPSHOT_KEY
|
||||
});
|
||||
|
||||
mocha.run(function(failures) {
|
||||
process.on('exit', function() {
|
||||
process.exit(failures); // exit with non-zero status if there were failures
|
||||
});
|
||||
if (takeScreenshots) {
|
||||
snapshot.finish();
|
||||
}
|
||||
devServer.close();
|
||||
driver.quit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
register: registerE2ETest,
|
||||
run: run
|
||||
};
|
@ -1,3 +1,131 @@
|
||||
'use strict';
|
||||
|
||||
require('./e2e-test-runner').run();
|
||||
const fs = require('fs');
|
||||
const glob = require('glob');
|
||||
const Mocha = require('mocha');
|
||||
const path = require('path');
|
||||
const webdriver = require('selenium-webdriver');
|
||||
|
||||
const Page = require('./E2ETestPage');
|
||||
const Snapshot = require('./Snapshot');
|
||||
|
||||
let driver;
|
||||
let snapshot;
|
||||
let specIndex = 0;
|
||||
let takeScreenshots = false;
|
||||
|
||||
function startDevServer() {
|
||||
const server = require('@stencil/dev-server/dist'); // TODO: fix after stencil-dev-server PR #16 is merged
|
||||
const cmdArgs = ['--config', path.join(__dirname, '../stencil.config.js'), '--no-open'];
|
||||
|
||||
return server.run(cmdArgs);
|
||||
}
|
||||
|
||||
function generateTestId() {
|
||||
let chars = 'abcdefghjkmnpqrstuvwxyz';
|
||||
let id = chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
chars += '0123456789';
|
||||
while (id.length < 3) {
|
||||
id += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function getTestFiles() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const src = path.join(__dirname, '../src/**/e2e.js');
|
||||
glob(src, (err, files) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(files);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function processCommandLine() {
|
||||
process.argv.forEach(arg => {
|
||||
if (arg === '--snapshot') {
|
||||
takeScreenshots = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function registerE2ETest(desc, tst) {
|
||||
// NOTE: Do not use an arrow function here because: https://mochajs.org/#arrow-functions
|
||||
it(desc, async function() {
|
||||
await tst(driver);
|
||||
if (takeScreenshots) {
|
||||
await snapshot.takeScreenshot(driver, {
|
||||
name: this.test.fullTitle(),
|
||||
specIndex: specIndex++
|
||||
});
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
function getTotalTests(suite) {
|
||||
let ttl = suite.tests.length;
|
||||
suite.suites.forEach(s => (ttl += getTotalTests(s)));
|
||||
return ttl;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const mocha = new Mocha({
|
||||
timeout: 5000,
|
||||
slow: 2000
|
||||
});
|
||||
|
||||
driver = new webdriver.Builder().forBrowser('chrome').build();
|
||||
|
||||
processCommandLine();
|
||||
|
||||
const devServer = await startDevServer();
|
||||
|
||||
const files = await getTestFiles();
|
||||
files.forEach(f => mocha.addFile(f));
|
||||
mocha.loadFiles(() => {
|
||||
specIndex = 0;
|
||||
|
||||
snapshot = new Snapshot({
|
||||
groupId: 'ionic-core',
|
||||
appId: 'snapshots',
|
||||
testId: generateTestId(),
|
||||
domain: 'ionic-snapshot-go.appspot.com',
|
||||
// domain: 'localhost:8080',
|
||||
sleepBetweenSpecs: 750,
|
||||
totalSpecs: getTotalTests(mocha.suite),
|
||||
platformDefaults: {
|
||||
browser: 'chrome',
|
||||
platform: 'linux',
|
||||
params: {
|
||||
platform_id: 'chrome_400x800',
|
||||
platform_index: 0,
|
||||
platform_count: 1,
|
||||
width: 400,
|
||||
height: 800
|
||||
}
|
||||
},
|
||||
accessKey: process.env.IONIC_SNAPSHOT_KEY
|
||||
});
|
||||
|
||||
mocha.run(function(failures) {
|
||||
process.on('exit', function() {
|
||||
process.exit(failures); // exit with non-zero status if there were failures
|
||||
});
|
||||
if (takeScreenshots) {
|
||||
snapshot.finish();
|
||||
}
|
||||
devServer.close();
|
||||
driver.quit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Page,
|
||||
register: registerE2ETest,
|
||||
run: run
|
||||
};
|
||||
|
3
packages/core/scripts/run-e2e.js
Normal file
3
packages/core/scripts/run-e2e.js
Normal file
@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
require('./e2e').run();
|
@ -1,15 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const webdriver = require('selenium-webdriver');
|
||||
const By = webdriver.By;
|
||||
const until = webdriver.until;
|
||||
const { By, until } = require('selenium-webdriver');
|
||||
const { register, Page } = require('../../../../../scripts/e2e');
|
||||
|
||||
const register = require('../../../../scripts/e2e-test-runner').register;
|
||||
const E2ETestPage = require('../../../../scripts/E2ETestPage');
|
||||
|
||||
class ActionSheetE2ETestPage extends E2ETestPage {
|
||||
class ActionSheetE2ETestPage extends Page {
|
||||
constructor(driver) {
|
||||
super(driver, 'http://localhost:3333/src/components/action-sheet/test/basic.html');
|
||||
super(driver, 'http://localhost:3333/src/components/action-sheet/test/basic/index.html');
|
||||
}
|
||||
|
||||
present(buttonId) {
|
Reference in New Issue
Block a user