diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 051a62ee6..eae88ffd6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,8 +11,6 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
- # Xvfb (nightmare on linux)
- DISPLAY: ':99.0'
# electron packager (win32 ia32 on macos) https://github.com/electron/electron-packager/pull/449#issuecomment-240508298
WINEDLLOVERRIDES: 'mscoree,mshtml='
@@ -25,10 +23,10 @@ jobs:
node-version: ${{ matrix.node-version }}
# linux dependencies
- - run: Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- if: matrix.os == 'ubuntu-latest'
- run: sudo apt update
if: matrix.os == 'ubuntu-latest'
+ - run: sudo apt install -y libgbm1
+ if: matrix.os == 'ubuntu-latest'
- run: sudo apt install -y wine64
if: matrix.os == 'ubuntu-latest'
- run: wine --version
diff --git a/.gitignore b/.gitignore
index 3f1191859..30114c0a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,11 +24,7 @@ report/
/node_modules/
-/clicktests/screenshots/
/build
-/*.dll
-/nw.exe
-/nw.pak
/components/**/*.css
/components/**/*.bundle.js
diff --git a/.npmignore b/.npmignore
index 23413c68d..e25642f57 100644
--- a/.npmignore
+++ b/.npmignore
@@ -32,7 +32,6 @@ public/devStyling.html
public/js/devStyling.js
clicktests/
-nmclicktests/
teststabilitytester.js
diff --git a/.travis.yml b/.travis.yml
index a5ff2f77f..dc5034446 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,8 +26,7 @@ jobs:
addons:
apt:
packages:
- - xvfb
- - libgconf-2-4
+ - libgbm1
- wine
homebrew:
update: true
@@ -36,8 +35,6 @@ addons:
- wine-stable
before_install:
# linux
- - if [[ $TRAVIS_OS_NAME = "linux" ]]; then export DISPLAY=':99.0'; fi
- - if [[ $TRAVIS_OS_NAME = "linux" ]]; then Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & fi
- if [[ $TRAVIS_OS_NAME = "linux" ]]; then wine --version; fi
- if [[ $TRAVIS_OS_NAME = "linux" && $GIT_VERSION = "edge" ]]; then sudo add-apt-repository ppa:git-core/ppa -y && sudo apt-get update -q && sudo apt-get install -y git; fi
# osx
@@ -55,7 +52,7 @@ before_script:
- git config --global user.email "test@testy.com"
- git config --global user.name "Test testy"
- git --version
- - DISPLAY= npm run package
+ - npm run package
after_success:
- npm run travisnpmpublish
before_deploy:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c0b4d3db..99b2ce7f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ We are following the [Keep a Changelog](https://keepachangelog.com/) format.
## [Unreleased](https://github.com/FredrikNoren/ungit/compare/v1.5.7...master)
+### Changed
+- Migrate clicktests from nightmare to puppeteer [#1336](https://github.com/FredrikNoren/ungit/pull/1336)
+
## [1.5.7](https://github.com/FredrikNoren/ungit/compare/v1.5.6...v1.5.7)
### Fixed
diff --git a/Gruntfile.js b/Gruntfile.js
index 2875dc242..d846cb7dc 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -69,10 +69,10 @@ module.exports = (grunt) => {
options: {
reporter: 'spec',
require: './source/utils/winston.js',
- timeout: 15000,
+ timeout: 35000,
bail: true
},
- src: 'nmclicktests/spec.*.js'
+ src: 'clicktests/spec.*.js'
}
},
@@ -80,7 +80,7 @@ module.exports = (grunt) => {
options: {
undef: true, // check for usage of undefined constiables
indent: 2,
- esnext: true,
+ esversion: 6,
'-W033': true, // ignore Missing semicolon
'-W041': true, // ignore Use '===' to compare with '0'
'-W065': true, // ignore Missing radix parameter
@@ -124,6 +124,7 @@ module.exports = (grunt) => {
},
mocha: {
options: {
+ esversion: 8,
node: true,
globals: {
'it': true,
@@ -138,7 +139,7 @@ module.exports = (grunt) => {
},
src: [
'test/**/*.js',
- 'nmclicktests/**/*.js'
+ 'clicktests/**/*.js'
]
}
},
@@ -305,7 +306,7 @@ module.exports = (grunt) => {
grunt.registerTask('clickParallel', 'Parallelized click tests.', function() {
const done = this.async();
- fs.readdirAsync('./nmclicktests')
+ fs.readdirAsync('./clicktests')
.then((files) => files.filter((file) => file.startsWith('spec.')))
.then((tests) => {
const genericIndx = tests.indexOf('spec.generic.js');
@@ -321,7 +322,7 @@ module.exports = (grunt) => {
grunt.log.writeln(cliColor.set(`Clicktest started! \t${file}`, 'blue'));
return new Bluebird((resolve, reject) => {
- const child = childProcess.execFile('./node_modules/mocha/bin/mocha', [path.join(__dirname, 'nmclicktests', file), '--timeout=20000', '-b'], { maxBuffer: 10*1024*1024 });
+ const child = childProcess.execFile('./node_modules/mocha/bin/mocha', [path.join(__dirname, 'clicktests', file), '--timeout=35000', '-b'], { maxBuffer: 10*1024*1024 });
child.stdout.on('data', outStream);
child.stderr.on('data', outStream);
child.on('exit', (code) => {
diff --git a/clicktests/environment.js b/clicktests/environment.js
new file mode 100644
index 000000000..ec49f6afd
--- /dev/null
+++ b/clicktests/environment.js
@@ -0,0 +1,315 @@
+'use strict';
+const winston = require('../source/utils/winston');
+const child_process = require('child_process');
+const puppeteer = require('puppeteer');
+const net = require('net');
+const request = require('superagent');
+const mkdirp = require('mkdirp');
+const util = require('util');
+const rimraf = util.promisify(require('rimraf'));
+const portrange = 45032;
+
+module.exports = (config) => new Environment(config);
+
+const prependLines = (pre, text) => {
+ return text.split('\n').filter((l) => l)
+ .map((line) => pre + line)
+ .join('\n');
+}
+
+// Environment provides
+class Environment {
+ constructor(config) {
+ this.config = config || {};
+ this.config.rootPath = typeof this.config.rootPath === 'string' ? this.config.rootPath : '';
+ this.config.serverTimeout = this.config.serverTimeout || 35000;
+ this.config.headless = this.config.headless === undefined ? true : this.config.headless;
+ this.config.viewWidth = 1920;
+ this.config.viewHeight = 1080;
+ this.config.showServerOutput = this.config.showServerOutput === undefined ? true : this.config.showServerOutput;
+ this.config.serverStartupOptions = this.config.serverStartupOptions || [];
+ this.shuttinDown = false;
+ }
+
+ getRootUrl() { return this.rootUrl; }
+
+ getPort() {
+ const tmpPortrange = portrange + Math.floor(Math.random() * 5000);
+
+ return new Promise((resolve, reject) => {
+ const server = net.createServer();
+
+ server.listen(tmpPortrange, () => {
+ server.once('close', () => {
+ this.port = tmpPortrange;
+ this.rootUrl = `http://localhost:${this.port}${this.config.rootPath}`;
+ resolve();
+ });
+ server.close();
+ });
+ server.on('error', () => {
+ this.getPort().then(resolve);
+ });
+ });
+ }
+
+ async init() {
+ try {
+ this.browser = await puppeteer.launch({
+ headless: this.config.headless,
+ defaultViewport: {
+ width: this.config.viewWidth,
+ height: this.config.viewHeight
+ }
+ });
+
+ await this.getPort();
+ await this.startServer();
+ } catch (err) {
+ winston.error(err);
+ throw new Error('Cannot confirm ungit start!!\n' + err);
+ }
+ }
+
+ startServer() {
+ winston.info('Starting ungit server...', this.config.serverStartupOptions);
+
+ this.hasStarted = false;
+ const options = ['bin/ungit',
+ '--cliconfigonly',
+ `--port=${this.port}`,
+ `--rootPath=${this.config.rootPath}`,
+ '--no-launchBrowser',
+ '--dev',
+ '--no-bugtracking',
+ `--autoShutdownTimeout=${this.config.serverTimeout}`,
+ '--logLevel=debug',
+ '--maxNAutoRestartOnCrash=0',
+ '--no-autoCheckoutOnBranchCreate',
+ '--alwaysLoadActiveBranch',
+ `--numRefsToShow=${this.config.numRefsToShow || 5}`]
+ .concat(this.config.serverStartupOptions);
+
+ const ungitServer = this.ungitServerProcess = child_process.spawn('node', options);
+
+ return new Promise((resolve, reject) => {
+ ungitServer.stdout.on('data', (stdout) => {
+ const stdoutStr = stdout.toString();
+ if (this.config.showServerOutput) winston.verbose(prependLines('[server] ', stdoutStr));
+
+ if (stdoutStr.indexOf('Ungit server already running') >= 0) {
+ winston.info('server-already-running');
+ }
+
+ if (stdoutStr.indexOf('## Ungit started ##') >= 0) {
+ if (this.hasStarted) {
+ reject(new Error('Ungit started twice, probably crashed.'));
+ } else {
+ this.hasStarted = true;
+ winston.info('Ungit server started.');
+ resolve();
+ }
+ }
+ });
+ ungitServer.stderr.on('data', (stderr) => {
+ const stderrStr = stderr.toString();
+ winston.error(prependLines('[server ERROR] ', stderrStr));
+ if (stderrStr.indexOf('EADDRINUSE') > -1) {
+ winston.info('retrying with different port');
+ ungitServer.kill('SIGINT');
+ reject(new Error('EADDRINUSE'));
+ }
+ });
+ ungitServer.on('exit', () => winston.info('UNGIT SERVER EXITED'));
+ });
+ }
+
+ async shutdown() {
+ this.shuttinDown = true;
+
+ await this.backgroundAction('POST', '/api/testing/cleanup')
+
+ if (this.ungitServerProcess) {
+ this.ungitServerProcess.kill('SIGINT');
+ this.ungitServerProcess = null;
+ }
+
+ if (this.browser) {
+ await this.browser.close();
+ this.browser = null;
+ this.page = null;
+ }
+ }
+
+ // server helpers
+
+ async backgroundAction(method, url, body) {
+ url = this.getRootUrl() + url;
+
+ let req;
+ if (method === 'GET') {
+ req = request.get(url).withCredentials().query(body);
+ } else if (method === 'POST') {
+ req = request.post(url).send(body);
+ } else if (method === 'DELETE') {
+ req = request.delete(url).send(body);
+ }
+
+ req.set({ 'encoding': 'utf8', 'cache-control': 'no-cache', 'Content-Type': 'application/json' });
+
+ const response = await req;
+ return response.body;
+ }
+
+ async createRepos(testRepoPaths, config) {
+ for (let i = 0; i < config.length; i++) {
+ const conf = config[i];
+ conf.bare = !!conf.bare;
+ await this.initRepo(conf);
+ await this.createCommits(conf, conf.initCommits);
+ testRepoPaths.push(conf.path);
+ }
+ }
+
+ async initRepo(options) {
+ if (options.path) {
+ await rimraf(options.path);
+ await mkdirp(options.path);
+ } else {
+ winston.info('Creating temp folder');
+ options.path = await this.createTempFolder();
+ }
+ await this.backgroundAction('POST', '/api/init', options);
+ }
+
+ async createTempFolder() {
+ const res = await this.backgroundAction('POST', '/api/testing/createtempdir');
+ return res.path;
+ }
+
+ async createCommits(config, limit, x) {
+ x = x || 0
+ if (!limit || limit < 0 || x === limit) return;
+
+ await this.createTestFile(`${config.path}/testy${x}`);
+ await this.backgroundAction('POST', '/api/commit', {
+ path: config.path,
+ message: `Init Commit ${x}`,
+ files: [{ name: `testy${x}` }]
+ });
+ await this.createCommits(config, limit, x + 1);
+ }
+
+ createTestFile(filename, repoPath) {
+ return this.backgroundAction('POST', '/api/testing/createfile', { file: filename, path: repoPath });
+ }
+
+ // browser helpers
+
+ async goto(url) {
+ winston.info('Go to page: ' + url);
+
+ if (!this.page) {
+ const pages = await this.browser.pages();
+ const page = this.page = pages[0];
+
+ page.on('console', (message) => {
+ const text = `[ui ${message.type()}] ${(new Date()).toISOString()} - ${message.text()}}`;
+
+ if (message.type() === 'error' && !this.shuttinDown) {
+ winston.error(text);
+ } else {
+ winston.info(text);
+ }
+ });
+ }
+
+ await this.page.goto(url);
+ }
+
+ async openUngit(tempDirPath) {
+ await this.goto(`${this.getRootUrl()}/#/repository?path=${encodeURIComponent(tempDirPath)}`);
+ await this.waitForElementVisible('.repository-actions');
+ await this.wait(1000);
+ }
+
+ waitForElementVisible(selector) {
+ return this.page.waitForSelector(selector, { visible: true });
+ }
+ waitForElementHidden(selector) {
+ return this.page.waitForSelector(selector, { hidden: true });
+ }
+ wait(duration) {
+ return this.page.waitFor(duration);
+ }
+
+ type(text) {
+ return this.page.keyboard.type(text);
+ }
+ async insert(selector, text) {
+ await this.waitForElementVisible(selector);
+ await this.page.$eval(selector, (ele) => ele.value = '');
+ await this.page.focus(selector);
+ await this.type(text);
+ }
+ press(key) {
+ return this.page.keyboard.press(key);
+ }
+
+ async click(selector) {
+ let elementHandle = await this.waitForElementVisible(selector);
+ try {
+ await elementHandle.click();
+ } catch (err1) {
+ elementHandle = await this.waitForElementVisible(selector);
+ try {
+ await elementHandle.click(); // try click a second time to reduce test flakiness
+ } catch (err2) {
+ winston.error(`Failed to click element: ${selector}`);
+ throw err2;
+ }
+ }
+ }
+
+ async commit(commitMessage) {
+ await this.waitForElementVisible('.files .file .btn-default');
+ await this.insert('.staging input.form-control', commitMessage);
+ await this.click('.commit-btn');
+ await this.waitForElementHidden('.files .file .btn-default');
+ await this.wait(1000);
+ }
+
+ async _createRef(type, name) {
+ await this.click('.current ~ .new-ref button.showBranchingForm');
+ await this.insert('.ref-icons.new-ref.editing input', name);
+ await this.click(`.new-ref ${type === 'branch' ? '.btn-primary' : '.btn-default'}`);
+ await this.waitForElementVisible(`.ref.${type}[data-ta-name="${name}"]`);
+ }
+ createTag(name) {
+ return this._createRef('tag', name);
+ }
+ createBranch(name) {
+ return this._createRef('branch', name);
+ }
+
+ async _verifyRefAction(action) {
+ try {
+ await this.page.waitForSelector('.modal-dialog .btn-primary', { visible: true, timeout: 2000 });
+ await this.click('.modal-dialog .btn-primary');
+ } catch (err) { /* ignore */ }
+ await this.waitForElementHidden(`[data-ta-action="${action}"]:not([style*="display: none"])`);
+ }
+
+ async refAction(ref, local, action) {
+ await this.click(`.branch[data-ta-name="${ref}"][data-ta-local="${local}"]`);
+ await this.click(`[data-ta-action="${action}"]:not([style*="display: none"]) .dropmask`);
+ await this._verifyRefAction(action);
+ }
+
+ async moveRef(ref, targetNodeCommitTitle) {
+ await this.click(`.branch[data-ta-name="${ref}"]`);
+ await this.click(`[data-ta-node-title="${targetNodeCommitTitle}"] [data-ta-action="move"]:not([style*="display: none"]) .dropmask`);
+ await this._verifyRefAction('move');
+ }
+
+}
diff --git a/clicktests/spec.authentication.js b/clicktests/spec.authentication.js
new file mode 100644
index 000000000..61f63e985
--- /dev/null
+++ b/clicktests/spec.authentication.js
@@ -0,0 +1,30 @@
+'use strict';
+const testuser = { username: 'testuser', password: 'testpassword' }
+const environment = require('./environment')({
+ serverStartupOptions: ['--authentication', `--users.${testuser.username}=${testuser.password}`],
+ showServerOutput: true
+});
+
+describe('[AUTHENTICATION]', () => {
+ before('Environment init without temp folder', () => environment.init());
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open home screen should show authentication dialog', async () => {
+ await environment.goto(environment.getRootUrl());
+ await environment.waitForElementVisible('.login');
+ });
+
+ it('Filling out the authentication with wrong details should result in an error', async () => {
+ await environment.insert('.login #inputUsername', testuser.username);
+ await environment.insert('.login #inputPassword', 'notthepassword');
+ await environment.click('.login button');
+ await environment.waitForElementVisible('.login .loginError');
+ });
+
+ it('Filling out the authentication should bring you to the home screen', async () => {
+ await environment.insert('.login #inputUsername', testuser.username);
+ await environment.insert('.login #inputPassword', testuser.password);
+ await environment.click('.login button');
+ await environment.waitForElementVisible('.container.home');
+ });
+});
diff --git a/clicktests/spec.bare.js b/clicktests/spec.bare.js
new file mode 100644
index 000000000..014349da2
--- /dev/null
+++ b/clicktests/spec.bare.js
@@ -0,0 +1,20 @@
+'use strict';
+const environment = require('./environment')();
+const testRepoPaths = [];
+
+describe('[BARE]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: true }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('update branches button without branches', async () => {
+ await environment.click('.btn-group.branch .btn-main');
+ await environment.waitForElementHidden('#nprogress');
+ });
+});
diff --git a/clicktests/spec.branches.js b/clicktests/spec.branches.js
new file mode 100644
index 000000000..05cf7689c
--- /dev/null
+++ b/clicktests/spec.branches.js
@@ -0,0 +1,131 @@
+'use strict';
+const environment = require('./environment')();
+const testRepoPaths = [];
+
+describe('[BRANCHES]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('add a commit', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.commit('commit-1');
+ })
+
+ // < branch search test >
+ it('add branches', async () => {
+ await environment.createBranch('search-1');
+ await environment.createBranch('search-2');
+ await environment.createBranch('search-3');
+ await environment.createBranch('search-4');
+ await environment.waitForElementVisible('[data-ta-name="search-4"]');
+ });
+
+ it('add tag should make one of the branch disappear', async () => {
+ await environment.createTag('tag-1');
+ await environment.waitForElementHidden('[data-ta-name="search-4"]');
+ });
+
+ it('search for the hidden branch', async () => {
+ await environment.wait(1000); // sleep to avoid `git-directory-changed` event, which refreshes git nodes and closes search box
+ await environment.click('.showSearchForm');
+
+ await environment.type('-4');
+ await environment.wait(500);
+ await environment.press('ArrowDown');
+ await environment.press('Enter');
+
+ await environment.waitForElementVisible('[data-ta-name="search-4"]');
+ });
+
+ it('updateBranches button without branches', async () => {
+ await environment.click('.btn-group.branch .btn-main');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('add a branch', () => {
+ return environment.createBranch('branch-1');
+ });
+
+ it('updateBranches button with one branch', async () => {
+ await environment.click('.btn-group.branch .btn-main');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('add second branch', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile2.txt`, testRepoPaths[0]);
+ await environment.commit('commit-2');
+
+ await environment.createBranch('branch-2');
+ await environment.createBranch('branch-3');
+ });
+
+ it('Check out a branch via selection', async () => {
+ await environment.click('.branch .dropdown-toggle');
+ await environment.click('[data-ta-clickable="checkoutrefs/heads/branch-2"]');
+ await environment.waitForElementVisible('[data-ta-name="branch-2"].current');
+ });
+
+ it('Delete a branch via selection', async () => {
+ await environment.click('.branch .dropdown-toggle');
+ await environment.click('[data-ta-clickable="refs/heads/branch-3-remove"]');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('add a commit', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile2.txt`, testRepoPaths[0]);
+ await environment.commit('commit-3');
+ });
+
+ it('checkout cherypick base', async () => {
+ await environment.click('.branch .dropdown-toggle');
+ await environment.click('[data-ta-clickable="checkoutrefs/heads/branch-1"]');
+ await environment.waitForElementVisible('[data-ta-name="branch-1"].current');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('cherrypick fail case', async () => {
+ await environment.click('[data-ta-clickable="node-clickable-0"]');
+ await environment.click('[data-ta-action="cherry-pick"]:not([style*="display: none"]) .dropmask');
+
+ await environment.click('.staging .btn-stg-abort');
+ await environment.click('.modal-dialog .btn-primary');
+
+ await environment.waitForElementVisible('[data-ta-clickable="node-clickable-0"]'); // wait for nodes to come back
+ });
+
+ it('cherrypick success case', async () => {
+ await environment.click('[data-ta-clickable="node-clickable-1"]');
+ await environment.click('[data-ta-action="cherry-pick"]:not([style*="display: none"]) .dropmask');
+ await environment.waitForElementVisible('[data-ta-node-title="commit-2"] .ref.branch.current');
+ });
+
+ it('test backward squash from own lineage', async () => {
+ await environment.click('.ref.branch.current');
+ await environment.click('[data-ta-node-title="commit-1"] .squash .dropmask');
+ await environment.waitForElementVisible('.staging .files .file');
+ await environment.click('.files button.discard');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementHidden('.staging .files .file');
+ });
+
+ it('test forward squash from different lineage', async () => {
+ await environment.click('.ref.branch.current');
+ await environment.click('[data-ta-node-title="commit-3"] .squash .dropmask');
+ await environment.waitForElementVisible('.staging .files .file');
+ });
+
+ it('Auto checkout on branch creation.', async () => {
+ await environment.page.evaluate(() => ungit.config.autoCheckoutOnBranchCreate = true);
+ await environment.createBranch('autoCheckout');
+ await environment.waitForElementVisible('[data-ta-name="autoCheckout"].current');
+ });
+
+});
diff --git a/clicktests/spec.commands.js b/clicktests/spec.commands.js
new file mode 100644
index 000000000..6d6afaeb1
--- /dev/null
+++ b/clicktests/spec.commands.js
@@ -0,0 +1,69 @@
+'use strict';
+const environment = require('./environment')();
+const testRepoPaths = [];
+
+const gitCommand = (options) => {
+ return environment.backgroundAction('POST', '/api/testing/git', options);
+}
+const testForBranchMove = async (branch, command) => {
+ const branchTagLoc = await environment.page.$eval(branch, (element) => JSON.stringify(element.getBoundingClientRect()));
+
+ await gitCommand({ command: command, path: testRepoPaths[0] });
+
+ await environment.page.waitForFunction((branch, oldLoc) => {
+ const newLoc = document.querySelector(branch).getBoundingClientRect();
+ return newLoc.top !== oldLoc.top || newLoc.left !== oldLoc.left;
+ }, {}, branch, JSON.parse(branchTagLoc));
+}
+
+describe('[COMMANDS]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('add a branch-1', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.commit('commit-1');
+ await environment.createBranch('branch-1');
+ });
+
+ it('add a branch-2', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.commit('commit-1');
+ await environment.createBranch('branch-2');
+ });
+
+ it('test branch create from command line', async () => {
+ await gitCommand({ command: ["branch", "gitCommandBranch"], path: testRepoPaths[0] });
+ await environment.waitForElementVisible('[data-ta-name="gitCommandBranch"]');
+ });
+
+ it('test branch move from command line', () => {
+ return testForBranchMove('[data-ta-name="gitCommandBranch"]', ["branch", "-f", "gitCommandBranch", "branch-1"]);
+ });
+
+ it('test branch delete from command line', async () => {
+ await gitCommand({ command: ["branch", "-D", "gitCommandBranch"], path: testRepoPaths[0] });
+ await environment.waitForElementHidden('[data-ta-name="gitCommandBranch"]');
+ });
+
+ it('test tag create from command line', async () => {
+ await gitCommand({ command: ["tag", "tag1"], path: testRepoPaths[0] });
+ await environment.waitForElementVisible('[data-ta-name="tag1"]');
+ });
+
+ it('test tag delete from command line', async () => {
+ await gitCommand({ command: ["tag", "-d", "tag1"], path: testRepoPaths[0] });
+ await environment.waitForElementHidden('[data-ta-name="tag1"]');
+ });
+
+ it('test reset from command line', () => {
+ return testForBranchMove('[data-ta-name="branch-1"]', ["reset", "branch-1"]);
+ });
+});
diff --git a/clicktests/spec.discard.js b/clicktests/spec.discard.js
new file mode 100644
index 000000000..ccbc60d6e
--- /dev/null
+++ b/clicktests/spec.discard.js
@@ -0,0 +1,72 @@
+'use strict';
+const muteGraceTimeDuration = 3000;
+const createAndDiscard = async (env, testRepoPath, dialogButtonToClick) => {
+ await env.createTestFile(testRepoPath + '/testfile2.txt', testRepoPath);
+ await env.waitForElementVisible('.files .file .btn-default');
+ await env.click('.files button.discard');
+
+ if (dialogButtonToClick === "yes") {
+ await env.click('.modal-dialog [data-ta-action="yes"]');
+ } else if (dialogButtonToClick === "mute") {
+ await env.click('.modal-dialog [data-ta-action="mute"]');
+ } else if (dialogButtonToClick === "no") {
+ await env.click('.modal-dialog [data-ta-action="no"]');
+ } else {
+ await env.waitForElementHidden('.modal-dialog [data-ta-action="yes"]');
+ }
+
+ if (dialogButtonToClick !== 'no') {
+ await env.waitForElementHidden('.files .file .btn-default');
+ } else {
+ await env.waitForElementVisible('.files .file .btn-default');
+ }
+}
+
+describe('[DISCARD - noWarn]', () => {
+ const environment = require('./environment')({ serverStartupOptions: ['--disableDiscardWarning'] });
+ const testRepoPaths = [];
+
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('Should be possible to discard a created file without warning message', () => {
+ return createAndDiscard(environment, testRepoPaths[0]);
+ });
+});
+
+describe('[DISCARD - withWarn]', () => {
+ const environment = require('./environment')({ serverStartupOptions: ['--no-disableDiscardWarning', '--disableDiscardMuteTime=' + muteGraceTimeDuration] });
+ const testRepoPaths = [];
+
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('Should be possible to select no from discard', () => {
+ return createAndDiscard(environment, testRepoPaths[0], 'no');
+ });
+
+ it('Should be possible to discard a created file', () => {
+ return createAndDiscard(environment, testRepoPaths[0], 'yes');
+ });
+
+ it('Should be possible to discard a created file and disable warn for awhile', async () => {
+ await createAndDiscard(environment, testRepoPaths[0], 'mute');
+ await createAndDiscard(environment, testRepoPaths[0]);
+ await environment.wait(2000);
+ await createAndDiscard(environment, testRepoPaths[0], 'yes');
+ });
+});
diff --git a/clicktests/spec.generic.js b/clicktests/spec.generic.js
new file mode 100644
index 000000000..6161d39fa
--- /dev/null
+++ b/clicktests/spec.generic.js
@@ -0,0 +1,224 @@
+'use strict';
+const environment = require('./environment')({ serverStartupOptions: ['--no-disableDiscardWarning'], rootPath: '/deep/root/path/to/app' });
+const mkdirp = require('mkdirp');
+const util = require('util');
+const rimraf = util.promisify(require('rimraf'));
+const testRepoPaths = [];
+
+const changeTestFile = async (filename, repoPath) => {
+ await environment.backgroundAction('POST', `/api/testing/changefile`, { file: filename, path: repoPath });
+};
+const checkout = async (branch) => {
+ await environment.click(`.branch[data-ta-name="${branch}"]`);
+ await environment.click('[data-ta-action="checkout"]:not([style*="display: none"]) .dropmask');
+ await environment.waitForElementVisible(`.ref.branch[data-ta-name="${branch}"].current`);
+};
+const amendCommit = async () => {
+ try {
+ await environment.page.waitForSelector('.amend-button', { visible: true, timeout: 2000 });
+ await environment.click('.amend-button');
+ } catch (err) {
+ await environment.click('.amend-link');
+ }
+ await environment.click('.commit-btn');
+ await environment.waitForElementHidden('.files .file .btn-default');
+};
+
+describe('[GENERIC]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+
+ // create a sub dir and change working dir to sub dir to prove functionality within subdir
+ testRepoPaths.push(`${testRepoPaths[0]}/asubdir`);
+ await rimraf(testRepoPaths[1]);
+ await mkdirp(testRepoPaths[1]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open repo screen', () => {
+ return environment.openUngit(testRepoPaths[1]);
+ });
+
+ it('Check for refresh button', () => {
+ return environment.click('.refresh-button');
+ });
+
+ it('Should be possible to create and commit a file', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.commit('Init');
+ await environment.waitForElementVisible('.commit');
+ });
+
+ it('Should be possible to amend a file', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.waitForElementVisible('.files .file .btn-default');
+ await amendCommit();
+ await environment.waitForElementVisible('.commit');
+ });
+
+ it('Should be possible to cancel amend a file', async () => {
+ await environment.click('.amend-link');
+ await environment.click('.btn-stg-cancel');
+ await environment.waitForElementVisible('.empty-commit-link');
+ });
+
+ it('Should be able to add a new file to .gitignore', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/addMeToIgnore.txt`, testRepoPaths[0]);
+ await environment.waitForElementVisible('.files .file .btn-default');
+ await environment.click('.files button.ignore');
+ await environment.wait(2000);
+ await environment.click('.files button.ignore');
+ await environment.waitForElementHidden('.files .file .btn-default');
+ });
+
+ it('Test showing commit diff between two commits', async () => {
+ await environment.click('[data-ta-clickable="node-clickable-0"]')
+ await environment.waitForElementVisible('.diff-wrapper');
+ await environment.click('.commit-diff-filename');
+ await environment.waitForElementVisible('.commit-line-diffs');
+ });
+
+ it('Test showing commit side by side diff between two commits', async () => {
+ await environment.click('.commit-sideBySideDiff');
+ await environment.waitForElementVisible('.commit-line-diffs');
+ });
+
+ it('Test wordwrap', async () => {
+ await environment.click('.commit-wordwrap');
+ await environment.waitForElementVisible('.word-wrap');
+ });
+
+ it('Test whitespace', async () => {
+ await environment.click('.commit-whitespace');
+ await environment.waitForElementVisible('.commit-line-diffs');
+ await environment.click('[data-ta-clickable="node-clickable-0"]');
+ });
+
+ it('Should be possible to discard a created file and ensure patching is not available for new file', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile2.txt`, testRepoPaths[0]);
+ await environment.waitForElementVisible('.files .file .btn-default');
+ await environment.click('.files button');
+ await environment.waitForElementHidden('[data-ta-container="patch-file"]');
+ await environment.click('.files button.discard');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementHidden('.files .file .btn-default');
+ });
+
+ it('Should be possible to create a branch', () => {
+ return environment.createBranch('testbranch');
+ });
+
+ it('Should be possible to create and destroy a branch', async () => {
+ await environment.createBranch('willbedeleted');
+ await environment.click('.branch[data-ta-name="willbedeleted"]');
+ await environment.click('[data-ta-action="delete"]:not([style*="display: none"]) .dropmask');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementHidden('.branch[data-ta-name="willbedeleted"]');
+ });
+
+ it('Should be possible to create and destroy a tag', async () => {
+ await environment.createTag('tagwillbedeleted');
+ await environment.click('.graph .ref.tag[data-ta-name="tagwillbedeleted"]');
+ await environment.click('[data-ta-action="delete"]:not([style*="display: none"]) .dropmask');
+ await environment.click('.modal-dialog .btn-primary')
+ await environment.waitForElementHidden('.graph .ref.tag[data-ta-name="tagwillbedeleted"]');
+ });
+
+ it('Commit changes to a file', async () => {
+ await changeTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.waitForElementVisible('.files .file .btn-default');
+ await environment.insert('.staging input.form-control', 'My commit message');
+ await environment.click('.commit-btn');
+ await environment.waitForElementHidden('.files .file .btn-default');
+ });
+
+ it('Show stats for changed file and discard it', async () => {
+ await changeTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.waitForElementVisible('.files .file .additions');
+ await environment.waitForElementVisible('.files .file .deletions');
+
+ await environment.click('.files button.discard');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementHidden('.files .file .btn-default');
+ });
+
+ it.skip('Should be possible to patch a file', async () => {
+ await changeTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ // .patch('patch')
+ environment.waitForElementVisible('.commit');
+ });
+
+ it('Checkout a branch', () => {
+ return checkout('testbranch');
+ });
+
+ it('Create another commit', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testy2.txt`, testRepoPaths[0]);
+ await environment.commit('Branch commit');
+ });
+
+ it('Rebase', () => {
+ return environment.refAction('testbranch', true, 'rebase');
+ });
+
+ it('Checkout master again', () => {
+ return checkout('master');
+ });
+
+ it('Create yet another commit', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testy3.txt`, testRepoPaths[0]);
+ await environment.commit('Branch commit');
+ });
+
+ it('Merge', () => {
+ return environment.refAction('testbranch', true, 'merge');
+ });
+
+ it('Revert merge', async () => {
+ await environment.click('[data-ta-clickable="node-clickable-0"]');
+ await environment.waitForElementVisible('[data-ta-action="revert"]');
+ await environment.click('[data-ta-action="revert"]');
+ await environment.waitForElementVisible('[data-ta-node-title="Revert \\"Merge branch \'testbranch\'\\""]');
+ });
+
+ it('Should be possible to move a branch', async () => {
+ await environment.createBranch('movebranch');
+ await environment.moveRef('movebranch', 'Init');
+ });
+
+ it('Should be possible to cancel creation of an empty commit', async () => {
+ await environment.click('.empty-commit-link');
+ await environment.click('.btn-stg-cancel');
+ await environment.waitForElementVisible('.empty-commit-link');
+ });
+
+ it('Should be possible to create an empty commit', async () => {
+ await environment.click('.empty-commit-link');
+ await environment.click('.commit-btn');
+ await environment.waitForElementVisible('.commit');
+ });
+
+ it('Should be possible to amend an empty commit', async () => {
+ await environment.click('.empty-commit-link');
+ await environment.click('.commit-btn');
+ await environment.waitForElementVisible('.commit');
+ await amendCommit();
+ await environment.waitForElementVisible('.commit');
+ });
+
+ it('Should be possible to cancel amend of an empty commit', async () => {
+ await environment.click('.amend-link');
+ await environment.click('.btn-stg-cancel');
+ await environment.waitForElementVisible('.empty-commit-link');
+ });
+
+ it('Should be possible to click refresh button', () => {
+ return environment.click('button.refresh-button');
+ });
+
+ it('Go to home screen', async () => {
+ await environment.click('.navbar .backlink');
+ await environment.waitForElementVisible('.home');
+ });
+});
diff --git a/clicktests/spec.load-ahead.js b/clicktests/spec.load-ahead.js
new file mode 100644
index 000000000..3809db679
--- /dev/null
+++ b/clicktests/spec.load-ahead.js
@@ -0,0 +1,42 @@
+'use strict';
+const environment = require('./environment')({ serverStartupOptions: ['--numberOfNodesPerLoad=1'] });
+const testRepoPaths = [];
+
+describe('[LOAD-AHEAD]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('Should be possible to create and commit 1', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.commit('commit-1');
+ await environment.createBranch('branch-1');
+ });
+
+ it('Should be possible to create and commit 2', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile.txt`, testRepoPaths[0]);
+ await environment.commit('commit-2');
+ });
+
+ it('Should be possible to create and commit 3', async () => {
+ await environment.click('.branch .dropdown-toggle');
+ await environment.click('[data-ta-clickable="checkoutrefs/heads/branch-1"]');
+ await environment.waitForElementVisible('[data-ta-name="branch-1"].current');
+ });
+
+ it('Create a branch during collapsed mode', () => {
+ return environment.createBranch('new-branch');
+ });
+
+ it('Load ahead', async () => {
+ await environment.click('.load-ahead-button');
+ await environment.waitForElementVisible('[data-ta-clickable="node-clickable-1"]');
+ await environment.waitForElementHidden('.loadAhead');
+ });
+});
diff --git a/clicktests/spec.no-header.js b/clicktests/spec.no-header.js
new file mode 100644
index 000000000..876450c02
--- /dev/null
+++ b/clicktests/spec.no-header.js
@@ -0,0 +1,22 @@
+'use strict';
+const environment = require('./environment')();
+const testRepoPaths = [];
+
+describe('[NO-HEADER]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', async () => {
+ await environment.openUngit(testRepoPaths[0]);
+ await environment.waitForElementVisible('.repository-view');
+ await environment.waitForElementHidden('[data-ta-container="remote-error-popup"]');
+ });
+
+ it('Check for refresh button', async () => {
+ await environment.click('.refresh-button');
+ await environment.waitForElementHidden('[data-ta-container="remote-error-popup"]');
+ });
+});
diff --git a/clicktests/spec.remotes.js b/clicktests/spec.remotes.js
new file mode 100644
index 000000000..ac283af37
--- /dev/null
+++ b/clicktests/spec.remotes.js
@@ -0,0 +1,126 @@
+'use strict';
+const environment = require('./environment')();
+const mkdirp = require('mkdirp');
+const util = require('util');
+const rimraf = util.promisify(require('rimraf'));
+const testRepoPaths = [];
+
+describe('[REMOTES]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: true }, { bare: false, initCommits: 2 }]);
+
+ testRepoPaths.push(`${testRepoPaths[1]}-cloned`); // A directory to test cloning
+ await rimraf(testRepoPaths[2]); // clean clone test dir
+ await mkdirp(testRepoPaths[2]); // create clone test dir
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[1]);
+ });
+
+ it('Should not be possible to push without remote', async () => {
+ await environment.click('.branch[data-ta-name="master"][data-ta-local="true"]');
+ await environment.waitForElementHidden('[data-ta-action="push"]:not([style*="display: none"])');
+ });
+
+ it('Should not be possible to commit & push without remote', async () => {
+ await environment.click('.amend-link');
+ await environment.click('.commit-grp .dropdown-toggle');
+ await environment.waitForElementVisible('.commitnpush.disabled');
+ });
+
+ it('Adding a remote', async () => {
+ await environment.click('.fetchButton .dropdown-toggle');
+ await environment.click('.add-new-remote');
+
+ await environment.insert('.modal #Name', 'myremote');
+ await environment.insert('.modal #Url', testRepoPaths[0]);
+ await environment.click('.modal .modal-footer .btn-primary');
+
+ await environment.click('.fetchButton .dropdown-toggle');
+ await environment.waitForElementVisible('.fetchButton .dropdown-menu [data-ta-clickable="myremote"]');
+ });
+
+ it('Fetch from newly added remote', async () => {
+ await environment.click('.fetchButton .btn-main');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('Remote delete check', async () => {
+ await environment.click('.fetchButton .dropdown-toggle');
+ await environment.click('[data-ta-clickable="myremote-remove"]');
+ await environment.click('.modal-dialog .btn-primary');
+
+ await environment.click('.fetchButton .dropdown-toggle');
+ await environment.waitForElementHidden('[data-ta-clickable="myremote"]');
+ });
+
+ // ----------- CLONING -------------
+ it('navigate to empty folder path', async () => {
+ await environment.goto(`${environment.getRootUrl()}/#/repository?path=${encodeURIComponent(testRepoPaths[2])}`);
+ await environment.waitForElementVisible('.uninited');
+ });
+
+ it('Clone repository should bring you to repo page', async () => {
+ await environment.insert('#cloneFromInput', testRepoPaths[1]);
+ await environment.insert('#cloneToInput', testRepoPaths[2]);
+ await environment.click('.uninited button[type="submit"]');
+ await environment.waitForElementVisible('.repository-view');
+ });
+
+ it('Should be possible to fetch', async () => {
+ await environment.click('.fetchButton .btn-main');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('Should be possible to create and push a branch', async () => {
+ await environment.createBranch('branchinclone');
+ await environment.refAction('branchinclone', true, 'push');
+ await environment.waitForElementVisible('[data-ta-name="origin/branchinclone"]');
+ });
+
+ it('Should be possible to force push a branch', async () => {
+ await environment.moveRef('branchinclone', 'Init Commit 0');
+ await environment.refAction('branchinclone', true, 'push');
+ await environment.waitForElementHidden('[data-ta-action="push"]:not([style*="display: none"])');
+ });
+
+ it('Check for fetching remote branches for the branch list', async () => {
+ await environment.click('.branch .dropdown-toggle');
+ await environment.click('.options input');
+ await environment.wait(1000);
+ try {
+ await environment.page.waitForSelector('li .octicon-globe', { visible: true, timeout: 2000 });
+ } catch (err) {
+ await environment.click('.options input');
+ await environment.waitForElementVisible('li .octicon-globe');
+ }
+ });
+
+ it('checkout remote branches with matching local branch at wrong place', async () => {
+ await environment.moveRef('branchinclone', 'Init Commit 1');
+ await environment.click('.branch .dropdown-toggle');
+ await environment.click('[data-ta-clickable="checkoutrefs/remotes/origin/branchinclone"]');
+ await environment.waitForElementVisible('[data-ta-name="branchinclone"][data-ta-local="true"]');
+ });
+
+ it('Should be possible to commitnpush', async () => {
+ await environment.createTestFile(`${testRepoPaths[2]}/commitnpush.txt`, testRepoPaths[2]);
+ await environment.waitForElementVisible('.files .file .btn-default');
+ await environment.insert('.staging input.form-control', 'Commit & Push');
+ await environment.click('.commit-grp .dropdown-toggle');
+ await environment.click('.commitnpush');
+ await environment.waitForElementVisible('[data-ta-node-title="Commit & Push"]')
+ });
+
+ it('Should be possible to commitnpush with ff', async () => {
+ await environment.click('.amend-link');
+ await environment.insert('.staging input.form-control', 'Commit & Push with ff');
+ await environment.click('.commit-grp .dropdown-toggle');
+ await environment.click('.commitnpush');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementVisible('[data-ta-node-title="Commit & Push with ff"]')
+ });
+});
diff --git a/clicktests/spec.screens.js b/clicktests/spec.screens.js
new file mode 100644
index 000000000..56b260548
--- /dev/null
+++ b/clicktests/spec.screens.js
@@ -0,0 +1,66 @@
+'use strict';
+const environment = require('./environment')();
+const mkdirp = require('mkdirp');
+const util = require('util');
+const rimraf = util.promisify(require('rimraf'));
+const testRepoPaths = [];
+
+describe('[SCREENS]', () => {
+ before('Environment init', () => environment.init());
+
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open home screen', async () => {
+ await environment.goto(environment.getRootUrl());
+ await environment.waitForElementVisible('.home');
+ });
+
+ it('Open path screen', async () => {
+ testRepoPaths.push(await environment.createTempFolder());
+
+ await environment.goto(`${environment.getRootUrl()}/#/repository?path=${encodeURIComponent(testRepoPaths[0])}`);
+ await environment.waitForElementVisible('.uninited');
+ });
+
+ it('Init repository should bring you to repo page', async () => {
+ await environment.click('.uninited button.btn-primary');
+ await environment.waitForElementVisible('.repository-view');
+ });
+
+ it('Clicking logo should bring you to home screen', async () => {
+ await environment.click('.navbar .backlink');
+ await environment.waitForElementVisible('.home');
+ });
+
+ it('Entering an invalid path and create directory in that location', async () => {
+ await environment.insert('.navbar .path-input-form input', `${testRepoPaths[0]}-test0/not/existing`);
+ await environment.press('Enter');
+ await environment.waitForElementVisible('.invalid-path');
+ await environment.click('.invalid-path button');
+ await environment.waitForElementVisible('.uninited button.btn-primary');
+ });
+
+ it('Entering an invalid path should bring you to an error screen', async () => {
+ await environment.insert('.navbar .path-input-form input', '/a/path/that/doesnt/exist');
+ await environment.press('Enter');
+ await environment.waitForElementVisible('.invalid-path');
+ });
+
+ it('Entering a path to a repo should bring you to that repo', async () => {
+ await environment.insert('.navbar .path-input-form input', testRepoPaths[0]);
+ await environment.press('Enter');
+ await environment.waitForElementVisible('.repository-view');
+ });
+
+ // getting odd cross-domain-error.
+ it('Create test directory with ampersand and open it', async () => {
+ const specialRepoPath = `${testRepoPaths[0]}-test1/test & repo`;
+
+ await rimraf(specialRepoPath);
+ await mkdirp(specialRepoPath);
+
+ await environment.goto(`${environment.getRootUrl()}/#/repository?path=${encodeURIComponent(specialRepoPath)}`);
+
+ await environment.waitForElementVisible('.uninited');
+ });
+});
diff --git a/clicktests/spec.stash.js b/clicktests/spec.stash.js
new file mode 100644
index 000000000..dc52a5390
--- /dev/null
+++ b/clicktests/spec.stash.js
@@ -0,0 +1,33 @@
+'use strict';
+const environment = require('./environment')();
+const testRepoPaths = [];
+
+describe('[STASH]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false, initCommits: 1 }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[0]);
+ });
+
+ it('Should be possible to stash a file', async () => {
+ await environment.createTestFile(`${testRepoPaths[0]}/testfile2.txt`, testRepoPaths[0]);
+ await environment.waitForElementVisible('.files .file .btn-default');
+ await environment.click('.stash-all');
+ await environment.click('.stash-toggle');
+ await environment.waitForElementVisible('.stash .list-group-item');
+ });
+
+ it('Should be possible to open stash diff', async () => {
+ await environment.click('.toggle-show-commit-diffs');
+ await environment.waitForElementVisible('.stash .diff-wrapper');
+ });
+
+ it('Should be possible to pop a stash', async () => {
+ await environment.click('.stash .stash-apply');
+ await environment.waitForElementVisible('.files .file .btn-default');
+ });
+});
diff --git a/clicktests/spec.submodules.js b/clicktests/spec.submodules.js
new file mode 100644
index 000000000..d20f39d47
--- /dev/null
+++ b/clicktests/spec.submodules.js
@@ -0,0 +1,39 @@
+'use strict';
+const environment = require('./environment')();
+const testRepoPaths = [];
+
+describe('[SUMBODULES]', () => {
+ before('Environment init', async () => {
+ await environment.init();
+ await environment.createRepos(testRepoPaths, [{ bare: false, initCommits: 1 }, { bare: false }]);
+ });
+ after('Environment stop', () => environment.shutdown());
+
+ it('Open path screen', () => {
+ return environment.openUngit(testRepoPaths[1]);
+ });
+
+ it('Submodule add', async () => {
+ await environment.click('.submodule .dropdown-toggle');
+ await environment.click('.fetchButton .add-submodule');
+
+ await environment.insert('.modal #Path', 'subrepo');
+ await environment.insert('.modal #Url', testRepoPaths[0]);
+ await environment.click('.modal-dialog .btn-primary');
+
+ await environment.click('.submodule .dropdown-toggle');
+ await environment.waitForElementVisible('.fetchButton .dropdown-menu [data-ta-clickable="subrepo"]');
+ });
+
+ it('Submodule update', async () => {
+ await environment.click('.fetchButton .update-submodule');
+ await environment.waitForElementHidden('#nprogress');
+ });
+
+ it('Submodule delete check', async () => {
+ await environment.click('.submodule .dropdown-toggle');
+ await environment.click('[data-ta-clickable="subrepo-remove"]');
+ await environment.click('.modal-dialog .btn-primary');
+ await environment.waitForElementHidden('#nprogress');
+ });
+});
diff --git a/components/stash/stash.html b/components/stash/stash.html
index db946df82..4b44faf0b 100644
--- a/components/stash/stash.html
+++ b/components/stash/stash.html
@@ -10,7 +10,7 @@
-
+
diff --git a/components/stash/stash.less b/components/stash/stash.less
index 24d408b39..9af98f047 100644
--- a/components/stash/stash.less
+++ b/components/stash/stash.less
@@ -2,12 +2,14 @@
z-index: 4;
margin-left: 20px;
margin-right: 20px;
+ margin-bottom: -15px;
background: #55323C;
h4 {
margin-top: 0px;
}
- margin-bottom: -15px;
-
+ .toggle-show-commit-diffs {
+ display: inline-block;
+ }
.diff-wrapper {
margin-top: 5px;
}
diff --git a/nmclicktests/environment.js b/nmclicktests/environment.js
deleted file mode 100644
index df9f8b508..000000000
--- a/nmclicktests/environment.js
+++ /dev/null
@@ -1,351 +0,0 @@
-'use strict';
-const winston = require('winston');
-const child_process = require('child_process');
-const Bluebird = require('bluebird');
-const Nightmare = require('nightmare');
-const net = require('net');
-const request = require('superagent');
-const mkdirp = require("mkdirp");
-const rimraf = Bluebird.promisify(require("rimraf"));
-const portrange = 45032;
-let rootUrl;
-
-module.exports = (config) => new Environment(config);
-
-Nightmare.action('ug', {
- 'log': function(message, done) {
- winston.info(`>>> ${message}`);
- done();
- },
- 'commit': function(commitMessage, done) {
- this.wait('.files .file .btn-default')
- .insert('.staging input.form-control', commitMessage)
- .wait(100)
- .ug.click('.commit-btn')
- .ug.waitForElementNotVisible('.files .file .btn-default')
- .wait(1000)
- .then(done.bind(null, null), done);
- },
- 'commitnpush': function(commitMessage, done) {
- this.wait('.files .file .btn-default')
- .insert('.staging input.form-control', commitMessage)
- .ug.click('.commit-grp .dropdown-toggle')
- .ug.click('.commitnpush')
- .then(done.bind(null, null), done);
- },
- 'amendCommit': function(done) {
- this.ug.click('.amend-link')
- .ug.click('.commit-btn')
- .ug.waitForElementNotVisible('.files .file .btn-default')
- .wait(1000)
- .then(done.bind(null, null), done);
- },
- 'emptyCommit': function(done) {
- this.ug.click('.empty-commit-link')
- .ug.click('.commit-btn')
- .ug.waitForElementNotVisible('.files .file .btn-default')
- .wait(1000)
- .then(done.bind(null, null), done);
- },
- 'checkout': function(branch, done) {
- this.ug.click(`.branch[data-ta-name="${branch}"]`)
- .ug.click('[data-ta-action="checkout"]:not([style*="display: none"]) .dropmask')
- .wait(`.ref.branch[data-ta-name="${branch}"].current`)
- .then(done.bind(null, null), done);
- },
- 'patch': function(commitMessage, done) {
- this.ug.click('.files .file .btn-default')
- .ug.click('.patch')
- .wait('.d2h-diff-tbody input')
- .ug.commit(commitMessage)
- .then(done.bind(null, null), done);
- },
- 'backgroundAction': function(method, url, body, done) {
- let req;
- if (method === 'GET') {
- req = request.get(url).withCredentials().query(body);
- } else if (method === 'POST') {
- req = request.post(url).send(body);
- } else if (method === 'DELETE') {
- req = request.delete(url).send(body);
- }
-
- req.set({'encoding': 'utf8', 'cache-control': 'no-cache', 'Content-Type': 'application/json'});
-
- req.end((err, res) => {
- let data = (res || {}).body
- try { data = JSON.parse(data); } catch(ex) {}
- done(err, data)
- });
- },
- 'createTestFile': function(filename, done) {
- this.ug.backgroundAction('POST', `${rootUrl}/api/testing/createfile`, { file: filename })
- .then(done.bind(null, null), done);
- },
-
- 'changeTestFile': function(filename, done) {
- this.ug.backgroundAction('POST', `${rootUrl}/api/testing/changefile`, { file: filename })
- .then(done.bind(null, null), done);
- },
- 'createTempFolder': function(done) {
- winston.info('Creating temp folder');
- this.ug.backgroundAction('POST', `${rootUrl}/api/testing/createtempdir`, undefined)
- .then(done.bind(null, null), done);
- },
- 'createFolder': function(dir, done) {
- winston.info(`Create folder: ${dir}`);
- this.ug.backgroundAction('POST', `${rootUrl}/api/createdir`, { dir: dir })
- .then(done.bind(null, null), done);
- },
- 'initRepo': function(options, done) {
- (options.path ? rimraf(options.path).then(() => mkdirp(options.path)) : this.ug.createTempFolder())
- .then((res) => {
- options.path = res.path ? res.path : res;
- return this.ug.backgroundAction('POST', `${rootUrl}/api/init`, options)
- }).then(done.bind(null, null), done);
- },
- 'gitCommand': function(options, done) {
- this.ug.backgroundAction('POST', `${rootUrl}/api/testing/git`, options)
- .then(done.bind(null, null), done);
- },
- 'waitForElementNotVisible': function(selector, done) {
- this.wait((selector) => !document.querySelector(selector), selector)
- .then(done.bind(null, null), done);
- },
- '_verifyRefAction': function(action, done) {
- this.visible('.modal-dialog .btn-primary')
- .then((isVisible) => {
- return (isVisible ? this.ug.click('.modal-dialog .btn-primary') : this)
- .ug.waitForElementNotVisible(`[data-ta-action="${action}"]:not([style*="display: none"])`)
- .wait(200)
- }).then(done.bind(null, null), done);
- },
- 'refAction': function(ref, local, action, done) {
- this.ug.click(`.branch[data-ta-name="${ref}"][data-ta-local="${local}"]`)
- .ug.click(`[data-ta-action="${action}"]:not([style*="display: none"]) .dropmask`)
- .then(() => this.ug._verifyRefAction(action))
- .then(done.bind(null, null), done);
- },
- 'moveRef': function(ref, targetNodeCommitTitle, done) {
- this.ug.click(`.branch[data-ta-name="${ref}"]`)
- .ug.click(`[data-ta-node-title="${targetNodeCommitTitle}"] [data-ta-action="move"]:not([style*="display: none"]) .dropmask`)
- .then(() => this.ug._verifyRefAction('move'))
- .then(done.bind(null, null), done);
- },
- '_createRef': function(type, name, done) {
- this.ug.click('.current ~ .new-ref button.showBranchingForm')
- // nightmare insert calls blur... (https://github.com/segmentio/nightmare/blob/b230e85375bb084007a54c6a1bf698d81b5f2feb/lib/actions.js#L347)
- .evaluate(function(selector, value) {
- var element = document.querySelector(selector);
- if (!element) {
- throw new Error(`Element not found ${selector}`);
- }
- element.value = value;
- /* jshint ignore:start */
- element.dispatchEvent(new KeyboardEvent('keydown'));
- /* jshint ignore:end */
- }, '.ref-icons.new-ref.editing input', name)
- .wait(500)
- // nightmare click calls blur... (https://github.com/segmentio/nightmare/blob/b230e85375bb084007a54c6a1bf698d81b5f2feb/lib/actions.js#L107)
- .evaluate(function(selector) {
- var element = document.querySelector(selector);
- if (!element) {
- throw new Error(`Element not found ${selector}`);
- }
- /* jshint ignore:start */
- element.dispatchEvent(new MouseEvent('click'));
- /* jshint ignore:end */
- }, `.new-ref ${type === 'branch' ? '.btn-primary' : '.btn-default'}`)
- // cannot use .ug.click as wait op will defocus and doms will disappear
- .wait(`.ref.${type}[data-ta-name="${name}"]`)
- .wait(300)
- .then(done.bind(null, null), done);
- },
- 'createTag': function(name, done) {
- this.ug._createRef('tag', name).then(done.bind(null, null), done);
- },
- 'createBranch': function(name, done) {
- this.ug._createRef('branch', name).then(done.bind(null, null), done);
- },
- 'click': function(selector, done) {
- this.wait(selector)
- .wait(300)
- .click(selector)
- .wait(300)
- .mouseover('img.headerLogo')
- .wait(300)
- .then(done.bind(null, null), done);
- },
- 'openUngit': function(tempDirPath, done) {
- this.goto(`${rootUrl}/#/repository?path=${encodeURIComponent(tempDirPath)}`)
- .wait('.repository-actions')
- .wait(1000)
- .then(done.bind(null, null), done);
- }
-});
-
-const prependLines = (pre, text) => {
- return text.split('\n').filter((l) => l)
- .map((line) => pre + line)
- .join('\n');
-}
-
-// Environment provides
-class Environment {
- constructor(config) {
- this.nm = Nightmare({ Promise: Bluebird, typeInterval: 500, show: false });
- this.config = config || {};
- this.config.rootPath = (typeof this.config.rootPath === 'string') ? this.config.rootPath : '';
- this.config.serverTimeout = this.config.serverTimeout || 15000;
- this.config.viewWidth = 2000;
- this.config.viewHeight = 2000;
- this.config.showServerOutput = this.config.showServerOutput === undefined ? true : this.config.showServerOutput;
- this.config.serverStartupOptions = this.config.serverStartupOptions || [];
- this.shuttinDown = false;
-
- // init
- this.nm.viewport(this.config.viewWidth, this.config.viewHeight);
- this.nm.on('console', (type, msg1, msg2) => {
- winston.info(`[ui ${type}] ${(new Date()).toISOString()} - ${msg1} ${JSON.stringify(msg2)}`);
-
- if (type === 'error' && !this.shuttinDown) {
- winston.info('ERROR DETECTED!');
- }
- })
- }
-
- getRootUrl() { return rootUrl; }
-
- getPort() {
- const tmpPortrange = portrange + Math.floor((Math.random() * 5000));
-
- return new Bluebird((resolve, reject) => {
- const server = net.createServer();
-
- server.listen(tmpPortrange, (err) => {
- server.once('close', () => {
- this.port = tmpPortrange;
- rootUrl = `http://localhost:${this.port}${this.config.rootPath}`
- resolve();
- });
- server.close();
- });
- server.on('error', (err) => {
- this.getPort().then(resolve);
- });
- });
- }
-
- ensureStarted() {
- return Bluebird.resolve()
- .then(() => {
- if (!this.hasStarted) {
- return Bluebird.resolve()
- .delay(50)
- .then(() => this.ensureStarted());
- }
- });
- }
-
- init() {
- return this.getPort()
- .then(() => this.startServer())
- .then(() => this.ensureStarted())
- .catch((err) => { winston.error(err); throw new Error("Cannot confirm ungit start!!", err); })
- }
-
- createRepos(testRepoPaths, config) {
- return Bluebird.map(config, (conf) => {
- conf.bare = !!conf.bare;
- return this.nm.ug.initRepo(conf)
- .then(() => this.createCommits(conf, conf.initCommits))
- .then(() => conf.path);
- }).then((paths) => {
- if (testRepoPaths) testRepoPaths.push(...paths)
- });
- }
-
- shutdown() {
- this.shuttinDown = true;
- return this.nm.ug.backgroundAction('POST', `${rootUrl}/api/testing/cleanup`, undefined)
- .then(() => {
- if (this.ungitServerProcess) {
- this.ungitServerProcess.kill('SIGINT');
- this.ungitServerProcess = null;
- }
- return this.nm.end();
- });
- }
-
- createCommits(config, limit, x) {
- x = x || 0
- if (!limit || limit < 0 || x === limit) return Bluebird.resolve();
-
- return this.nm.ug.createTestFile(`${config.path}/testy${x}`)
- .then(() => {
- return this.nm.ug.backgroundAction('POST', `${rootUrl}/api/commit`, {
- path: config.path,
- message: `Init Commit ${x}`,
- files: [{ name: `testy${x}` }]
- });
- }).then(() => this.createCommits(config, limit, x + 1))
- }
-
- goto(url) {
- this.nm = this.nm.goto(url);
- return this.nm;
- }
-
- startServer() {
- winston.info('Starting ungit server...', this.config.serverStartupOptions);
-
- this.hasStarted = false;
- const options = ['bin/ungit',
- '--cliconfigonly',
- `--port=${this.port}`,
- `--rootPath=${this.config.rootPath}`,
- '--no-launchBrowser',
- '--dev',
- '--no-bugtracking',
- `--autoShutdownTimeout=${this.config.serverTimeout}`,
- '--logLevel=debug',
- '--maxNAutoRestartOnCrash=0',
- '--no-autoCheckoutOnBranchCreate',
- '--alwaysLoadActiveBranch',
- `--numRefsToShow=${this.config.numRefsToShow || 5}`]
- .concat(this.config.serverStartupOptions);
- const ungitServer = child_process.spawn('node', options);
- ungitServer.stdout.on('data', (stdout) => {
- const stdoutStr = stdout.toString();
- if (this.config.showServerOutput) winston.verbose(prependLines('[server] ', stdoutStr));
-
- if (stdoutStr.indexOf('Ungit server already running') >= 0) {
- winston.info('server-already-running');
- }
-
- if (stdoutStr.indexOf('## Ungit started ##') >= 0) {
- if (this.hasStarted) {
- winston.info('Ungit started twice, probably crashed.');
- } else {
- this.hasStarted = true;
- winston.info('Ungit server started.');
- }
- }
- });
- ungitServer.stderr.on("data", (stderr) => {
- const stderrStr = stderr.toString();
- winston.error(prependLines('[server ERROR] ', stderrStr));
- if (stderrStr.indexOf("EADDRINUSE") > -1) {
- winston.info("retrying with different port");
- ungitServer.kill('SIGINT');
- this.ungitServerProcess = null;
- this.getPort().then(() => this.startServer());
- }
- });
- ungitServer.on('exit', () => winston.info('UNGIT SERVER EXITED'));
-
- this.ungitServerProcess = ungitServer;
-
- return Bluebird.resolve();
- }
-}
diff --git a/nmclicktests/spec.authentication.js b/nmclicktests/spec.authentication.js
deleted file mode 100644
index a179faf57..000000000
--- a/nmclicktests/spec.authentication.js
+++ /dev/null
@@ -1,32 +0,0 @@
-'use strict';
-const testuser = { username: 'testuser', password: 'testpassword' }
-const environment = require('./environment')({
- serverStartupOptions: ['--authentication', `--users.${testuser.username}=${testuser.password}`],
- showServerOutput: true
-});
-
-describe('[AUTHENTICATION]', () => {
- before('Environment init without temp folder', () => environment.init());
- after('Environment stop', () => environment.shutdown());
-
- it('Open home screen should show authentication dialog', () => {
- return environment.goto(environment.getRootUrl())
- .wait('.login');
- });
-
- it('Filling out the authentication with wrong details should result in an error', () => {
- return environment.nm.insert('.login #inputUsername', testuser.username)
- .insert('.login #inputPassword', 'notthepassword')
- .click('.login button')
- .wait('.login .loginError');
- });
-
- it('Filling out the authentication should bring you to the home screen', () => {
- return environment.nm.insert('.login #inputUsername')
- .insert('.login #inputUsername', testuser.username)
- .insert('.login #inputPassword')
- .insert('.login #inputPassword', testuser.password)
- .click('.login button')
- .wait('.container.home');
- });
-});
diff --git a/nmclicktests/spec.bare.js b/nmclicktests/spec.bare.js
deleted file mode 100644
index 2ed3a8f39..000000000
--- a/nmclicktests/spec.bare.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const testRepoPaths = [];
-
-describe('[BARE]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: true }]));
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0]);
- });
-
- it('update branches button without branches', () => {
- return environment.nm.ug.click('.btn-group.branch .btn-main')
- .ug.waitForElementNotVisible('#nprogress');
- });
-});
diff --git a/nmclicktests/spec.branches.js b/nmclicktests/spec.branches.js
deleted file mode 100644
index 1a618911c..000000000
--- a/nmclicktests/spec.branches.js
+++ /dev/null
@@ -1,142 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const testRepoPaths = [];
-
-describe('[BRANCHES]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]));
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0])
- });
-
- it('add a commit', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.commit('commit-1');
- })
-
- // < branch search test >
- it('add branches', () => {
- return environment.nm.ug.createBranch("search-1")
- .ug.createBranch("search-2")
- .ug.createBranch("search-3")
- .ug.createBranch("search-4")
- .wait('[data-ta-name="search-4"]')
- });
-
- it('add tag should make one of the branch disappear', () => {
- return environment.nm.ug.createTag('tag-1')
- .ug.waitForElementNotVisible('[data-ta-name="search-4"]');
- });
-
- // https://github.com/segmentio/nightmare/issues/932
- it.skip('search for the hidden branch', () => {
- return environment.nm.wait(5000) // sleep to avoid `git-directory-changed` event, which refreshes git nodes and closes search box
- .nm.click('.showSearchForm')
- .wait(200)
- .type('input.name', '-4\u0028\u000d')
- .wait('[data-ta-name="search-4"]')
- });
- // < /branch search test>
-
- it('updateBranches button without branches', () => {
- return environment.nm.wait('.btn-group.branch .btn-main')
- .click('.btn-group.branch .btn-main')
- .ug.waitForElementNotVisible('#nprogress');
- });
-
- it('add a branch', () => {
- return environment.nm.ug.createBranch('branch-1');
- });
-
- it('updateBranches button with one branch', () => {
- return environment.nm.ug.click('.btn-group.branch .btn-main')
- .ug.waitForElementNotVisible('#nprogress');
- });
-
- it('add second branch', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile2.txt`)
- .wait(500)
- .ug.commit('commit-2')
- .wait('.commit')
- .ug.createBranch('branch-2')
- .ug.createBranch('branch-3');
- });
-
- it('Check out a branch via selection', () => {
- return environment.nm.ug.click('.branch .dropdown-toggle')
- .ug.click('[data-ta-clickable="checkoutrefs/heads/branch-2"]')
- .ug.waitForElementNotVisible('#nprogress')
- });
-
- it('Delete a branch via selection', () => {
- return environment.nm.wait(1000)
- .ug.click('.branch .dropdown-toggle')
- .ug.click('[data-ta-clickable="refs/heads/branch-3-remove"]')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('#nprogress')
- .wait(500);
- });
-
- it('add a commit', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile2.txt`)
- .ug.commit('commit-3');
- });
-
- it('checkout cherypick base', () => {
- return environment.nm.ug.click('.branch .dropdown-toggle')
- .ug.click('[data-ta-clickable="checkoutrefs/heads/branch-1"]')
- .ug.waitForElementNotVisible('#nprogress')
- });
-
- it('cherrypick fail case', () => {
- return environment.nm.ug.click('[data-ta-clickable="node-clickable-0"]')
- .ug.click('[data-ta-action="cherry-pick"]:not([style*="display: none"]) .dropmask')
- .wait(3000) // on windows clicking on cherry pick which results in conflicts might take some time
- .ug.click('.staging .btn-stg-abort')
- .ug.click('.modal-dialog .btn-primary')
- .wait(500)
- });
-
- it('cherrypick success case', () => {
- return environment.nm.ug.click('[data-ta-clickable="node-clickable-1"]')
- .ug.click('[data-ta-action="cherry-pick"]:not([style*="display: none"]) .dropmask')
- .wait(500)
- .visible('.staging .btn-stg-abort')
- .then((isVisible) => {
- if (isVisible) {
- throw new Error("Cherry pick errored when success was expected.");
- }
- });
- });
-
- // I've spent way too much tracking this issue. but it seems that this is
- // a legitimate bug. We can see that `/log` result is not including newly
- // created `autoCheckout` branch and it seems that it needs to wait. I think
- // it passes within phantomjs due to other activity triggering another refresh
- it('Auto checkout on branch creation.', () => {
- return environment.nm.evaluate(() => { ungit.config.autoCheckoutOnBranchCreate = true; })
- .wait(250)
- .ug.createBranch('autoCheckout')
- .wait(1000)
- .wait('[data-ta-name="autoCheckout"].current');
- });
-
- it('test backward squash from own lineage', () => {
- return environment.nm.ug.click('.ref.branch.current')
- .ug.click('[data-ta-node-title="commit-1"] .squash .dropmask')
- .wait('.staging .files .file')
- .ug.click('.files button.discard')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('.staging .files .file')
- });
-
- it('test forward squash from different lineage', () => {
- return environment.nm.ug.click('.ref.branch.current')
- .ug.click('[data-ta-node-title="commit-3"] .squash .dropmask')
- .wait('.staging .files .file')
- });
-});
diff --git a/nmclicktests/spec.commands.js b/nmclicktests/spec.commands.js
deleted file mode 100644
index 2e1035734..000000000
--- a/nmclicktests/spec.commands.js
+++ /dev/null
@@ -1,70 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const testRepoPaths = [];
-
-const testForBranchMove = (branch, command) => {
- let branchTagLoc;
- return environment.nm.evaluate((branch) => document.querySelector(branch).getBoundingClientRect(), branch)
- .then((oldLoc) => {
- branchTagLoc = oldLoc;
- return environment.nm.ug.gitCommand({ command: command, repo: testRepoPaths[0] })
- .wait((branch, oldLoc) => {
- let newLoc = document.querySelector(branch).getBoundingClientRect();
- return newLoc.top !== oldLoc.top || newLoc.left !== oldLoc.left;
- }, branch, branchTagLoc);
- });
-}
-
-describe('[COMMANDS]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]));
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0]);
- });
-
- it('add a branch-1', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.commit('commit-1')
- .wait('.commit')
- .ug.createBranch('branch-1');
- });
-
- it('add a branch-2', () =>{
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.commit('commit-1')
- .wait('.commit')
- .ug.createBranch('branch-2');
- });
-
- it('test branch create from command line', () => {
- return environment.nm.ug.gitCommand({ command: ["branch", "gitCommandBranch"], repo: testRepoPaths[0] })
- .then(() => environment.nm.wait('[data-ta-name="gitCommandBranch"]'));
- });
-
- it('test branch move from command line', () => {
- return testForBranchMove('[data-ta-name="gitCommandBranch"]', ["branch", "-f", "gitCommandBranch", "branch-1"]);
- });
-
- it('test branch delete from command line', () => {
- return environment.nm.ug.gitCommand({ command: ["branch", "-D", "gitCommandBranch"], repo: testRepoPaths[0] })
- .ug.waitForElementNotVisible('[data-ta-name="gitCommandBranch');
- });
-
- it('test tag create from command line', () => {
- return environment.nm.ug.gitCommand({ command: ["tag", "tag1"], repo: testRepoPaths[0] })
- .wait('[data-ta-name="tag1"]')
- });
-
- it('test tag delete from command line', () => {
- return environment.nm.ug.gitCommand({ command: ["tag", "-d", "tag1"], repo: testRepoPaths[0] })
- .ug.waitForElementNotVisible('[data-ta-name="tag1"]');
- });
-
- it('test reset from command line', () => {
- return testForBranchMove('[data-ta-name="branch-1"]', ["reset", "branch-1"]);
- });
-});
diff --git a/nmclicktests/spec.discard.js b/nmclicktests/spec.discard.js
deleted file mode 100644
index 06dae9067..000000000
--- a/nmclicktests/spec.discard.js
+++ /dev/null
@@ -1,76 +0,0 @@
-'use strict';
-const muteGraceTimeDuration = 3000;
-const createAndDiscard = (env, testRepoPath, dialogButtonToClick) => {
- return env.nm.ug.createTestFile(testRepoPath + '/testfile2.txt')
- .wait('.files .file .btn-default')
- .wait(250)
- .ug.click('.files button.discard')
- .wait(250)
- .then(() => {
- if (dialogButtonToClick === "yes") {
- return env.nm.ug.click('.modal-dialog [data-ta-action="yes"]');
- } else if (dialogButtonToClick === "mute") {
- return env.nm.ug.click('.modal-dialog [data-ta-action="mute"]');
- } else if (dialogButtonToClick === "no") {
- return env.nm.ug.click('.modal-dialog [data-ta-action="no"]');
- } else {
- return env.nm.visible('.modal-dialog [data-ta-action="yes"]')
- .then((isVisible) => { if (isVisible) throw new Error('Should not see yes button'); });
- }
- }).then(() => {
- if (dialogButtonToClick !== 'no') {
- return env.nm.ug.waitForElementNotVisible('.files .file .btn-default');
- } else {
- return env.nm.wait('.files .file .btn-default');
- }
- });
-}
-
-describe('[DISCARD - noWarn]', () => {
- const environment = require('./environment')({ serverStartupOptions: ['--disableDiscardWarning'] });
- const testRepoPaths = [];
-
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]))
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0]);
- });
-
- it('Should be possible to discard a created file without warning message', () => {
- return createAndDiscard(environment, testRepoPaths[0]);
- });
-});
-
-describe('[DISCARD - withWarn]', () => {
- const environment = require('./environment')({ serverStartupOptions: ['--no-disableDiscardWarning', '--disableDiscardMuteTime=' + muteGraceTimeDuration] });
- const testRepoPaths = [];
-
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]))
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0]);
- });
-
- it('Should be possible to select no from discard', () => {
- return createAndDiscard(environment, testRepoPaths[0], 'no');
- });
-
- it('Should be possible to discard a created file', () => {
- return createAndDiscard(environment, testRepoPaths[0], 'yes');
- });
-
- it('Should be possible to discard a created file and disable warn for awhile', () => {
- return createAndDiscard(environment, testRepoPaths[0], 'mute')
- .then(() => createAndDiscard(environment, testRepoPaths[0]))
- .delay(2000)
- .then(() => createAndDiscard(environment, testRepoPaths[0], 'yes'));
- });
-});
diff --git a/nmclicktests/spec.generic.js b/nmclicktests/spec.generic.js
deleted file mode 100644
index f2f49de00..000000000
--- a/nmclicktests/spec.generic.js
+++ /dev/null
@@ -1,205 +0,0 @@
-'use strict';
-const environment = require('./environment')({ serverStartupOptions: ['--no-disableDiscardWarning'], rootPath: '/deep/root/path/to/app' });
-const Bluebird = require('bluebird');
-const mkdirp = require("mkdirp");
-const rimraf = Bluebird.promisify(require("rimraf"));
-const testRepoPaths = [];
-
-describe('[GENERIC]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]))
- // create a sub dir and change working dir to sub dir to prove functionality within subdir
- .then(() => testRepoPaths.push(`${testRepoPaths[0]}/asubdir`))
- .then(() => rimraf(testRepoPaths[1]))
- .then(() => mkdirp(testRepoPaths[1]));
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open repo screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[1]);
- });
-
- it('Check for refresh button', () => {
- return environment.nm.wait('.refresh-button')
- .ug.click('.refresh-button');
- });
-
- it('Should be possible to create and commit a file', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.commit('Init')
- .wait('.commit');
- });
-
- it('Should be possible to amend a file', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.amendCommit()
- .wait('.commit');
- });
-
- it('Should be possible to cancel amend a file', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile2.txt`)
- .ug.amendCommit()
- .wait('.btn-stg-cancel');
- });
-
- it('Should be able to add a new file to .gitignore', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/addMeToIgnore.txt`)
- .wait('.files .file .btn-default')
- .ug.click('.files button.ignore')
- .ug.click('.files button.ignore')
- .ug.waitForElementNotVisible('.files .file .btn-default');
- });
-
- it('Test showing commit diff between two commits', () => {
- return environment.nm.wait('[data-ta-clickable="node-clickable-0"]')
- .ug.click('[data-ta-clickable="node-clickable-0"]')
- .wait('.diff-wrapper')
- .ug.click('.commit-diff-filename')
- .wait('.commit-line-diffs');
- });
-
- it('Test showing commit side by side diff between two commits', () => {
- return environment.nm.ug.click('.commit-sideBySideDiff')
- .wait('.commit-line-diffs');
- });
-
- it('Test wordwrap', () => {
- return environment.nm.ug.click('.commit-wordwrap')
- .wait('.word-wrap');
- });
-
- it('Test wordwrap', () => {
- return environment.nm.ug.click('.commit-whitespace')
- .wait('.commit-line-diffs')
- .ug.click('[data-ta-clickable="node-clickable-0"]');
- });
-
- it('Should be possible to discard a created file and ensure patching is not available for new file', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile2.txt`)
- .wait('.files .file .btn-default')
- .ug.click('.files button')
- .wait('.files .file .btn-default')
- .ug.click('.files button')
- .ug.waitForElementNotVisible('[data-ta-container="patch-file"]')
- .ug.click('.files button.discard')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('.files .file .btn-default')
- });
-
- it('Should be possible to create a branch', () => {
- return environment.nm.ug.createBranch('testbranch');
- });
-
- it('Should be possible to create and destroy a branch', () => {
- return environment.nm.ug.createBranch('willbedeleted')
- .ug.click('.branch[data-ta-name="willbedeleted"]')
- .ug.click('[data-ta-action="delete"]:not([style*="display: none"]) .dropmask')
- .wait('[data-ta-container="yes-no-dialog"]')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('.branch[data-ta-name="willbedeleted"]');
- });
-
- it('Should be possible to create and destroy a tag', () => {
- return environment.nm.ug.createTag('tagwillbedeleted')
- .ug.click('.graph .ref.tag[data-ta-name="tagwillbedeleted"]')
- .ug.click('[data-ta-action="delete"]:not([style*="display: none"]) .dropmask')
- .wait('[data-ta-container="yes-no-dialog"]')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('.graph .ref.tag[data-ta-name="tagwillbedeleted"]');
- });
-
- it('Commit changes to a file', () => {
- return environment.nm.ug.changeTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .wait('.files .file .btn-default')
- .insert('.staging input.form-control', 'My commit message')
- .click('.commit-btn')
- .ug.waitForElementNotVisible('.files .file .btn-default');
- });
-
- it('Show stats for changed file and discard it', () => {
- return environment.nm.ug.changeTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .wait('.files .file .additions')
- .wait('.files .file .deletions')
- .ug.click('.files button.discard')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('.files .file .btn-default');
- });
-
- it.skip('Should be possible to patch a file', () => {
- return environment.nm.ug.changeTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .patch('patch')
- .waitForElementVisible('.commit');
- });
-
- it('Checkout a branch', () => {
- return environment.nm.ug.checkout('testbranch');
- });
-
- it('Create another commit', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testy2.txt`)
- .ug.commit('Branch commit');
- });
-
- it('Rebase', () => {
- return environment.nm.ug.refAction('testbranch', true, 'rebase');
- });
-
- it('Checkout master again', () => {
- return environment.nm.ug.checkout('master');
- });
-
- it('Create yet another commit', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testy3.txt`)
- .ug.commit('Branch commit');
- });
-
- it('Merge', () => {
- return environment.nm.ug.refAction('testbranch', true, 'merge');
- });
-
- it('Revert merge', () => {
- return environment.nm.ug.click('[data-ta-clickable="node-clickable-0"]')
- .wait('[data-ta-action="revert"]')
- .ug.click('[data-ta-action="revert"]')
- .ug.waitForElementNotVisible('.crash');
- });
-
- it('Should be possible to move a branch', () => {
- return environment.nm.ug.createBranch('movebranch')
- .ug.moveRef('movebranch', 'Init');
- });
-
- it('Should be possible to cancel creation of an empty commit', () => {
- return environment.nm.ug.emptyCommit()
- .ug.click('.btn-stg-cancel')
- .wait('.empty-commit-link');
- });
-
- it('Should be possible to create an empty commit', () => {
- return environment.nm.ug.emptyCommit()
- .wait('.commit');
- });
-
- it('Should be possible to amend an empty commit', () => {
- return environment.nm.ug.emptyCommit()
- .wait('.commit')
- .ug.amendCommit()
- .wait('.commit');
- });
-
- it('Should be possible to cancel amend of an empty commit', () => {
- return environment.nm.ug.amendCommit()
- .ug.click('.btn-stg-cancel')
- .wait('.empty-commit-link');
- });
-
- it('Should be possible to click refresh button', () => {
- return environment.nm.ug.click('button.refresh-button');
- });
-
- it('Go to home screen', () => {
- return environment.nm.ug.click('.navbar .backlink')
- .wait('.home');
- });
-});
diff --git a/nmclicktests/spec.load-ahead.js b/nmclicktests/spec.load-ahead.js
deleted file mode 100644
index 7b08f910c..000000000
--- a/nmclicktests/spec.load-ahead.js
+++ /dev/null
@@ -1,44 +0,0 @@
-'use strict';
-const environment = require('./environment')({ serverStartupOptions: ['--numberOfNodesPerLoad=1'] });
-const testRepoPaths = [];
-
-describe('[LOAD-AHEAD]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]));
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0]);
- });
-
- it('Should be possible to create and commit 1', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.commit('commit-1')
- .wait('.commit')
- .ug.createBranch('branch-1');
- });
-
- it('Should be possible to create and commit 2', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile.txt`)
- .ug.commit('commit-2')
- .wait('.commit');
- });
-
- it('Should be possible to create and commit 3', () => {
- return environment.nm.ug.click('.branch .dropdown-toggle')
- .ug.click('[data-ta-clickable="checkoutrefs/heads/branch-1"]')
- .ug.waitForElementNotVisible('#nprogress');
- });
-
- it('Create a branch during collapsed mode', () => {
- return environment.nm.ug.createBranch('new-branch');
- });
-
- it('Load ahead', () => {
- return environment.nm.ug.click('.load-ahead-button')
- .wait('[data-ta-clickable="node-clickable-1"]')
- .ug.waitForElementNotVisible('.loadAhead')
- });
-});
diff --git a/nmclicktests/spec.no-header.js b/nmclicktests/spec.no-header.js
deleted file mode 100644
index 20c3838a7..000000000
--- a/nmclicktests/spec.no-header.js
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const testRepoPaths = [];
-
-describe('[NO-HEADER]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false }]));
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0])
- .wait('.repository-view')
- .exists('[data-ta-container="remote-error-popup"]')
- .then((isVisible) => { if (isVisible) throw new Error('Should not find remote error popup'); });
- });
-
- it('Check for refresh button', () => {
- return environment.nm.wait('.refresh-button')
- .click('.refresh-button')
- .wait(2000)
- .exists('[data-ta-container="remote-error-popup"]')
- .then((isVisible) => { if (isVisible) throw new Error('Should not find remote error popup'); });
- });
-});
diff --git a/nmclicktests/spec.remotes.js b/nmclicktests/spec.remotes.js
deleted file mode 100644
index c23d40083..000000000
--- a/nmclicktests/spec.remotes.js
+++ /dev/null
@@ -1,128 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const Bluebird = require('bluebird');
-const mkdirp = require('mkdirp');
-const rimraf = Bluebird.promisify(require('rimraf'));
-const testRepoPaths = [];
-
-describe('[REMOTES]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: true }, { bare: false, initCommits: 2 }]))
- .then(() => testRepoPaths.push(`${testRepoPaths[1]}-cloned`)) // A directory to test cloning
- .then(() => rimraf(testRepoPaths[2])) // clean clone test dir
- .then(() => mkdirp(testRepoPaths[2])); // create clone test dir
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[1]);
- });
-
- it('Should not be possible to push without remote', () => {
- return environment.nm.ug.click('.branch[data-ta-name="master"][data-ta-local="true"]')
- .ug.waitForElementNotVisible('[data-ta-action="push"]:not([style*="display: none"])');
- });
-
- it('Should not be possible to commit & push without remote', () => {
- return environment.nm.ug.click('.amend-link')
- .ug.click('.commit-grp .dropdown-toggle')
- .wait('.commitnpush.disabled');
- });
-
- it('Adding a remote', () => {
- return environment.nm.ug.click('.fetchButton .dropdown-toggle')
- .ug.click('.add-new-remote')
- .wait('.modal')
- .insert('.modal #Name', 'myremote')
- .insert('.modal #Url', testRepoPaths[0])
- .click('.modal .modal-footer .btn-primary')
- .wait(500)
- .click('.fetchButton .dropdown-toggle')
- .wait('.fetchButton .dropdown-menu [data-ta-clickable="myremote"]');
- });
-
- it('Fetch from newly added remote', () => {
- return environment.nm.click('.fetchButton .btn-main')
- .wait(500)
- .ug.waitForElementNotVisible('#nprogress');
- });
-
- it('Remote delete check', () => {
- return environment.nm.click('.fetchButton .dropdown-toggle')
- .ug.click('[data-ta-clickable="myremote-remove"]')
- .ug.click('.modal-dialog .btn-primary')
- .ug.waitForElementNotVisible('#nprogress')
- .ug.click('.fetchButton .dropdown-toggle')
- .exists('[data-ta-clickable="myremote"]')
- .then((isVisible) => { if (isVisible) throw new Error('Remote exists after delete'); });
- });
-
- // ----------- CLONING -------------
- it('navigate to empty folder path', () => {
- return environment.nm.goto(`${environment.getRootUrl()}/#/repository?path=${encodeURIComponent(testRepoPaths[2])}`)
- .wait('.uninited');
- });
-
- it('Clone repository should bring you to repo page', () => {
- return environment.nm.insert('#cloneFromInput', testRepoPaths[1])
- .insert('#cloneToInput', testRepoPaths[2])
- .ug.click('.uninited button[type="submit"]')
- .wait('.repository-view')
- .exists('[data-ta-container="remote-error-popup"]')
- .then((isVisible) => { if (isVisible) throw new Error('Should not find remote error popup'); });
- });
-
- it('Should be possible to fetch', () => {
- return environment.nm.click('.fetchButton .btn-main')
- .wait('#nprogress')
- .ug.waitForElementNotVisible('#nprogress');
- });
-
- it('Should be possible to create and push a branch', () => {
- return environment.nm.ug.createBranch('branchinclone')
- .ug.refAction('branchinclone', true, 'push')
- .wait('[data-ta-name="origin/branchinclone"]');
- });
-
- it('Should be possible to force push a branch', () => {
- return environment.nm.ug.moveRef('branchinclone', 'Init Commit 0')
- .ug.refAction('branchinclone', true, 'push')
- .ug.waitForElementNotVisible('[data-ta-action="push"]:not([style*="display: none"])');
- });
-
- it('Check for fetching remote branches for the branch list', () => {
- return environment.nm.ug.click('.branch .dropdown-toggle')
- .ug.click('.options input')
- .wait(200)
- .visible('li .octicon-globe')
- .then((isVisble) => {
- if (!isVisble) {
- return environment.nm.ug.click('.options input')
- .wait('li .octicon-globe');
- }
- });
- });
-
- it('checkout remote branches with matching local branch at wrong place', () => {
- return environment.nm.ug.moveRef('branchinclone', 'Init Commit 1')
- .ug.click('.branch .dropdown-toggle')
- .ug.click('[data-ta-clickable="checkoutrefs/remotes/origin/branchinclone"]')
- .wait(200)
- .wait('[data-ta-name="branchinclone"][data-ta-local="true"]');
- });
-
- it('Should be possible to commitnpush', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[2]}/commitnpush.txt`)
- .ug.commitnpush('Commit & Push')
- .wait('.nux');
- });
-
- it('Should be possible to commitnpush with ff', () => {
- return environment.nm.ug.click('.amend-link')
- .ug.click('.commit-grp .dropdown-toggle')
- .ug.click('.commitnpush')
- .ug.click('.modal-dialog .btn-primary')
- .wait('.nux');
- });
-});
diff --git a/nmclicktests/spec.screens.js b/nmclicktests/spec.screens.js
deleted file mode 100644
index a2aa5f18d..000000000
--- a/nmclicktests/spec.screens.js
+++ /dev/null
@@ -1,72 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const Bluebird = require('bluebird');
-const mkdirp = require("mkdirp");
-const rimraf = Bluebird.promisify(require("rimraf"));
-const testRepoPaths = [];
-
-describe('[SCREENS]', () => {
- before('Environment init', () => environment.init());
-
- after('Environment stop', () => environment.shutdown());
-
- it('Open home screen', () => {
- return environment.nm.goto(environment.getRootUrl())
- .wait('.home');
- });
-
- it('Open path screen', () => {
- return environment.nm.ug.createTempFolder().then(res => {
- testRepoPaths.push(res.path ? res.path : res)
- return environment.nm.goto(`${environment.getRootUrl()}/#/repository?path=${encodeURIComponent(testRepoPaths[0])}`)
- .wait('.uninited');
- });
- });
-
- it('Init repository should bring you to repo page', () => {
- return environment.nm.ug.click('.uninited button.btn-primary')
- .wait('.repository-view')
- .exists('[data-ta-container="remote-error-popup"]')
- .then((isVisible) => { if (isVisible) throw new Error('Should not find remote error popup'); });
- });
-
- it('Clicking logo should bring you to home screen', () => {
- return environment.nm.ug.click('.navbar .backlink')
- .wait('.home')
- });
-
- it('Entering an invalid path and create directory in that location', () => {
- return environment.nm.insert('.navbar .path-input-form input')
- .insert('.navbar .path-input-form input', `${testRepoPaths[0]}-test0/not/existing`)
- .type('.navbar .path-input-form input', '\u000d')
- .wait('.invalid-path')
- .ug.click('.invalid-path button')
- .wait('.uninited button.btn-primary');
- });
-
- it('Entering an invalid path should bring you to an error screen', () => {
- return environment.nm.insert('.navbar .path-input-form input')
- .insert('.navbar .path-input-form input', '/a/path/that/doesnt/exist')
- .type('.navbar .path-input-form input', '\u000d')
- .wait('.invalid-path');
- });
-
- it('Entering a path to a repo should bring you to that repo', () => {
- return environment.nm.insert('.navbar .path-input-form input')
- .insert('.navbar .path-input-form input', testRepoPaths[0])
- .type('.navbar .path-input-form input', '\u000d')
- .wait('.repository-view');
- });
-
- // getting odd cross-domain-error.
- it('Create test directory with ampersand and open it', () => {
- var specialRepoPath = `${testRepoPaths[0]}-test1/test & repo`;
- return rimraf(specialRepoPath)
- .then(() => mkdirp(specialRepoPath))
- .then(() => {
- return environment.nm.wait(2000)
- .goto(`${environment.getRootUrl()}/#/repository?path=${encodeURIComponent(specialRepoPath)}`)
- .wait('.uninited')
- });
- });
-});
diff --git a/nmclicktests/spec.stash.js b/nmclicktests/spec.stash.js
deleted file mode 100644
index d7f2a2d88..000000000
--- a/nmclicktests/spec.stash.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const testRepoPaths = [];
-
-describe('[STASH]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false, initCommits: 1 }]))
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[0]);
- });
-
- it('Should be possible to stash a file', () => {
- return environment.nm.ug.createTestFile(`${testRepoPaths[0]}/testfile2.txt`)
- .wait('.files .file .btn-default')
- .ug.click('.stash-all')
- .visible('.stash-toggle')
- .then((isVisible) => {
- // if stash is currently collapsed show it. (storage['showStash'] might already be 'true')
- return (isVisible ? environment.nm.click('.stash-toggle') : environment.nm)
- .wait('.stash .list-group-item')
- });
- });
-
- it('Should be possible to open stash diff', () => {
- return environment.nm.click('.toggle-show-commit-diffs')
- .wait('.stash .diff-wrapper')
- });
-
- it('Should be possible to pop a stash', () => {
- return environment.nm.click('.stash .stash-apply')
- .wait('.files .file .btn-default')
- });
-});
diff --git a/nmclicktests/spec.submodules.js b/nmclicktests/spec.submodules.js
deleted file mode 100644
index 3ac3b17a8..000000000
--- a/nmclicktests/spec.submodules.js
+++ /dev/null
@@ -1,42 +0,0 @@
-'use strict';
-const environment = require('./environment')();
-const testRepoPaths = [];
-
-describe('[SUMBODULES]', () => {
- before('Environment init', () => {
- return environment.init()
- .then(() => environment.createRepos(testRepoPaths, [{ bare: false, initCommits: 1 }, { bare: false }]))
- });
- after('Environment stop', () => environment.shutdown());
-
- it('Open path screen', () => {
- return environment.nm.ug.openUngit(testRepoPaths[1]);
- });
-
- it('Submodule add', () => {
- return environment.nm.ug.click('.submodule .dropdown-toggle')
- .ug.click('.fetchButton .add-submodule')
- .wait('.modal')
- .insert('.modal #Path', 'subrepo')
- .insert('.modal #Url', testRepoPaths[0])
- .click('.modal .modal-footer .btn-primary')
- .wait(500)
- .click('.submodule .dropdown-toggle')
- .wait('.fetchButton .dropdown-menu [data-ta-clickable="subrepo"]');
- });
-
- it('Submodule update', () => {
- return environment.nm.ug.click('.fetchButton .update-submodule')
- .wait(500)
- .ug.waitForElementNotVisible('#nprogress');
- });
-
- it('Submodule delete check', () => {
- return environment.nm.click('.submodule .dropdown-toggle')
- .ug.click('[data-ta-clickable="subrepo-remove"]')
- .wait('[data-ta-container="yes-no-dialog"]')
- .ug.click('.modal-dialog .btn-primary')
- .wait(500)
- .ug.waitForElementNotVisible('#nprogress')
- });
-});
diff --git a/package-lock.json b/package-lock.json
index 69a270e29..8dccb3d6d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -83,6 +83,12 @@
"@types/node": "*"
}
},
+ "@types/mime-types": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz",
+ "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=",
+ "dev": true
+ },
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@@ -97,6 +103,16 @@
"dev": true,
"optional": true
},
+ "@types/yauzl": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
+ "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"JSONStream": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
@@ -149,11 +165,18 @@
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
+ "agent-base": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+ "dev": true
+ },
"ajv": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
"integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
"dev": true,
+ "optional": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -393,6 +416,7 @@
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dev": true,
+ "optional": true,
"requires": {
"safer-buffer": "~2.1.0"
}
@@ -447,7 +471,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"async": {
"version": "2.6.3",
@@ -478,13 +503,15 @@
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"aws4": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"backo2": {
"version": "1.0.2",
@@ -517,6 +544,7 @@
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
+ "optional": true,
"requires": {
"tweetnacl": "^0.14.3"
}
@@ -1035,7 +1063,8 @@
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"chalk": {
"version": "2.4.2",
@@ -1089,6 +1118,12 @@
}
}
},
+ "chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "dev": true
+ },
"chromium-pickle-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
@@ -1138,12 +1173,6 @@
"mimic-response": "^1.0.0"
}
},
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
- },
"coffeescript": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
@@ -1586,6 +1615,7 @@
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
+ "optional": true,
"requires": {
"assert-plus": "^1.0.0"
}
@@ -1633,15 +1663,6 @@
"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
"dev": true
},
- "deep-defaults": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/deep-defaults/-/deep-defaults-1.0.5.tgz",
- "integrity": "sha512-5ev/sNkiHTmeTqbDJEDgdQa/Ub0eOMQNix9l+dLLGbwOos7/in5HdvHXI014wqxsET4YeJG9Eq4qj0PJRL8rSw==",
- "dev": true,
- "requires": {
- "lodash": "^4.17.5"
- }
- },
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -1653,23 +1674,6 @@
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
- "defaults": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
- "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
- "dev": true,
- "requires": {
- "clone": "^1.0.2"
- },
- "dependencies": {
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- }
- }
- },
"defer-to-connect": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
@@ -1885,6 +1889,7 @@
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
+ "optional": true,
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
@@ -1914,81 +1919,6 @@
}
}
},
- "electron-download": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
- "integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=",
- "dev": true,
- "requires": {
- "debug": "^2.2.0",
- "fs-extra": "^0.30.0",
- "home-path": "^1.0.1",
- "minimist": "^1.2.0",
- "nugget": "^2.0.0",
- "path-exists": "^2.1.0",
- "rc": "^1.1.2",
- "semver": "^5.3.0",
- "sumchecker": "^1.2.0"
- },
- "dependencies": {
- "fs-extra": {
- "version": "0.30.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
- "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^2.1.0",
- "klaw": "^1.0.0",
- "path-is-absolute": "^1.0.0",
- "rimraf": "^2.2.8"
- }
- },
- "jsonfile": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
- "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- },
- "path-exists": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
- "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
- "dev": true,
- "requires": {
- "pinkie-promise": "^2.0.0"
- }
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
- },
- "sumchecker": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz",
- "integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=",
- "dev": true,
- "requires": {
- "debug": "^2.2.0",
- "es6-promise": "^4.0.5"
- }
- }
- }
- },
"electron-notarize": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-0.2.1.tgz",
@@ -2223,23 +2153,6 @@
"has-binary2": "~1.0.2"
}
},
- "enqueue": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/enqueue/-/enqueue-1.0.2.tgz",
- "integrity": "sha1-kBTpvOVw7pPKlubI5jrVTBkra8g=",
- "dev": true,
- "requires": {
- "sliced": "0.0.5"
- },
- "dependencies": {
- "sliced": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz",
- "integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8=",
- "dev": true
- }
- }
- },
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
@@ -2330,12 +2243,6 @@
"dev": true,
"optional": true
},
- "es6-promise": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
- "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
- "dev": true
- },
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -2538,19 +2445,22 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"fast-deep-equal": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"fast-levenshtein": {
"version": "2.0.6",
@@ -2707,7 +2617,8 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"form-data": {
"version": "3.0.0",
@@ -2771,12 +2682,6 @@
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
- "function-source": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/function-source/-/function-source-0.1.0.tgz",
- "integrity": "sha1-2RBL8+RniLVUaMAr8bL6vPj8Ga8=",
- "dev": true
- },
"galactus": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/galactus/-/galactus-0.2.1.tgz",
@@ -2888,6 +2793,7 @@
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
+ "optional": true,
"requires": {
"assert-plus": "^1.0.0"
}
@@ -3496,13 +3402,15 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"har-validator": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"dev": true,
+ "optional": true,
"requires": {
"ajv": "^6.5.5",
"har-schema": "^2.0.0"
@@ -3641,12 +3549,6 @@
}
}
},
- "home-path": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.7.tgz",
- "integrity": "sha512-tM1pVa+u3ZqQwIkXcWfhUlY3HWS3TsnKsfi2OHHvnhkX52s9etyktPyy1rQotkr0euWimChDq+QkQuDe8ngUlQ==",
- "dev": true
- },
"hooker": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
@@ -3748,6 +3650,7 @@
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
+ "optional": true,
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
@@ -3760,6 +3663,33 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true
},
+ "https-proxy-agent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+ "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "5",
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -3953,7 +3883,8 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"is-utf8": {
"version": "0.2.1",
@@ -3990,7 +3921,8 @@
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"istanbul": {
"version": "0.4.5",
@@ -4110,13 +4042,8 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
- "dev": true
- },
- "jsesc": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
- "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"jshint": {
"version": "2.10.3",
@@ -4160,13 +4087,15 @@
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"json-stable-stringify": {
"version": "0.0.1",
@@ -4181,7 +4110,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"jsonfile": {
"version": "4.0.0",
@@ -4209,6 +4139,7 @@
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
+ "optional": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
@@ -4227,12 +4158,6 @@
"resolved": "https://registry.npmjs.org/just-detect-adblock/-/just-detect-adblock-1.0.0.tgz",
"integrity": "sha1-e/hmDPFVcf5887ScIi5HFuFgWgw="
},
- "keypress": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz",
- "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=",
- "dev": true
- },
"keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@@ -4241,15 +4166,6 @@
"json-buffer": "3.0.0"
}
},
- "klaw": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
- "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.9"
- }
- },
"knockout": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/knockout/-/knockout-3.5.1.tgz",
@@ -4703,35 +4619,15 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
- "minstache": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minstache/-/minstache-1.2.0.tgz",
- "integrity": "sha1-/xzEA6woRPaNvxjGYhKb5+sO/EE=",
- "dev": true,
- "requires": {
- "commander": "1.0.4"
- },
- "dependencies": {
- "commander": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/commander/-/commander-1.0.4.tgz",
- "integrity": "sha1-Xt6xruI8T7VBprcNaSq+8ZZpotM=",
- "dev": true,
- "requires": {
- "keypress": "0.1.x"
- }
- }
- }
- },
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
},
"mkdirp-classic": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
- "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz",
+ "integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g==",
"dev": true
},
"mocha": {
@@ -5023,15 +4919,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
- "multiline": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/multiline/-/multiline-1.0.2.tgz",
- "integrity": "sha1-abHyX/B00oKJBPJE3dBrfZbvbJM=",
- "dev": true,
- "requires": {
- "strip-indent": "^1.0.0"
- }
- },
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@@ -5043,65 +4930,6 @@
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
- "nightmare": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/nightmare/-/nightmare-3.0.2.tgz",
- "integrity": "sha512-z6Sr7k71pFcNHFH0orejum9xMzrsdU1lcxlbvNGRsKgDltmu4r52sK5opDnoqfyWS+w9SNthj/4Bbt5zNofzhw==",
- "dev": true,
- "requires": {
- "debug": "^2.2.0",
- "deep-defaults": "^1.0.3",
- "defaults": "^1.0.2",
- "electron": "^2.0.18",
- "enqueue": "^1.0.2",
- "function-source": "^0.1.0",
- "jsesc": "^0.5.0",
- "minstache": "^1.2.0",
- "mkdirp": "^0.5.1",
- "multiline": "^1.0.2",
- "once": "^1.3.3",
- "rimraf": "^2.4.3",
- "sliced": "1.0.1",
- "split2": "^2.0.1"
- },
- "dependencies": {
- "@types/node": {
- "version": "8.10.59",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz",
- "integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==",
- "dev": true
- },
- "electron": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/electron/-/electron-2.0.18.tgz",
- "integrity": "sha512-PQRHtFvLxHdJzMMIwTddUtkS+Te/fZIs+PHO+zPmTUTBE76V3Od3WRGzMQwiJHxN679licmCKhJpMyxZfDEVWQ==",
- "dev": true,
- "requires": {
- "@types/node": "^8.0.24",
- "electron-download": "^3.0.1",
- "extract-zip": "^1.0.3"
- }
- },
- "mkdirp": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
- "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
"node-cache": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.0.tgz",
@@ -5186,44 +5014,12 @@
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
"integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
},
- "nugget": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
- "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=",
- "dev": true,
- "requires": {
- "debug": "^2.1.3",
- "minimist": "^1.1.0",
- "pretty-bytes": "^1.0.2",
- "progress-stream": "^1.1.0",
- "request": "^2.45.0",
- "single-line-log": "^1.1.2",
- "throttleit": "0.0.2"
- },
- "dependencies": {
- "pretty-bytes": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
- "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
- "dev": true,
- "requires": {
- "get-stdin": "^4.0.1",
- "meow": "^3.1.0"
- }
- }
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
- },
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -5560,7 +5356,8 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"picomatch": {
"version": "2.2.2",
@@ -5638,67 +5435,6 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
- "progress-stream": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz",
- "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=",
- "dev": true,
- "requires": {
- "speedometer": "~0.1.2",
- "through2": "~0.2.3"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- },
- "object-keys": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
- "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
- "dev": true
- },
- "readable-stream": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
- "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
- },
- "through2": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
- "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
- "dev": true,
- "requires": {
- "readable-stream": "~1.1.9",
- "xtend": "~2.1.1"
- }
- },
- "xtend": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
- "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
- "dev": true,
- "requires": {
- "object-keys": "~0.4.0"
- }
- }
- }
- },
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
@@ -5725,6 +5461,12 @@
"ipaddr.js": "1.9.1"
}
},
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
@@ -5741,7 +5483,8 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"public-encrypt": {
"version": "4.0.3",
@@ -5780,6 +5523,70 @@
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
},
+ "puppeteer": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-3.0.3.tgz",
+ "integrity": "sha512-sWtx9XezIwXdXHNelvnyPEmMjXXiCAuUulEONZFqRO3l+w0vP7dNcGDUIf2HLr4HLLi6r9hcUuO62s/W6rkD/w==",
+ "dev": true,
+ "requires": {
+ "@types/mime-types": "^2.1.0",
+ "debug": "^4.1.0",
+ "extract-zip": "^2.0.0",
+ "https-proxy-agent": "^4.0.0",
+ "mime": "^2.0.3",
+ "mime-types": "^2.1.25",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^3.0.2",
+ "tar-fs": "^2.0.0",
+ "unbzip2-stream": "^1.3.3",
+ "ws": "^7.2.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "extract-zip": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz",
+ "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==",
+ "dev": true,
+ "requires": {
+ "@types/yauzl": "^2.9.1",
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ }
+ },
+ "get-stream": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
+ "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "mime": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz",
+ "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
@@ -6058,6 +5865,7 @@
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"dev": true,
+ "optional": true,
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@@ -6086,6 +5894,7 @@
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
+ "optional": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
@@ -6096,7 +5905,8 @@
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -6321,58 +6131,6 @@
"is-arrayish": "^0.3.1"
}
},
- "single-line-log": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz",
- "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=",
- "dev": true,
- "requires": {
- "string-width": "^1.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
- }
- },
- "sliced": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
- "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=",
- "dev": true
- },
"snapsvg": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/snapsvg/-/snapsvg-0.5.1.tgz",
@@ -6538,21 +6296,6 @@
"integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
"dev": true
},
- "speedometer": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz",
- "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=",
- "dev": true
- },
- "split2": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
- "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
- "dev": true,
- "requires": {
- "through2": "^2.0.2"
- }
- },
"sprintf-js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
@@ -6564,6 +6307,7 @@
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dev": true,
+ "optional": true,
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
@@ -7032,6 +6776,52 @@
"acorn-node": "^1.2.0"
}
},
+ "tar-fs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
+ "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
+ "dev": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.0.0"
+ },
+ "dependencies": {
+ "bl": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
+ "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ }
+ }
+ },
+ "tar-stream": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz",
+ "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==",
+ "dev": true,
+ "requires": {
+ "bl": "^4.0.1",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ }
+ }
+ }
+ },
"tar-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
@@ -7102,12 +6892,6 @@
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
- "throttleit": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz",
- "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=",
- "dev": true
- },
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -7261,6 +7045,7 @@
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"dev": true,
+ "optional": true,
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
@@ -7270,7 +7055,8 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -7318,6 +7104,7 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.0.1"
}
@@ -7326,7 +7113,8 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"type-check": {
"version": "0.3.2",
@@ -7393,6 +7181,16 @@
"integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==",
"dev": true
},
+ "unbzip2-stream": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.2.tgz",
+ "integrity": "sha512-pZMVAofMrrHX6Ik39hCk470kulCbmZ2SWfQLPmTWqfJV/oUm0gn1CblvHdUu4+54Je6Jq34x8kY6XjTy6dMkOg==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ }
+ },
"undeclared-identifiers": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz",
@@ -7432,6 +7230,7 @@
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"dev": true,
+ "optional": true,
"requires": {
"punycode": "^2.1.0"
},
@@ -7440,7 +7239,8 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
@@ -7499,7 +7299,8 @@
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"validate-npm-package-license": {
"version": "3.0.4",
@@ -7521,6 +7322,7 @@
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
+ "optional": true,
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
diff --git a/package.json b/package.json
index e802bdf2a..842d0014a 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"start": "node ./bin/ungit",
"test": "grunt test",
"unittest": "grunt unittest",
+ "clicktest": "grunt clicktest",
"build": "grunt",
"watch": "grunt watch",
"package": "grunt package",
@@ -83,8 +84,8 @@
"grunt-zip-directories": "~1.0.1",
"istanbul": "~0.4.5",
"mocha": "~7.1.2",
- "nightmare": "~3.0.2",
"pkg-versions": "~2.1.0",
+ "puppeteer": "~3.0.3",
"superagent": "~5.2.2",
"supertest": "~4.0.2"
},
diff --git a/source/git-api.js b/source/git-api.js
index 0cef94a78..8f6802c45 100644
--- a/source/git-api.js
+++ b/source/git-api.js
@@ -132,13 +132,13 @@ exports.registerApi = (env) => {
}
const emitWorkingTreeChanged = _.debounce((repoPath) => {
- if (io) {
+ if (io && repoPath) {
io.sockets.in(path.normalize(repoPath)).emit('working-tree-changed', { repository: repoPath });
winston.info('emitting working-tree-changed to sockets, manually triggered');
}
}, 500, { 'maxWait': 2000 })
const emitGitDirectoryChanged = _.debounce((repoPath) => {
- if (io) {
+ if (io && repoPath) {
io.sockets.in(path.normalize(repoPath)).emit('git-directory-changed', { repository: repoPath });
winston.info('emitting git-directory-changed to sockets, manually triggered');
}
@@ -692,23 +692,34 @@ exports.registerApi = (env) => {
});
app.post(`${exports.pathPrefix}/testing/createfile`, ensureAuthenticated, (req, res) => {
const content = req.body.content ? req.body.content : (`test content\n${Math.random()}\n`);
- fs.writeFile(req.body.file, content, () => res.json({}));
+ fs.writeFileAsync(req.body.file, content)
+ .then(() => res.json({}))
+ .then(emitWorkingTreeChanged.bind(null, req.body.path));
});
app.post(`${exports.pathPrefix}/testing/changefile`, ensureAuthenticated, (req, res) => {
const content = req.body.content ? req.body.content : (`test content\n${Math.random()}\n`);
- fs.writeFile(req.body.file, content, () => res.json({}));
+ fs.writeFileAsync(req.body.file, content)
+ .then(() => res.json({}))
+ .then(emitWorkingTreeChanged.bind(null, req.body.path));
});
app.post(`${exports.pathPrefix}/testing/createimagefile`, ensureAuthenticated, (req, res) => {
- fs.writeFile(req.body.file, 'png', { encoding: 'binary' }, () => res.json({}));
+ fs.writeFileAsync(req.body.file, 'png', { encoding: 'binary' })
+ .then(() => res.json({}))
+ .then(emitWorkingTreeChanged.bind(null, req.body.path));
});
app.post(`${exports.pathPrefix}/testing/changeimagefile`, ensureAuthenticated, (req, res) => {
- fs.writeFile(req.body.file, 'png ~~', { encoding: 'binary' }, () => res.json({}));
+ fs.writeFileAsync(req.body.file, 'png ~~', { encoding: 'binary' })
+ .then(() => res.json({}))
+ .then(emitWorkingTreeChanged.bind(null, req.body.path));
});
app.post(`${exports.pathPrefix}/testing/removefile`, ensureAuthenticated, (req, res) => {
- fs.unlink(req.body.file, () => res.json({}));
+ fs.unlinkAsync(req.body.file)
+ .then(() => res.json({}))
+ .then(emitWorkingTreeChanged.bind(null, req.body.path));
});
app.post(`${exports.pathPrefix}/testing/git`, ensureAuthenticated, (req, res) => {
- jsonResultOrFailProm(res, gitPromise(req.body.command, req.body.repo));
+ jsonResultOrFailProm(res, gitPromise(req.body.command, req.body.path))
+ .then(emitWorkingTreeChanged.bind(null, req.body.path));
});
app.post(`${exports.pathPrefix}/testing/cleanup`, (req, res) => {
temp.cleanup((err, cleaned) => {
diff --git a/test/spec.git-api.diff.js b/test/spec.git-api.diff.js
index 82ae75cf0..66c4174db 100644
--- a/test/spec.git-api.diff.js
+++ b/test/spec.git-api.diff.js
@@ -125,7 +125,7 @@ describe('git-api diff', () => {
});
it('should be possible to rename a modified file', () => {
- return common.post(req, '/testing/git', { repo: testDir, command: ['mv', testFile, testFile2] });
+ return common.post(req, '/testing/git', { path: testDir, command: ['mv', testFile, testFile2] });
});
it('diff on renamed and modified file should work', () => {
diff --git a/test/spec.git-api.discardchanges.js b/test/spec.git-api.discardchanges.js
index ef99e808a..e9d44c5ce 100644
--- a/test/spec.git-api.discardchanges.js
+++ b/test/spec.git-api.discardchanges.js
@@ -57,7 +57,7 @@ describe('git-api discardchanges', () => {
const testFile1 = 'test.txt';
return common.post(req, '/testing/createfile', { file: path.join(dir, testFile1) })
- .then(() => common.post(req, '/testing/git', { repo: dir, command: ['add', testFile1] }))
+ .then(() => common.post(req, '/testing/git', { path: dir, command: ['add', testFile1] }))
.then(() => common.post(req, '/discardchanges', { path: dir, file: testFile1 }))
.then(() => common.get(req, '/status', { path: dir }))
.then((res) => expect(Object.keys(res.files).length).to.be(0));
@@ -69,7 +69,7 @@ describe('git-api discardchanges', () => {
const testFile1 = 'test.txt';
return common.post(req, '/testing/createfile', { file: path.join(dir, testFile1) })
- .then(() => common.post(req, '/testing/git', { repo: dir, command: ['add', testFile1] }))
+ .then(() => common.post(req, '/testing/git', { path: dir, command: ['add', testFile1] }))
.then(() => common.post(req, '/testing/removefile', { file: path.join(dir, testFile1) }))
.then(() => common.post(req, '/discardchanges', { path: dir, file: testFile1 }))
.then(() => common.get(req, '/status', { path: dir }))
@@ -108,7 +108,7 @@ describe('git-api discardchanges', () => {
() => {common.post(req, '/testing/createfile', { file: path.join(dir, testFile1) });
() => {common.post(req, '/commit', { path: dir, message: 'lol', files: [{ name: testFile1 }] });
() => {common.post(req, '/testing/changefile', { file: path.join(dir, testFile1) });
- () => {common.post(req, '/testing/git', { repo: dir, command: ['add', testFile1] });
+ () => {common.post(req, '/testing/git', { path: dir, command: ['add', testFile1] });
() => {common.post(req, '/testing/removefile', { file: path.join(dir, testFile1) });
() => {common.post(req, '/discardchanges', { path: dir, file: testFile1 });
() => {common.get(req, '/status', { path: dir }).then((res) => {
diff --git a/test/spec.git-api.js b/test/spec.git-api.js
index c77792be1..8538aaeef 100644
--- a/test/spec.git-api.js
+++ b/test/spec.git-api.js
@@ -351,7 +351,7 @@ describe('git-api', () => {
const testFile4 = path.join(testSubDir, 'renamed.txt').replace(/\\/, '/');
it('renaming a file should work', () => {
- return common.post(req, '/testing/git', { repo: testDir, command: ['mv', testFile3, testFile4] });
+ return common.post(req, '/testing/git', { path: testDir, command: ['mv', testFile3, testFile4] });
});
it('status should list the renamed file', () => {