Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2713b56

Browse files
authoredOct 4, 2018
feature: add jasmine support (#158)
* feature: add jasmine support
1 parent 3104475 commit 2713b56

30 files changed

+639
-323
lines changed
 

‎.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ node_modules
66
e2e/reports
77
.vscode
88
package-lock.json
9+
samples/reports
10+
!samples/jasmine.json
11+
!samples/mocha.opts
12+
!samples/config
13+
!samples/e2e-tsc/*.ts
14+
!samples/e2e-js/*.js
15+
!samples/e2e-tsc/tsconfig.json

‎.npmignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
/**/*.map
44
!/**/*.d.ts
55
samples/reports
6-
samples/e2e-tsc/*.js
7-
!samples/e2e-tsc/*.ts
6+
!samples/jasmine.json
7+
!samples/mocha.opts
8+
!samples/config
9+
!samples/e2e-ts/*.ts
10+
!samples/e2e-js/*.js
811
!samples/e2e-tsc/tsconfig.json
912
publish-next.js
1013
test-app

‎check-dev-deps.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const { basename, resolve } = require("path");
2+
const { existsSync, readFileSync } = require("fs");
3+
const childProcess = require("child_process");
4+
const appRootPath = require('app-root-path').toString();
5+
const packageJsonPath = resolve(appRootPath, "package.json");
6+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
7+
const isWin = /^win/.test(process.platform);
8+
9+
10+
const executeNpmInstall = (cwd, devDependenciesToInstall) => {
11+
let spawnArgs = [];
12+
let command = "";
13+
if (isWin) {
14+
command = "cmd.exe"
15+
spawnArgs = ["/c", "npm", "install"];
16+
} else {
17+
command = "npm"
18+
spawnArgs = ["install"];
19+
}
20+
21+
if (devDependenciesToInstall && devDependenciesToInstall.length > 0) {
22+
spawnArgs = ["install", "-D", ...devDependenciesToInstall];
23+
}
24+
25+
childProcess.spawnSync(command, spawnArgs, { cwd, stdio: "inherit" });
26+
}
27+
28+
if (basename(appRootPath) !== "nativescript-dev-appium") {
29+
const devDependencies = packageJson.devDependencies;
30+
const modulesPath = resolve(appRootPath, "node_modules");
31+
const devDependenciesToInstall = Object.keys(devDependencies).filter((name => !existsSync(resolve(modulesPath, name))));
32+
if (devDependenciesToInstall && devDependenciesToInstall.length > 0) {
33+
executeNpmInstall(appRootPath, devDependenciesToInstall)
34+
}
35+
}

‎lib/appium-driver.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ export class AppiumDriver {
276276
} catch (error) {
277277
console.log(error);
278278
console.log("Rety launching appium driver!");
279+
hasStarted = false;
280+
279281
if (error && error.message && error.message.includes("WebDriverAgent")) {
280282
const freePort = await findFreePort(100, args.wdaLocalPort);
281283
console.log("args.appiumCaps['wdaLocalPort']", freePort);
@@ -713,8 +715,6 @@ export class AppiumDriver {
713715
try {
714716
if (!this._args.attachToDebug) {
715717
await this._driver.quit();
716-
await this._driver.quit();
717-
await this._webio.quit();
718718
} else {
719719
await this._webio.detach();
720720
}
@@ -739,7 +739,7 @@ export class AppiumDriver {
739739
if (args.appiumCaps.platformName.toLowerCase() === Platform.IOS) {
740740
args.appiumCaps["useNewWDA"] = args.appiumCaps.useNewWDA;
741741
args.appiumCaps["wdaStartupRetries"] = 5;
742-
args.appiumCaps["shouldUseSingletonTestManager"] = args.appiumCaps.shouldUseSingletonTestManager;
742+
args.appiumCaps["shouldUseSingletonTestManager"] = args.appiumCaps.shouldUseSingletonTestManager;
743743

744744
// It looks we need it for XCTest (iOS 10+ automation)
745745
if (args.appiumCaps.platformVersion >= 10 && args.wdaLocalPort) {
@@ -878,7 +878,7 @@ export class AppiumDriver {
878878
* @param imageThreshold The degree of match for current search, on the scale between 0 and 1. Default 0.4
879879
*/
880880
public async findElementByImage(image: string, imageThreshold = 0.4) {
881-
await this._driver.updateSettings({imageMatchThreshold: imageThreshold});
881+
await this._driver.updateSettings({ imageMatchThreshold: imageThreshold });
882882
const imageName = addExt(image, AppiumDriver.pngFileExt);
883883
const pathExpectedImage = this.getExpectedImagePath(imageName);
884884

@@ -893,9 +893,9 @@ export class AppiumDriver {
893893
throw new Error(error);
894894
} finally {
895895
// reset setting to default value
896-
await this._driver.updateSettings({imageMatchThreshold: 0.4});
896+
await this._driver.updateSettings({ imageMatchThreshold: 0.4 });
897897
}
898-
898+
899899
return new UIElement(searchResult, this._driver, this._wd, this._webio, this._args, "elementByImage", imageAsBase64);
900900
}
901901
}

‎lib/appium-server.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ export class AppiumServer {
9393
}
9494

9595
return response;
96+
} else if (!this._args.attachToDebug) {
97+
return true;
9698
}
99+
100+
return false;
101+
97102
}
98103

