UNPKG

@google/clasp

Version:

Develop Apps Script Projects locally

381 lines (380 loc) 19.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var _this = this; Object.defineProperty(exports, "__esModule", { value: true }); var os = require("os"); var path = require("path"); var chai_1 = require("chai"); var fs = require("fs-extra"); var mocha_1 = require("mocha"); var tmp = require("tmp"); var files_1 = require("./../src/files"); var utils_js_1 = require("./../src/utils.js"); var spawnSync = require('child_process').spawnSync; var TEST_CODE_JS = 'function test() { Logger.log(\'test\'); }'; var TEST_JSON = '{"timeZone": "America/New_York"}'; var CLASP = (os.type() === 'Windows_NT') ? 'clasp.cmd' : 'clasp'; var isPR = process.env.TRAVIS_PULL_REQUEST; mocha_1.describe('Test --help for each function', function () { var expectHelp = function (command, expected) { var result = spawnSync(CLASP, [command, '--help'], { encoding: 'utf8' }); chai_1.expect(result.status).to.equal(0); chai_1.expect(result.stdout).to.include(expected); }; mocha_1.it('should run --help', function () { return expectHelp('run', 'Run a function in your Apps Scripts project'); }); mocha_1.it('should logs --help', function () { return expectHelp('logs', 'Shows the StackDriver logs'); }); mocha_1.it('should login --help', function () { return expectHelp('login', 'Log in to script.google.com'); }); mocha_1.it('should logout --help', function () { return expectHelp('logout', 'Log out'); }); mocha_1.it('should create --help', function () { return expectHelp('create', 'Create a script'); }); mocha_1.it('should clone --help', function () { return expectHelp('clone', 'Clone a project'); }); mocha_1.it('should pull --help', function () { return expectHelp('pull', 'Fetch a remote project'); }); mocha_1.it('should push --help', function () { return expectHelp('push', 'Update the remote project'); }); mocha_1.it('should status --help', function () { return expectHelp('status', 'Lists files that will be pushed by clasp'); }); mocha_1.it('should open --help', function () { return expectHelp('open', 'Open a script'); }); mocha_1.it('should deployments --help', function () { return expectHelp('deployments', 'List deployment ids of a script'); }); mocha_1.it('should undeploy --help', function () { return expectHelp('undeploy', 'Undeploy a deployment of a project'); }); mocha_1.it('should redeploy --help', function () { return expectHelp('redeploy', 'Update a deployment'); }); mocha_1.it('should versions --help', function () { return expectHelp('versions', 'List versions of a script'); }); mocha_1.it('should version --help', function () { return expectHelp('version', 'Creates an immutable version of the script'); }); mocha_1.it('should list --help', function () { return expectHelp('list', 'List App Scripts projects'); }); mocha_1.it('should apis --help', function () { return expectHelp('apis', 'List, enable, or disable apis'); }); mocha_1.it('should help --help', function () { return expectHelp('help', 'Display help'); }); }); mocha_1.describe('Test clasp list function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should list clasp projects correctly', function () { var result = spawnSync(CLASP, ['list'], { encoding: 'utf8' }); // Every project starts with this base URL, thus // using clasp list should at least contain this // in its output. chai_1.expect(result.stdout).to.contain('https://script.google.com/d/'); chai_1.expect(result.status).to.equal(0); }); }); mocha_1.describe('Test clasp create function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should prompt for a project name correctly', function () { spawnSync('rm', ['.clasp.json']); var result = spawnSync(CLASP, ['create'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Give a script title:'); }); mocha_1.it('should not prompt for project name', function () { fs.writeFileSync('.clasp.json', ''); var result = spawnSync(CLASP, ['create'], { encoding: 'utf8' }); chai_1.expect(result.stderr).to.contain('Project file (.clasp.json) already exists.'); }); }); mocha_1.describe('Test clasp create <title> function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should create a new project named <title> correctly', function () { spawnSync('rm', ['.clasp.json']); var result = spawnSync(CLASP, ['create', 'myTitle'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Created new script: https://script.google.com/d/'); chai_1.expect(result.status).to.equal(0); }); }); mocha_1.describe('Test clasp clone <scriptId> function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should clone an existing project correctly', function () { var settings = JSON.parse(fs.readFileSync('.clasp.json', 'utf8')); fs.removeSync('.clasp.json'); var result = spawnSync(CLASP, ['clone', settings.scriptId], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Cloned'); chai_1.expect(result.stdout).to.contain('files.'); chai_1.expect(result.status).to.equal(0); }); mocha_1.it('should give an error on a non-existing project', function () { var settings = JSON.parse(fs.readFileSync('.clasp.json', 'utf8')); fs.removeSync('.clasp.json'); var result = spawnSync(CLASP, ['clone', 'non-existing-project'], { encoding: 'utf8' }); chai_1.expect(result.stderr).to.contain('> Did you provide the correct scriptId?'); chai_1.expect(result.status).to.equal(1); fs.writeFileSync('.clasp.json', JSON.stringify(settings)); }); }); mocha_1.describe('Test clasp pull function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should pull an existing project correctly', function () { var result = spawnSync(CLASP, ['pull'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Cloned'); chai_1.expect(result.stdout).to.contain('files.'); chai_1.expect(result.status).to.equal(0); }); }); mocha_1.describe('Test clasp push function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should push local project correctly', function () { fs.removeSync('.claspignore'); fs.writeFileSync('Code.js', TEST_CODE_JS); fs.writeFileSync('appsscript.json', TEST_JSON); fs.writeFileSync('.claspignore', '**/**\n!Code.js\n!appsscript.json'); var result = spawnSync(CLASP, ['push'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Pushed'); chai_1.expect(result.stdout).to.contain('files.'); chai_1.expect(result.status).to.equal(0); }); mocha_1.it('should return non-0 exit code when push failed', function () { fs.writeFileSync('.claspignore', '**/**\n!Code.js\n!appsscript.json\n!unexpected_file'); fs.writeFileSync('unexpected_file', TEST_CODE_JS); var result = spawnSync(CLASP, ['push'], { encoding: 'utf8' }); chai_1.expect(result.stderr).to.contain('Invalid value at'); chai_1.expect(result.stderr).to.contain('UNEXPECTED_FILE'); chai_1.expect(result.stderr).to.contain('Files to push were:'); chai_1.expect(result.status).to.equal(1); }); }); mocha_1.describe('Test clasp status function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); function setupTmpDirectory(filepathsAndContents) { fs.ensureDirSync('tmp'); var tmpdir = tmp.dirSync({ unsafeCleanup: true, dir: 'tmp/', keep: false }).name; filepathsAndContents.forEach(function (_a) { var file = _a.file, data = _a.data; fs.outputFileSync(path.join(tmpdir, file), data); }); return tmpdir; } mocha_1.it('should respect globs and negation rules', function () { var tmpdir = setupTmpDirectory([ { file: '.claspignore', data: '**/**\n!build/main.js\n!appsscript.json' }, { file: 'build/main.js', data: TEST_CODE_JS }, { file: 'appsscript.json', data: TEST_JSON }, { file: 'shouldBeIgnored', data: TEST_CODE_JS }, { file: 'should/alsoBeIgnored', data: TEST_CODE_JS }, ]); spawnSync(CLASP, ['create', '[TEST] clasp status'], { encoding: 'utf8', cwd: tmpdir }); var result = spawnSync(CLASP, ['status', '--json'], { encoding: 'utf8', cwd: tmpdir }); chai_1.expect(result.status).to.equal(0); var resultJson = JSON.parse(result.stdout); chai_1.expect(resultJson.untrackedFiles).to.have.members(['shouldBeIgnored', 'should/alsoBeIgnored']); chai_1.expect(resultJson.filesToPush).to.have.members(['build/main.js', 'appsscript.json']); }); // https://github.com/google/clasp/issues/67 - This test currently fails mocha_1.it.skip('should ignore dotfiles if the parent folder is ignored', function () { var tmpdir = setupTmpDirectory([ { file: '.claspignore', data: '**/node_modules/**\n**/**\n!appsscript.json' }, { file: 'appsscript.json', data: TEST_JSON }, { file: 'node_modules/fsevents/build/Release/.deps/Release/.node.d', data: TEST_CODE_JS }, ]); spawnSync(CLASP, ['create', '[TEST] clasp status'], { encoding: 'utf8', cwd: tmpdir }); var result = spawnSync(CLASP, ['status', '--json'], { encoding: 'utf8', cwd: tmpdir }); chai_1.expect(result.status).to.equal(0); var resultJson = JSON.parse(result.stdout); chai_1.expect(resultJson.untrackedFiles).to.have.members([ 'node_modules/fsevents/build/Release/.deps/Release/.node.d' ]); chai_1.expect(resultJson.filesToPush).to.have.members(['appsscript.json']); }); }); mocha_1.describe('Test clasp open function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should open a project correctly', function () { var result = spawnSync(CLASP, ['open'], { encoding: 'utf8' }); //should open a browser with the project chai_1.expect(result.status).to.equal(0); }); }); mocha_1.describe('Test clasp deployments function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should list deployments correctly', function () { var result = spawnSync(CLASP, ['deployments'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Deployment'); chai_1.expect(result.status).to.equal(0); }); }); mocha_1.describe('Test clasp deploy function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should deploy correctly', function () { var result = spawnSync(CLASP, ['deploy'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Created version '); chai_1.expect(result.status).to.equal(0); }); }); mocha_1.describe('Test clasp version and versions function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); var versionNumber = ''; mocha_1.it('should create new version correctly', function () { var result = spawnSync(CLASP, ['version'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Created version '); chai_1.expect(result.status).to.equal(0); versionNumber = result.stdout.substring(result.stdout.lastIndexOf(' '), result.stdout.length - 2); mocha_1.it('should list versions correctly', function () { var result = spawnSync(CLASP, ['versions'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Versions'); chai_1.expect(result.stdout).to.contain(versionNumber + ' - '); chai_1.expect(result.status).to.equal(0); }); }); }); mocha_1.describe('Test clasp clone function', function () { before(function () { if (isPR !== 'false') { this.skip(); } }); mocha_1.it('should prompt for which script to clone correctly', function () { spawnSync('rm', ['.clasp.json']); var result = spawnSync(CLASP, ['clone'], { encoding: 'utf8' }); chai_1.expect(result.stdout).to.contain('Clone which script?'); }); mocha_1.it('should give an error if .clasp.json already exists', function () { fs.writeFileSync('.clasp.json', ''); var result = spawnSync(CLASP, ['clone'], { encoding: 'utf8' }); chai_1.expect(result.stderr).to.contain('Project file (.clasp.json) already exists.'); chai_1.expect(result.status).to.equal(1); }); }); mocha_1.describe('Test getScriptURL function from utils', function () { mocha_1.it('should return the scriptURL correctly', function () { var url = utils_js_1.getScriptURL('abcdefghijklmnopqrstuvwxyz'); chai_1.expect(url).to.equal('https://script.google.com/d/abcdefghijklmnopqrstuvwxyz/edit'); }); }); mocha_1.describe('Test getFileType function from utils', function () { mocha_1.it('should return the lowercase file type correctly', function () { chai_1.expect(files_1.getFileType('SERVER_JS')).to.equal('js'); chai_1.expect(files_1.getFileType('GS')).to.equal('gs'); chai_1.expect(files_1.getFileType('JS')).to.equal('js'); }); }); mocha_1.describe('Test getAPIFileType function from utils', function () { mocha_1.it('should return the uppercase file type correctly', function () { chai_1.expect(utils_js_1.getAPIFileType('file.GS')).to.equal('SERVER_JS'); chai_1.expect(utils_js_1.getAPIFileType('file.JS')).to.equal('SERVER_JS'); chai_1.expect(utils_js_1.getAPIFileType('file.js')).to.equal('SERVER_JS'); chai_1.expect(utils_js_1.getAPIFileType('file.jsx')).to.equal('JSX'); chai_1.expect(utils_js_1.getAPIFileType('file.js.html')).to.equal('HTML'); }); }); mocha_1.describe('Test saveProjectId function from utils', function () { mocha_1.it('should save the scriptId correctly', function () { spawnSync('rm', ['.clasp.json']); var isSaved = function () { return __awaiter(_this, void 0, void 0, function () { var id; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, utils_js_1.saveProjectId('12345')]; case 1: _a.sent(); id = fs.readFileSync(path.join(__dirname, '/../.clasp.json'), 'utf8'); chai_1.expect(id).to.equal('{"scriptId":"12345"}'); return [2 /*return*/]; } }); }); }; chai_1.expect(isSaved).to.not.equal(null); }); }); mocha_1.describe('Test clasp apis functions', function () { mocha_1.it('should list apis correctly', function () { var result = spawnSync('clasp', ['apis', 'list'], { encoding: 'utf8' }); chai_1.expect(result.status).to.equal(0); chai_1.expect(result.stdout).to.contain('abusiveexperiencereport - abusiveexperiencereport:v1'); chai_1.expect(result.stdout).to.contain('youtubereporting - youtubereporting:v1'); }); mocha_1.it('should enable apis correctly', function () { var result = spawnSync('clasp', ['apis', 'enable'], { encoding: 'utf8' }); chai_1.expect(result.status).to.equal(0); chai_1.expect(result.stdout).to.contain('In development...'); }); mocha_1.it('should disable apis correctly', function () { var result = spawnSync('clasp', ['apis', 'disable'], { encoding: 'utf8' }); chai_1.expect(result.status).to.equal(0); chai_1.expect(result.stdout).to.contain('In development...'); }); mocha_1.it('should error with unknown subcommand', function () { var result = spawnSync('clasp', ['apis', 'unknown'], { encoding: 'utf8' }); chai_1.expect(result.status).to.equal(1); chai_1.expect(result.stderr).to.contain('Unknown command "apis unknown"'); }); }); mocha_1.describe('Test clasp logout function', function () { mocha_1.it('should logout correctly', function () { fs.writeFileSync('.clasprc.json', TEST_JSON); fs.writeFileSync(path.join(os.homedir(), '/.clasprc.json'), TEST_JSON); var result = spawnSync(CLASP, ['logout'], { encoding: 'utf8' }); chai_1.expect(result.status).to.equal(0); var localDotExists = fs.existsSync('.clasprc.json'); chai_1.expect(localDotExists).to.equal(false); var dotExists = fs.existsSync('~/.clasprc.json'); chai_1.expect(dotExists).to.equal(false); }); });