UNPKG

@hkvstore/taco-cli

Version:

taco-cli is a command-line interface for rapid Apache Cordova development (forked from Microsoft taco-cli)

262 lines (260 loc) 12.9 kB
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. /// <reference path="../../typings/mocha.d.ts" /> /// <reference path="../../typings/node.d.ts" /> /// <reference path="../../typings/should.d.ts" /> /// <reference path="../../typings/del.d.ts" /> /// <reference path="../../typings/node.d.ts"/> /// <reference path="../../typings/tacoTestsUtils.d.ts"/> "use strict"; var fs = require("fs"); var os = require("os"); var path = require("path"); var Q = require("q"); var should = require("should"); var Settings = require("../cli/utils/settings"); var TacoUtility = require("taco-utils"); var CheckForNewerVersion = require("../cli/utils/checkForNewerVersion"); var tacoTestsUtils = require("taco-tests-utils"); var http = require("http"); var ServerMock = require("./utils/serverMock"); var utils = TacoUtility.UtilHelper; var MemoryStream = tacoTestsUtils.MemoryStream; var MessageExpectation; (function (MessageExpectation) { MessageExpectation[MessageExpectation["WillBeShown"] = 0] = "WillBeShown"; MessageExpectation[MessageExpectation["WontBeShown"] = 1] = "WontBeShown"; })(MessageExpectation || (MessageExpectation = {})); describe("Check for newer version", function () { var tacoHome = path.join(os.tmpdir(), "taco-cli", "check-for-new-version"); // Use a dummy home location so we don't trash any real configurations process.env["TACO_HOME"] = tacoHome; // because of function overloading assigning "(buffer: string, cb?: Function) => boolean" as the type for // stdoutWrite just doesn't work var stdoutWrite = process.stdout.write; // We save the original implementation, so we can restore it later var memoryStdout; var expectedRequestAndResponse; var tacoCliLatestInformation; var fakeServer = "http://localhost:8080"; var repositoryPath = "/taco-cli/latest"; var repositoryInFakeServerPath = fakeServer + repositoryPath; var packageFilePath = path.join(utils.tacoHome, "package.json"); before(function () { // Set up mocked out resources process.env["TACO_UNIT_TEST"] = true; process.listeners("beforeExit").should.be.empty; // We can't run the tests if we have unexpected beforeExit listeners }); beforeEach(function () { memoryStdout = new MemoryStream; // Each individual test gets a new and empty console process.stdout.write = memoryStdout.writeAsFunction(); // We'll be printing into an "in-memory" console, so we can test the output // These contents were copied from http://registry.npmjs.org/remotebuild/latest and then renamed to what should be a taco-cli response tacoCliLatestInformation = { name: "taco-cli", description: "Front-end server that serves modules that implement remote build functionality, such as taco-remote.", version: "1.0.0", author: { name: "Microsoft Corporation", email: "vscordovatools-admin@microsoft.com" }, homepage: "http://msdn.microsoft.com/en-us/vstudio/dn722381", main: "./lib/server.js", bin: { remotebuild: "./bin/remotebuild" }, keywords: [ "cordova", "osx ", "remote build" ], preferGlobal: true, dependencies: { express: "4.12.2", morgan: "1.5.1", errorhandler: "1.3.4", nconf: "0.6.9", q: "1.0.1", rimraf: "2.2.6", "taco-utils": "1.0.0", "taco-remote": "1.0.0" }, optionalDependencies: { "taco-remote": "1.0.0" }, devDependencies: { typescript: "1.3.0", mocha: "2.0.1", mkdirp: "0.3.5", should: "4.3.0", request: "2.36.0" }, scripts: { test: "mocha" }, directories: { lib: "lib", doc: ".", test: "test", example: "examples" }, license: "MIT", _id: "remotebuild@1.0.0", _shasum: "9b33d502b22f8ba8977e11c4a7db93bde5037e88", _resolved: "file:remotebuild.tgz", _from: "remotebuild.tgz", _npmVersion: "2.7.4", _nodeVersion: "0.12.2", _npmUser: { name: "multidevicehybridapp", email: "vscordovatools-admin@microsoft.com" }, dist: { shasum: "9b33d502b22f8ba8977e11c4a7db93bde5037e88", tarball: "http://registry.npmjs.org/remotebuild/-/remotebuild-1.0.0.tgz" }, maintainers: [ { name: "multidevicehybridapp", email: "vscordovatools-admin@microsoft.com" } ] }; // Create the package.json utils.createDirectoryIfNecessary(tacoHome); fs.writeFileSync(packageFilePath, JSON.stringify(tacoCliLatestInformation)); // Default request answered by the fake NPM server expectedRequestAndResponse = { expectedUrl: repositoryPath, head: { "Content-Type": "application/json" }, statusCode: 200, response: JSON.stringify(tacoCliLatestInformation) }; /* By default there is an update available. We do this after writing the package.json file Because we want 1.0.0 to be the current version, and after the expectedRequestAndResponse because it's required */ setLatestReleasedVersion("1.0.1"); }); afterEach(function () { process.stdout.write = stdoutWrite; process.removeAllListeners("beforeExit"); Settings.forgetSettings(); try { // Not all tests create the file, so we ignore the exception fs.unlinkSync(Settings.settingsFile); } catch (exception) { utils.emptyMethod(); } }); function simulateBeforeExit() { var listeners = process.listeners("beforeExit"); listeners.length.should.eql(1, "There should be only a single listener for the beforeExit event"); listeners[0].call(process); // The listener expects "this" to be process process.listeners("beforeExit").length.should.eql(0, "The beforeExit listener should clean itself up"); } function launchFakeNPMServer(done) { var serverIsListening = Q.defer(); // Port for the web server var PORT = 8080; // Create the server var server = http.createServer(ServerMock.generateServerFunction(done, [expectedRequestAndResponse])); server.listen(PORT); // If there is any error, we reject the promise server.on("error", function (error) { serverIsListening.reject(error); }); // Make the server start listening server.listen(PORT, function () { serverIsListening.resolve(server); }); return serverIsListening.promise; } function testCheckForNewerVersion(messageExpectation, done) { var timeBeforeTest = Date.now(); var fakeNPMServer; return launchFakeNPMServer(done) .then(function (server) { fakeNPMServer = server; should(fakeNPMServer).have.property("close"); }) .then(function () { return new CheckForNewerVersion(repositoryInFakeServerPath, packageFilePath) .showOnExit() .fail(function (error) { return TacoUtility.UtilHelper.emptyMethod(error); }); }) .then(function () { // CheckForNewerVersion doesn't print anything synchronically. It prints it on the beforeExit event var actual = memoryStdout.contentsAsText(); should(actual).be.empty; if (messageExpectation === MessageExpectation.WillBeShown) { simulateBeforeExit(); actual = memoryStdout.contentsAsText(); actual.should.be.equal("NewerTacoCLIVersionAvailable\n", "The output of the console should match what we expected"); return Settings.loadSettings().then(function (settings) { var lastCheck = new Date(settings.lastCheckForNewerVersionTimestamp).getTime(); lastCheck.should.be.greaterThan(timeBeforeTest, "The last check for newer version timestamp: " + lastCheck + " should be updated after each attempt to check for a newer version and thus be greater than " + timeBeforeTest); }); } else { process.listeners("beforeExit").should.be.empty; // We shouldn't have any listeners if no message is expected } }) .finally(function () { fakeNPMServer.close(); }); } function setCheckedTimestampToHoursAgo(howManyHoursAgo) { var someHoursAgo = new Date(); someHoursAgo.setHours(someHoursAgo.getHours() - howManyHoursAgo); var lastCheckForNewerVersionTimestamp = someHoursAgo.getTime(); return Settings.updateSettings(function (settings) { return settings.lastCheckForNewerVersionTimestamp = lastCheckForNewerVersionTimestamp; }).then(function () { return lastCheckForNewerVersionTimestamp; }); } function setLatestReleasedVersion(version) { tacoCliLatestInformation.version = version; expectedRequestAndResponse.response = JSON.stringify(tacoCliLatestInformation); } it("shows message when there is an update available and it's the first time we've ever checked", function (done) { testCheckForNewerVersion(MessageExpectation.WillBeShown, done).done(function () { return done(); }, done); }); it("doesn't run the check if we've checked 3 hours ago", function (done) { var lastCheckForNewerVersionTimestamp; setCheckedTimestampToHoursAgo(3) .then(function (storedNumber) { return lastCheckForNewerVersionTimestamp = storedNumber; }) .then(function () { return new CheckForNewerVersion(repositoryInFakeServerPath, packageFilePath).showOnExit().fail(utils.emptyMethod); }) .done(function () { var listeners = process.listeners("beforeExit"); listeners.length.should.eql(0, "There should be no listeners for the beforeExit event"); var actual = memoryStdout.contentsAsText(); should(actual).be.empty; return Settings.loadSettings().then(function (settings) { settings.lastCheckForNewerVersionTimestamp.should.be.equal(lastCheckForNewerVersionTimestamp, "The last checked time shouldn't had changed expected: " + lastCheckForNewerVersionTimestamp + " actual: " + settings.lastCheckForNewerVersionTimestamp.should); done(); }); }); }); it("does run the check if we've checked 5 hours ago", function (done) { setCheckedTimestampToHoursAgo(5) .then(function () { return testCheckForNewerVersion(MessageExpectation.WillBeShown, done); }) .done(function () { return done(); }, done); }); it("doesn't show a message when there is not an update available", function (done) { setLatestReleasedVersion("1.0.0"); testCheckForNewerVersion(MessageExpectation.WontBeShown, done).done(function () { return done(); }, done); }); it("doesn't show any errors if the http request times out", function (done) { expectedRequestAndResponse.responseDelay = 10 * 1000; // 10 seconds testCheckForNewerVersion(MessageExpectation.WontBeShown, done).done(function () { return done(); }, done); }); it("doesn't show any errors if the http request fails with 4xx", function (done) { expectedRequestAndResponse.statusCode = 401; testCheckForNewerVersion(MessageExpectation.WontBeShown, done).done(function () { return done(); }, done); }); it("doesn't show any errors if the http request fails", function (done) { expectedRequestAndResponse.statusCode = 500; expectedRequestAndResponse.response = "There was a fake internal error"; // The body.version property doesn't exist with this response. It's also not JSON testCheckForNewerVersion(MessageExpectation.WontBeShown, done).done(function () { return done(); }, done); }); it("works if the settings file is empty", function (done) { // Create an empty settings file Settings.saveSettings({}); testCheckForNewerVersion(MessageExpectation.WillBeShown, done).done(function () { return done(); }, done); }); }); //# sourceMappingURL=checkForNewerVersion.js.map