From f24ab5c2028d785573e6828dd7774da8f23930e3 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Mon, 19 Aug 2019 18:46:15 +0300 Subject: [PATCH] feat: add tracking for React and Svelte projecs Add tracking in CLI analytics for React and Svelte project types. As we do not have templates for those two project types, when CLI detects a project from this type and the `tns update` command is executed, get the dependencies for update from the default hellow world JS template. --- lib/constants.ts | 2 + lib/controllers/update-controller.ts | 4 + lib/project-data.ts | 8 ++ test/controllers/update-controller.ts | 111 ++++++++++++++++++++++---- test/project-data.ts | 8 ++ 5 files changed, 119 insertions(+), 14 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index 10af1b2ce8..93c3516fca 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -136,6 +136,8 @@ export class ProjectTypes { public static VueFlavorName = VueFlavorName; public static TsFlavorName = "Pure TypeScript"; public static JsFlavorName = "Pure JavaScript"; + public static ReactFlavorName = "React"; + public static SvelteFlavorName = "Svelte"; } export const BUILD_OUTPUT_EVENT_NAME = "buildOutput"; export const CONNECTION_ERROR_EVENT_NAME = "connectionError"; diff --git a/lib/controllers/update-controller.ts b/lib/controllers/update-controller.ts index 873451cca0..a7045f1425 100644 --- a/lib/controllers/update-controller.ts +++ b/lib/controllers/update-controller.ts @@ -204,6 +204,10 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon template = constants.RESERVED_TEMPLATE_NAMES.javascript; break; } + default: { + template = constants.RESERVED_TEMPLATE_NAMES.javascript; + break; + } } return template; diff --git a/lib/project-data.ts b/lib/project-data.ts index cd8ac33e6a..813e2d616b 100644 --- a/lib/project-data.ts +++ b/lib/project-data.ts @@ -27,6 +27,14 @@ export class ProjectData implements IProjectData { type: constants.ProjectTypes.VueFlavorName, requiredDependencies: ["nativescript-vue"] }, + { + type: constants.ProjectTypes.ReactFlavorName, + requiredDependencies: ["react-nativescript"] + }, + { + type: constants.ProjectTypes.SvelteFlavorName, + requiredDependencies: ["svelte-native"] + }, { type: constants.ProjectTypes.TsFlavorName, requiredDependencies: ["typescript", "nativescript-dev-typescript"] diff --git a/test/controllers/update-controller.ts b/test/controllers/update-controller.ts index 2296f1b4e6..5ea0e1b864 100644 --- a/test/controllers/update-controller.ts +++ b/test/controllers/update-controller.ts @@ -2,7 +2,7 @@ import * as stubs from "./../stubs"; import * as yok from "../../lib/common/yok"; import { UpdateController } from "../../lib/controllers/update-controller"; import { assert } from "chai"; -import * as sinon from 'sinon'; +import * as sinon from "sinon"; import * as path from "path"; import { Options } from "../../lib/options"; import { StaticConfig } from "../../lib/config"; @@ -21,7 +21,7 @@ function createTestInjector( checkConsent: async (): Promise => undefined, trackFeature: async (): Promise => undefined }); - testInjector.register('errors', stubs.ErrorsStub); + testInjector.register("errors", stubs.ErrorsStub); testInjector.register("staticConfig", StaticConfig); testInjector.register("projectData", { projectDir, @@ -32,29 +32,29 @@ function createTestInjector( testInjector.register("migrateController", { shouldMigrate: () => { return false; }, }); - testInjector.register('fs', stubs.FileSystemStub); - testInjector.register('platformCommandHelper', { + testInjector.register("fs", stubs.FileSystemStub); + testInjector.register("platformCommandHelper", { getCurrentPlatformVersion: () => { return "5.2.0"; } }); - testInjector.register('packageManager', { + testInjector.register("packageManager", { getTagVersion: () => { return "2.3.0"; } }); testInjector.register("addPlatformService", { - setPlatformVersion: () => {/**/} + setPlatformVersion: () => {/**/ } }); testInjector.register("pluginsService", { - addToPackageJson: () => {/**/} + addToPackageJson: () => {/**/ } }); - testInjector.register('devicePlatformsConstants', DevicePlatformsConstants); - testInjector.register('packageInstallationManager', stubs.PackageInstallationManagerStub); - testInjector.register('platformsDataService', stubs.NativeProjectDataStub); + testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); + testInjector.register("packageInstallationManager", stubs.PackageInstallationManagerStub); + testInjector.register("platformsDataService", stubs.NativeProjectDataStub); testInjector.register("pacoteService", stubs.PacoteServiceStub); - testInjector.register('projectDataService', stubs.ProjectDataService); + testInjector.register("projectDataService", stubs.ProjectDataService); testInjector.register("updateController", UpdateController); return testInjector; @@ -78,7 +78,7 @@ describe("update controller method tests", () => { sandbox.stub(fs, "copyFile").throws(); const updateController = testInjector.resolve("updateController"); - await updateController.update({projectDir: projectFolder, version: "3.3.0"}); + await updateController.update({ projectDir: projectFolder, version: "3.3.0" }); assert.isTrue(deleteDirectory.calledWith(path.join(projectFolder, UpdateController.backupFolder))); assert.isFalse(deleteDirectory.calledWith(path.join(projectFolder, "platforms"))); @@ -90,7 +90,7 @@ describe("update controller method tests", () => { const copyFileStub = sandbox.stub(fs, "copyFile"); const updateController = testInjector.resolve("updateController"); - await updateController.update({projectDir: projectFolder, version: "3.3.0"}); + await updateController.update({ projectDir: projectFolder, version: "3.3.0" }); assert.isTrue(copyFileStub.calledWith(path.join(projectFolder, "package.json"))); for (const folder of UpdateController.folders) { @@ -108,11 +108,94 @@ describe("update controller method tests", () => { const updateController = testInjector.resolve("updateController"); const tempDir = path.join(projectFolder, UpdateController.backupFolder); - await updateController.update({projectDir: projectFolder, version: "3.3.0"}); + await updateController.update({ projectDir: projectFolder, version: "3.3.0" }); assert.isTrue(copyFileStub.calledWith(path.join(tempDir, "package.json"), projectFolder)); for (const folder of UpdateController.folders) { assert.isTrue(copyFileStub.calledWith(path.join(tempDir, folder), projectFolder)); } }); + + for (const projectType of ["Angular", "React"]) { + it(`should update dependencies from project type: ${projectType}`, async () => { + const testInjector = createTestInjector(); + testInjector.resolve("platformCommandHelper").removePlatforms = () => { + throw new Error(); + }; + + const fs = testInjector.resolve("fs"); + const copyFileStub = sandbox.stub(fs, "copyFile"); + const updateController = testInjector.resolve("updateController"); + const tempDir = path.join(projectFolder, UpdateController.backupFolder); + + const projectDataService = testInjector.resolve("projectDataService"); + projectDataService.getProjectData = (projectDir: string) => { + return { + projectDir, + projectType, + dependencies: { + "tns-core-modules": "0.1.0", + }, + devDependencies: { + "nativescript-dev-webpack": "1.1.3" + } + }; + }; + + const packageInstallationManager = testInjector.resolve("packageInstallationManager"); + const latestCompatibleVersion = "1.1.1"; + packageInstallationManager.getLatestCompatibleVersionSafe = async (packageName: string, referenceVersion?: string): Promise => { + assert.isString(packageName); + assert.isFalse(_.isEmpty(packageName)); + return latestCompatibleVersion; + }; + + const pacoteService = testInjector.resolve("pacoteService"); + pacoteService.manifest = async (packageName: string, options?: IPacoteManifestOptions): Promise => { + assert.isString(packageName); + assert.isFalse(_.isEmpty(packageName)); + + return { + dependencies: { + "tns-core-modules": "1.0.0", + "dep2": "1.1.0" + }, + devDependencies: { + "devDep1": "1.2.0", + "nativescript-dev-webpack": "1.3.0" + }, + name: "template1" + }; + }; + + const pluginsService = testInjector.resolve("pluginsService"); + const dataAddedToPackageJson: IDictionary = { + dependencies: {}, + devDependencies: {} + }; + pluginsService.addToPackageJson = (plugin: string, version: string, isDev: boolean, projectDir: string): void => { + if (isDev) { + dataAddedToPackageJson.devDependencies[plugin] = version; + } else { + dataAddedToPackageJson.dependencies[plugin] = version; + } + }; + + await updateController.update({ projectDir: projectFolder }); + + assert.isTrue(copyFileStub.calledWith(path.join(tempDir, "package.json"), projectFolder)); + for (const folder of UpdateController.folders) { + assert.isTrue(copyFileStub.calledWith(path.join(tempDir, folder), projectFolder)); + } + + assert.deepEqual(dataAddedToPackageJson, { + dependencies: { + "tns-core-modules": "1.0.0", + }, + devDependencies: { + "nativescript-dev-webpack": "1.3.0" + } + }); + }); + } }); diff --git a/test/project-data.ts b/test/project-data.ts index e420ae99ff..19ba822181 100644 --- a/test/project-data.ts +++ b/test/project-data.ts @@ -100,6 +100,14 @@ describe("projectData", () => { assertProjectType({ "nativescript-vue": "*" }, { "typescript": "*" }, "Vue.js"); }); + it("detects project as React when react-nativescript exists as dependency and typescript is devDependency", () => { + assertProjectType({ "react-nativescript": "*" }, null, "React"); + }); + + it("detects project as Svelte when react-nativescript exists as dependency and typescript is devDependency", () => { + assertProjectType({ "svelte-native": "*" }, null, "Svelte"); + }); + it("detects project as TypeScript when nativescript-dev-typescript exists as dependency", () => { assertProjectType(null, { "nativescript-dev-typescript": "*" }, "Pure TypeScript"); });