99104
private startAppiumServer(logLevel: string, isSauceLab: boolean) {

‎lib/parser.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,26 +70,26 @@ const config = (() => {
7070
projectBinary: projectBinary,
7171
pluginRoot: pluginRoot,
7272
pluginBinary: pluginBinary,
73-
port: process.env["APPIUM_PORT"] || process.env.npm_config_port || options.port || 8300,
74-
wdaLocalPort: process.env["WDA_LOCAL_PORT"] || options.wdaLocalPort,
73+
port: options.port || process.env.npm_config_port || process.env["APPIUM_PORT"] || 8300,
74+
wdaLocalPort: options.wdaLocalPort || process.env.npm_config_wdaLocalPort || process.env["WDA_LOCAL_PORT"],
7575
testFolder: options.testFolder || process.env.npm_config_testFolder || "e2e",
7676
runType: options.runType || process.env.npm_config_runType,
77-
appiumCapsLocation: options.appiumCapsLocation || join(projectDir, options.testFolder, "config", options.capabilitiesName),
77+
appiumCapsLocation: options.appiumCapsLocation || process.env.npm_config_appiumCapsLocation || join(projectDir, options.testFolder, "config", options.capabilitiesName),
7878
isSauceLab: options.sauceLab || process.env.npm_config_sauceLab,
7979
verbose: options.verbose || process.env.npm_config_loglevel === "verbose",
8080
appPath: options.appPath || process.env.npm_config_appPath,
8181
storage: options.storage || process.env.npm_config_STORAGE || process.env.STORAGE,
82-
testReports: options.testReports || process.env.npm_config_TEST_REPORTS || process.env.TEST_REPORTS,
83-
reuseDevice: options.devMode ? true : options.reuseDevice || process.env.npm_config_REUSE_DEVICE || process.env.REUSE_DEVICE,
84-
devMode: options.devMode || process.env.npm_config_REUSE_APP,
82+
testReports: options.testReports || process.env.npm_config_testReports || process.env.TEST_REPORTS,
83+
devMode: options.devMode || process.env.npm_config_devMode || process.env.REUSE_APP,
84+
reuseDevice: options.devMode ? true : options.reuseDevice || process.env.npm_config_reuseDevice || process.env.REUSE_DEVICE,
8585
cleanApp: !options.devMode && options.cleanApp && !options.sauceLab && !options.ignoreDeviceController,
86-
ignoreDeviceController: options.ignoreDeviceController,
87-
path: options.path,
88-
relaxedSecurity: options.relaxedSecurity,
89-
attachToDebug: options.attachToDebug,
90-
sessionId: options.sessionId,
91-
startSession: options.startSession,
92-
capabilitiesName: options.capabilitiesName,
86+
ignoreDeviceController: options.ignoreDeviceController || process.env.npm_ignoreDeviceController,
87+
path: options.path || process.env.npm_path,
88+
relaxedSecurity: options.relaxedSecurity || process.env.npm_relaxedSecurity,
89+
attachToDebug: options.attachToDebug || process.env.npm_attachToDebug,
90+
sessionId: options.sessionId || process.env.npm_sessionId,
91+
startSession: options.startSession || process.env.npm_startSession,
92+
capabilitiesName: options.capabilitiesName || process.env.npm_capabilitiesName,
9393
imagesPath: options.imagesPath || process.env.npm_config_imagesPath
9494
};
9595

‎lib/utils.d.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ export declare function isFile(fullName: any): boolean;
1111
export declare function copy(src: any, dest: any, verbose: any): any;
1212
export declare function contains(source: any, check: any): boolean;
1313
export declare function searchFiles(folder: any, words: any, recursive?: boolean, files?: any[]): Array<string>;
14-
export declare function log(message: any, verbose: any): void;
15-
export declare function loglogOut(line: any, verbose: any): void;
16-
export declare function logErr(line: any, verbose: any): void;
1714
export declare function shutdown(processToKill: childProcess.ChildProcess, verbose: any): void;
1815
export declare function killPid(pid: any, verbose: any): void;
1916
export declare function waitForOutput(process: any, matcher: any, errorMatcher: any, timeout: any, verbose: any): Promise<boolean>;
@@ -45,7 +42,35 @@ export declare function getSessions(port: any, host?: string): Promise<{}>;
4542
export declare const prepareDevice: (args: INsCapabilities, deviceManager: IDeviceManager) => Promise<INsCapabilities>;
4643
export declare const prepareApp: (args: INsCapabilities) => Promise<INsCapabilities>;
4744
export declare const sessionIds: (port: any) => Promise<any[]>;
45+
export declare function encodeImageToBase64(path: any): string;
4846
export declare function logInfo(info: any, obj?: any): void;
4947
export declare function logWarn(info: any, obj?: any): void;
5048
export declare function logError(info: any, obj?: any): void;
51-
export declare function encodeImageToBase64(path: any): string;
49+
export declare function log(message: any, verbose: any): void;
50+
export declare const logColorized: (bgColor: ConsoleColor, frontColor: ConsoleColor, info: any) => void;
51+
declare enum ConsoleColor {
52+
Reset = "\u001B[0m",
53+
Bright = "\u001B[1m",
54+
Dim = "\u001B[2m",
55+
Underscore = "\u001B[4m",
56+
Blink = "\u001B[5m",
57+
Reverse = "\u001B[7m",
58+
Hidden = "\u001B[8m",
59+
FgBlack = "\u001B[30m",
60+
FgRed = "\u001B[31m",
61+
FgGreen = "\u001B[32m",
62+
FgYellow = "\u001B[33m",
63+
FgBlue = "\u001B[34m",
64+
FgMagenta = "\u001B[35m",
65+
FgCyan = "\u001B[36m",
66+
FgWhite = "\u001B[37m",
67+
BgBlack = "\u001B[40m",
68+
BgRed = "\u001B[41m",
69+
BgGreen = "\u001B[42m",
70+
BgYellow = "\u001B[43m",
71+
BgBlue = "\u001B[44m",
72+
BgMagenta = "\u001B[45m",
73+
BgCyan = "\u001B[46m",
74+
BgWhite = "\u001B[47m"
75+
}
76+
export {};

‎lib/utils.ts

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ export function fileExists(p) {
3535
return false;
3636
} catch (e) {
3737
if (e.code == 'ENOENT') {
38-
logErr("File does not exist. " + p, true);
38+
logError("File does not exist. " + p, true);
3939
return false;
4040
}
4141

42-
logErr("Exception fs.statSync (" + path + "): " + e, true);
42+
logError("Exception fs.statSync (" + path + "): " + e, true);
4343
throw e;
4444
}
4545
}
@@ -63,7 +63,7 @@ export function isFile(fullName) {
6363
return true;
6464
}
6565
} catch (e) {
66-
logErr(e.message, true);
66+
logError(e.message, true);
6767
return false;
6868
}
6969

