mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge branch 'ErjanGavalji/run-tests-on-build'
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,6 +15,7 @@ dist/
|
||||
!css-value/**/*.*
|
||||
!fetch/**/*.*
|
||||
!apps/TelerikNEXT/lib/**/*.*
|
||||
!build/*.*
|
||||
CrossPlatformModules.sln.ide/
|
||||
*.suo
|
||||
CrossPlatformModules.suo
|
||||
@@ -27,3 +28,6 @@ obj/
|
||||
.baseDir.ts
|
||||
.ctags-exclude
|
||||
tags
|
||||
|
||||
TestRunResult.txt
|
||||
.testsapprun
|
||||
|
||||
@@ -1,50 +1,23 @@
|
||||
import pages = require("ui/page");
|
||||
import gridModule = require("ui/layouts/grid-layout");
|
||||
import {Page} from "ui/page";
|
||||
import * as trace from "trace";
|
||||
import tests = require("../testRunner");
|
||||
import bm = require("ui/button");
|
||||
import trace = require("trace");
|
||||
import textViewModule = require("ui/text-view");
|
||||
|
||||
class MyTraceWriter implements trace.TraceWriter {
|
||||
public write(message: any, category: string) {
|
||||
if (textView && message && message.toLowerCase().indexOf("failed") !== -1) {
|
||||
if (textView.android) {
|
||||
textView.text = message + "\r\n" + textView.text;
|
||||
}
|
||||
else {
|
||||
textView.text = message + "\n" + textView.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace.addWriter(new MyTraceWriter());
|
||||
trace.enable();
|
||||
trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
|
||||
|
||||
var textView = new textViewModule.TextView();
|
||||
textView.editable = false;
|
||||
textView.style.fontSize = 8;
|
||||
let started = false;
|
||||
let page = new Page();
|
||||
|
||||
page.on(Page.navigatedToEvent, function () {
|
||||
if (!started) {
|
||||
started = true;
|
||||
setTimeout(function () {
|
||||
tests.runAll();
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
|
||||
export function createPage() {
|
||||
var button = new bm.Button();
|
||||
button.text = "Run Tests";
|
||||
button.on(bm.Button.tapEvent, function () {
|
||||
tests.runAll();
|
||||
});
|
||||
|
||||
var grid = new gridModule.GridLayout();
|
||||
|
||||
grid.addRow(new gridModule.ItemSpec(1, gridModule.GridUnitType.auto));
|
||||
grid.addRow(new gridModule.ItemSpec());
|
||||
|
||||
gridModule.GridLayout.setRow(textView, 1);
|
||||
|
||||
grid.addChild(button);
|
||||
grid.addChild(textView);
|
||||
|
||||
var page = new pages.Page();
|
||||
page.content = grid;
|
||||
return page;
|
||||
}
|
||||
//export var Page = page;
|
||||
|
||||
|
||||
301
build/run-testsapp.grunt.js
Normal file
301
build/run-testsapp.grunt.js
Normal file
@@ -0,0 +1,301 @@
|
||||
module.exports = {
|
||||
|
||||
run: function(grunt) {
|
||||
var pathModule = require("path");
|
||||
|
||||
var modulesPackageConfig = grunt.file.readJSON('package.json');
|
||||
|
||||
//Construct and validate the arguments
|
||||
var args = {
|
||||
platform: grunt.option("platform"),
|
||||
modulesPath: grunt.option("modulesPath"),
|
||||
tnsPath: grunt.option("tnsPath"),
|
||||
emulatorProcessIdentifier: grunt.option("emuPId"),
|
||||
emuAvdName: grunt.option("avd"),
|
||||
outFile: grunt.option("logFilePath"),
|
||||
runtimePath: grunt.option("runtimePath"),
|
||||
showEmu: grunt.option("showEmu")
|
||||
};
|
||||
|
||||
(function validateInput(){
|
||||
if (!(/^(Android|iOS)$/).test(args.platform)) {
|
||||
throw new Error("Invalid target platform specified! Use --platform=Android|iOS");
|
||||
}
|
||||
|
||||
if (args.platform === "Android") {
|
||||
if (!args.emulatorProcessIdentifier) {
|
||||
throw new Error("Please, specify an identifier of the emulator process so that it can be stopped (--emuPId=...). Too many emulators started might cause machine overload");
|
||||
}
|
||||
if (!args.emuAvdName) {
|
||||
throw new Error("Please, specify the name of the AVD to start (--avd=...).");
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
var localCfg = {
|
||||
tnsPath: args.tnsPath || "tns",
|
||||
emulatorProcessIdentifier: args.emulatorProcessIdentifier,
|
||||
modulesPath: args.modulesPath || "./bin/dist/tns-core-modules-" + modulesPackageConfig.version + ".tgz",
|
||||
emuAvdName: args.emuAvdName,
|
||||
outFile: args.outFile || "./TestRunResult.txt",
|
||||
frameworkArgument: args.runtimePath ? " --frameworkPath=" + args.runtimePath : "",
|
||||
showEmu: args.showEmu || false,
|
||||
|
||||
workingDir:".testsapprun",
|
||||
testsAppName:"TestsApp",
|
||||
applicationDir: pathModule.join(".testsapprun", "TestsApp"),
|
||||
appDir: pathModule.join(".testsapprun", "TestsApp", "app"),
|
||||
pathToApk: "./platforms/android/build/outputs/apk/TestsApp-debug.apk",
|
||||
pathToApp: "./platforms/ios/build/emulator/TestsApp.app",
|
||||
deployedAppName:"org.nativescript.TestsApp",
|
||||
mainActivityName:"com.tns.NativeScriptActivity",
|
||||
pathToCompiledTests: "bin/dist/apps/tests",
|
||||
simulatorSysLog: pathModule.join(process.env.HOME, "Library/Logs/CoreSimulator", args.emuAvdName, "/system.log"),
|
||||
platform: args.platform
|
||||
}
|
||||
|
||||
grunt.initConfig({
|
||||
clean: {
|
||||
workingDir: {
|
||||
src: localCfg.workingDir
|
||||
},
|
||||
originalAppDir: {
|
||||
src: [
|
||||
localCfg.appDir + "/*",
|
||||
"!" + pathModule.join(localCfg.appDir, "App_Resources") + ""
|
||||
]
|
||||
},
|
||||
modules: {
|
||||
src: pathModule.join(localCfg.applicationDir, "node_modules", "tns-core-modules")
|
||||
},
|
||||
tempExtractedModules: {
|
||||
src: pathModule.join(localCfg.applicationDir, "node_modules", "package")
|
||||
},
|
||||
simulatorLog: {
|
||||
src: localCfg.simulatorSysLog,
|
||||
options: {
|
||||
force: true
|
||||
}
|
||||
}
|
||||
},
|
||||
mkdir: {
|
||||
workingDir: {
|
||||
options: {
|
||||
create: [localCfg.workingDir],
|
||||
mode: 0700
|
||||
}
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
testsAppToRunDir: {
|
||||
src: "**/*.*",
|
||||
dest: localCfg.appDir,
|
||||
cwd: localCfg.pathToCompiledTests,
|
||||
expand: true
|
||||
},
|
||||
modulesToDir: {
|
||||
expand: true,
|
||||
src: "**/*.*",
|
||||
cwd: pathModule.join(localCfg.applicationDir, "node_modules", "package"),
|
||||
dest: pathModule.join(localCfg.applicationDir, "node_modules", "tns-core-modules")
|
||||
},
|
||||
addAndroidPermissions: {
|
||||
src: "AndroidManifest.xml",
|
||||
dest: localCfg.applicationDir + "/platforms/android/src/main/",
|
||||
cwd: localCfg.applicationDir + "/platforms/android/src/main",
|
||||
expand: true,
|
||||
options: {
|
||||
process: function(content, srcPath) {
|
||||
var newContent = content;
|
||||
|
||||
var internetPermissionFinder = /((\s*)<uses-permission[^>]*android\.permission\.INTERNET[^>]*>)/;
|
||||
|
||||
if (!/uses-permission[^>]*android\.permission\.ACCESS_NETWORK_STATE/.test(content)) {
|
||||
newContent = newContent.replace(internetPermissionFinder, "$1$2<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>");
|
||||
}
|
||||
if (!/uses-permission[^>]*android\.permission\.ACCESS_FINE_LOCATION/.test(content)) {
|
||||
newContent = newContent.replace(internetPermissionFinder, "$1$2<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>");
|
||||
}
|
||||
return newContent;
|
||||
}
|
||||
}
|
||||
},
|
||||
addiOSPermissions: {
|
||||
src: localCfg.testsAppName + "-Info.plist",
|
||||
dest: pathModule.join(localCfg.applicationDir,"/platforms/ios/", localCfg.testsAppName) + "/",
|
||||
cwd: pathModule.join(localCfg.applicationDir,"/platforms/ios/", localCfg.testsAppName),
|
||||
expand: true,
|
||||
options: {
|
||||
process: function(content, srcPath) {
|
||||
var newContent = content;
|
||||
|
||||
var lastDictLocator = /(<\/dict>\s*<\/plist>)$/gm;
|
||||
|
||||
if (!/NSAppTransportSecurity/.test(content)) {
|
||||
newContent = newContent.replace(lastDictLocator, "<key>NSAppTransportSecurity</key>\n$1");
|
||||
}
|
||||
if (!/NSAllowsArbitraryLoads/.test(content)) {
|
||||
newContent = newContent.replace(lastDictLocator, "<dict>\n<key>NSAllowsArbitraryLoads</key>\n<true/>\n</dict>\n$1");
|
||||
}
|
||||
return newContent;
|
||||
}
|
||||
}
|
||||
},
|
||||
simulatorLog: {
|
||||
src: localCfg.simulatorSysLog,
|
||||
dest: localCfg.outFile
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
killAndroidEmulator: {
|
||||
cmd: "pkill '" + localCfg.emulatorProcessIdentifier + "'",
|
||||
exitCode: [0, 1]
|
||||
},
|
||||
killiOSEmulator: {
|
||||
cmd: "pkill Simulator",
|
||||
exitCode: [0, 1]
|
||||
},
|
||||
createApp: {
|
||||
cmd: localCfg.tnsPath + " create " + localCfg.testsAppName,
|
||||
cwd: localCfg.workingDir
|
||||
},
|
||||
addPlatform: {
|
||||
cmd: "tns platform add " + localCfg.platform.toLowerCase() + " " + localCfg.frameworkArgument,
|
||||
cwd: localCfg.applicationDir
|
||||
},
|
||||
restartAdb: {
|
||||
cmd: "adb kill-server && adb start-server"
|
||||
},
|
||||
uninstallExistingAndroidApp: {
|
||||
cmd: "adb uninstall " + localCfg.deployedAppName
|
||||
},
|
||||
installNewAndroidApp: {
|
||||
cmd: "adb install " + localCfg.pathToApk,
|
||||
cwd: localCfg.applicationDir
|
||||
},
|
||||
startAndroidEmulator: {
|
||||
cmd: "emulator -avd " + localCfg.emuAvdName + " -no-audio " + (args.showEmu ? "" : "-no-window") + "&"
|
||||
},
|
||||
startAndroidApp: {
|
||||
cmd: "adb shell am start -n " + localCfg.deployedAppName + "/" + localCfg.mainActivityName
|
||||
},
|
||||
uninstallExistingiOSApp: {
|
||||
cmd: "xcrun simctl uninstall " + localCfg.emuAvdName + " org.nativescript." + localCfg.testsAppName,
|
||||
cwd: localCfg.applicationDir
|
||||
},
|
||||
installNewiOSApp: {
|
||||
cmd: "xcrun simctl install " + localCfg.emuAvdName + " " + localCfg.pathToApp,
|
||||
cwd: localCfg.applicationDir
|
||||
},
|
||||
startiOSApp: {
|
||||
cmd: "xcrun simctl launch " + localCfg.emuAvdName + " org.nativescript." + localCfg.testsAppName
|
||||
},
|
||||
},
|
||||
untar: {
|
||||
modules: {
|
||||
src: localCfg.modulesPath,
|
||||
dest: pathModule.join(localCfg.applicationDir, "node_modules")
|
||||
}
|
||||
},
|
||||
shell: {
|
||||
collectAndroidLog: {
|
||||
command: "./expect.exp " + "'adb logcat' " + localCfg.outFile,
|
||||
options: {
|
||||
execOptions: {
|
||||
maxBuffer: Infinity
|
||||
}
|
||||
}
|
||||
},
|
||||
waitiOSLogCompletion: {
|
||||
command: "./expect.exp " + "'tail -f " + localCfg.simulatorSysLog + "' " + localCfg.outFile,
|
||||
options: {
|
||||
execOptions: {
|
||||
maxBuffer: Infinity
|
||||
}
|
||||
}
|
||||
},
|
||||
startiOSSimulator: {
|
||||
command: "xcrun instruments -w " + localCfg.emuAvdName,
|
||||
options: {
|
||||
failOnError: false
|
||||
},
|
||||
},
|
||||
buildApp: {
|
||||
command: "tns build " + localCfg.platform.toLowerCase(),
|
||||
options: {
|
||||
execOptions: {
|
||||
maxBuffer: Infinity,
|
||||
cwd: localCfg.applicationDir
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks("grunt-shell");
|
||||
grunt.loadNpmTasks("grunt-exec");
|
||||
grunt.loadNpmTasks("grunt-mkdir");
|
||||
grunt.loadNpmTasks("grunt-contrib-clean");
|
||||
grunt.loadNpmTasks("grunt-contrib-copy");
|
||||
grunt.loadNpmTasks("grunt-untar");
|
||||
|
||||
var getPlatformSpecificTask = function(templatedTaskName) {
|
||||
return templatedTaskName.replace(/\{platform\}/, localCfg.platform);
|
||||
}
|
||||
|
||||
grunt.registerTask("startEmulatorAndroid", [
|
||||
getPlatformSpecificTask("exec:startAndroidEmulator"),
|
||||
]);
|
||||
|
||||
grunt.registerTask("startEmulatoriOS", [
|
||||
getPlatformSpecificTask("shell:startiOSSimulator"),
|
||||
]);
|
||||
|
||||
grunt.registerTask("collectLogAndroid", [
|
||||
"shell:collectAndroidLog"
|
||||
]);
|
||||
|
||||
grunt.registerTask("collectLogiOS", [
|
||||
"shell:waitiOSLogCompletion",
|
||||
"copy:simulatorLog"
|
||||
]);
|
||||
|
||||
grunt.registerTask("doPostPlatformAddAndroid", [
|
||||
"exec:restartAdb"
|
||||
]);
|
||||
|
||||
grunt.registerTask("doPostPlatformAddiOS", [
|
||||
"clean:simulatorLog"
|
||||
]);
|
||||
|
||||
|
||||
//xcrun instruments -s
|
||||
grunt.registerTask("testsapp", [
|
||||
"clean:workingDir",
|
||||
"mkdir:workingDir",
|
||||
getPlatformSpecificTask("exec:kill{platform}Emulator"),
|
||||
getPlatformSpecificTask("startEmulator{platform}"),
|
||||
|
||||
"exec:createApp",
|
||||
"clean:originalAppDir",
|
||||
"copy:testsAppToRunDir",
|
||||
"clean:modules",
|
||||
"untar:modules",
|
||||
"copy:modulesToDir",
|
||||
"clean:tempExtractedModules",
|
||||
|
||||
"exec:addPlatform",
|
||||
getPlatformSpecificTask("copy:add{platform}Permissions"),
|
||||
"shell:buildApp",
|
||||
getPlatformSpecificTask("doPostPlatformAdd{platform}"),
|
||||
|
||||
getPlatformSpecificTask("exec:uninstallExisting{platform}App"),
|
||||
getPlatformSpecificTask("exec:installNew{platform}App"),
|
||||
getPlatformSpecificTask("exec:start{platform}App"),
|
||||
getPlatformSpecificTask("collectLog{platform}"),
|
||||
|
||||
// getPlatformSpecificTask("exec:kill{platform}Emulator"),
|
||||
// "clean:workingDir"
|
||||
]);
|
||||
}
|
||||
}
|
||||
20
expect.exp
Executable file
20
expect.exp
Executable file
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/expect
|
||||
|
||||
#exp_internal 1
|
||||
|
||||
#set timeout 600
|
||||
|
||||
#spawn grunt
|
||||
#expect "TypeScript compilation complete"
|
||||
#send \003
|
||||
|
||||
|
||||
set cmd [lindex $argv 0];
|
||||
set outfile [lindex $argv 1];
|
||||
|
||||
set timeout 600
|
||||
#spawn (adb logcat | tee ./__TESTRESULT__.txt)
|
||||
log_file -noappend $outfile
|
||||
eval spawn $cmd
|
||||
expect "=== ALL TESTS COMPLETE ==="
|
||||
send \003
|
||||
1055
gruntfile.js
1055
gruntfile.js
File diff suppressed because it is too large
Load Diff
@@ -13,18 +13,20 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"chai": "3.2.0",
|
||||
"grunt": "0.4.5",
|
||||
"grunt-contrib-clean": "0.6.0",
|
||||
"grunt-contrib-copy": "git+https://github.com/ErjanGavalji/grunt-contrib-copy.git#1c976a133210be4ce8c96313f5daf14833f7f8f9",
|
||||
"grunt-env": "0.4.4",
|
||||
"grunt-exec": "0.4.6",
|
||||
"grunt-mkdir": "^0.1.2",
|
||||
"grunt-multi-dest": "1.0.0",
|
||||
"grunt-shell": "1.1.2",
|
||||
"grunt-simple-mocha": "0.4.0",
|
||||
"grunt-ts": "5.0.0-beta.5",
|
||||
"grunt-tslint": "2.5.0",
|
||||
"grunt-untar": "0.0.1",
|
||||
"mocha": "2.2.5",
|
||||
"grunt-simple-mocha": "0.4.0",
|
||||
"grunt-env": "0.4.4",
|
||||
"chai": "3.2.0",
|
||||
"typescript": "1.6.2"
|
||||
}
|
||||
}
|
||||
|
||||
59
running-tests.md
Normal file
59
running-tests.md
Normal file
@@ -0,0 +1,59 @@
|
||||
Running NativeScript Tests
|
||||
=========================
|
||||
|
||||
|
||||
# Details
|
||||
NativeScript is a framework for building applications on mobile devices. Many
|
||||
of its components are UI elements which get tested most efficiently on the
|
||||
respective device or simulator/emulator. Thus, running the tests involves
|
||||
the following steps:
|
||||
|
||||
- Create a NativeScript project
|
||||
- Build it to a native image
|
||||
- Start a simulator/emulator
|
||||
- Deploy the application image
|
||||
- Start the application
|
||||
- Monitor its output
|
||||
- Gather test output
|
||||
|
||||
These steps are automated via the `run-testsapp.grunt.js` grunt script, located
|
||||
under the `build` directory. It gets called by the main `gruntfile.js`, but is
|
||||
split to a separate file for simplicity.
|
||||
|
||||
# Prerequisites
|
||||
- Node JS
|
||||
- grunt
|
||||
- NativeScript CLI
|
||||
- Android/iOS setup
|
||||
- expect
|
||||
|
||||
# Arguments:
|
||||
|
||||
>As this is a [grunt](http://gruntjs.com/) script, the arguments are passed
|
||||
the grunt way (`--argName=argValue`)
|
||||
|
||||
- `platform`: The platform to run the tests application on: iOS or Android
|
||||
- `showEmu`: [Optional] Specifies whether the emulator should get launched
|
||||
in a window or headless mode. Defaults to `false`.
|
||||
- `modulesPath`: [Optional] The path to the tns-core-modules npm package
|
||||
to be tested. Defaults to the npm package, located in the current
|
||||
`bin/dist/` folder. The modules must have been built before that.
|
||||
- `tnsPath`: [Optional] The path to the NativeScript executable. If not
|
||||
found, the globally installed `tns` gets called.
|
||||
- `emuPId`: The ID of the emulator process. This one is used to refresh the
|
||||
emulator process, as the emulator sometimes hangs.
|
||||
- `avd`: The name of the Android Virtual Device or the iOS simulator GUID
|
||||
to be started to run the tests.
|
||||
- `logFilePath`: [Optional] The path to the file, which the test app run
|
||||
log will get saved to. Defaults to "./TestRunResult.txt".
|
||||
- `runtimePath`: [Optional] The path to a custom iOS or Android Runtime
|
||||
package to have the tests run onto. If not specified, the newest available
|
||||
build on [npmjs.com](http://npmjs.com) -
|
||||
[tns-ios](https://www.npmjs.com/package/tns-ios) or
|
||||
[tns-android](https://www.npmjs.com/package/tns-android).
|
||||
|
||||
# Sample run:
|
||||
```
|
||||
grunt testsapp --platform=Android [--tnsPath="tns"] --emuPId=".*emulator64-x86"
|
||||
--avd="Api19" [--logFilePath="./TestRunResult.txt"] [--androidRuntimePath="./tns-android.tgz"] --showEmu=true
|
||||
```
|
||||
Reference in New Issue
Block a user