Skip to content

Commit c2fd394

Browse files
Fatme HavaluovaFatme Havaluova
Fatme Havaluova
authored and
Fatme Havaluova
committed
Add unit tests
1 parent d600317 commit c2fd394

File tree

9 files changed

+248
-36
lines changed

9 files changed

+248
-36
lines changed

lib/definitions/plugins.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ interface IPluginsService {
44
prepare(pluginData: IDependencyData): IFuture<void>;
55
getAllInstalledPlugins(): IFuture<IPluginData[]>;
66
ensureAllDependenciesAreInstalled(): IFuture<void>;
7+
afterPrepareAllPlugins(): IFuture<void>;
78
}
89

910
interface IPluginData extends INodeModuleData {

lib/definitions/project.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ interface IPlatformProjectService {
4040
updatePlatform(currentVersion: string, newVersion: string): IFuture<void>;
4141
preparePluginNativeCode(pluginData: IPluginData): IFuture<void>;
4242
removePluginNativeCode(pluginData: IPluginData): IFuture<void>;
43+
afterPrepareAllPlugins(): IFuture<void>;
4344
}
4445

4546
interface IAndroidProjectPropertiesManager {

lib/services/android-project-service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,10 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
296296
}).future<void>()();
297297
}
298298

299+
public afterPrepareAllPlugins(): IFuture<void> {
300+
return Future.fromResult();
301+
}
302+
299303
private getLibraryRelativePath(basePath: string, libraryPath: string): string {
300304
return path.relative(basePath, libraryPath).split("\\").join("/");
301305
}

lib/services/ios-project-service.ts

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
"use strict";
33

44
import Future = require("fibers/future");
5-
import path = require("path");
5+
import * as path from "path";
66
import shell = require("shelljs");
77
import util = require("util");
8+
import * as os from "os";
89
import xcode = require("xcode");
910
import constants = require("./../constants");
1011
import helpers = require("./../common/helpers");
1112
import projectServiceBaseLib = require("./platform-project-service-base");
1213

13-
class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
14+
export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
1415
private static XCODE_PROJECT_EXT_NAME = ".xcodeproj";
1516
private static XCODEBUILD_MIN_VERSION = "6.0";
1617
private static IOS_PROJECT_NAME_PLACEHOLDER = "__PROJECT_NAME__";
@@ -262,14 +263,6 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
262263

263264
this.savePbxProj(project).wait();
264265
}
265-
266-
if(this.$fs.exists(this.projectPodFilePath).wait() && this.$fs.getFsStats(this.projectPodFilePath).wait().mtime < this.$fs.getFsStats(this.$projectData.projectFilePath).wait().mtime) {
267-
try {
268-
this.$childProcess.exec("pod install", { cwd: this.platformData.projectRoot }).wait();
269-
} catch(e) {
270-
this.$errors.failWithoutHelp("CocoaPods are not installed. Run `sudo gem install cocoapods` and try again.");
271-
}
272-
}
273266
}).future<void>()();
274267
}
275268

@@ -314,35 +307,31 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
314307
public preparePluginNativeCode(pluginData: IPluginData): IFuture<void> {
315308
return (() => {
316309
let pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(IOSProjectService.IOS_PLATFORM_NAME);
317-
_.each(this.getAllDynamicFrameworksForPlugin(pluginData).wait(), fileName => this.addLibrary(path.join(pluginPlatformsFolderPath, fileName)).wait());
318-
319-
let pluginPodFilePath = path.join(pluginPlatformsFolderPath, "Podfile");
320-
if(this.$fs.exists(pluginPodFilePath).wait()) {
321-
let pluginPodFileContent = this.$fs.readText(pluginPodFilePath).wait();
322-
this.$fs.appendFile(this.projectPodFilePath, pluginPodFileContent).wait();
323-
}
310+
this.prepareDynamicFrameworks(pluginPlatformsFolderPath, pluginData).wait();
311+
this.prepareCocoapods(pluginPlatformsFolderPath).wait();
324312
}).future<void>()();
325313
}
326314

