1
1
import * as yok from "../lib/common/yok" ;
2
- import * as stubs from "./stubs" ;
3
2
import * as constants from "../lib/constants" ;
4
- import { ChildProcess } from "../lib/common/child-process" ;
5
3
import * as ProjectServiceLib from "../lib/services/project-service" ;
6
- import { ProjectNameService } from "../lib/services/project-name-service" ;
7
- import * as ProjectDataServiceLib from "../lib/services/project-data-service" ;
8
- import * as ProjectHelperLib from "../lib/common/project-helper" ;
9
- import { StaticConfig } from "../lib/config" ;
10
- import * as NpmLib from "../lib/node-package-manager" ;
11
- import * as YarnLib from "../lib/yarn-package-manager" ;
12
- import * as PackageManagerLib from "../lib/package-manager" ;
13
- import { PackageInstallationManager } from "../lib/package-installation-manager" ;
14
- import { FileSystem } from "../lib/common/file-system" ;
15
- import * as path from "path" ;
16
- import temp = require( "temp" ) ;
17
- import helpers = require( "../lib/common/helpers" ) ;
18
4
import { assert } from "chai" ;
19
- import { Options } from "../lib/options" ;
20
- import { HostInfo } from "../lib/common/host-info" ;
21
- import { ProjectTemplatesService } from "../lib/services/project-templates-service" ;
22
5
import { SettingsService } from "../lib/common/test/unit-tests/stubs" ;
23
- import { DevicePlatformsConstants } from "../lib/common/mobile/device-platforms-constants" ;
24
- import { PacoteService } from "../lib/services/pacote-service" ;
25
-
26
- const mockProjectNameValidator = {
27
- validate : ( ) => true
28
- } ;
29
-
30
- const dummyString : string = "dummyString" ;
31
- let hasPromptedForString = false ;
32
- const originalIsInteractive = helpers . isInteractive ;
33
-
34
- temp . track ( ) ;
35
-
36
- async function prepareTestingPath ( testInjector : IInjector , packageToInstall : string , packageName : string , options ?: INpmInstallOptions ) : Promise < string > {
37
- options = options || { dependencyType : "save" } ;
38
- const fs = testInjector . resolve < IFileSystem > ( "fs" ) ;
39
-
40
- const packageInstallationManager = testInjector . resolve < IPackageInstallationManager > ( "packageInstallationManager" ) ;
41
- const defaultTemplateDir = temp . mkdirSync ( "project-service" ) ;
42
- fs . writeJson ( path . join ( defaultTemplateDir , constants . PACKAGE_JSON_FILE_NAME ) , {
43
- "name" : "defaultTemplate" ,
44
- "version" : "1.0.0" ,
45
- "description" : "dummy" ,
46
- "license" : "MIT" ,
47
- "readme" : "dummy" ,
48
- "repository" : "dummy"
49
- } ) ;
50
-
51
- await packageInstallationManager . install ( packageToInstall , defaultTemplateDir , options ) ;
52
- const defaultTemplatePath = path . join ( defaultTemplateDir , constants . NODE_MODULES_FOLDER_NAME , packageName ) ;
53
-
54
- fs . deleteDirectory ( path . join ( defaultTemplatePath , constants . NODE_MODULES_FOLDER_NAME ) ) ;
55
-
56
- return defaultTemplatePath ;
57
- }
58
-
59
- class ProjectIntegrationTest {
60
- public testInjector : IInjector ;
61
-
62
- constructor ( ) {
63
- this . createTestInjector ( ) ;
64
- }
65
-
66
- public async createProject ( projectOptions : IProjectSettings ) : Promise < ICreateProjectData > {
67
- const projectService : IProjectService = this . testInjector . resolve ( "projectService" ) ;
68
- if ( ! projectOptions . template ) {
69
- projectOptions . template = constants . RESERVED_TEMPLATE_NAMES [ "default" ] ;
70
- }
71
- return projectService . createProject ( projectOptions ) ;
72
- }
73
-
74
- public async assertProject ( tempFolder : string , projectName : string , appId : string , projectSourceDirectory : string ) : Promise < void > {
75
- const fs : IFileSystem = this . testInjector . resolve ( "fs" ) ;
76
- const projectDir = path . join ( tempFolder , projectName ) ;
77
- const appDirectoryPath = path . join ( projectDir , "app" ) ;
78
- const tnsProjectFilePath = path . join ( projectDir , "package.json" ) ;
79
- const tnsModulesPath = path . join ( projectDir , constants . NODE_MODULES_FOLDER_NAME , constants . TNS_CORE_MODULES_NAME ) ;
80
- const packageJsonContent = fs . readJson ( tnsProjectFilePath ) ;
81
-
82
- assert . isTrue ( fs . exists ( appDirectoryPath ) ) ;
83
- assert . isTrue ( fs . exists ( tnsProjectFilePath ) ) ;
84
- assert . isTrue ( fs . exists ( tnsModulesPath ) ) ;
85
-
86
- assert . isFalse ( fs . isEmptyDir ( appDirectoryPath ) ) ;
87
-
88
- const actualAppId = packageJsonContent [ "nativescript" ] . id ;
89
- const expectedAppId = appId ;
90
- assert . equal ( actualAppId , expectedAppId ) ;
91
-
92
- const tnsCoreModulesRecord = packageJsonContent [ "dependencies" ] [ constants . TNS_CORE_MODULES_NAME ] ;
93
- assert . isTrue ( tnsCoreModulesRecord !== null ) ;
94
-
95
- const sourceDir = projectSourceDirectory ;
96
-
97
- // assert dependencies and devDependencies are copied from template to real project
98
- const sourcePackageJsonContent = fs . readJson ( path . join ( sourceDir , "package.json" ) ) ;
99
- const missingDeps = _ . difference ( _ . keys ( sourcePackageJsonContent . dependencies ) , _ . keys ( packageJsonContent . dependencies ) ) ;
100
- const missingDevDeps = _ . difference ( _ . keys ( sourcePackageJsonContent . devDependencies ) , _ . keys ( packageJsonContent . devDependencies ) ) ;
101
- assert . deepEqual ( missingDeps , [ ] , `All dependencies from template must be copied to project's package.json. Missing ones are: ${ missingDeps . join ( ", " ) } .` ) ;
102
- assert . deepEqual ( missingDevDeps , [ ] , `All devDependencies from template must be copied to project's package.json. Missing ones are: ${ missingDevDeps . join ( ", " ) } .` ) ;
103
-
104
- // assert App_Resources are prepared correctly
105
- const appResourcesDir = path . join ( appDirectoryPath , "App_Resources" ) ;
106
- const appResourcesContents = fs . readDirectory ( appResourcesDir ) ;
107
- assert . deepEqual ( appResourcesContents , [ "Android" , "iOS" ] , "Project's app/App_Resources must contain Android and iOS directories." ) ;
108
- }
109
-
110
- public dispose ( ) : void {
111
- this . testInjector = undefined ;
112
- }
113
-
114
- private createTestInjector ( ) : void {
115
- this . testInjector = new yok . Yok ( ) ;
116
- this . testInjector . register ( "childProcess" , ChildProcess ) ;
117
- this . testInjector . register ( "errors" , stubs . ErrorsStub ) ;
118
- this . testInjector . register ( 'logger' , stubs . LoggerStub ) ;
119
- this . testInjector . register ( "projectService" , ProjectServiceLib . ProjectService ) ;
120
- this . testInjector . register ( "projectNameService" , ProjectNameService ) ;
121
- this . testInjector . register ( "projectHelper" , ProjectHelperLib . ProjectHelper ) ;
122
- this . testInjector . register ( "projectTemplatesService" , ProjectTemplatesService ) ;
123
- this . testInjector . register ( "projectNameValidator" , mockProjectNameValidator ) ;
124
- this . testInjector . register ( "projectData" , stubs . ProjectDataStub ) ;
125
-
126
- this . testInjector . register ( "fs" , FileSystem ) ;
127
- this . testInjector . register ( "projectDataService" , ProjectDataServiceLib . ProjectDataService ) ;
128
- this . testInjector . register ( "staticConfig" , StaticConfig ) ;
129
- this . testInjector . register ( "analyticsService" , {
130
- track : async ( ) : Promise < any > => undefined ,
131
- trackEventActionInGoogleAnalytics : ( data : IEventActionData ) => Promise . resolve ( )
132
- } ) ;
133
-
134
- this . testInjector . register ( "userSettingsService" , {
135
- getSettingValue : async ( settingName : string ) : Promise < void > => undefined
136
- } ) ;
137
- this . testInjector . register ( "npm" , NpmLib . NodePackageManager ) ;
138
- this . testInjector . register ( "yarn" , YarnLib . YarnPackageManager ) ;
139
- this . testInjector . register ( "packageManager" , PackageManagerLib . PackageManager ) ;
140
- this . testInjector . register ( "httpClient" , { } ) ;
141
-
142
- this . testInjector . register ( "options" , Options ) ;
143
- this . testInjector . register ( "hostInfo" , HostInfo ) ;
144
- this . testInjector . register ( "prompter" , {
145
- confirm : async ( message : string ) : Promise < boolean > => true ,
146
- getString : async ( message : string ) : Promise < string > => {
147
- hasPromptedForString = true ;
148
- return dummyString ;
149
- }
150
- } ) ;
151
- this . testInjector . register ( "packageInstallationManager" , PackageInstallationManager ) ;
152
- this . testInjector . register ( "settingsService" , SettingsService ) ;
153
- this . testInjector . register ( "devicePlatformsConstants" , DevicePlatformsConstants ) ;
154
- this . testInjector . register ( "androidResourcesMigrationService" , {
155
- hasMigrated : ( appResourcesDir : string ) : boolean => true
156
- } ) ;
157
- this . testInjector . register ( "hooksService" , {
158
- executeAfterHooks : async ( commandName : string , hookArguments ?: IDictionary < any > ) : Promise < void > => undefined
159
- } ) ;
160
- this . testInjector . register ( "pacoteService" , PacoteService ) ;
161
- this . testInjector . register ( "proxyService" , {
162
- getCache : async ( ) : Promise < IProxySettings > => null
163
- } ) ;
164
- }
165
- }
166
-
167
- describe ( "Project Service Tests" , ( ) => {
168
- describe ( "project service integration tests" , ( ) => {
169
- let defaultTemplatePath : string ;
170
-
171
- before ( async ( ) => {
172
- const projectIntegrationTest = new ProjectIntegrationTest ( ) ;
173
-
174
- defaultTemplatePath = await prepareTestingPath ( projectIntegrationTest . testInjector , constants . RESERVED_TEMPLATE_NAMES [ "default" ] , constants . RESERVED_TEMPLATE_NAMES [ "default" ] ) ;
175
- } ) ;
6
+ import { LoggerStub , ErrorsStub } from "./stubs" ;
7
+ import * as path from "path" ;
176
8
177
- describe ( "project name validation tests" , ( ) => {
178
- const validProjectName = "valid" ;
179
- const invalidProjectName = "1invalid" ;
180
- let projectIntegrationTest : ProjectIntegrationTest ;
181
- let tempFolder : string ;
182
- let prompter : IPrompter ;
9
+ describe ( "projectService" , ( ) => {
10
+ describe ( "createProject" , ( ) => {
11
+ const invalidProjectName = "1invalid" ;
12
+ const dirToCreateProject : string = path . resolve ( "projectDir" ) ;
183
13
184
- beforeEach ( ( ) => {
185
- hasPromptedForString = false ;
186
- helpers . isInteractive = ( ) => true ;
187
- projectIntegrationTest = new ProjectIntegrationTest ( ) ;
188
- tempFolder = temp . mkdirSync ( "project" ) ;
189
- prompter = projectIntegrationTest . testInjector . resolve ( "prompter" ) ;
14
+ /* tslint:disable:no-empty */
15
+ const getTestInjector = ( opts : { projectName : string } ) : IInjector => {
16
+ const testInjector = new yok . Yok ( ) ;
17
+ testInjector . register ( "packageManager" , {
18
+ install : async ( ) => { }
190
19
} ) ;
191
-
192
- afterEach ( ( ) => {
193
- helpers . isInteractive = originalIsInteractive ;
20
+ testInjector . register ( "errors" , ErrorsStub ) ;
21
+ testInjector . register ( "fs" , {
22
+ exists : ( ) => true ,
23
+ isEmptyDir : ( ) => true ,
24
+ createDirectory : ( ) => { } ,
25
+ writeJson : ( ) => { } ,
26
+ deleteDirectory : ( ) => { } ,
27
+ ensureDirectoryExists : ( ) => { } ,
28
+ readJson : ( ) => ( { } )
194
29
} ) ;
195
-
196
- it ( "creates project when is interactive and incorrect name is specified and the --force option is set" , async ( ) => {
197
- const projectName = invalidProjectName ;
198
- await projectIntegrationTest . createProject ( { projectName : projectName , pathToProject : tempFolder , force : true } ) ;
199
- await projectIntegrationTest . assertProject ( tempFolder , projectName , `org.nativescript.${ projectName } ` , defaultTemplatePath ) ;
30
+ testInjector . register ( "logger" , LoggerStub ) ;
31
+ testInjector . register ( "projectDataService" , {
32
+ getProjectData : ( projectDir ?: string ) : IProjectData => ( < any > {
33
+ getAppResourcesDirectoryPath : ( ) => "appResourcesDirectoryPath"
34
+ } ) ,
35
+ setNSValue : ( ) => { }
200
36
} ) ;
201
-
202
- it ( "creates project when is interactive and incorrect name is specified and the user confirms to use the incorrect name" , async ( ) => {
203
- const projectName = invalidProjectName ;
204
- prompter . confirm = ( message : string ) : Promise < boolean > => Promise . resolve ( true ) ;
205
-
206
- await projectIntegrationTest . createProject ( { projectName : projectName , pathToProject : tempFolder } ) ;
207
- await projectIntegrationTest . assertProject ( tempFolder , projectName , `org.nativescript.${ projectName } ` , defaultTemplatePath ) ;
37
+ testInjector . register ( "projectData" , { } ) ;
38
+ testInjector . register ( "projectNameService" , {
39
+ ensureValidName : async ( ) => opts . projectName
208
40
} ) ;
209
-
210
- it ( "prompts for new name when is interactive and incorrect name is specified and the user does not confirm to use the incorrect name" , async ( ) => {
211
- const projectName = invalidProjectName ;
212
-
213
- prompter . confirm = ( message : string ) : Promise < boolean > => Promise . resolve ( false ) ;
214
-
215
- await projectIntegrationTest . createProject ( { projectName : projectName , pathToProject : tempFolder } ) ;
216
- assert . isTrue ( hasPromptedForString ) ;
41
+ testInjector . register ( "projectTemplatesService" , {
42
+ prepareTemplate : async ( ) => ( {
43
+ templateName : constants . RESERVED_TEMPLATE_NAMES [ "default" ] ,
44
+ templatePath : "some path" ,
45
+ templateVersion : "v2" ,
46
+ templatePackageJsonContent : {
47
+ dependencies : {
48
+ [ "tns-core-modules" ] : "1.0.0"
49
+ }
50
+ } ,
51
+ version : "1.0.0"
52
+ } )
217
53
} ) ;
218
-
219
- it ( "creates project when is interactive and incorrect name s specified and the user does not confirm to use the incorrect name and enters incorrect name again several times and then enters correct name" , async ( ) => {
220
- const projectName = invalidProjectName ;
221
-
222
- prompter . confirm = ( message : string ) : Promise < boolean > => Promise . resolve ( false ) ;
223
-
224
- const incorrectInputsLimit = 5 ;
225
- let incorrectInputsCount = 0 ;
226
-
227
- prompter . getString = async ( message : string ) : Promise < string > => {
228
- if ( incorrectInputsCount < incorrectInputsLimit ) {
229
- incorrectInputsCount ++ ;
230
- } else {
231
- hasPromptedForString = true ;
232
-
233
- return validProjectName ;
234
- }
235
-
236
- return projectName ;
237
- } ;
238
-
239
- await projectIntegrationTest . createProject ( { projectName : projectName , pathToProject : tempFolder } ) ;
240
- assert . isTrue ( hasPromptedForString ) ;
54
+ testInjector . register ( "staticConfig" , {
55
+ PROJECT_FILE_NAME : "package.json"
241
56
} ) ;
242
-
243
- it ( "does not create project when is not interactive and incorrect name is specified" , async ( ) => {
244
- const projectName = invalidProjectName ;
245
- helpers . isInteractive = ( ) => false ;
246
-
247
- await assert . isRejected ( projectIntegrationTest . createProject ( { projectName : projectName , pathToProject : tempFolder , force : false } ) ) ;
57
+ testInjector . register ( "projectHelper" , {
58
+ generateDefaultAppId : ( ) => `org.nativescript.${ opts . projectName } `
59
+ } ) ;
60
+ testInjector . register ( "packageInstallationManager" , { } ) ;
61
+ testInjector . register ( "settingsService" , SettingsService ) ;
62
+ testInjector . register ( "hooksService" , {
63
+ executeAfterHooks : async ( commandName : string , hookArguments ?: IDictionary < any > ) : Promise < void > => undefined
64
+ } ) ;
65
+ testInjector . register ( "pacoteService" , {
66
+ manifest : ( ) => Promise . resolve ( ) ,
67
+ downloadAndExtract : ( ) => Promise . resolve ( ) ,
68
+ extractPackage : ( ) => Promise . resolve ( )
248
69
} ) ;
249
70
250
- it ( "creates project when is not interactive and incorrect name is specified and the --force option is set" , async ( ) => {
251
- const projectName = invalidProjectName ;
252
- helpers . isInteractive = ( ) => false ;
253
-
254
- await projectIntegrationTest . createProject ( { projectName : projectName , pathToProject : tempFolder , force : true } ) ;
71
+ return testInjector ;
72
+ } ;
73
+ /* tslint:enable:no-empty */
74
+
75
+ it ( "creates project with invalid name when projectNameService does not fail" , async ( ) => {
76
+ const projectName = invalidProjectName ;
77
+ const testInjector = getTestInjector ( { projectName } ) ;
78
+ const projectService = testInjector . resolve < IProjectService > ( ProjectServiceLib . ProjectService ) ;
79
+ const projectCreationData = await projectService . createProject ( { projectName : projectName , pathToProject : dirToCreateProject , force : true , template : constants . RESERVED_TEMPLATE_NAMES [ "default" ] } ) ;
80
+ assert . deepEqual ( projectCreationData , { projectName, projectDir : path . join ( dirToCreateProject , projectName ) } ) ;
81
+ } ) ;
255
82
256
- await projectIntegrationTest . assertProject ( tempFolder , projectName , `org.nativescript.${ projectName } ` , defaultTemplatePath ) ;
257
- } ) ;
83
+ it ( "fails when invalid name is passed when projectNameService fails" , async ( ) => {
84
+ const projectName = invalidProjectName ;
85
+ const testInjector = getTestInjector ( { projectName } ) ;
86
+ const projectNameService = testInjector . resolve < IProjectNameService > ( "projectNameService" ) ;
87
+ const err = new Error ( "Invalid name" ) ;
88
+ projectNameService . ensureValidName = ( name : string ) => {
89
+ throw err ;
90
+ } ;
91
+ const projectService = testInjector . resolve < IProjectService > ( ProjectServiceLib . ProjectService ) ;
92
+ await assert . isRejected ( projectService . createProject ( { projectName : projectName , pathToProject : dirToCreateProject , template : constants . RESERVED_TEMPLATE_NAMES [ "default" ] } ) , err . message ) ;
258
93
} ) ;
259
94
95
+ it ( "fails when project directory is not empty" , async ( ) => {
96
+ const projectName = invalidProjectName ;
97
+ const testInjector = getTestInjector ( { projectName } ) ;
98
+ const fs = testInjector . resolve < IFileSystem > ( "fs" ) ;
99
+ fs . isEmptyDir = ( name : string ) => false ;
100
+ const projectService = testInjector . resolve < IProjectService > ( ProjectServiceLib . ProjectService ) ;
101
+ await assert . isRejected ( projectService . createProject ( { projectName : projectName , pathToProject : dirToCreateProject , template : constants . RESERVED_TEMPLATE_NAMES [ "default" ] } ) , `Path already exists and is not empty ${ path . join ( dirToCreateProject , projectName ) } ` ) ;
102
+ } ) ;
260
103
} ) ;
261
104
262
105
describe ( "isValidNativeScriptProject" , ( ) => {
@@ -291,7 +134,7 @@ describe("Project Service Tests", () => {
291
134
const testInjector = getTestInjector ( {
292
135
projectDir : "projectDir" ,
293
136
projectId : "projectId" ,
294
- projectIdentifiers : { android : "projectId" , ios : "projectId" } ,
137
+ projectIdentifiers : { android : "projectId" , ios : "projectId" } ,
295
138
} ) ;
296
139
297
140
const projectService : IProjectService = testInjector . resolve ( ProjectServiceLib . ProjectService ) ;
@@ -304,7 +147,7 @@ describe("Project Service Tests", () => {
304
147
const projectData : any = {
305
148
projectDir : "projectDir" ,
306
149
projectId : "projectId" ,
307
- projectIdentifiers : { android : "projectId" , ios : "projectId" }
150
+ projectIdentifiers : { android : "projectId" , ios : "projectId" }
308
151
} ;
309
152
310
153
let returnedProjectData : any = null ;
0 commit comments