@@ -156,24 +156,6 @@ export function searchFiles(folder, words, recursive: boolean = true, files = ne
156156
return files;
157157
}
158158

159-
export function log(message, verbose) {
160-
if (verbose) {
161-
console.log(message);
162-
}
163-
}
164-
165-
export function loglogOut(line, verbose) {
166-
if (verbose) {
167-
process.stdout.write(line);
168-
}
169-
}
170-
171-
export function logErr(line, verbose) {
172-
if (verbose) {
173-
process.stderr.write(line);
174-
}
175-
}
176-
177159
export function shutdown(processToKill: childProcess.ChildProcess, verbose) {
178160
try {
179161
if (processToKill && processToKill !== null) {
@@ -187,7 +169,7 @@ export function shutdown(processToKill: childProcess.ChildProcess, verbose) {
187169
console.log("Shut down!!!");
188170
}
189171
} catch (error) {
190-
logErr(error, verbose);
172+
logError(error, verbose);
191173
}
192174
}
193175

@@ -243,7 +225,7 @@ const getDeviceName = (args) => {
243225

244226
export function getStorageByDeviceName(args: INsCapabilities) {
245227
let storage = getStorage(args);
246-
if(args.imagesPath){
228+
if (args.imagesPath) {
247229
const segments = args.imagesPath.split(/[\/\\]+/);
248230
storage = path.join(storage, segments.join(path.sep));
249231
return storage;
@@ -589,6 +571,12 @@ export const sessionIds = async (port) => {
589571
return ids;
590572
}
591573

574+
export function encodeImageToBase64(path) {
575+
const bitmap = fs.readFileSync(path);
576+
// convert binary data to base64 encoded string
577+
return new Buffer(bitmap).toString('base64');
578+
}
579+
592580
export function logInfo(info, obj = undefined) {
593581
if (obj) {
594582
info += " " + JSON.stringify(obj);
@@ -610,10 +598,14 @@ export function logError(info, obj = undefined) {
610598
console.log(`${ConsoleColor.BgRed}%s${ConsoleColor.Reset}`, info);
611599
}
612600

613-
export function encodeImageToBase64(path) {
614-
const bitmap = fs.readFileSync(path);
615-
// convert binary data to base64 encoded string
616-
return new Buffer(bitmap).toString('base64');
601+
export function log(message, verbose) {
602+
if (verbose) {
603+
console.log(message);
604+
}
605+
}
606+
607+
export const logColorized = (bgColor: ConsoleColor, frontColor: ConsoleColor, info) => {
608+
console.log(`${ConsoleColor.BgYellow}${ConsoleColor.FgBlack}%s${ConsoleColor.Reset}`, info);
617609
}
618610

619611
enum ConsoleColor {

‎package.json

Lines changed: 53 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,56 @@
11
{
2-
"name": "nativescript-dev-appium",
3-
"version": "4.0.9",
4-
"description": "A NativeScript plugin to help integrate and run Appium tests",
5-
"author": "NativeScript",
6-
"license": "MIT",
7-
"main": "./index.js",
8-
"directories": {
9-
"lib": "./lib",
10-
"bin": "./bin"
11-
},
12-
"repository": {
13-
"type": "git",
14-
"url": "https://github.com/NativeScript/nativescript-dev-appium.git"
15-
},
16-
"keywords": [
17-
"nativescript",
18-
"appium",
19-
"test"
20-
],
21-
"maintainers": [
22-
{
23-
"name": "SvetoslavTsenov",
24-
"email": "tsenov@progress.com"
25-
}
26-
],
27-
"bin": {
28-
"nativescript-dev-appium": "./bin/nativescript-dev-appium",
29-
"ns-dev-appium": "./bin/nativescript-dev-appium",
30-
"ns-appium": "./bin/nativescript-dev-appium"
31-
},
32-
"dependencies": {
33-
"app-root-path": "~2.0.1",
34-
"blink-diff": "~1.0.13",
35-
"chai": "~4.1.0",
36-
"chai-as-promised": "~7.1.0",
37-
"frame-comparer": "^2.0.1",
38-
"glob": "7.1.0",
39-
"mobile-devices-controller": "~2.8.6",
40-
"mocha": "~5.1.0",
41-
"mocha-junit-reporter": "~1.17.0",
42-
"mocha-multi": "~1.0.0",
43-
"wd": "~1.10.3",
44-
"webdriverio": "~4.12.0",
45-
"yargs": "~8.0.2"
46-
},
47-
"devDependencies": {
48-
"@types/chai": "^4.1.3",
49-
"@types/mocha": "^5.2.0",
50-
"@types/node": "^8.10.13",
51-
"@types/webdriverio": "~4.8.4",
52-
"typescript": "^2.8.0"
53-
},
54-
"scripts": {
55-
"postinstall": "node ./postinstall.js",
56-
"prepare": "tsc",
57-
"watch": "tsc --watch"
2+
"name": "nativescript-dev-appium",
3+
"version": "4.0.9",
4+
"description": "A NativeScript plugin to help integrate and run Appium tests",
5+
"author": "NativeScript",
6+
"license": "MIT",
7+
"main": "./index.js",
8+
"directories": {
9+
"lib": "./lib",
10+
"bin": "./bin"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/NativeScript/nativescript-dev-appium.git"
15+
},
16+
"keywords": [
17+
"nativescript",
18+
"appium",
19+
"test"
20+
],
21+
"maintainers": [
22+
{
23+
"name": "SvetoslavTsenov",
24+
"email": "tsenov@progress.com"
5825
}
26+
],
27+
"bin": {
28+
"nativescript-dev-appium": "./bin/nativescript-dev-appium",
29+
"ns-dev-appium": "./bin/nativescript-dev-appium",
30+
"ns-appium": "./bin/nativescript-dev-appium"
31+
},
32+
"dependencies": {
33+
"app-root-path": "~2.0.1",
34+
"blink-diff": "~1.0.13",
35+
"chai": "~4.1.0",
36+
"chai-as-promised": "~7.1.0",
37+
"frame-comparer": "^2.0.1",
38+
"glob": "7.1.0",
39+
"mobile-devices-controller": "~2.8.6",
40+
"wd": "~1.10.3",
41+
"webdriverio": "~4.12.0",
42+
"yargs": "~8.0.2",
43+
"chalk": "^2.4.1",
44+
"figlet": "^1.2.0",
45+
"inquirer": "^6.2.0"
46+
},
47+
"devDependencies": {
48+
"@types/node": "10.11.4",
49+
"typescript": "^3.0.0"
50+
},
51+
"scripts": {
52+
"postinstall": "node ./postinstall.js",
53+
"prepare": "tsc",
54+
"watch": "tsc --watch"
55+
}
5956
}

‎postinstall.js

Lines changed: 218 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,62 @@ const {
88
statSync,
99
writeFileSync
1010
} = require("fs");
11+
1112
const { basename, resolve } = require("path");
12-
const childProcess = require("child_process");
1313
const appRootPath = require('app-root-path').toString();
1414

15-
const sampleTestsFolder = "samples";
16-
const e2eTests = "e2e";
17-
const sampleTestsProjectFolderPath = resolve(appRootPath, e2eTests);
18-
const sampleTestsPluginFolderPath = resolve(appRootPath, "node_modules", "nativescript-dev-appium", sampleTestsFolder);
15+
const inquirer = require("inquirer");
16+
const chalk = require("chalk");
17+
const figlet = require("figlet");
18+
19+
const jasmine = "jasmine";
20+
const mocha = "mocha";
21+
const none = "none";
22+
const js = "javascript";
23+
const tsc = "typescript";
24+
const ng = "angular"
25+
const vue = "vue"
26+
const sharedNg = "shared-ng-project"
27+
const sharedVue = "shared-vue-project"
28+
const projectTypes = `${tsc} | ${js} | ${ng} | ${vue} | ${sharedNg} | ${sharedVue}`;
29+
const testingFrameworks = `${mocha} | ${jasmine} | ${none}`;
30+
1931
const packageJsonPath = resolve(appRootPath, "package.json");
2032
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
2133

22-
const isTypeScriptProject =
23-
(packageJson.dependencies && packageJson.dependencies.hasOwnProperty("typescript"))
24-
|| (packageJson.devDependencies && packageJson.devDependencies.hasOwnProperty("typescript"));
25-
const isWin = /^win/.test(process.platform);
26-
27-
const executeNpmInstall = cwd => {
28-
let spawnArgs = [];
29-
let command = "";
30-
if (isWin) {
31-
command = "cmd.exe"
32-
spawnArgs = ["/c", "npm", "install"];
33-
} else {
34-
command = "npm"
35-
spawnArgs = ["install"];
34+
class Template {
35+
constructor(testingFramwork, projectType, storage, fileExt) {
36+
this._testingFramwork = testingFramwork;
37+
this._projectType = projectType;
38+
this._storage = storage;
39+
this._fileExt = fileExt;
40+
}
41+
42+
get testingFramwork() {
43+
return this._testingFramwork;
44+
}
45+
46+
get projectType() {
47+
return this._projectType;
48+
}
49+
50+
get storage() {
51+
return this._storage;
52+
}
53+
54+
get fileExt() {
55+
return this._fileExt;
3656
}
37-
childProcess.spawnSync(command, spawnArgs, { cwd, stdio: "inherit" });
3857
}
3958

4059
const copy = (src, dest) => {
4160
if (!existsSync(src)) {
4261
return Error("Source doesn't exist: " + src);
4362
}
63+
4464
if (statSync(src).isDirectory()) {
4565
if (!existsSync(dest)) {
66+
console.log(`Create folder ${dest}`);
4667
mkdirSync(dest);
4768
}
4869

@@ -61,92 +82,199 @@ const copy = (src, dest) => {
6182
}
6283
}
6384

64-
const getDevDependencies = () => {
65-
// These are nativescript-dev-appium plugin's dependencies.
66-
// There is NO need to explicitly install them to the project.
67-
// const requiredDevDependencies = [
68-
// { name: "chai", version: "~4.1.1" },
69-
// { name: "chai-as-promised", version: "~7.1.1" },
70-
// { name: "mocha", version: "~5.2.0" },
71-
// { name: "mocha-junit-reporter", version: "^1.13.0" },
72-
// { name: "mocha-multi", version: "^1.0.1" },
73-
// ];
74-
75-
// These are nativescript-dev-appium plugin's devDependencies.
76-
// There is need to explicitly install them to the project.
77-
// const typeScriptDevDependencies = [
78-
// { name: "@types/chai", version: "~4.1.3" },
79-
// { name: "@types/mocha", version: "~5.2.1" },
80-
// { name: "@types/node", version: "^7.0.5" },
81-
// ];
82-
83-
// return isTypeScriptProject ?
84-
// [
85-
// ...requiredDevDependencies,
86-
// ...typeScriptDevDependencies,
87-
// ] :
88-
// requiredDevDependencies;
89-
90-
return !isTypeScriptProject ? [] :
91-
[
92-
{ name: "@types/chai", version: "~4.1.3" },
93-
{ name: "@types/mocha", version: "~5.2.1" },
94-
{ name: "@types/node", version: "^7.0.5" },
95-
];
85+
const getDevDependencies = (frameworkType) => {
86+
const tesstingFrameworkDeps = new Map();
87+
88+
tesstingFrameworkDeps.set(jasmine, [
89+
{ name: "jasmine", version: "~3.2.0" },
90+
{ name: "jasmine-core", version: "~2.99.1" },
91+
{ name: "jasmine-spec-reporter", version: "~4.2.1" },
92+
{ name: "@types/jasmine", version: "~2.8.8" },
93+
{ name: "@types/node", version: "10.11.4" },
94+
]);
95+
96+
tesstingFrameworkDeps.set(mocha, [
97+
{ name: "mocha", version: "~5.1.0" },
98+
{ name: "mocha-junit-reporter", version: "~1.17.0" },
99+
{ name: "mocha-multi", version: "~1.0.0" },
100+
{ name: "@types/mocha", version: "~5.2.1" },
101+
{ name: "@types/chai", version: "~4.1.3" },
102+
{ name: "@types/node", version: "10.11.4" },
103+
]);
104+
105+
tesstingFrameworkDeps.set(js, []);
106+
107+
return tesstingFrameworkDeps.get(frameworkType);
108+
96109
}
97110

98-
const configureDevDependencies = packageJson => {
111+
const configureDevDependencies = (packageJson, frameworkType) => {
99112
if (!packageJson.devDependencies) {
100113
packageJson.devDependencies = {};
101114
}
115+
const devDependencies = packageJson.devDependencies || {};
102116

103-
const devDependencies = packageJson.devDependencies;
104-
const newDevDependencies = getDevDependencies();
105-
const devDependenciesToInstall = newDevDependencies.filter(({ name }) => !devDependencies[name]);
106-
devDependenciesToInstall.forEach(({ name, version }) => devDependencies[name] = version);
107-
108-
if (devDependenciesToInstall.length) {
109-
console.info("Installing new devDependencies ...");
110-
// Execute `npm install` after everything else
111-
setTimeout(function () {
112-
executeNpmInstall(appRootPath);
113-
}, 300);
114-
}
117+
getDevDependencies(frameworkType)
118+
.filter(({ name }) => !devDependencies[name])
119+
.forEach(({ name, version }) => {
120+
devDependencies[name] = version;
121+
});
115122
}
116123

117-
const updatePackageJsonDependencies = (packageJson, isTypeScriptProject) => {
118-
if (!packageJson.scripts) {
119-
packageJson.scripts = {};
120-
}
124+
const updatePackageJsonDependencies = (packageJson, projectType, testingFrameworkType) => {
125+
packageJson.scripts = packageJson.scripts || {};
126+
127+
const checkDevDepsScript = "node ./node_modules/nativescript-dev-appium/check-dev-deps.js";
128+
const mochaCommand = " mocha --opts ./e2e/config/mocha.opts ";
129+
const jasmineCommand = " jasmine --config=./e2e/config/jasmine.json ";
130+
const tscTranspile = " tsc -p e2e ";
121131

122-
if (!packageJson.scripts["e2e"]) {
123-
if (isTypeScriptProject) {
124-
packageJson.scripts["e2e"] = "tsc -p e2e && mocha --opts ./e2e/config/mocha.opts";
125-
packageJson.scripts["e2e-watch"] = "tsc -p e2e --watch";
126-
} else {
127-
packageJson.scripts["e2e"] = "mocha --opts ./e2e/config/mocha.opts";
132+
const runner = (testingFrameworkType === none) ? undefined : (testingFrameworkType === mocha ? mochaCommand : jasmineCommand);
133+
const executeTestsCommand = projectType !== sharedNg ? "e2e" : "e2e-appium";
134+
const watchTestsCommandName = executeTestsCommand + "-watch";// = "tsc -p e2e --watch";"
135+
const watchTestsCommand = "tsc -p e2e --watch";
136+
137+
if (!packageJson.scripts[executeTestsCommand] && runner) {
138+
switch (projectType) {
139+
case tsc:
140+
case ng:
141+
case sharedNg:
142+
packageJson.scripts[executeTestsCommand] = checkDevDepsScript + " && " + tscTranspile + " && " + runner;
143+
packageJson.scripts[watchTestsCommandName] = watchTestsCommand;
144+
break;
145+
case js:
146+
case vue:
147+
case sharedVue:
148+
packageJson.scripts[executeTestsCommand] = checkDevDepsScript + " && " + runner;
149+
break;
150+
default:
151+
break;
128152
}
129153
}
130154

131-
configureDevDependencies(packageJson);
155+
configureDevDependencies(packageJson, testingFrameworkType);
132156
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
133157
}
134158

135-
if (basename(appRootPath) !== "nativescript-dev-appium") {
136-
updatePackageJsonDependencies(packageJson, isTypeScriptProject);
137-
if (!existsSync(sampleTestsProjectFolderPath)) {
159+
const printLogo = () => {
160+
console.log(
161+
chalk.green(
162+
figlet.textSync("{ N }-dev-appium", {
163+
font: "doom",
164+
horizontalLayout: "default",
165+
verticalLayout: "default"
166+
})
167+
)
168+
);
169+
};
170+
171+
const frameworkQuestion = () => {
172+
const questions = [
173+
{
174+
type: "list",
175+
name: "PROJECT_TYPE",
176+
message: "What kind of project do you use?",
177+
choices: [js, tsc, ng, vue, sharedNg, sharedVue]
178+
}
179+
];
180+
return inquirer.prompt(questions);
181+
};
182+
183+
const testingFrameworkQuestion = () => {
184+
const questions = [
185+
{
186+
type: "list",
187+
name: "TESTING_FRAMEWORK",
188+
message: "Which testing framework do you prefer?",
189+
choices: [mocha, jasmine, none]
190+
}
191+
];
192+
return inquirer.prompt(questions);
193+
};
194+
195+
const isTscProject = (PROJECT_TYPE) => { return PROJECT_TYPE === tsc || PROJECT_TYPE === ng || PROJECT_TYPE === sharedNg; }
196+
197+
const getTemplates = (name) => {
198+
const templates = new Map();
199+
200+
templates.set("javascript.jasmine", new Template("jasmine", "javascript", "e2e-js", "js"));
201+
templates.set("javascript.mocha", new Template("mocha", "javascript", "e2e-js", "js"));
202+
templates.set("vue.mocha", new Template("mocha", "vue", "e2e-js", "js"));
203+
templates.set("vue.jasmine", new Template("jasmine", "vue", "e2e-js", "js"));
204+
templates.set("typescript.mocha", new Template("mocha", "typescript", "e2e-ts", "ts"));
205+
templates.set("typescript.jasmine", new Template("jasmine", "typescript", "e2e-ts", "ts"));
206+
templates.set("shared-ng-project.jasmine", new Template("jasmine", "shared-ng-project", "e2e-ts", "ts"));
207+
208+
return templates.get(name);
209+
}
210+
211+
const run = async () => {
212+
printLogo();
213+
console.log("", getTemplates())
214+
215+
const envProjectType = process.env.npm_config_projectType || process.env["PROJECT_TYPE"];
216+
const envTestsingFramework = process.env.npm_config_testsingFramework || process.env["TESTING_FRAMEWORK"];
217+
const hasSetProjectTypeAndTestingFrameworkAsEnvSet = envProjectType && envTestsingFramework;
218+
const isDevAppiumAlreadyInstalled = packageJson.devDependencies && packageJson.devDependencies["nativescript-dev-appium"];
219+
220+
const skipPostInstallOnPluginRoot = basename(appRootPath) === "nativescript-dev-appium"
221+
if ((!hasSetProjectTypeAndTestingFrameworkAsEnvSet && isDevAppiumAlreadyInstalled) || skipPostInstallOnPluginRoot) {
222+
console.log("Skip instalation!!!!")
223+
return false;
224+
}
225+
226+
// use env or ask questions
227+
const { PROJECT_TYPE } = envProjectType ? { PROJECT_TYPE: envProjectType } : await frameworkQuestion();
228+
const { TESTING_FRAMEWORK } = envTestsingFramework ? { TESTING_FRAMEWORK: envTestsingFramework } : await testingFrameworkQuestion();
229+
230+
if (!projectTypes.includes(PROJECT_TYPE)) {
231+
console.error(`Please provide PROJECT_TYPE of type ${projectTypes}!`);
232+
return;
233+
}
234+
235+
if (!testingFrameworks.includes(TESTING_FRAMEWORK)) {
236+
console.error(`Please provide testingFramework of type ${testingFrameworks}!`);
237+
return;
238+
}
239+
240+
const sampleTestsProjectFolderPath = resolve(appRootPath, "e2e");
241+
const basicSampleTestsPluginFolderPath = resolve(appRootPath, "node_modules", "nativescript-dev-appium", "samples");
242+
243+
if (!existsSync(sampleTestsProjectFolderPath) && TESTING_FRAMEWORK !== none) {
138244
mkdirSync(sampleTestsProjectFolderPath);
139-
if (isTypeScriptProject) {
140-
console.info(`TypeScript project - adding sample config and test ...`);
141-
const tscSampleTestsPath = resolve(sampleTestsPluginFolderPath, "e2e-tsc")
142-
console.info(`Copying ${tscSampleTestsPath} to ${sampleTestsProjectFolderPath} ...`);
143-
copy(tscSampleTestsPath, sampleTestsProjectFolderPath);
144-
} else {
145-
const jsSampleTestsPath = resolve(sampleTestsPluginFolderPath, "e2e-js")
146-
console.info("JavaScript project - adding sample config and test ...");
147-
console.info(`Copying ${jsSampleTestsPath} to ${sampleTestsProjectFolderPath} ...`);
148-
copy(jsSampleTestsPath, sampleTestsProjectFolderPath);
245+
const template = getTemplates(`${PROJECT_TYPE}.${TESTING_FRAMEWORK}`);
246+
const e2eSamplesFolder = resolve(basicSampleTestsPluginFolderPath, template.storage);
247+
248+
if (isTscProject(template.projectType)) {
249+
const tsConfigJsonFile = resolve(e2eSamplesFolder, "tsconfig.json");
250+
const tsConfigJson = JSON.parse(readFileSync(tsConfigJsonFile, "utf8"));
251+
switch (template.testingFramwork) {
252+
case jasmine:
253+
tsConfigJson.compilerOptions.types.push("jasmine");
254+
break;
255+
case mocha:
256+
tsConfigJson.compilerOptions.types.push("mocha");
257+
tsConfigJson.compilerOptions.types.push("chai");
258+
break;
259+
default:
260+
break;
261+
}
262+
263+
writeFileSync(tsConfigJsonFile, JSON.stringify(tsConfigJson, null, 2));
264+
copy(tsConfigJsonFile, resolve(sampleTestsProjectFolderPath, "tsconfig.json"));
149265
}
266+
267+
const samplesFilePostfix = "sample.e2e-spec";
268+
269+
copy(resolve(e2eSamplesFolder, `${template.projectType}.${template.testingFramwork}.${samplesFilePostfix}.${template.fileExt}`), resolve(sampleTestsProjectFolderPath, `${samplesFilePostfix}.${template.fileExt}`));
270+
copy(resolve(e2eSamplesFolder, `${template.testingFramwork}.setup.${template.fileExt}`), resolve(sampleTestsProjectFolderPath, `setup.${template.fileExt}`));
271+
272+
copy(resolve(basicSampleTestsPluginFolderPath, "config"), resolve(sampleTestsProjectFolderPath, "config"));
273+
const settingsFile = template.testingFramwork === jasmine ? `${template.testingFramwork}.json` : `${template.testingFramwork}.opts`;
274+
copy(resolve(basicSampleTestsPluginFolderPath, settingsFile), resolve(sampleTestsProjectFolderPath, "config", settingsFile));
150275
}
151-
}
152276

277+
updatePackageJsonDependencies(packageJson, PROJECT_TYPE, TESTING_FRAMEWORK);
278+
};
279+
280+
run();

‎samples/e2e-js/config/appium.capabilities.json renamed to ‎samples/config/appium.capabilities.json

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@
7676
"fullReset": false,
7777
"app": ""
7878
},
79+
"android28": {
80+
"platformName": "Android",
81+
"platformVersion": "28",
82+
"deviceName": "Emulator-Api28-Google",
83+
"avd": "Emulator-Api28-Google",
84+
"lt": 60000,
85+
"newCommandTimeout": 720,
86+
"noReset": true,
87+
"fullReset": false,
88+
"app": ""
89+
},
7990
"sim.iPhone7.100": {
8091
"platformName": "iOS",
8192
"platformVersion": "10.0",
@@ -94,18 +105,26 @@
94105
},
95106
"sim.iPhone8": {
96107
"platformName": "iOS",
97-
"platformVersion": "11.3",
108+
"platformVersion": "11.4",
98109
"deviceName": "iPhone 8",
99110
"noReset": true,
100111
"fullReset": false,
101112
"app": ""
102113
},
103114
"sim.iPhoneX": {
104115
"platformName": "iOS",
105-
"platformVersion": "11.3",
116+
"platformVersion": "11.4",
106117
"deviceName": "iPhone X",
107118
"noReset": true,
108119
"fullReset": false,
109120
"app": ""
121+
},
122+
"sim.iPhoneXS": {
123+
"platformName": "iOS",
124+
"platformVersion": "12.0",
125+
"deviceName": "iPhone XS",
126+
"noReset": true,
127+
"fullReset": false,
128+
"app": ""
110129
}
111130
}

‎samples/e2e-js/jasmine.setup.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const nsAppium = require("nativescript-dev-appium");
2+
3+
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
4+
5+
jasmine.getEnv().clearReporters();
6+
jasmine.getEnv().addReporter(new SpecReporter({
7+
spec: {
8+
displayPending: true
9+
}
10+
}));
11+
12+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1200000;
13+
14+
beforeAll(async () => {
15+
await nsAppium.startServer();
16+
});
17+
18+
afterAll(async () => {
19+
await nsAppium.stopServer();
20+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const nsAppium = require("nativescript-dev-appium");
2+
3+
describe("sample scenario", () => {
4+
let driver;
5+
6+
beforeAll(async () => {
7+
driver = await nsAppium.createDriver();
8+
});
9+
10+
afterAll(async () => {
11+
await driver.quit();
12+
console.log("Quit driver!");
13+
});
14+
15+
afterEach(async function () {
16+
await driver.logTestArtifacts("failure");
17+
});
18+
19+
it("should find an element by text", async () => {
20+
const btnTap = await driver.findElementByText("TAP", nsAppium.SearchOptions.exact);
21+
await btnTap.click();
22+
23+
const message = " taps left";
24+
const lblMessage = await driver.findElementByText(message, nsAppium.SearchOptions.contains);
25+
expect(await lblMessage.text()).toContain("41");
26+
// Image verification
27+
// const screen = await driver.compareScreen("hello-world-41");
28+
// assert.isTrue(screen);
29+
// expect(screen).toBeTruthy();
30+
});
31+
32+
it("should find an element by type", async () => {
33+
const btnTap = await driver.findElementByClassName(driver.locators.button);
34+
await btnTap.click();
35+
36+
const message = " taps left";
37+
const lblMessage = await driver.findElementByText(message, nsAppium.SearchOptions.contains);
38+
expect(await lblMessage.text()).toContain("40");
39+
});
40+
});
File renamed without changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const nsAppium = require("nativescript-dev-appium");
2+
3+
describe("sample scenario", () => {
4+
let driver;
5+
6+
beforeAll(async () => {
7+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1200000;
8+
driver = await nsAppium.createDriver();
9+
});
10+
11+
afterAll(async () => {
12+
await driver.quit();
13+
console.log("Quit driver!");
14+
});
15+
16+
afterEach(async function () {
17+
await driver.logTestArtifacts("failure");
18+
});
19+
20+
it("should find Welcome message", async () => {
21+
const label = await driver.findElementByText("Welcome", "contains");
22+
expect(await label.isDisplayed()).toBeTruthy();
23+
});
24+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const nsAppium = require("nativescript-dev-appium");
2+
const assert = require("chai").assert;
3+
4+
describe("sample scenario", () => {
5+
let driver;
6+
7+
before(async () => {
8+
driver = await nsAppium.createDriver();
9+
});
10+
11+
after(async () => {
12+
await driver.quit();
13+
console.log("Quit driver!");
14+
});
15+
16+
afterEach(async function () {
17+
if (this.currentTest.state === "failed") {
18+
await driver.logTestArtifacts(this.currentTest.title);
19+
}
20+
});
21+
22+
it("should find an element by text", async () => {
23+
const label = await driver.findElementByText("Welcome", "contains");
24+
assert.isTrue(await label.isDisplayed());
25+
});
26+
});

‎samples/e2e-ts/jasmine.setup.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { startServer, stopServer } from "nativescript-dev-appium";
2+
3+
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
4+
5+
jasmine.getEnv().clearReporters();
6+
jasmine.getEnv().addReporter(new SpecReporter({
7+
spec: {
8+
displayPending: true
9+
}
10+
}));
11+
12+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1200000;
13+
14+
beforeAll(async () => {
15+
await startServer();
16+
});
17+
18+
afterAll(async () => {
19+
await stopServer();
20+
});
File renamed without changes.
File renamed without changes.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium";
2+
3+
describe("sample scenario", () => {
4+
let driver: AppiumDriver;
5+
6+
beforeAll(async () => {
7+
driver = await createDriver();
8+
});
9+
10+
afterAll(async () => {
11+
await driver.quit();
12+
console.log("Quit driver!");
13+
});
14+
15+
afterEach(async function () {
16+
await driver.logTestArtifacts("report");
17+
});
18+
19+
it("should find an element by text", async () => {
20+
const btnTap = await driver.findElementByText("TAP", SearchOptions.exact);
21+
await btnTap.click();
22+
23+
const message = " taps left";
24+
const lblMessage = await driver.findElementByText(message, SearchOptions.contains);
25+
expect(await lblMessage.text()).toContain("41");
26+
// Image verification
27+
// const screen = await driver.compareScreen("hello-world-41");
28+
// assert.isTrue(screen);
29+
// expect(screen).toBeTruthy();
30+
});
31+
32+
it("should find an element by type", async () => {
33+
const btnTap = await driver.findElementByClassName(driver.locators.button);
34+
await btnTap.click();
35+
36+
const message = " taps left";
37+
const lblMessage = await driver.findElementByText(message, SearchOptions.contains);
38+
expect(await lblMessage.text()).toContain("40");
39+
});
40+
});

‎samples/e2e-tsc/tsconfig.json renamed to ‎samples/e2e-ts/tsconfig.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55
"experimentalDecorators": true,
66
"emitDecoratorMetadata": true,
77
"importHelpers": false,
8-
"types": [
9-
"node",
10-
"mocha",
11-
"chai"
12-
],
8+
"types": [ ],
139
"lib": [
1410
"es2015",
1511
"dom"
16-
]
12+
],
13+
"baseUrl": "."
1714
}
1815
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium";
2+
3+
describe("sample scenario", () => {
4+
let driver: AppiumDriver;
5+
6+
beforeAll(async () => {
7+
driver = await createDriver();
8+
});
9+
10+
afterAll(async () => {
11+
await driver.quit();
12+
console.log("Quit driver!");
13+
});
14+
15+
afterEach(async function () {
16+
await driver.logTestArtifacts("report");
17+
});
18+
19+
it("should find an element by text", async () => {
20+
const btnTap = await driver.findElementByText("TAP", SearchOptions.exact);
21+
await btnTap.click();
22+
23+
const message = " taps left";
24+
const lblMessage = await driver.findElementByText(message, SearchOptions.contains);
25+
expect(await lblMessage.text()).toContain("41");
26+
// Image verification
27+
// const screen = await driver.compareScreen("hello-world-41");
28+
// assert.isTrue(screen);
29+
// expect(screen).toBeTruthy();
30+
});
31+
32+
it("should find an element by type", async () => {
33+
const btnTap = await driver.findElementByClassName(driver.locators.button);
34+
await btnTap.click();
35+
36+
const message = " taps left";
37+
const lblMessage = await driver.findElementByText(message, SearchOptions.contains);
38+
expect(await lblMessage.text()).toContain("40");
39+
});
40+
});

‎samples/e2e-tsc/config/appium.capabilities.json

Lines changed: 0 additions & 111 deletions
This file was deleted.

‎samples/e2e-tsc/config/mocha.opts

Lines changed: 0 additions & 5 deletions
This file was deleted.

‎samples/jasmine.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"spec_dir": "e2e",
3+
"spec_files": [
4+
"**/*.js"
5+
],
6+
"helpers": [
7+
"config/**/*.js", "setup.js"
8+
],
9+
"stopSpecOnExpectationFailure": false,
10+
"random": false
11+
}
File renamed without changes.

‎tsconfig.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"dom",
1313
"es2015"
1414
],
15-
"baseUrl": "."
15+
"baseUrl": ".",
16+
"typeRoots": [
17+
"./node_modules/@types"
18+
]
1619
},
1720
"exclude": [
1821
"samples",

0 commit comments

Comments
 (0)
Please sign in to comment.