327315
public removePluginNativeCode(pluginData: IPluginData): IFuture<void> {
328316
return (() => {
329317
let pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(IOSProjectService.IOS_PLATFORM_NAME);
330-
let project = this.createPbxProj();
331-
332-
_.each(this.getAllDynamicFrameworksForPlugin(pluginData).wait(), fileName => {
333-
let fullFrameworkPath = path.join(pluginPlatformsFolderPath, fileName);
334-
let relativeFrameworkPath = this.getFrameworkRelativePath(fullFrameworkPath);
335-
project.removeFramework(relativeFrameworkPath, { customFramework: true, embed: true })
336-
});
337-
338-
this.savePbxProj(project).wait();
339-
340-
let pluginPodFilePath = path.join(pluginPlatformsFolderPath, "Podfile");
341-
if(this.$fs.exists(pluginPodFilePath).wait()) {
342-
let pluginPodFileContent = this.$fs.readText(pluginPodFilePath).wait();
343-
let projectPodFileContent = this.$fs.readText(this.projectPodFilePath).wait();
344-
projectPodFileContent = helpers.stringReplaceAll(projectPodFileContent, pluginPodFileContent, "");
345-
this.$fs.writeFile(this.projectPodFilePath, projectPodFileContent).wait();
318+
this.removeDynamicFrameworks(pluginPlatformsFolderPath, pluginData).wait();
319+
this.removeCocoapods(pluginPlatformsFolderPath).wait();
320+
}).future<void>()();
321+
}
322+
323+
public afterPrepareAllPlugins(): IFuture<void> {
324+
return (() => {
325+
if(this.$fs.exists(this.projectPodFilePath).wait()) {
326+
// Check availability
327+
try {
328+
this.$childProcess.exec("gem which cocoapods").wait();
329+
} catch(e) {
330+
this.$errors.failWithoutHelp("CocoaPods are not installed. Run `sudo gem install cocoapods` and try again.");
331+
}
332+
333+
this.$logger.info("Installing pods...");
334+
this.$childProcess.exec("pod install", { cwd: this.platformData.projectRoot }).wait();
346335
}
347336
}).future<void>()();
348337
}
@@ -404,5 +393,57 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
404393
this.$fs.rename(path.join(fileRootLocation, oldFileName), path.join(fileRootLocation, newFileName)).wait();
405394
}).future<void>()();
406395
}
396+
397+
private prepareDynamicFrameworks(pluginPlatformsFolderPath: string, pluginData: IPluginData): IFuture<void> {
398+
return (() => {
399+
_.each(this.getAllDynamicFrameworksForPlugin(pluginData).wait(), fileName => this.addLibrary(path.join(pluginPlatformsFolderPath, fileName)).wait());
400+
}).future<void>()();
401+
}
402+
403+
private prepareCocoapods(pluginPlatformsFolderPath: string): IFuture<void> {
404+
return (() => {
405+
let pluginPodFilePath = path.join(pluginPlatformsFolderPath, "Podfile");
406+
if(this.$fs.exists(pluginPodFilePath).wait()) {
407+
let pluginPodFileContent = this.$fs.readText(pluginPodFilePath).wait();
408+
let contentToWrite = this.buildPodfileContent(pluginPodFilePath, pluginPodFileContent);
409+
this.$fs.appendFile(this.projectPodFilePath, contentToWrite).wait();
410+
}
411+
}).future<void>()();
412+
}
413+
414+
private removeDynamicFrameworks(pluginPlatformsFolderPath: string, pluginData: IPluginData): IFuture<void> {
415+
return (() => {
416+
let project = this.createPbxProj();
417+
418+
_.each(this.getAllDynamicFrameworksForPlugin(pluginData).wait(), fileName => {
419+
let fullFrameworkPath = path.join(pluginPlatformsFolderPath, fileName);
420+
let relativeFrameworkPath = this.getFrameworkRelativePath(fullFrameworkPath);
421+
project.removeFramework(relativeFrameworkPath, { customFramework: true, embed: true })
422+
});
423+
424+
this.savePbxProj(project).wait();
425+
}).future<void>()();
426+
}
427+
428+
private removeCocoapods(pluginPlatformsFolderPath: string): IFuture<void> {
429+
return (() => {
430+
let pluginPodFilePath = path.join(pluginPlatformsFolderPath, "Podfile");
431+
if(this.$fs.exists(pluginPodFilePath).wait()) {
432+
let pluginPodFileContent = this.$fs.readText(pluginPodFilePath).wait();
433+
let projectPodFileContent = this.$fs.readText(this.projectPodFilePath).wait();
434+
let contentToRemove= this.buildPodfileContent(pluginPodFilePath, pluginPodFileContent);
435+
projectPodFileContent = helpers.stringReplaceAll(projectPodFileContent, contentToRemove, "");
436+
if(_.isEmpty(projectPodFileContent)) {
437+
this.$fs.deleteFile(this.projectPodFilePath).wait();
438+
} else {
439+
this.$fs.writeFile(this.projectPodFilePath, projectPodFileContent).wait();
440+
}
441+
}
442+
}).future<void>()();
443+
}
444+
445+
private buildPodfileContent(pluginPodFilePath: string, pluginPodFileContent: string): string {
446+
return `# Begin Podfile - ${pluginPodFilePath} ${os.EOL} ${pluginPodFileContent} ${os.EOL} # End Podfile ${os.EOL}`;
447+
}
407448
}
408449
$injector.register("iOSProjectService", IOSProjectService);

