diff --git a/.gitignore b/.gitignore
index 780d8dd9321..75a79012578 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,3 +157,5 @@ bld/
tsdoc-metadata.json
*.dmp
+**/errorShots
+**/appium.txt
\ No newline at end of file
diff --git a/change/react-native-windows-2020-04-23-16-03-11-treedumpRNTester.json b/change/react-native-windows-2020-04-23-16-03-11-treedumpRNTester.json
new file mode 100644
index 00000000000..3361a6f6115
--- /dev/null
+++ b/change/react-native-windows-2020-04-23-16-03-11-treedumpRNTester.json
@@ -0,0 +1,8 @@
+{
+ "type": "prerelease",
+ "comment": "RNTester visual tests",
+ "packageName": "react-native-windows",
+ "email": "asklar@winse.microsoft.com",
+ "dependentChangeType": "patch",
+ "date": "2020-04-23T23:03:11.029Z"
+}
diff --git a/packages/playground/dist/wdio/pages/BasePage.d.ts b/packages/playground/dist/wdio/pages/BasePage.d.ts
new file mode 100644
index 00000000000..5284bab4318
--- /dev/null
+++ b/packages/playground/dist/wdio/pages/BasePage.d.ts
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+///
+export declare function By(testId: string): WebdriverIO.Element;
+export declare function wait(timeout: number): Promise;
+export declare class BasePage {
+ isPageLoaded(): boolean;
+ waitForPageLoaded(timeout?: number): void;
+ protected timeoutForPageLoaded(currentTimeout?: number): number;
+ protected get loadButton(): WebdriverIO.Element;
+ private get reactControlErrorMessage();
+ private isPagedLoadedOrLoadBundleError;
+ private waitforPageTimeout;
+}
diff --git a/packages/playground/dist/wdio/pages/BasePage.js b/packages/playground/dist/wdio/pages/BasePage.js
new file mode 100644
index 00000000000..a3ad193b30e
--- /dev/null
+++ b/packages/playground/dist/wdio/pages/BasePage.js
@@ -0,0 +1,79 @@
+"use strict";
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+// import {
+// REACT_CONTROL_ERROR_TEST_ID,
+// HOME_BUTTON,
+// TREE_DUMP_RESULT,
+// } from '../../app/Consts';
+Object.defineProperty(exports, "__esModule", { value: true });
+const REACT_CONTROL_ERROR_TEST_ID = 'ReactControlErrorMessage';
+function By(testId) {
+ return $('~' + testId);
+}
+exports.By = By;
+function wait(timeout) {
+ return new Promise(resolve => {
+ setTimeout(resolve, timeout);
+ });
+}
+exports.wait = wait;
+class BasePage {
+ constructor() {
+ // private get treeDumpResult() {
+ // return By(TREE_DUMP_RESULT);
+ // }
+ // Default timeout for waitForPageLoaded command in PageObject
+ this.waitforPageTimeout = 10000;
+ }
+ isPageLoaded() {
+ return this.loadButton.isDisplayed();
+ }
+ waitForPageLoaded(timeout) {
+ browser.waitUntil(() => {
+ return this.isPagedLoadedOrLoadBundleError();
+ }, this.timeoutForPageLoaded(timeout), 'Wait for page ' + this.constructor.name + ' timeout');
+ }
+ // getTreeDumpResult() {
+ // var testResult = false;
+ // const maxWait = 20;
+ // var waitCount = 1;
+ // do {
+ // testResult = this.treeDumpResult.getText() == 'TreeDump:Passed';
+ // if (!testResult) {
+ // console.log(
+ // '####Waiting for treedump comparison result ' +
+ // waitCount +
+ // '/' +
+ // maxWait +
+ // '...####'
+ // );
+ // wait(100);
+ // waitCount += 1;
+ // }
+ // } while (waitCount <= maxWait && !testResult);
+ // return testResult;
+ // }
+ timeoutForPageLoaded(currentTimeout) {
+ if (currentTimeout)
+ return currentTimeout;
+ return this.waitforPageTimeout;
+ }
+ get loadButton() {
+ return By('x_LoadButton');
+ }
+ get reactControlErrorMessage() {
+ return By(REACT_CONTROL_ERROR_TEST_ID);
+ }
+ isPagedLoadedOrLoadBundleError() {
+ if (this.reactControlErrorMessage.isDisplayed()) {
+ throw "ReactControl doesn't load bundle successfully: " +
+ this.reactControlErrorMessage.getText();
+ }
+ return this.isPageLoaded();
+ }
+}
+exports.BasePage = BasePage;
+//# sourceMappingURL=BasePage.js.map
\ No newline at end of file
diff --git a/packages/playground/dist/wdio/pages/BasePage.js.map b/packages/playground/dist/wdio/pages/BasePage.js.map
new file mode 100644
index 00000000000..485aa396cb0
--- /dev/null
+++ b/packages/playground/dist/wdio/pages/BasePage.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"BasePage.js","sourceRoot":"","sources":["../../../wdio/pages/BasePage.ts"],"names":[],"mappings":";AAAA;;;GAGG;AACH,WAAW;AACX,iCAAiC;AACjC,iBAAiB;AACjB,sBAAsB;AACtB,6BAA6B;;AAE7B,MAAM,2BAA2B,GAAG,0BAA0B,CAAC;AAE/D,SAAgB,EAAE,CAAC,MAAc;IAC/B,OAAO,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;AACzB,CAAC;AAFD,gBAEC;AAED,SAAgB,IAAI,CAAC,OAAe;IAClC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAJD,oBAIC;AAED,MAAa,QAAQ;IAArB;QA0DE,iCAAiC;QACjC,iCAAiC;QACjC,IAAI;QAEJ,8DAA8D;QACtD,uBAAkB,GAAW,KAAK,CAAC;IAC7C,CAAC;IA/DC,YAAY;QACV,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAED,iBAAiB,CAAC,OAAgB;QAChC,OAAO,CAAC,SAAS,CACf,GAAG,EAAE;YACH,OAAO,IAAI,CAAC,8BAA8B,EAAE,CAAC;QAC/C,CAAC,EACD,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAClC,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,UAAU,CACtD,CAAC;IACJ,CAAC;IAED,wBAAwB;IACxB,4BAA4B;IAC5B,wBAAwB;IACxB,uBAAuB;IACvB,SAAS;IACT,uEAAuE;IACvE,yBAAyB;IACzB,qBAAqB;IACrB,0DAA0D;IAC1D,wBAAwB;IACxB,kBAAkB;IAClB,sBAAsB;IACtB,sBAAsB;IACtB,WAAW;IACX,mBAAmB;IACnB,wBAAwB;IACxB,QAAQ;IACR,mDAAmD;IAEnD,uBAAuB;IACvB,IAAI;IAEM,oBAAoB,CAAC,cAAuB;QACpD,IAAI,cAAc;YAAE,OAAO,cAAc,CAAC;QAC1C,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,IAAc,UAAU;QACtB,OAAO,EAAE,CAAC,cAAc,CAAC,CAAC;IAC5B,CAAC;IAED,IAAY,wBAAwB;QAClC,OAAO,EAAE,CAAC,2BAA2B,CAAC,CAAC;IACzC,CAAC;IAEO,8BAA8B;QACpC,IAAI,IAAI,CAAC,wBAAwB,CAAC,WAAW,EAAE,EAAE;YAC/C,MAAM,iDAAiD;gBACrD,IAAI,CAAC,wBAAwB,CAAC,OAAO,EAAE,CAAC;SAC3C;QACD,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;CAQF;AAhED,4BAgEC"}
\ No newline at end of file
diff --git a/packages/playground/dist/wdio/pages/HomePage.d.ts b/packages/playground/dist/wdio/pages/HomePage.d.ts
new file mode 100644
index 00000000000..7289f301ab7
--- /dev/null
+++ b/packages/playground/dist/wdio/pages/HomePage.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+import { BasePage } from './BasePage';
+declare class HomePage extends BasePage {
+ loadRNTester(): void;
+}
+declare const _default: HomePage;
+export default _default;
diff --git a/packages/playground/dist/wdio/pages/HomePage.js b/packages/playground/dist/wdio/pages/HomePage.js
new file mode 100644
index 00000000000..8a3a4819dbb
--- /dev/null
+++ b/packages/playground/dist/wdio/pages/HomePage.js
@@ -0,0 +1,28 @@
+"use strict";
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+const BasePage_1 = require("./BasePage");
+// import TextInputTestPage from './TextInputTestPage';
+// import {
+// TEXTINPUT_TESTPAGE,
+// LOGIN_TESTPAGE,
+// DIRECT_MANIPULATION_TESTPAGE,
+// IMAGE_TESTPAGE,
+// CONTROL_STYLE_TESTPAGE,
+// TRANSFORM_TESTPAGE,
+// } from '../../app/Consts';
+// import LoginPage from './LoginPage';
+// import DirectManipulationPage from './DirectManipulationPage';
+// import ImageTestPage from './ImageTestPage';
+// import ControlStyleTestPage from './ControlStylePage';
+class HomePage extends BasePage_1.BasePage {
+ loadRNTester() {
+ this.loadButton.click();
+ this.waitForPageLoaded();
+ }
+}
+exports.default = new HomePage();
+//# sourceMappingURL=HomePage.js.map
\ No newline at end of file
diff --git a/packages/playground/dist/wdio/pages/HomePage.js.map b/packages/playground/dist/wdio/pages/HomePage.js.map
new file mode 100644
index 00000000000..ee94c54d775
--- /dev/null
+++ b/packages/playground/dist/wdio/pages/HomePage.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"HomePage.js","sourceRoot":"","sources":["../../../wdio/pages/HomePage.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAEH,yCAA8C;AAC9C,uDAAuD;AACvD,WAAW;AACX,wBAAwB;AACxB,oBAAoB;AACpB,kCAAkC;AAClC,oBAAoB;AACpB,4BAA4B;AAC5B,wBAAwB;AACxB,6BAA6B;AAC7B,uCAAuC;AACvC,iEAAiE;AACjE,+CAA+C;AAC/C,yDAAyD;AAEzD,MAAM,QAAS,SAAQ,mBAAQ;IAC7B,YAAY;QACV,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;CA2DF;AAED,kBAAe,IAAI,QAAQ,EAAE,CAAC"}
\ No newline at end of file
diff --git a/packages/playground/dist/wdio/test/Image.spec.d.ts b/packages/playground/dist/wdio/test/Image.spec.d.ts
new file mode 100644
index 00000000000..a8f94049193
--- /dev/null
+++ b/packages/playground/dist/wdio/test/Image.spec.d.ts
@@ -0,0 +1,5 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+export {};
diff --git a/packages/playground/dist/wdio/test/Image.spec.js b/packages/playground/dist/wdio/test/Image.spec.js
new file mode 100644
index 00000000000..f538a31cc11
--- /dev/null
+++ b/packages/playground/dist/wdio/test/Image.spec.js
@@ -0,0 +1,50 @@
+"use strict";
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const HomePage_1 = __importDefault(require("../pages/HomePage"));
+const BasePage_1 = require("../pages/BasePage");
+// import ImageTestPage from '../pages/ImageTestPage';
+const assert_1 = __importDefault(require("assert"));
+beforeAll(() => {
+ HomePage_1.default.loadRNTester();
+ HomePage_1.default.waitForPageLoaded();
+ // HomePage.clickAndGotoImagePage();
+});
+describe('basicTest', () => {
+ it('basicTest', () => {
+ const treedump = BasePage_1.By('x_TreeDump');
+ const text = treedump.getValue();
+ assert_1.default(text == 'fail', `text = ${text}`);
+ });
+});
+// describe('ImageWithoutBorderTest', () => {
+// /* Test case #1: view and image displayed with no border and cornerRadius */
+// it('ImageWithoutBorderTest', () => {
+// const result = ImageTestPage.getTreeDumpResult();
+// assert(result, '#1. Dump comparison for image without border!');
+// });
+// /* Test case #2: Click button once, update view and image with round border*/
+// it('ImageWithBorderTest', () => {
+// ImageTestPage.toggleImageBorder();
+// const result = ImageTestPage.getTreeDumpResult();
+// assert(result, '#2. Dump comparison for image with border!');
+// });
+// /* Test case #3: Click button one more, remove border from view and image but tree sturcture is different from #1*/
+// it('ImageWithoutBorderTest', () => {
+// ImageTestPage.toggleImageBorder();
+// const result = ImageTestPage.getTreeDumpResult();
+// assert(result, '#3. Second dump comparison for image without border!');
+// });
+// it('ImageRTLTest', () => {
+// ImageTestPage.toggleRTLMode();
+// const result = ImageTestPage.getTreeDumpResult();
+// assert(result, '#4. Dump comparison for image RTL');
+// });
+// });
+//# sourceMappingURL=Image.spec.js.map
\ No newline at end of file
diff --git a/packages/playground/dist/wdio/test/Image.spec.js.map b/packages/playground/dist/wdio/test/Image.spec.js.map
new file mode 100644
index 00000000000..8870a0b4c57
--- /dev/null
+++ b/packages/playground/dist/wdio/test/Image.spec.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"Image.spec.js","sourceRoot":"","sources":["../../../wdio/test/Image.spec.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAEH,iEAAyC;AACzC,gDAAuC;AACvC,sDAAsD;AACtD,oDAA4B;AAE5B,SAAS,CAAC,GAAG,EAAE;IACb,kBAAQ,CAAC,YAAY,EAAE,CAAC;IACxB,kBAAQ,CAAC,iBAAiB,EAAE,CAAC;IAC7B,oCAAoC;AACtC,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;QACnB,MAAM,QAAQ,GAAG,aAAE,CAAC,YAAY,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACjC,gBAAM,CAAC,IAAI,IAAI,MAAM,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AACH,6CAA6C;AAC7C,iFAAiF;AACjF,yCAAyC;AACzC,wDAAwD;AACxD,uEAAuE;AACvE,QAAQ;AAER,kFAAkF;AAClF,sCAAsC;AACtC,yCAAyC;AACzC,wDAAwD;AACxD,oEAAoE;AACpE,QAAQ;AAER,wHAAwH;AACxH,yCAAyC;AACzC,yCAAyC;AACzC,wDAAwD;AACxD,8EAA8E;AAC9E,QAAQ;AAER,+BAA+B;AAC/B,qCAAqC;AACrC,wDAAwD;AACxD,2DAA2D;AAC3D,QAAQ;AACR,MAAM"}
\ No newline at end of file
diff --git a/packages/playground/just-task.js b/packages/playground/just-task.js
index ad9f3c8a1b8..a72c1058850 100644
--- a/packages/playground/just-task.js
+++ b/packages/playground/just-task.js
@@ -5,7 +5,7 @@
* @ts-check
*/
-const {task, series, eslintTask} = require('just-scripts');
+const {task, series, eslintTask, argv, tscTask} = require('just-scripts');
task('eslint', () => {
return eslintTask();
@@ -16,3 +16,16 @@ task('eslint:fix', () => {
task('lint', series('eslint'));
task('lint:fix', series('eslint:fix'));
+
+task('ts', () => {
+ return tscTask({
+ pretty: true,
+ ...(argv().production && {
+ inlineSources: true,
+ }),
+ target: 'es6',
+ module: 'commonjs',
+ });
+});
+
+task('build', series('ts'));
\ No newline at end of file
diff --git a/packages/playground/package.json b/packages/playground/package.json
index 99dffded717..4c1f834ef76 100644
--- a/packages/playground/package.json
+++ b/packages/playground/package.json
@@ -3,12 +3,14 @@
"version": "0.0.54",
"private": true,
"scripts": {
+ "build": "just-scripts build",
"start": "react-native start",
"lint:fix": "just-scripts lint:fix",
"lint": "just-scripts lint",
"windows": "react-native run-windows"
},
"dependencies": {
+ "chalk": "^4.0.0",
"react": "16.9.0",
"react-native": "0.62.2",
"react-native-windows": "0.0.0-master.46"
@@ -16,11 +18,28 @@
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/runtime": "^7.8.4",
+ "@types/jasmine": "2.8.7",
+ "@types/jquery": "^3.3.35",
+ "@types/node": "^10.14.8",
"@types/react": "16.9.0",
"@types/react-native": "^0.62.2",
+ "@wdio/appium-service": "5.12.1",
+ "@wdio/cli": "5.12.1",
+ "@wdio/dot-reporter": "5.12.1",
+ "@wdio/jasmine-framework": "5.12.1",
+ "@wdio/junit-reporter": "5.12.1",
+ "@wdio/local-runner": "5.12.1",
+ "@wdio/sync": "5.12.1",
+ "appium": "1.14.1",
"just-scripts": "^0.36.1",
"metro-react-native-babel-preset": "^0.56.0",
+ "prettier": "^1.18.2",
"react-test-renderer": "16.9.0",
- "@react-native-community/eslint-config": "^1.0.0"
+ "rimraf": "^3.0.0",
+ "ts-node": "^7.0.1",
+ "tsconfig-paths": "^3.8.0",
+ "typescript": "^3.8.3",
+ "webdriver": "git+https://github.com/react-native-windows/webdriver.git",
+ "webdriverio": "5.12.1"
}
}
diff --git a/packages/playground/run_wdio.js b/packages/playground/run_wdio.js
new file mode 100644
index 00000000000..8ab95e3d1a0
--- /dev/null
+++ b/packages/playground/run_wdio.js
@@ -0,0 +1,150 @@
+const path = require('path');
+const fs = require('fs');
+const xml2js = require('xml2js');
+const parser = new xml2js.Parser({ attrkey: 'ATTR' });
+const child_process = require('child_process');
+const prompt = require('prompt-sync')();
+const chalk = require('chalk');
+
+const specFolder = 'wdio/test';
+
+function GetMetadata(specPath) {
+ const contents = fs.readFileSync(specPath);
+ const metadataTag = '// @metadata ';
+ const metadataStart = contents.indexOf(metadataTag);
+ if (metadataStart != -1) {
+ let metadata = contents
+ .toString()
+ .substr(metadataStart + metadataTag.length)
+ .split(/[\r\n]/)[0];
+ return metadata.split(' ');
+ }
+ return [];
+}
+
+const filters = {
+ SkipCI: specPath => {
+ return process.env.BUILD_QUEUEDBY == 'GitHub';
+ },
+};
+
+// Returns true if the spec is to run.
+// Specs marked SkipCI are excluded from CI (identified by environment variables in the ADO lab)
+function FilterSpec(specPath) {
+ const metadata = GetMetadata(specPath);
+ for (let i = 0; i < metadata.length; i++) {
+ if (filters[metadata[i]](specPath)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function SelectSpecs(folder) {
+ let specs = [];
+ if (process.argv.length > 2) {
+ specs = process.argv.splice(2).map(spec => spec + '.spec.ts');
+ } else {
+ specs = fs.readdirSync(folder).filter(x => x.endsWith('.spec.ts'));
+ }
+ specs = specs.map(spec => path.join(folder, spec)).filter(FilterSpec);
+ return specs;
+}
+
+let opts = SelectSpecs(specFolder);
+console.log(`Selected tests: ${opts}`);
+
+function OverrideHyperV() {
+ const baseboardMfr = child_process
+ .execSync('powershell.exe (gwmi Win32_BaseBoard).Manufacturer')
+ .toString()
+ .replace(/[\r\n]/, '');
+ if (!baseboardMfr.startsWith('Microsoft Corporation')) {
+ console.log(`Not running in HyperV. Mfr = ${baseboardMfr}`);
+ const answer = prompt(
+ 'E2ETest is meant to be run in a HyperV VM. Continue? (Y/N)'
+ );
+ if (answer.toUpperCase() != 'Y') {
+ process.exit(0);
+ }
+ }
+}
+
+// OverrideHyperV();
+
+const Launcher = require('@wdio/cli').default;
+
+const wdio = new Launcher('wdio.conf.js', { specs: opts });
+
+function parseLog(logfile) {
+ const xmlString = fs.readFileSync(logfile);
+ let failures = {};
+ parser.parseString(xmlString, (err, res) => {
+ if (!res.testsuites) {
+ failures = 'something went wrong';
+ } else {
+ for (let i = 0; i < res.testsuites.testsuite.length; i++) {
+ const attr = res.testsuites.testsuite[i].ATTR;
+ if (attr.errors > 0 || attr.failures > 0) {
+ let name = attr.name;
+ failures[name] = {};
+ const testcases = res.testsuites.testsuite[i].testcase;
+ for (let j = 0; j < testcases.length; j++) {
+ if (testcases[j].error && testcases[j].error[0].ATTR) {
+ failures[name].testcase = testcases[j].ATTR.name;
+ failures[name].error = testcases[j].error[0].ATTR.message;
+ const systemErr = testcases[j]['system-err'][0];
+ const stack = systemErr.substr(systemErr.indexOf('\n at ') + 1);
+ failures[name].stack = stack;
+ }
+ }
+ }
+
+ }
+ }
+ });
+ return failures;
+}
+
+function parseLogs() {
+ const reportsDir = path.join(__dirname, 'reports');
+ const logs = fs.readdirSync(reportsDir).filter(x => x.endsWith('.log'));
+ const names = logs
+ .map(x => parseLog(path.join(reportsDir, x)))
+ .filter(x => x != null);
+ return names;
+}
+
+function PrintFailedTests(ft) {
+ for (let i = 0; i < Object.keys(ft).length; i++) {
+ const key = Object.keys(ft)[i];
+ console.log(chalk.redBright(key));
+ console.log(' ', chalk.underline('testcase'), chalk.bold(ft[key].testcase));
+ console.log(' ', chalk.underline('error'), chalk.bold(ft[key].error));
+ console.log(' ', chalk.underline('stack'));
+ console.log(ft[key].stack);
+ }
+}
+
+function Process(code) {
+ const failedTests = parseLogs();
+ for (let i = 0; i < failedTests.length; i++) {
+ console.log('Failed tests: ');
+ PrintFailedTests(failedTests[i]);
+ }
+ process.exit(code);
+}
+
+function RunWdio() {
+ wdio.run().then(
+ code => {
+ Process(code);
+ },
+ error => {
+ console.error('Launcher failed to start the test', error.stacktrace);
+ process.exit(1);
+ }
+ );
+}
+
+RunWdio();
diff --git a/packages/playground/tsconfig.json b/packages/playground/tsconfig.json
index 16e778a02f9..54c59dd48cb 100644
--- a/packages/playground/tsconfig.json
+++ b/packages/playground/tsconfig.json
@@ -4,18 +4,29 @@
"target": "es6",
"module": "commonjs",
"jsx": "react",
- "outDir": ".",
+ "outDir": "dist",
"declaration": true,
"sourceMap": true,
- "experimentalDecorators": true,
"noEmitOnError": true,
"skipLibCheck": true,
"moduleResolution": "node",
+ "noEmit": false,
"noUnusedLocals": true,
"strict": true,
- "noEmit": true,
- "rootDir": "."
+ "rootDir": ".",
+ "esModuleInterop": true,
+ "types": [
+ "@wdio/sync",
+ "@wdio/jasmine-framework",
+ "@types/jasmine",
+ "node"
+ ]
},
- "include": ["."],
- "exclude": ["node_modules"]
-}
+ "include": [
+ "app",
+ "wdio"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/packages/playground/wdio.conf.js b/packages/playground/wdio.conf.js
new file mode 100644
index 00000000000..0c6df2f66ce
--- /dev/null
+++ b/packages/playground/wdio.conf.js
@@ -0,0 +1,291 @@
+const baseUrl = 'https://webdriver.io';
+
+exports.config = {
+ //
+ // ====================
+ // Runner Configuration
+ // ====================
+ //
+ // WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
+ // on a remote machine).
+ runner: 'local',
+ //
+ // =====================
+ // Server Configurations
+ // =====================
+ // Host address of the running Selenium server. This information is usually obsolete as
+ // WebdriverIO automatically connects to localhost. Also, if you are using one of the
+ // supported cloud services like Sauce Labs, Browserstack, or Testing Bot you don't
+ // need to define host and port information because WebdriverIO can figure that out
+ // according to your user and key information. However, if you are using a private Selenium
+ // backend you should define the host address, port, and path here.
+ //
+ // hostname: '172.18.5.185',
+ // port: 4444,
+ // path: '/wd/hub',
+
+ //
+ // ==================
+ // Specify Test Files
+ // ==================
+ // Define which test specs should run. The pattern is relative to the directory
+ // from which `wdio` was called. Notice that, if you are calling `wdio` from an
+ // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working
+ // directory is where your package.json resides, so `wdio` will be called from there.
+ //
+ specs: [
+ 'wdio/test/**/*.ts',
+ ],
+ // Patterns to exclude.
+ exclude: [
+ // 'path/to/excluded/files'
+ ],
+ //
+ // ============
+ // Capabilities
+ // ============
+ // Define your capabilities here. WebdriverIO can run multiple capabilities at the same
+ // time. Depending on the number of capabilities, WebdriverIO launches several test
+ // sessions. Within your capabilities you can overwrite the spec and exclude options in
+ // order to group specific specs to a specific capability.
+ //
+ // First, you can define how many instances should be started at the same time. Let's
+ // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
+ // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
+ // files and you set maxInstances to 10, all spec files will get tested at the same time
+ // and 30 processes will get spawned. The property handles how many capabilities
+ // from the same test should run tests.
+ //
+ maxInstances: 1,
+ //
+ // If you have trouble getting all important capabilities together, check out the
+ // Sauce Labs platform configurator - a great tool to configure your capabilities:
+ // https://docs.saucelabs.com/reference/platforms-configurator
+ //
+ capabilities: [
+ {
+ // maxInstances can get overwritten per capability. So if you have an in-house Selenium
+ // grid with only 5 firefox instances available you can make sure that not more than
+ // 5 instances get started at a time.
+ maxInstances: 1,
+ //
+ platformName: 'windows',
+ // For W3C the appium capabilities need to have an extension prefix
+ // http://appium.io/docs/en/writing-running-appium/caps/
+ // This is `appium:` for all Appium Capabilities which can be found here
+ 'appium:deviceName': 'WindowsPC',
+ 'appium:app': 'a752ebd1-71f2-4731-af80-c81e1782cc2b_gg9qsjdrgpss6!App',
+ 'deviceName': 'WindowsPC',
+ 'app': 'RNWPlayground_gg9qsjdrgpss6!App',
+ 'winAppDriver:experimental-w3c': true,
+ },
+ // {
+ // // maxInstances can get overwritten per capability. So if you have an in house Selenium
+ // // grid with only 5 firefox instance available you can make sure that not more than
+ // // 5 instance gets started at a time.
+ // maxInstances: 5,
+ // browserName: 'firefox',
+ // // specs: [
+ // // 'test/ffOnly/*'
+ // // ],
+ // "moz:firefoxOptions": {
+ // // flag to activate Firefox headless mode (see https://github.com/mozilla/geckodriver/blob/master/README.md#firefox-capabilities for more details about moz:firefoxOptions)
+ // // args: ['-headless']
+ // }
+ // }
+ ],
+ //
+ // ===================
+ // Test Configurations
+ // ===================
+ // Define all options that are relevant for the WebdriverIO instance here
+ //
+ // Level of logging verbosity: trace | debug | info | warn | error
+ logLevel: 'trace',
+ //
+ // Warns when a deprecated command is used
+ deprecationWarnings: true,
+ //
+ // If you only want to run your tests until a specific amount of tests have failed use
+ // bail (default is 0 - don't bail, run all tests).
+ bail: 0,
+ //
+ // Set a base URL in order to shorten url command calls. If your `url` parameter starts
+ // with `/`, the base url gets prepended, not including the path portion of your baseUrl.
+ // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
+ // gets prepended directly.
+ baseUrl: baseUrl,
+ //
+ // Default timeout for all waitFor* commands.
+ waitforTimeout: 10000,
+ //
+ // Default timeout in milliseconds for request
+ // if Selenium Grid doesn't send response
+ connectionRetryTimeout: 90000,
+ //
+ // Default request retries count
+ connectionRetryCount: 1,
+
+ port: 4723,
+ //
+ // Test runner services
+ // Services take over a specific job you don't want to take care of. They enhance
+ // your test setup with almost no effort. Unlike plugins, they don't add new
+ // commands. Instead, they hook themselves up into the test process.
+ services: ['appium'],
+ appium: {
+ logPath: './reports/',
+ args: {
+ port: '4723',
+ },
+ },
+
+ //
+ // Framework you want to run your specs with.
+ // The following are supported: Mocha, Jasmine, and Cucumber
+ // see also: https://webdriver.io/docs/frameworks.html
+ //
+ // Make sure you have the wdio adapter package for the specific framework installed
+ // before running any tests.
+ framework: 'jasmine',
+ //
+ // Test reporter for stdout.
+ // The only one supported by default is 'dot'
+ // see also: https://webdriver.io/docs/dot-reporter.html
+ reporters: ['dot', ['junit', { outputDir : '.\\reports' }]],
+
+ //
+ // Options to be passed to Mocha.
+ // See the full list at http://mochajs.org/
+ mochaOpts: {
+ ui: 'bdd',
+ timeout: 60000,
+ compilers: [
+ // 'ts-node/register',
+ 'tsconfig-paths/register',
+ ],
+ },
+
+ jasmineNodeOpts: {
+ defaultTimeoutInterval: 60000,
+ },
+
+ //
+ // =====
+ // Hooks
+ // =====
+ // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
+ // it and to build services around it. You can either apply a single function or an array of
+ // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
+ // resolved to continue.
+ /**
+ * Gets executed once before all workers get launched.
+ * @param {Object} config wdio configuration object
+ * @param {Array.