Skip to content

Commit 807f1cc

Browse files
author
DimitarTachev
committed
test: add a few tests for the interactive app creation
1 parent c595c0e commit 807f1cc

File tree

2 files changed

+72
-20
lines changed

2 files changed

+72
-20
lines changed

test/project-commands.ts

+64-17
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { Yok } from "../lib/common/yok";
22
import * as stubs from "./stubs";
33
import { CreateProjectCommand } from "../lib/commands/create-project";
4-
import { StringParameterBuilder } from "../lib/common/command-params";
4+
import { StringCommandParameter } from "../lib/common/command-params";
5+
import helpers = require("../lib/common/helpers");
56
import * as constants from "../lib/constants";
67
import { assert } from "chai";
8+
import { PrompterStub } from "./stubs";
9+
10+
const NgFlavor = "Angular";
11+
const VueFlavor = "Vue.js";
12+
const TsFlavor = "Plain TypeScript";
13+
const JsFlavor = "Plain JavaScript";
714

815
let selectedTemplateName: string;
916
let isProjectCreated: boolean;
1017
const dummyArgs = ["dummyArgsString"];
1118

1219
class ProjectServiceMock implements IProjectService {
13-
async validateProjectName(opts: { projectName: string, force: boolean, pathToProject: string }) : Promise<string> {
20+
async validateProjectName(opts: { projectName: string, force: boolean, pathToProject: string }): Promise<string> {
1421
return null;
1522
}
1623

@@ -45,7 +52,8 @@ function createTestInjector() {
4552
template: undefined
4653
});
4754
testInjector.register("createCommand", CreateProjectCommand);
48-
testInjector.register("stringParameterBuilder", StringParameterBuilder);
55+
testInjector.register("stringParameter", StringCommandParameter);
56+
testInjector.register("prompter", PrompterStub);
4957

5058
return testInjector;
5159
}
@@ -55,8 +63,31 @@ describe("Project commands tests", () => {
5563
let options: IOptions;
5664
let createProjectCommand: ICommand;
5765

66+
function setupAnswers(opts: {
67+
projectNameAnswer?: string,
68+
flavorAnswer?: string,
69+
templateAnswer?: string,
70+
}) {
71+
const prompterStub = <stubs.PrompterStub>testInjector.resolve("$prompter");
72+
const choices: IDictionary<string> = {};
73+
if (opts.projectNameAnswer) {
74+
choices["First, what will be the name of your app?"] = opts.projectNameAnswer;
75+
}
76+
if (opts.flavorAnswer) {
77+
choices[opts.projectNameAnswer ? "Next" : "First" + ", which flavor would you like to use?"] = opts.flavorAnswer;
78+
}
79+
if (opts.templateAnswer) {
80+
choices[opts.projectNameAnswer ? "Finally" : "Next" + ", which template would you like to start from?"] = opts.templateAnswer;
81+
}
82+
83+
prompterStub.expect({
84+
choices
85+
});
86+
}
87+
5888
beforeEach(() => {
5989
testInjector = createTestInjector();
90+
helpers.isInteractive = () => true;
6091
isProjectCreated = false;
6192
selectedTemplateName = undefined;
6293
options = testInjector.resolve("$options");
@@ -104,34 +135,50 @@ describe("Project commands tests", () => {
104135
assert.deepEqual(selectedTemplateName, constants.TYPESCRIPT_NAME);
105136
});
106137

107-
it("should not set the template name when --ng is not used.", async () => {
108-
options.ng = false;
138+
it("should fail when --ng and --template are used simultaneously.", async () => {
139+
options.ng = true;
140+
options.template = "ng";
141+
142+
await assert.isRejected(createProjectCommand.execute(dummyArgs));
143+
});
144+
145+
it("should fail when --tsc and --template are used simultaneously.", async () => {
146+
options.tsc = true;
147+
options.template = "tsc";
148+
149+
await assert.isRejected(createProjectCommand.execute(dummyArgs));
150+
});
151+
152+
it("should ask for a template when ng flavor is selected.", async () => {
153+
setupAnswers({ flavorAnswer: NgFlavor, templateAnswer: "Hello World" });
109154

110155
await createProjectCommand.execute(dummyArgs);
111156

112-
assert.isUndefined(selectedTemplateName);
157+
assert.deepEqual(selectedTemplateName, "tns-template-hello-world-ng");
113158
});
114159

115-
it("should not set the template name when --tsc is not used.", async () => {
116-
options.tsc = false;
160+
it("should ask for a template when ts flavor is selected.", async () => {
161+
setupAnswers({ flavorAnswer: TsFlavor, templateAnswer: "Hello World" });
117162

118163
await createProjectCommand.execute(dummyArgs);
119164

120-
assert.isUndefined(selectedTemplateName);
165+
assert.deepEqual(selectedTemplateName, "tns-template-hello-world-ts");
121166
});
122167

123-
it("should fail when --ng and --template are used simultaneously.", async () => {
124-
options.ng = true;
125-
options.template = "ng";
168+
it("should ask for a template when js flavor is selected.", async () => {
169+
setupAnswers({ flavorAnswer: JsFlavor, templateAnswer: "Hello World" });
126170

127-
await assert.isRejected(createProjectCommand.execute(dummyArgs));
171+
await createProjectCommand.execute(dummyArgs);
172+
173+
assert.deepEqual(selectedTemplateName, "tns-template-hello-world");
128174
});
129175

130-
it("should fail when --tsc and --template are used simultaneously.", async () => {
131-
options.tsc = true;
132-
options.template = "tsc";
176+
it("should select the default vue template when the vue flavor is selected.", async () => {
177+
setupAnswers({ flavorAnswer: VueFlavor });
133178

134-
await assert.isRejected(createProjectCommand.execute(dummyArgs));
179+
await createProjectCommand.execute(dummyArgs);
180+
181+
assert.deepEqual(selectedTemplateName, "https://github.com/NativeScript/template-blank-vue/tarball/0.9.0");
135182
});
136183
});
137184
});

test/stubs.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,13 @@ export class LockFile {
514514
export class PrompterStub implements IPrompter {
515515
private strings: IDictionary<string> = {};
516516
private passwords: IDictionary<string> = {};
517+
private choices: IDictionary<string> = {};
517518

518-
expect(options?: { strings: IDictionary<string>, passwords: IDictionary<string> }) {
519+
expect(options?: { strings?: IDictionary<string>, passwords?: IDictionary<string>, choices?: IDictionary<string> }) {
519520
if (options) {
520521
this.strings = options.strings || this.strings;
521522
this.passwords = options.passwords || this.passwords;
523+
this.choices = options.choices || this.choices;
522524
}
523525
}
524526

@@ -540,8 +542,11 @@ export class PrompterStub implements IPrompter {
540542
async promptForChoice(promptMessage: string, choices: any[]): Promise<string> {
541543
throw unreachable();
542544
}
543-
async promptForDetailedChoice(promptMessage: string, choices: any[]): Promise<string> {
544-
throw unreachable();
545+
async promptForDetailedChoice(question: string, choices: any[]): Promise<string> {
546+
chai.assert.ok(question in this.choices, `PrompterStub didn't expect to be asked: ${question}`);
547+
const result = this.choices[question];
548+
delete this.choices[question];
549+
return result;
545550
}
546551
async confirm(prompt: string, defaultAction?: () => boolean): Promise<boolean> {
547552
throw unreachable();

0 commit comments

Comments
 (0)