UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

417 lines (352 loc) 16.4 kB
import { expect } from "chai"; import CodePushDeploymentListListCommand from "../../../../src/commands/codepush/deployment/list"; import { models } from "../../../../src/util/apis"; import { CommandArgs, CommandFailedResult } from "../../../../src/util/commandline"; import * as Sinon from "sinon"; import * as Nock from "nock"; import { formatDate } from "../../../../src/commands/codepush/deployment/lib/date-helper"; import { getFakeParamsForRequest, FakeParamsForRequests } from "../utils"; import * as chalk from "chalk"; import { out } from "../../../../src/util/interaction/index"; describe("CodePush deployment list tests", () => { const fakeBlobUrl = "fakeURL"; const fakeIsDisabled = false; const fakeIsMandatory = false; const fakeLabel = "fakeLabel"; const fakePackageHash = "fakeHash"; const fakeReleasedBy = "fakeAuthor"; const fakeReleaseMethod = "Upload"; const fakeRollout = 100; const fakeSize = 100; const fakeTargetBinaryRange = "fakeTarget"; const fakeUploadTime = 1538747519563; const fakeDescription = "fakeDescription"; const fakeReleasesTotalActive = 3; const successfulStatus = 200; const unsuccessfulStatus = 404; // tslint:disable-next-line:no-http-string const fakeHost = "http://localhost:1700"; const fakeParamsForRequest: FakeParamsForRequests = getFakeParamsForRequest(); const defaultCommandArgsForListCommand: CommandArgs = getCommandArgsForListCommand(fakeParamsForRequest); const fakeMetadataRelease: models.CodePushRelease = { blobUrl: fakeBlobUrl, isDisabled: fakeIsDisabled, isMandatory: fakeIsMandatory, label: fakeLabel, packageHash: fakePackageHash, releasedBy: fakeReleasedBy, releaseMethod: fakeReleaseMethod, rollout: fakeRollout, size: fakeSize, targetBinaryRange: fakeTargetBinaryRange, uploadTime: fakeUploadTime, }; const fakeReleaseForRequest = { target_binary_range: fakeTargetBinaryRange, blob_url: fakeBlobUrl, description: fakeDescription, is_disabled: fakeIsDisabled, is_mandatory: fakeIsMandatory, label: fakeLabel, package_hash: fakePackageHash, released_by: fakeReleasedBy, release_method: fakeReleaseMethod, rollout: fakeRollout, size: fakeSize, upload_time: fakeUploadTime, diff_package_map: {} }; const noUpdatesString = "No updates released"; const noMetricsString = "No installs recorded"; const fakeDeployment: models.Deployment = { name: "fakeDeploymentName", key: "fakeDeploymentKey", }; const fakeDeploymentWithRelease: models.Deployment = Object.assign({ latest_release: fakeReleaseForRequest }, fakeDeployment); const expectedGeneratedMetadataString = "Label: " + fakeLabel + "\nApp Version: " + fakeTargetBinaryRange + "\nMandatory: No" + "\nRelease Time: " + formatDate(fakeUploadTime) + "\nReleased By: " + fakeReleasedBy; const expectedOutputHelperText = "Note: To display deployment keys add -k|--displayKeys option"; const expectedErrorMessage = `The app ${fakeParamsForRequest.userName}/${fakeParamsForRequest.appName} does not exist.`; describe("deployment list unit tests", () => { it("generateMetadataString", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateMetadataString: (release: models.CodePushRelease) => string = command["generateMetadataString"]; // Act const result = generateMetadataString(fakeMetadataRelease); // Assert expect(result).to.be.an("string"); expect(removeColorFromText(result)).to.be.eql(expectedGeneratedMetadataString); }); it("generateColoredTableTitles", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateColoredTableTitles: (tableTitles: string[]) => string[] = command["generateColoredTableTitles"]; const fakeDeploymentsName = ["fakeDeployment", "fakeDeployment2"]; const expected = [chalk.cyan("fakeDeployment"), chalk.cyan("fakeDeployment2")]; // Act const result = generateColoredTableTitles(fakeDeploymentsName); // Assert expect(result).to.be.an("array"); expect(result).to.be.eql(expected); }); describe("generateMetricsString", () => { it("should return correct metrics for any% active releases", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateMetricsString: (releaseMetrics: models.CodePushReleaseMetric, releasesTotalActive: number) => string = command["generateMetricsString"]; const fakeReleaseMetrics = { active: 1, downloaded: 1, failed: 0, installed: 1, label: fakeLabel }; const fakeActiveString: string = "33% (1 of 3)"; const fakeInstalled: string = "1"; const expectedMetrics = getExpectedMetricsString(fakeActiveString, fakeInstalled); // Act const result = generateMetricsString(fakeReleaseMetrics, fakeReleasesTotalActive); // Assert expect(result).to.be.an("string"); expect(removeColorFromText(result)).to.be.eql(expectedMetrics); }); it("should return correct metrics for 0% active releases", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateMetricsString: (releaseMetrics: models.CodePushReleaseMetric, releasesTotalActive: number) => string = command["generateMetricsString"]; const fakeReleaseMetrics = { active: 0, downloaded: 1, failed: 0, installed: 1, label: fakeLabel, }; const fakeActiveString: string = "0% (0 of 3)"; const fakeInstalled: string = "1"; const expectedMetrics = getExpectedMetricsString(fakeActiveString, fakeInstalled); // Act const result = generateMetricsString(fakeReleaseMetrics, fakeReleasesTotalActive); // Assert expect(result).to.be.an("string"); expect(removeColorFromText(result)).to.be.eql(expectedMetrics); }); it("should return correct metrics for 100% active releases", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateMetricsString: (releaseMetrics: models.CodePushReleaseMetric, releasesTotalActive: number) => string = command["generateMetricsString"]; const fakeReleaseMetrics = { active: 3, downloaded: 3, failed: 0, installed: 3, label: fakeLabel, }; const fakeActiveString: string = "100% (3 of 3)"; const fakeInstalled: string = "3"; const expectedMetrics = getExpectedMetricsString(fakeActiveString, fakeInstalled); // Act const result = generateMetricsString(fakeReleaseMetrics, fakeReleasesTotalActive); // Assert expect(result).to.be.an("string"); expect(removeColorFromText(result)).to.be.eql(expectedMetrics); }); }); it("should return correct metrics with pending releases", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateMetricsString: (releaseMetrics: models.CodePushReleaseMetric, releasesTotalActive: number) => string = command["generateMetricsString"]; const fakeReleaseMetrics = { active: 3, downloaded: 5, failed: 0, installed: 3, label: fakeLabel, }; const fakeActiveString = "100% (3 of 3)"; const fakeInstalled = "3"; const fakePending = " (2 pending)"; const expectedMetrics = getExpectedMetricsString(fakeActiveString, fakeInstalled, fakePending); // Act const result = generateMetricsString(fakeReleaseMetrics, fakeReleasesTotalActive); // Assert expect(result).to.be.an("string"); expect(removeColorFromText(result)).to.be.eql(expectedMetrics); }); it("should return correct string for empty metrics", () => { // Arrange const command = new CodePushDeploymentListListCommand(defaultCommandArgsForListCommand); const generateMetricsString: (releaseMetrics: models.CodePushReleaseMetric, releasesTotalActive: number) => string = command["generateMetricsString"]; const expectedMetrics = noMetricsString; // Act const result = generateMetricsString(undefined, fakeReleasesTotalActive); // Assert expect(result).to.be.an("string"); expect(removeColorFromText(result)).to.be.eql(expectedMetrics); }); }); describe("deployment list tests", () => { let sandbox: Sinon.SinonSandbox; let nockScope: Nock.Scope; beforeEach(() => { sandbox = Sinon.createSandbox(); nockScope = Nock(fakeHost); }); afterEach((() => { sandbox.restore(); Nock.cleanAll(); })); it("should output table without releases and metrics", async () => { // Arrange setupNockGetDeploymentsResponse(nockScope, fakeParamsForRequest, [fakeDeployment]); const expectedOutputTable = [[fakeDeployment.name, noUpdatesString, noMetricsString]]; const spyOutTable = sandbox.stub(out, "table"); const spyOutText = sandbox.stub(out, "text"); // Act const command = new CodePushDeploymentListListCommand(getCommandArgsForListCommand(fakeParamsForRequest)); const result = await command.execute(); // Assert expect(result.succeeded).to.be.true; expect(spyOutTable.calledOnce).to.be.true; expect(spyOutText.calledOnce).to.be.true; const resultTable = spyOutTable.getCall(0).args[1]; expect(resultTable[0]).to.be.an("array"); expect(removeColorFromTableRows(resultTable)).to.be.eql(expectedOutputTable); const resultText = spyOutText.getCall(0).args[0]; expect(resultText).to.be.an("string"); expect(resultText).to.be.eql(expectedOutputHelperText); nockScope.done(); }); it("should output table with correct data for releases without metrics", async () => { // Arrange setupNockGetDeploymentsResponse(nockScope, fakeParamsForRequest, [fakeDeploymentWithRelease]); setupNockGetDeploymentMetricsResponse(nockScope, fakeParamsForRequest, {}, fakeDeployment); const expectedOutputTable = [[fakeDeployment.name, expectedGeneratedMetadataString, noMetricsString]]; const spyOutTable = sandbox.stub(out, "table"); const spyOutText = sandbox.stub(out, "text"); // Act const command = new CodePushDeploymentListListCommand(getCommandArgsForListCommand(fakeParamsForRequest)); const result = await command.execute(); // Assert expect(result.succeeded).to.be.true; expect(spyOutTable.calledOnce).to.be.true; expect(spyOutText.calledOnce).to.be.true; const resultTable = spyOutTable.getCall(0).args[1]; expect(resultTable[0]).to.be.an("array"); expect(removeColorFromTableRows(resultTable)).to.be.eql(expectedOutputTable); const resultText = spyOutText.getCall(0).args[0]; expect(resultText).to.be.an("string"); expect(resultText).to.be.eql(expectedOutputHelperText); nockScope.done(); }); it("should output table with correct data for releases with metrics", async () => { // Arrange const fakeReleaseMetrics = { active: 3, downloaded: 5, failed: 0, installed: 3, label: fakeLabel, }; setupNockGetDeploymentsResponse(nockScope, fakeParamsForRequest, [fakeDeploymentWithRelease, fakeDeploymentWithRelease]); setupNockGetDeploymentMetricsResponse(nockScope, fakeParamsForRequest, [fakeReleaseMetrics], fakeDeployment, successfulStatus, 2); const fakeActiveString = "100% (3 of 3)"; const fakeInstalled = "3"; const fakePending = " (2 pending)"; const expectedLine = [fakeDeployment.name, expectedGeneratedMetadataString, getExpectedMetricsString(fakeActiveString, fakeInstalled, fakePending)]; const expectedOutputTable = [expectedLine, expectedLine]; const spyOutTable = sandbox.stub(out, "table"); const spyOutText = sandbox.stub(out, "text"); // Act const command = new CodePushDeploymentListListCommand(getCommandArgsForListCommand(fakeParamsForRequest)); const result = await command.execute(); // Assert expect(result.succeeded).to.be.true; expect(spyOutTable.calledOnce).to.be.true; expect(spyOutText.calledOnce).to.be.true; const resultTable = spyOutTable.getCall(0).args[1]; expect(removeColorFromTableRows(resultTable)).to.be.eql(expectedOutputTable); const resultText = spyOutText.getCall(0).args[0]; expect(resultText).to.be.an("string"); expect(resultText).to.be.eql(expectedOutputHelperText); nockScope.done(); }); it("should output table with deployment keys", async () => { // Arrange setupNockGetDeploymentsResponse(nockScope, fakeParamsForRequest, [fakeDeployment]); const expectedOutputTable = [fakeDeployment.name, fakeDeployment.key]; const spyOutTable = sandbox.stub(out, "table"); // Act const command = new CodePushDeploymentListListCommand(getCommandArgsForListCommand(fakeParamsForRequest, ["-k"])); const result = await command.execute(); // Assert expect(result.succeeded).to.be.true; expect(spyOutTable.calledOnce).to.be.true; const resultTable = spyOutTable.getCall(0).args[1][0]; expect(resultTable).to.be.an("array"); expect(resultTable).to.be.eql(expectedOutputTable); nockScope.done(); }); it("should output error when app does not exist", async () => { // Arrange setupNockGetDeploymentsResponse(nockScope, fakeParamsForRequest, {}, unsuccessfulStatus); // Act const command = new CodePushDeploymentListListCommand(getCommandArgsForListCommand(fakeParamsForRequest)); const result = await command.execute(); // Assert expect(result.succeeded).to.be.false; expect((result as CommandFailedResult).errorMessage).contain(expectedErrorMessage); nockScope.done(); }); }); function getExpectedMetricsString(fakeActiveString: string, fakeInstalled: string, pendingString?: string): string { let metricsString = "Active: " + fakeActiveString + "\nInstalled: " + fakeInstalled; if (pendingString) { metricsString += pendingString; } return metricsString; } function setupNockGetDeploymentsResponse( nockScope: Nock.Scope, fakeParamsForRequest: FakeParamsForRequests, returnDeployments: models.Deployment[] | {}, statusCode: number = 200 ): void { nockScope.get(`/${fakeParamsForRequest.appVersion}/apps/${fakeParamsForRequest.userName}/${fakeParamsForRequest.appName}/deployments`) .reply(statusCode, (uri: any, requestBody: any) => { return returnDeployments; } ); } function setupNockGetDeploymentMetricsResponse( nockScope: Nock.Scope, fakeParamsForRequest: FakeParamsForRequests, returnMetrics: models.CodePushReleaseMetric[] | {}, fakeDeployment: models.Deployment, statusCode: number = 200, times: number = 1 ): void { nockScope.get(`/${fakeParamsForRequest.appVersion}/apps/${fakeParamsForRequest.userName}/${fakeParamsForRequest.appName}/deployments/${fakeDeployment.name}/metrics`).times(times) .reply(statusCode, (uri: any, requestBody: any): any => { return returnMetrics; } ); } function removeColorFromText(text: string): string { return chalk.stripColor(text); } function removeColorFromTableRows(tableRows: string[][]) { return tableRows.map((row) => row.map((element) => chalk.stripColor(element))); } function getCommandArgsForListCommand(fakeConsts: FakeParamsForRequests, additionalArgs: string[] = []): CommandArgs { const args: string[] = ["-a", `${fakeConsts.userName}/${fakeConsts.appName}`, "--token", fakeConsts.token, "--env", "local"].concat(additionalArgs); return { args, command: ["codepush", "deployment", "list"], commandPath: fakeConsts.path, }; } });