diff --git a/.gitignore b/.gitignore
index 73461007f0..d70c8479e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+.DS_Store
+
*.js
!/*.js
!bin/nativescript.js
diff --git a/.travis.yml b/.travis.yml
index 81e4797d9e..02bd53c25e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ install:
- npm install
- grunt pack --no-color
script:
-- 'true'
+- npm test
git:
submodules: false
deploy:
diff --git a/Gruntfile.js b/Gruntfile.js
index 26988ffd53..0f48d46272 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -56,7 +56,10 @@ module.exports = function(grunt) {
watch: {
devall: {
files: ["lib/**/*.ts", 'test/**/*.ts'],
- tasks: ['ts:devall'],
+ tasks: [
+ 'ts:devall',
+ 'shell:npm_test'
+ ],
options: {
atBegin: true,
interrupt: true
@@ -67,7 +70,8 @@ module.exports = function(grunt) {
shell: {
options: {
stdout: true,
- stderr: true
+ stderr: true,
+ failOnError: true
},
build_package: {
@@ -81,7 +85,12 @@ module.exports = function(grunt) {
})()
}
}
+ },
+
+ npm_test: {
+ command: "npm test"
}
+
},
copy: {
@@ -125,8 +134,6 @@ module.exports = function(grunt) {
"clean",
"ts:release_build",
- //"shell:ci_unit_tests",
-
"set_package_version",
"shell:build_package",
diff --git a/package.json b/package.json
index 56b693ce5d..8fa856746c 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
},
"main": "./lib/nativescript-cli.js",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "node_modules\\.bin\\_mocha --ui mocha-fibers --recursive --reporter spec --require test/test-bootstrap.js --timeout 15000 test/"
},
"repository": {
"type": "git",
@@ -24,29 +24,32 @@
"dependencies": {
"fibers": "https://github.com/icenium/node-fibers/tarball/master",
"filesize": "2.0.3",
- "progress-stream": "0.5.0",
"log4js": "0.6.9",
+ "mkdirp": "0.3.5",
+ "npm": "1.4.10",
"osenv": "0.1.0",
+ "progress-stream": "0.5.0",
+ "properties-parser": "0.2.3",
+ "rimraf": "2.2.6",
+ "semver": "3.0.1",
+ "shelljs": "0.3.0",
"tabtab": "https://github.com/tailsu/node-tabtab/tarball/master",
"underscore": "1.5.2",
"unzip": "0.1.9",
- "yargs": "1.2.2",
- "npm": "1.4.10",
- "properties-parser": "0.2.3",
"watchr": "2.4.11",
- "rimraf": "2.2.6",
- "mkdirp": "0.3.5",
- "shelljs": "0.3.0",
- "semver": "3.0.1"
+ "yargs": "1.2.2"
},
"analyze": true,
"devDependencies": {
"grunt": "0.4.2",
- "grunt-ts": "1.11.2",
"grunt-contrib-clean": "0.5.0",
+ "grunt-contrib-copy": "0.5.0",
"grunt-contrib-watch": "0.5.3",
"grunt-shell": "0.6.4",
- "grunt-contrib-copy": "0.5.0"
+ "grunt-ts": "1.11.2",
+ "mocha": "1.21.4",
+ "mocha-fibers": "https://github.com/tailsu/mocha-fibers/tarball/master",
+ "should": "4.0.4"
},
"license": "Apache-2.0",
"engines": {
diff --git a/test/.d.ts b/test/.d.ts
new file mode 100644
index 0000000000..b9a278d22c
--- /dev/null
+++ b/test/.d.ts
@@ -0,0 +1,4 @@
+///
+///
+///
+
diff --git a/test/definitions/mocha.d.ts b/test/definitions/mocha.d.ts
new file mode 100644
index 0000000000..64255a7ba1
--- /dev/null
+++ b/test/definitions/mocha.d.ts
@@ -0,0 +1,110 @@
+// Type definitions for mocha 1.17.1
+// Project: http://visionmedia.github.io/mocha/
+// Definitions by: Kazi Manzur Rashid , otiai10
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+interface Mocha {
+ // Setup mocha with the given setting options.
+ setup(options: MochaSetupOptions): Mocha;
+
+ //Run tests and invoke `fn()` when complete.
+ run(callback?: () => void): void;
+
+ // Set reporter as function
+ reporter(reporter: () => void): Mocha;
+
+ // Set reporter, defaults to "dot"
+ reporter(reporter: string): Mocha;
+
+ // Enable growl support.
+ growl(): Mocha
+}
+
+interface MochaSetupOptions {
+ //milliseconds to wait before considering a test slow
+ slow?: number;
+
+ // timeout in milliseconds
+ timeout?: number;
+
+ // ui name "bdd", "tdd", "exports" etc
+ ui?: string;
+
+ //array of accepted globals
+ globals?: any[];
+
+ // reporter instance (function or string), defaults to `mocha.reporters.Dot`
+ reporter?: any;
+
+ // bail on the first test failure
+ bail?: Boolean;
+
+ // ignore global leaks
+ ignoreLeaks?: Boolean;
+
+ // grep string or regexp to filter tests with
+ grep?: any;
+}
+
+interface MochaDone {
+ (error?: Error): void;
+}
+
+declare var mocha: Mocha;
+
+declare var describe : {
+ (description: string, spec: () => void): void;
+ only(description: string, spec: () => void): void;
+ skip(description: string, spec: () => void): void;
+ timeout(ms: number): void;
+}
+
+// alias for `describe`
+declare var context : {
+ (contextTitle: string, spec: () => void): void;
+ only(contextTitle: string, spec: () => void): void;
+ skip(contextTitle: string, spec: () => void): void;
+ timeout(ms: number): void;
+}
+
+declare var it: {
+ (expectation: string, assertion?: () => void): void;
+ (expectation: string, assertion?: (done: MochaDone) => void): void;
+ only(expectation: string, assertion?: () => void): void;
+ only(expectation: string, assertion?: (done: MochaDone) => void): void;
+ skip(expectation: string, assertion?: () => void): void;
+ skip(expectation: string, assertion?: (done: MochaDone) => void): void;
+ timeout(ms: number): void;
+};
+
+declare function before(action: () => void): void;
+
+declare function before(action: (done: MochaDone) => void): void;
+
+declare function setup(action: () => void): void;
+
+declare function setup(action: (done: MochaDone) => void): void;
+
+declare function after(action: () => void): void;
+
+declare function after(action: (done: MochaDone) => void): void;
+
+declare function teardown(action: () => void): void;
+
+declare function teardown(action: (done: MochaDone) => void): void;
+
+declare function beforeEach(action: () => void): void;
+
+declare function beforeEach(action: (done: MochaDone) => void): void;
+
+declare function suiteSetup(action: () => void): void;
+
+declare function suiteSetup(action: (done: MochaDone) => void): void;
+
+declare function afterEach(action: () => void): void;
+
+declare function afterEach(action: (done: MochaDone) => void): void;
+
+declare function suiteTeardown(action: () => void): void;
+
+declare function suiteTeardown(action: (done: MochaDone) => void): void;
diff --git a/test/definitions/should.d.ts b/test/definitions/should.d.ts
new file mode 100644
index 0000000000..8b4c21fc1e
--- /dev/null
+++ b/test/definitions/should.d.ts
@@ -0,0 +1,118 @@
+// Type definitions for should.js 3.1.2
+// Project: https://github.com/visionmedia/should.js
+// Definitions by: Alex Varju , Maxime LUCE
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+interface Object {
+ should: ShouldAssertion;
+}
+
+interface ShouldAssertion {
+ // basic grammar
+ a: ShouldAssertion;
+ an: ShouldAssertion;
+ and: ShouldAssertion;
+ be: ShouldAssertion;
+ have: ShouldAssertion;
+ with: ShouldAssertion;
+ of: ShouldAssertion;
+ not: ShouldAssertion;
+
+ // validators
+ arguments: ShouldAssertion;
+ empty: ShouldAssertion;
+ ok: ShouldAssertion;
+ true: ShouldAssertion;
+ false: ShouldAssertion;
+ NaN: ShouldAssertion;
+ Infinity: ShouldAssertion;
+ Array: ShouldAssertion;
+ Object: ShouldAssertion;
+ String: ShouldAssertion;
+ Boolean: ShouldAssertion;
+ Number: ShouldAssertion;
+ Error: ShouldAssertion;
+ Function: ShouldAssertion;
+ eql(expected: any, description?: string): ShouldAssertion;
+ equal(expected: any, description?: string): ShouldAssertion;
+ within(start: number, finish: number, description?: string): ShouldAssertion;
+ approximately(value: number, delta: number, description?: string): ShouldAssertion;
+ type(expected: any, description?: string): ShouldAssertion;
+ instanceof(constructor: Function, description?: string): ShouldAssertion;
+ above(n: number, description?: string): ShouldAssertion;
+ below(n: number, description?: string): ShouldAssertion;
+ match(other: {}, description?: string): ShouldAssertion;
+ match(other: (val: any) => any, description?: string): ShouldAssertion;
+ match(regexp: RegExp, description?: string): ShouldAssertion;
+ match(other: any, description?: string): ShouldAssertion;
+ matchEach(other: {}, description?: string): ShouldAssertion;
+ matchEach(other: (val: any) => any, description?: string): ShouldAssertion;
+ matchEach(regexp: RegExp, description?: string): ShouldAssertion;
+ matchEach(other: any, description?: string): ShouldAssertion;
+ length(n: number, description?: string): ShouldAssertion;
+ property(name: string, description?: string): ShouldAssertion;
+ property(name: string, val: any, description?: string): ShouldAssertion;
+ properties(names: string[]): ShouldAssertion;
+ properties(name: string): ShouldAssertion;
+ properties(descriptor: any): ShouldAssertion;
+ properties(...properties: string[]): ShouldAssertion;
+ ownProperty(name: string, description?: string): ShouldAssertion;
+ contain(obj: any): ShouldAssertion;
+ containEql(obj: any): ShouldAssertion;
+ containDeep(obj: any): ShouldAssertion;
+ keys(...allKeys: string[]): ShouldAssertion;
+ keys(allKeys: string[]): ShouldAssertion;
+ header(field: string, val?: string): ShouldAssertion;
+ status(code: number): ShouldAssertion;
+ json: ShouldAssertion;
+ html: ShouldAssertion;
+ startWith(expected: string, message?: any): ShouldAssertion;
+ endWith(expected: string, message?: any): ShouldAssertion;
+ throw(message?: any): ShouldAssertion;
+
+ // deprecated
+ include(obj: any, description?: string): ShouldAssertion;
+ includeEql(obj: any[], description?: string): ShouldAssertion;
+
+ // aliases
+ exactly(expected: any, description?: string): ShouldAssertion;
+ instanceOf(constructor: Function, description?: string): ShouldAssertion;
+ throwError(message?: any): ShouldAssertion;
+ lengthOf(n: number, description?: string): ShouldAssertion;
+ key(key: string): ShouldAssertion;
+ haveOwnProperty(name: string, description?: string): ShouldAssertion;
+ greaterThan(n: number, description?: string): ShouldAssertion;
+ lessThan(n: number, description?: string): ShouldAssertion;
+}
+
+interface ShouldInternal {
+ // should.js's extras
+ exist(actual: any): void;
+ exists(actual: any): void;
+ not: ShouldInternal;
+}
+
+interface Internal extends ShouldInternal {
+ (obj: any): ShouldAssertion;
+
+ // node.js's assert functions
+ fail(actual: any, expected: any, message: string, operator: string): void;
+ assert(value: any, message: string): void;
+ ok(value: any, message?: string): void;
+ equal(actual: any, expected: any, message?: string): void;
+ notEqual(actual: any, expected: any, message?: string): void;
+ deepEqual(actual: any, expected: any, message?: string): void;
+ notDeepEqual(actual: any, expected: any, message?: string): void;
+ strictEqual(actual: any, expected: any, message?: string): void;
+ notStrictEqual(actual: any, expected: any, message?: string): void;
+ throws(block: any, error?: any, message?: string): void;
+ doesNotThrow(block: any, message?: string): void;
+ ifError(value: any): void;
+ inspect(value: any, obj: any): any;
+}
+
+declare var should: Internal;
+
+declare module "should" {
+ export = should;
+}
diff --git a/test/platform-service.ts b/test/platform-service.ts
new file mode 100644
index 0000000000..4c12ac216f
--- /dev/null
+++ b/test/platform-service.ts
@@ -0,0 +1,29 @@
+///
+
+import PlatformServiceLib = require('../lib/services/platform-service');
+import NodePackageManagerLib = require('../lib/node-package-manager');
+import ProjectLib = require('../lib/services/project-service');
+import stubs = require('./stubs');
+
+import yok = require('../lib/common/yok');
+
+require('should');
+
+var testInjector = new yok.Yok();
+testInjector.register('platformService', PlatformServiceLib.PlatformService);
+testInjector.register('errors', stubs.ErrorsStub);
+testInjector.register('fs', stubs.FileSystemStub);
+testInjector.register('logger', stubs.LoggerStub);
+testInjector.register('npm', stubs.NPMStub);
+testInjector.register('projectData', stubs.ProjectDataStub);
+testInjector.register('platformsData', stubs.PlatformsDataStub);
+
+describe('PlatformService', function(){
+ describe('#updatePlatforms()', function(){
+ it('should fail when no services provided', function(){
+ var platformService = testInjector.resolve('platformService');
+ (function(){return platformService.updatePlatforms().wait(); }).should.throw();
+
+ })
+ })
+});
diff --git a/test/stubs.ts b/test/stubs.ts
new file mode 100644
index 0000000000..46656cf2b9
--- /dev/null
+++ b/test/stubs.ts
@@ -0,0 +1,172 @@
+///
+
+import Future = require("fibers/future");
+import util = require("util");
+import path = require("path");
+
+export class LoggerStub implements ILogger {
+ setLevel(level: string): void {}
+ fatal(...args: string[]): void {}
+ error(...args: string[]): void {}
+ warn(...args: string[]): void {}
+ info(...args: string[]): void {}
+ debug(...args: string[]): void {}
+ trace(...args: string[]): void {}
+
+ public output = "";
+
+ out(...args: string[]): void {
+ this.output += util.format.apply(null, args) + "\n";
+ }
+
+ write(...args: string[]): void { }
+}
+
+export class FileSystemStub implements IFileSystem {
+ zipFiles(zipFile: string, files: string[], zipPathCallback: (path: string) => string): IFuture {
+ return undefined;
+ }
+
+ unzip(zipFile: string, destination: string): IFuture {
+ return undefined;
+ }
+ exists(path: string): IFuture {
+ return Future.fromResult(true);
+ }
+
+ deleteFile(path:string):IFuture {
+ return undefined;
+ }
+
+ deleteDirectory(directory: string): IFuture {
+ return undefined;
+ }
+
+ getFileSize(path:string):IFuture {
+ return undefined;
+ }
+
+ futureFromEvent(eventEmitter: any, event: string): IFuture {
+ return undefined;
+ }
+
+ createDirectory(path:string):IFuture {
+ return undefined;
+ }
+
+ readDirectory(path:string):IFuture {
+ return undefined;
+ }
+
+ readFile(filename:string):IFuture {
+ return undefined;
+ }
+
+ readText(filename:string, encoding?:string):IFuture {
+ return undefined;
+ }
+
+ readJson(filename:string, encoding?:string):IFuture {
+ return Future.fromResult({});
+ }
+
+ writeFile(filename: string, data: any, encoding?: string): IFuture {
+ return undefined;
+ }
+
+ writeJson(filename: string, data: any, space?: string, encoding?: string): IFuture {
+ return undefined;
+ }
+
+ copyFile(sourceFileName:string, destinationFileName:string):IFuture {
+ return undefined;
+ }
+
+ openFile(filename: string): void { }
+
+ createReadStream(path:string, options?:{flags?: string; encoding?: string; fd?: string; mode?: number; bufferSize?: number}): any {
+ return undefined;
+ }
+
+ createWriteStream(path:string, options?:{flags?: string; encoding?: string; string?: string}): any {
+ return undefined;
+ }
+
+ chmod(path: string, mode: number): IFuture {
+ return undefined;
+ }
+
+ getUniqueFileName(baseName: string): IFuture {
+ return undefined;
+ }
+
+ getFsStats(path: string): IFuture {
+ return undefined;
+ }
+
+ isEmptyDir(directoryPath: string): IFuture {
+ return undefined;
+ }
+
+ ensureDirectoryExists(directoryPath: string): IFuture {
+ return undefined;
+ }
+
+ rename(oldPath: string, newPath: string): IFuture {
+ return undefined;
+ }
+}
+
+export class ErrorsStub implements IErrors {
+ private impl: IErrors = new (require("../lib/common/errors").Errors)();
+
+ fail(formatStr:string, ...args: any[]): void;
+ fail(opts:{formatStr?: string; errorCode?: number; suppressCommandHelp?: boolean}, ...args: any[]): void;
+
+ fail(...args: any[]) {
+ throw args;
+ }
+
+ beginCommand(action:() => void, printHelpCommand: () => void) {
+ throw new Error("not supported");
+ }
+
+ verifyHeap(message: string): void {
+
+ }
+}
+
+export class NPMStub implements INodePackageManager {
+ get cache(): string {
+ return undefined;
+ }
+
+ load(config?: any): IFuture {
+ return undefined;
+ }
+
+ install(packageName: string, pathToSave?: string, version?: string): IFuture {
+ return undefined;
+ }
+}
+
+export class ProjectDataStub implements IProjectData {
+ public projectDir: string;
+ public platformsDir: string;
+ public projectFilePath: string;
+ public projectId: string;
+ public projectName: string;
+}
+
+export class PlatformsDataStub implements IPlatformsData {
+ public get platformsNames(): string[] {
+ return undefined;
+ }
+
+ public getPlatformData(platform: string): IPlatformData {
+ return undefined;
+ }
+}
+
+
+
diff --git a/test/test-bootstrap.ts b/test/test-bootstrap.ts
new file mode 100644
index 0000000000..21358bba2e
--- /dev/null
+++ b/test/test-bootstrap.ts
@@ -0,0 +1,6 @@
+global._ = require("underscore");
+global.$injector = require("../lib/common/yok").injector;
+
+process.on('exit', (code: number) => {
+ require("fibers/future").assertNoFutureLeftBehind();
+});