lib/services/plugins-service.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ export class PluginsService implements IPluginsService {
144144
}).future<IPluginData[]>()();
145145
}
146146

147+
public afterPrepareAllPlugins(): IFuture<void> {
148+
let action = (pluginDestinationPath: string, platform: string, platformData: IPlatformData) => {
149+
return platformData.platformProjectService.afterPrepareAllPlugins();
150+
};
151+
152+
return this.executeForAllInstalledPlatforms(action);
153+
}
154+
147155
private get nodeModulesPath(): string {
148156
return path.join(this.$projectData.projectDir, "node_modules");
149157
}

lib/tools/broccoli/node-modules-dest-copy.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ export class DestCopy implements IBroccoliPlugin {
7676
this.$pluginsService.prepare(dependency).wait();
7777
}
7878
});
79+
80+
if(_.keys(this.dependencies).length > 0) {
81+
this.$pluginsService.afterPrepareAllPlugins().wait();
82+
}
7983
}
8084

8185
public rebuild(treeDiff: IDiffResult): void {

test/ios-project-service.ts

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/// <reference path=".d.ts" />
2+
"use strict";
3+
4+
import Future = require("fibers/future");
5+
import * as path from "path";
6+
import temp = require("temp");
7+
8+
import ChildProcessLib = require("../lib/common/child-process");
9+
import ConfigLib = require("../lib/config");
10+
import ErrorsLib = require("../lib/common/errors");
11+
import FileSystemLib = require("../lib/common/file-system");
12+
import HostInfoLib = require("../lib/common/host-info");
13+
import iOSProjectServiceLib = require("../lib/services/ios-project-service");
14+
import LoggerLib = require("../lib/common/logger");
15+
import OptionsLib = require("../lib/options");
16+
import ProjectDataLib = require("../lib/project-data");
17+
18+
import yok = require("../lib/common/yok");
19+
20+
let assert = require("chai").assert;
21+
22+
function createTestInjector(projectPath: string, projectName: string): IInjector {
23+
let testInjector = new yok.Yok();
24+
testInjector.register("childProcess", ChildProcessLib.ChildProcess);
25+
testInjector.register("config", ConfigLib.Configuration);
26+
testInjector.register("errors", ErrorsLib.Errors);
27+
testInjector.register("fs", FileSystemLib.FileSystem);
28+
testInjector.register("hostInfo", HostInfoLib.HostInfo);
29+
testInjector.register("injector", testInjector);
30+
testInjector.register("iOSEmulatorServices", {});
31+
testInjector.register("iOSProjectService", iOSProjectServiceLib.IOSProjectService);
32+
testInjector.register("logger", LoggerLib.Logger);
33+
testInjector.register("options", OptionsLib.Options);
34+
testInjector.register("projectData", {
35+
platformsDir: projectPath,
36+
projectName: projectName
37+
});
38+
testInjector.register("projectHelper", {});
39+
testInjector.register("staticConfig", ConfigLib.StaticConfig);
40+
41+
return testInjector;
42+
}
43+
44+
describe("Cocoapods support", () => {
45+
it("adds plugin with Podfile", () => {
46+
let projectName = "projectDirectory";
47+
let projectPath = temp.mkdirSync(projectName);
48+
49+
let testInjector = createTestInjector(projectPath, projectName);
50+
let fs: IFileSystem = testInjector.resolve("fs");
51+
52+
let packageJsonData = {
53+
"name": "myProject",
54+
"version": "0.1.0",
55+
"nativescript": {
56+
"id": "org.nativescript.myProject",
57+
"tns-android": {
58+
"version": "1.0.0"
59+
}
60+
}
61+
};
62+
fs.writeJson(path.join(projectPath, "package.json"), packageJsonData).wait();
63+
64+
let platformsFolderPath = path.join(projectPath, "ios");
65+
fs.createDirectory(platformsFolderPath).wait();
66+
67+
let iOSProjectService = testInjector.resolve("iOSProjectService");
68+
iOSProjectService.prepareDynamicFrameworks = (pluginPlatformsFolderPath: string, pluginData: IPluginData): IFuture<void> => {
69+
return Future.fromResult();
70+
};
71+
72+
let pluginPath = temp.mkdirSync("pluginDirectory");
73+
let pluginPlatformsFolderPath = path.join(pluginPath, "platforms", "ios");
74+
let pluginPodfilePath = path.join(pluginPlatformsFolderPath, "Podfile");
75+
let pluginPodfileContent = ["source 'https://github.com/CocoaPods/Specs.git'", "platform :ios, '8.1'", "pod 'GoogleMaps'"].join("\n");
76+
fs.writeFile(pluginPodfilePath, pluginPodfileContent).wait();
77+
78+
let pluginData = {
79+
pluginPlatformsFolderPath(platform: string): string {
80+
return pluginPlatformsFolderPath;
81+
}
82+
};
83+
84+
iOSProjectService.preparePluginNativeCode(pluginData).wait();
85+
86+
let projectPodfilePath = path.join(platformsFolderPath, "Podfile");
87+
assert.isTrue(fs.exists(projectPodfilePath).wait());
88+
89+
let actualProjectPodfileContent = fs.readText(projectPodfilePath).wait();
90+
let expectedProjectPodfileContent = [`# Begin Podfile - ${pluginPodfilePath} `, ` ${pluginPodfileContent} `, " # End Podfile \n"].join("\n");
91+
assert.equal(actualProjectPodfileContent, expectedProjectPodfileContent);
92+
});
93+
it("adds and removes plugin with Podfile", () => {
94+
let projectName = "projectDirectory2";
95+
let projectPath = temp.mkdirSync(projectName);
96+
97+
let testInjector = createTestInjector(projectPath, projectName);
98+
let fs: IFileSystem = testInjector.resolve("fs");
99+
100+
let packageJsonData = {
101+
"name": "myProject2",
102+
"version": "0.1.0",
103+
"nativescript": {
104+
"id": "org.nativescript.myProject2",
105+
"tns-android": {
106+
"version": "1.0.0"
107+
}
108+
}
109+
};
110+
fs.writeJson(path.join(projectPath, "package.json"), packageJsonData).wait();
111+
112+
let platformsFolderPath = path.join(projectPath, "ios");
113+
fs.createDirectory(platformsFolderPath).wait();
114+
115+
let iOSProjectService = testInjector.resolve("iOSProjectService");
116+
iOSProjectService.prepareDynamicFrameworks = (pluginPlatformsFolderPath: string, pluginData: IPluginData): IFuture<void> => {
117+
return Future.fromResult();
118+
};
119+
iOSProjectService.removeDynamicFrameworks = (pluginPlatformsFolderPath: string, pluginData: IPluginData): IFuture<void> => {
120+
return Future.fromResult();
121+
}
122+
123+
let pluginPath = temp.mkdirSync("pluginDirectory");
124+
let pluginPlatformsFolderPath = path.join(pluginPath, "platforms", "ios");
125+
let pluginPodfilePath = path.join(pluginPlatformsFolderPath, "Podfile");
126+
let pluginPodfileContent = ["source 'https://github.com/CocoaPods/Specs.git'", "platform :ios, '8.1'", "pod 'GoogleMaps'"].join("\n");
127+
fs.writeFile(pluginPodfilePath, pluginPodfileContent).wait();
128+
129+
let pluginData = {
130+
pluginPlatformsFolderPath(platform: string): string {
131+
return pluginPlatformsFolderPath;
132+
}
133+
};
134+
135+
iOSProjectService.preparePluginNativeCode(pluginData).wait();
136+
137+
let projectPodfilePath = path.join(platformsFolderPath, "Podfile");
138+
assert.isTrue(fs.exists(projectPodfilePath).wait());
139+
140+
let actualProjectPodfileContent = fs.readText(projectPodfilePath).wait();
141+
let expectedProjectPodfileContent = [`# Begin Podfile - ${pluginPodfilePath} `, ` ${pluginPodfileContent} `, " # End Podfile \n"].join("\n");
142+
assert.equal(actualProjectPodfileContent, expectedProjectPodfileContent);
143+
144+
iOSProjectService.removePluginNativeCode(pluginData).wait();
145+
146+
assert.isFalse(fs.exists(projectPodfilePath).wait());
147+
});
148+
});

test/npm-support.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ function setupProject(): IFuture<any> {
120120
normalizedPlatformName: "Android",
121121
platformProjectService: {
122122
prepareProject: () => Future.fromResult(),
123-
prepareAppResources: () => Future.fromResult()
123+
prepareAppResources: () => Future.fromResult(),
124+
afterPrepareAllPlugins: () => Future.fromResult()
124125
}
125126
}
126127
};

