Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified creating angular template project #1638

Merged
merged 2 commits into from
Mar 23, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/man_pages/project/creation/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ create
Usage | Synopsis
---|---
Create from default JavaScript template | `$ tns create <App Name> [--path <Directory>] [--appid <App ID>]`
Create from default TypeScript template | `$ tns create <App Name> [--path <Directory>] [--appid <App ID> --template typescript` OR `$ tns create <App Name> [--path <Directory>] [--appid <App ID> --template tsc`
Create from default TypeScript template | `$ tns create <App Name> --template typescript [--path <Directory>] [--appid <App ID>]` OR `$ tns create <App Name> --template tsc [--path <Directory>] [--appid <App ID>]`
Create from default Angular template | `$ tns create <App Name> --template angular [--path <Directory>] [--appid <App ID>]` OR `$ tns create <App Name> --template ng [--path <Directory>] [--appid <App ID>]` OR `$ tns create <App Name> --ng [--path <Directory>] [--appid <App ID>]`
Copy from existing project | `$ tns create <App Name> [--path <Directory>] [--appid <App ID>] --copy-from <Directory>`
Create from custom template | `$ tns create <App Name> [--path <Directory>] [--appid <App ID>] --template <Template>`

Expand All @@ -15,6 +16,7 @@ Creates a new project for native development with NativeScript.
* `--appid` - Sets the application identifier for your project.
* `--copy-from` - Specifies a directory which contains an existing NativeScript project. If `--copy-from` and `--template` are not set, the NativeScript CLI creates the project from the default JavaScript hello-world template.
* `--template` - Specifies a valid npm package which you want to use to create your project. If `--copy-from` and `--template` are not set, the NativeScript CLI creates the project from the default JavaScript hello-world template.<% if(isHtml) { %> If one or more application assets are missing from the `App_Resources` directory in the package, the CLI adds them using the assets available in the default hello-world template.<% } %>
* `--ng` - Sets the template for your project to the Angular template.

### Attributes
* `<App Name>` is the name of project. The specified name must meet the requirements of all platforms that you want to target. <% if(isConsole) { %>For more information about the `<App Name>` requirements, run `$ tns help create`<% } %><% if(isHtml) { %>For projects that target Android, you can use uppercase or lowercase letters, numbers, and underscores. The name must start with a letter.
Expand Down
12 changes: 11 additions & 1 deletion lib/commands/create-project.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
///<reference path="../.d.ts"/>
"use strict";

import * as constants from "../constants";

export class ProjectCommandParameter implements ICommandParameter {
constructor(private $errors: IErrors,
private $logger: ILogger,
Expand All @@ -27,12 +29,20 @@ export class CreateProjectCommand implements ICommand {
private $errors: IErrors,
private $logger: ILogger,
private $projectNameValidator: IProjectNameValidator,
private $options: ICommonOptions) { }
private $options: IOptions) { }

public enableHooks = false;

execute(args: string[]): IFuture<void> {
return (() => {
if (this.$options.ng && this.$options.template) {
this.$errors.fail("You cannot use --ng and --template simultaneously.");
}

if (this.$options.ng) {
this.$options.template = constants.ANGULAR_NAME;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of setting this.$options.template you can use something like:

let selectedTemplate = this.$options.ng ? constants.ANGULARE_NAME : this.$options.template;
this.$projectService.createProject(args[0], selectedTemplate).wait();

}

this.$projectService.createProject(args[0], this.$options.template).wait();
}).future<void>()();
}
Expand Down
2 changes: 2 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ class ItunesConnectApplicationTypesClass implements IiTunesConnectApplicationTyp
}

export let ItunesConnectApplicationTypes = new ItunesConnectApplicationTypesClass();

export let ANGULAR_NAME = "angular";
39 changes: 20 additions & 19 deletions lib/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,33 @@ interface ILiveSyncService {
}

interface IOptions extends ICommonOptions {
ipa: string;
frameworkPath: string;
frameworkName: string;
framework: string;
frameworkVersion: string;
baseConfig: string;
client: boolean;
compileSdk: number;
copyFrom: string;
linkTo: string;
copyTo: string;
debugTransport: boolean;
emulator: boolean;
symlink: boolean;
forDevice: boolean;
client: boolean;
production: boolean;
keyStorePath: string;
keyStorePassword: string;
framework: string;
frameworkName: string;
frameworkPath: string;
frameworkVersion: string;
ignoreScripts: boolean;
ipa: string;
keyStoreAlias: string;
keyStoreAliasPassword: string;
keyStorePassword: string;
keyStorePath: string;
linkTo: string;
ng: boolean;
platformTemplate: string;
port: Number;
production: boolean;
sdk: string;
debugTransport: boolean;
ignoreScripts: boolean;
tnsModulesVersion: string;
staticBindings: boolean;
compileSdk: number;
port: Number;
copyTo: string;
baseConfig: string;
platformTemplate: string;
symlink: boolean;
tnsModulesVersion: string;
}

interface IInitService {
Expand Down
3 changes: 2 additions & 1 deletion lib/npm-installation-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export class NpmInstallationManager implements INpmInstallationManager {
"tns-ios": constants.PROJECT_FRAMEWORK_FOLDER_NAME,
"tns-ios-inspector": "WebInspectorUI",
"tns-template-hello-world": constants.APP_RESOURCES_FOLDER_NAME,
"tns-template-hello-world-ts": constants.APP_RESOURCES_FOLDER_NAME
"tns-template-hello-world-ts": constants.APP_RESOURCES_FOLDER_NAME,
"tns-template-hello-world-ng": constants.APP_RESOURCES_FOLDER_NAME
};

constructor(private $npm: INodePackageManager,
Expand Down
3 changes: 2 additions & 1 deletion lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export class Options extends commonOptionsLibPath.OptionsBase {
port: { type: OptionType.Number },
copyTo: { type: OptionType.String },
baseConfig: { type: OptionType.String },
platformTemplate: { type: OptionType.String }
platformTemplate: { type: OptionType.String },
ng: {type: OptionType.Boolean }
},
path.join($hostInfo.isWindows ? process.env.AppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"),
$errors, $staticConfig);
Expand Down
2 changes: 2 additions & 0 deletions lib/services/project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ export class ProjectService implements IProjectService {
this.$fs.symlink(appSourcePath, appDestinationPath).wait();
} else {
shelljs.cp('-R', path.join(appSourcePath, "*"), appDestinationPath);
// Copy hidden files.
shelljs.cp('-R', path.join(appSourcePath, ".*"), appDestinationPath);
}

this.createBasicProjectStructure(projectDir, projectId).wait();
Expand Down
4 changes: 3 additions & 1 deletion lib/services/project-templates-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export class ProjectTemplatesService implements IProjectTemplatesService {
private static RESERVED_TEMPLATE_NAMES: IStringDictionary = {
"default": "tns-template-hello-world",
"tsc": "tns-template-hello-world-ts",
"typescript": "tns-template-hello-world-ts"
"typescript": "tns-template-hello-world-ts",
"ng": "tns-template-hello-world-ng",
"angular": "tns-template-hello-world-ng"
};

public constructor(private $errors: IErrors,
Expand Down
114 changes: 114 additions & 0 deletions test/project-commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/// <reference path=".d.ts" />
"use strict";

import * as yok from "../lib/common/yok";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use:

import { Yok } from "../lib/common/yok"; 

and define it as new Yok() directly later in your code

import * as stubs from "./stubs";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use:

import { LoggerStub, ErrorsStub } from "./stubs"; 

and use them directly later in your code

import { CreateProjectCommand } from "../lib/commands/create-project";
import * as constants from "../lib/constants";
import {assert} from "chai";

let selectedTemplateName: string;
let isProjectCreated: boolean;
let dummyArgsString = "dummyArgsString";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can define this as array:

let dummyArgs = [ "dummyString" ];

and use it later as:

createProjectCommand.execute(dummyArgsString).wait();


class ProjectServiceMock implements IProjectService {
createProject(projectName: string, selectedTemplate?: string): IFuture<void> {
return (() => {
selectedTemplateName = selectedTemplate;
isProjectCreated = true;
}).future<void>()();
}
}

class ProjectNameValidatorMock implements IProjectNameValidator {
public validate(name: string): boolean {
return true;
}
}

function createTestInjector() {
let testInjector = new yok.Yok();

testInjector.register("injector", testInjector);
testInjector.register("staticConfig", {});
testInjector.register("projectService", ProjectServiceMock);
testInjector.register("errors", stubs.ErrorsStub);
testInjector.register("logger", stubs.LoggerStub);
testInjector.register("projectNameValidator", ProjectNameValidatorMock);
testInjector.register("options", {
ng: false,
template: undefined
});
testInjector.register("createCommand", CreateProjectCommand);

return testInjector;
}

describe('Project Service Tests', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are testing just the command, not the project Service itself, so you do not need this describe.
Please remove it and move the beforeEach and testInjector in the other describe.

let testInjector: IInjector;

beforeEach(() => {
testInjector = createTestInjector();
isProjectCreated = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set selectedTemplateName to null just to be sure the tests are correct

});

describe("project commands tests", () => {
describe("#CreateProjectCommand", () => {
it("should not fail when using only --ng.", () => {
let options: IOptions = testInjector.resolve("$options");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line is used in all tests, consider moving it to beforeEach method.

options.ng = true;

let createProjectCommand: ICommand = testInjector.resolve("$createCommand");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line is used in all tests, consider moving it to beforeEach method.


createProjectCommand.execute([dummyArgsString]).wait();

assert.isTrue(isProjectCreated);
});

it("should not fail when using only --template.", () => {
let options: IOptions = testInjector.resolve("$options");
options.template = "ng";

let createProjectCommand: ICommand = testInjector.resolve("$createCommand");

createProjectCommand.execute([dummyArgsString]).wait();

assert.isTrue(isProjectCreated);
});

it("should set the template name correctly when used --ng.", () => {
let options: IOptions = testInjector.resolve("$options");
options.ng = true;

let createProjectCommand: ICommand = testInjector.resolve("$createCommand");

createProjectCommand.execute([dummyArgsString]).wait();

assert.deepEqual(options.template, constants.ANGULAR_NAME);
});

it("should not set the template name when --ng is not used.", () => {
let options: IOptions = testInjector.resolve("$options");
options.ng = false;

let createProjectCommand: ICommand = testInjector.resolve("$createCommand");

createProjectCommand.execute([dummyArgsString]).wait();

assert.isUndefined(options.template);
});

it("should fail when --ng and --template are used simultaneously.", () => {
let options: IOptions = testInjector.resolve("$options");
options.ng = true;
options.template = "ng";

let createProjectCommand: ICommand = testInjector.resolve("$createCommand");

assert.throws(() => {
createProjectCommand.execute([dummyArgsString]).wait();
});
});
});
});
});
26 changes: 26 additions & 0 deletions test/project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,32 @@ describe("Project Service Tests", () => {
projectIntegrationTest.assertProject(tempFolder, projectName, "org.nativescript.myapp", projectTemplatesService.prepareTemplate("tsc").wait()).wait();
});

it("creates valid project from angular template", () => {
let projectIntegrationTest = new ProjectIntegrationTest();
let tempFolder = temp.mkdirSync("projectAngular");
let projectName = "myapp";
let options = projectIntegrationTest.testInjector.resolve("options");

options.path = tempFolder;
projectIntegrationTest.createProject(projectName, "angular").wait();

let projectTemplatesService: IProjectTemplatesService = projectIntegrationTest.testInjector.resolve("projectTemplatesService");
projectIntegrationTest.assertProject(tempFolder, projectName, "org.nativescript.myapp", projectTemplatesService.prepareTemplate("angular").wait()).wait();
});

it("creates valid project from ng template", () => {
let projectIntegrationTest = new ProjectIntegrationTest();
let tempFolder = temp.mkdirSync("projectNg");
let projectName = "myapp";
let options = projectIntegrationTest.testInjector.resolve("options");

options.path = tempFolder;
projectIntegrationTest.createProject(projectName, "ng").wait();

let projectTemplatesService: IProjectTemplatesService = projectIntegrationTest.testInjector.resolve("projectTemplatesService");
projectIntegrationTest.assertProject(tempFolder, projectName, "org.nativescript.myapp", projectTemplatesService.prepareTemplate("ng").wait()).wait();
});

it("creates valid project from local directory template", () => {
let projectIntegrationTest = new ProjectIntegrationTest();
let tempFolder = temp.mkdirSync("projectLocalDir");
Expand Down