test/stubs.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ export class PlatformsDataStub implements IPlatformsData {
250250
appDestinationDirectoryPath: "",
251251
appResourcesDestinationDirectoryPath: "",
252252
preparePluginNativeCode: () => Future.fromResult(),
253-
removePluginNativeCode: () => Future.fromResult()
253+
removePluginNativeCode: () => Future.fromResult(),
254+
afterPrepareAllPlugins: () => Future.fromResult()
254255
};
255256
}
256257

@@ -271,7 +272,7 @@ export class PlatformProjectServiceStub implements IPlatformProjectService {
271272
validPackageNamesForDevice: [],
272273
frameworkFilesExtensions: [],
273274
appDestinationDirectoryPath: "",
274-
appResourcesDestinationDirectoryPath: ""
275+
appResourcesDestinationDirectoryPath: "",
275276
};
276277
}
277278
validate(): IFuture<void> {
@@ -316,6 +317,9 @@ export class PlatformProjectServiceStub implements IPlatformProjectService {
316317
removePluginNativeCode(pluginData: IPluginData): IFuture<void> {
317318
return Future.fromResult();
318319
}
320+
afterPrepareAllPlugins(): IFuture<void> {
321+
return Future.fromResult();
322+
}
319323
}
320324

321325
export class ProjectDataService implements IProjectDataService {

0 commit comments

Comments
 (0)