<commit_before>angular.module('app.AIControl', ['starter.factory', 'hljs', 'starter.utils'])
  .controller('AIControl', function ($scope, $ionicModal, $storageServices, $analytics, $http, $ionicLoading, utilsFactory) {
    $analytics.trackView('AI Controller');
    $ionicLoading.show({
      template: 'Computing...'
    });

    $scope.improves = [];
    $scope.goodSkills = [];
    $scope.aiTodoLists = TODO_LISTS;
    var todoMenuKeys = Object.keys(TODO_LISTS);

    angular.forEach(todoMenuKeys, function (listsKey) {
      $storageServices.get(listsKey + 'Finish', function (result) {
        if (result !== 'true') {
          var todoItems = $scope.aiTodoLists[listsKey].basic;
          var suggest = todoItems[utilsFactory.getRandomInt(todoItems.length)];
          $scope.improves.push(suggest);
        } else if (result === 'true') {
          $scope.goodSkills.push(listsKey);
        }
      });
    });

    var skills = {
      server: 0,
      front: 0,
      devops: 0,
      coding: 0,
      analytics: 0
    };

    if ($scope.goodSkills.indexOf('front') !== -1) {
      skills.front = 5;
    }

    if ($scope.goodSkills.indexOf('mvc') !== -1) {
      skills.server = 5;
    }

    if ($scope.goodSkills.indexOf('refactor') !== -1) {
      skills.coding = 5;
    }

    if ($scope.goodSkills.indexOf('analytics') !== -1) {
      skills.analytics = 5;
    }

    if ($scope.goodSkills.indexOf('container') !== -1 && $scope.goodSkills.indexOf('ci') !== -1) {
      skills.devops = 5;
    }

    $http.get('rules/rules.nools').then(function (response) {
      var flow;
      if (nools.getFlow("AI Flow") === undefined) {
        flow = nools.compile(response.data, {
          name: 'AI Flow'
        });
      } else {
        flow = nools.getFlow("AI Flow");
      }

      var SkillCal = flow.getDefined("skillcal");

      $scope.finallyWords = "你是一个";

      var session = flow.getSession(new SkillCal(skills))
        .on("modify", function (fact) {
          $scope.finallyWords += fact.text;
        })
        .on("fire", function (ruleName) {
          console.log('AI Analytics: ' + ruleName);
        });

      session.match(function (err) {
        $ionicLoading.hide();
        if (err) {
          console.error(err.stack);
        } else {
          console.log("AI Analytics: done");
        }
      });
    });
  });
<commit_msg>add basic ai controler<commit_after>angular.module('app.AIControl', ['starter.factory', 'hljs', 'starter.utils'])
  .controller('AIControl', function ($scope, $ionicModal, $storageServices, $analytics, $http, $ionicLoading, utilsFactory) {
    $analytics.trackView('AI Controller');
    $ionicLoading.show({
      template: 'Computing...'
    });

    $scope.improves = [];
    $scope.goodSkills = [];
    $scope.aiTodoLists = TODO_LISTS;
    var todoMenuKeys = Object.keys(TODO_LISTS);

    angular.forEach(todoMenuKeys, function (listsKey) {
      $storageServices.get(listsKey + 'Finish', function (result) {
        if (result !== 'true') {
          var todoItems = $scope.aiTodoLists[listsKey].basic;
          var suggest = todoItems[utilsFactory.getRandomInt(todoItems.length)];
          $scope.improves.push(suggest);
        } else if (result === 'true') {
          $scope.goodSkills.push(listsKey);
        }
      });
    });

    var skills = {
      server: 0,
      front: 0,
      devops: 0,
      coding: 0,
      analytics: 0
    };

    if ($scope.goodSkills.indexOf('front') !== -1) {
      skills.front = 5;
    }

    if ($scope.goodSkills.indexOf('mvc') !== -1) {
      skills.server = 5;
    }

    if ($scope.goodSkills.indexOf('refactor') !== -1) {
      skills.coding = 5;
    }

    if ($scope.goodSkills.indexOf('analytics') !== -1) {
      skills.analytics = 5;
    }

    if ($scope.goodSkills.indexOf('container') !== -1 && $scope.goodSkills.indexOf('ci') !== -1) {
      skills.devops = 5;
    }

    $http.get('rules/rules.nools').then(function (response) {
      var flow;
      if (nools.getFlow("AI Flow") === undefined) {
        flow = nools.compile(response.data, {
          name: 'AI Flow'
        });
      } else {
        flow = nools.getFlow("AI Flow");
      }

      var SkillCal = flow.getDefined("skillcal");

      var originSuggestions = "你是一个";
        $scope.finallyWords = originSuggestions;

      var session = flow.getSession(new SkillCal(skills))
        .on("modify", function (fact) {
          $scope.finallyWords += fact.text;
        })
        .on("fire", function (ruleName) {
          console.log('AI Analytics: ' + ruleName);
        });

      session.match(function (err) {
        if($scope.finallyWords === originSuggestions) {
          $scope.finallyWords = "你是一个有潜力的新星!";
        }

        $ionicLoading.hide();
        if (err) {
          console.error(err.stack);
        } else {
          console.log("AI Analytics: done");
        }
      });
    });
  });
<|endoftext|>


<commit_before>// adopted from https://github.com/jonschlinkert/fs-utils
// Copyright (c) 2014 Jon Schlinkert, Brian Woodward. (MIT)

var separator = '/'

// return an array of path segments
function segments (fp) {
  return fp.split(/[\/]/g)
}

// the last `num` segments of a filepath. If a number
// isn't passed for `num`, the last segment is returned
function last (fp, num, opt) {
  return segments(fp)
    .slice(-(num || 1))
    .join(opt || separator)
}

// the last `num` segments removed from a filepath. If a number
// isn't passed for `num`, the last segment is removed.
function fromLast (fp, num, opt) {
  return segments(fp)
    .slice(0, -(num || 1))
    .join(opt || separator)
}

// the first `num` segments of a filepath. If a number
// isn't passed for `num`, the first segment is returned
function first (fp, num, opt) {
  return segments(fp)
    .slice(0, num || 1)
    .join(opt || separator)
}

// the first `num` segments removed from a filepath. If a number
// isn't passed for `num`, the first segment is removed.
function fromFirst (fp, num, opt) {
  return segments(fp)
    .slice(num || 1)
    .join(opt || separator)
}

module.exports = segments
module.exports.last = last
module.exports.fromLast = fromLast
module.exports.first = first
module.exports.fromFirst = fromFirst
<commit_msg>update path/segments<commit_after>// adopted from https://github.com/jonschlinkert/fs-utils
// Copyright (c) 2014 Jon Schlinkert, Brian Woodward. (MIT)

var separator = '/'

// return an array of path segments
function segments (fp) {
  return fp.split(/[\\\/]/g)
}

// the last `num` segments of a filepath. If a number
// isn't passed for `num`, the last segment is returned
function last (fp, num, opt) {
  return segments(fp)
    .slice(-(num || 1))
    .join(opt || separator)
}

// the last `num` segments removed from a filepath. If a number
// isn't passed for `num`, the last segment is removed.
function fromLast (fp, num, opt) {
  return segments(fp)
    .slice(0, -(num || 1))
    .join(opt || separator)
}

// the first `num` segments of a filepath. If a number
// isn't passed for `num`, the first segment is returned
function first (fp, num, opt) {
  return segments(fp)
    .slice(0, num || 1)
    .join(opt || separator)
}

// the first `num` segments removed from a filepath. If a number
// isn't passed for `num`, the first segment is removed.
function fromFirst (fp, num, opt) {
  return segments(fp)
    .slice(num || 1)
    .join(opt || separator)
}

module.exports = segments
module.exports.last = last
module.exports.fromLast = fromLast
module.exports.first = first
module.exports.fromFirst = fromFirst
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');

module.exports = function attributes() {
  var engine = this;
  _.forEach(arguments, function (key) {
    let keyName, prop;
    if (_.isObject(key)) {
      [key, keyName] = _.chain(key).toPairs().flatten().value();
    }
    prop = engine.datum[key];
    engine.resultObject[keyName ? keyName : key] = _.isFunction(prop) ? prop() : prop;
  });
};
<commit_msg>refactoring to es6<commit_after>'use strict';
const _ = require('lodash');

module.exports = function attributes(...args) {
  args.forEach(key => {
    let keyName, prop;
    if (_.isObject(key)) {
      [key, keyName] = _.chain(key).toPairs().flatten().value();
    }
    prop = this.datum[key];
    this.resultObject[keyName ? keyName : key] = _.isFunction(prop) ? prop() : prop;
  });
};
<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 */
var utils = require('../utils'),
	openTags = require('../parsers/open-tags'),
	strictTags = /span|script|meta/,
	Context = require('../context'),
	Template = require('../template'),
	View = require('../view');

// String Output Descriptor
function SOD() {
	this.attributes = '';
	this.classes = '';
	this.children = '';
	this.style = '';
}

function tagOutput(descriptor, innerDescriptor, name) {
	var out = '<' + name + innerDescriptor.attributes;
	if (innerDescriptor.style)
		out += ' style="' + innerDescriptor.style + '"';
	if (innerDescriptor.classes)
		out += ' class="' + innerDescriptor.classes + '"';
	if (innerDescriptor.children)
		descriptor.children += out + '>' + innerDescriptor.children + '</' + name + '>';
	else if (openTags.test(name))
		descriptor.children += out + '>';
	else if (strictTags.test(name))
		descriptor.children += out + '></' + name + '>';
	else
		descriptor.children += out + '/>';
}
utils.tagOutput = tagOutput;

var methods = {
	SOD: SOD,
	//_________________________________ local context management
	newContext: function(context, descriptor, args) {
		var data = args[0],
			parent = args[1] || context,
			path = args[2];
		descriptor.context = new Context(data, parent, path);
	},
	//_________________________________________ EACH
	each: function(context, descriptor, args) {
		var path = args[0],
			values = (typeof path === 'string') ? context.get(path) : path;
		if (values && values.length) {
			var template = args[1];
			for (var i = 0, len = values.length; i < len; ++i)
				template.toHTMLString(new Context(values[i], context), descriptor);
		} else if (args[2])
			args[2].toHTMLString(context, descriptor);
	},
	// ____________________________________ WITH
	with: function(context, descriptor, args) {
		var path = args[0],
			template = args[1];
		var ctx = new Context(typeof path === 'string' ? context.get(path) : path, context, path);
		template.toHTMLString(ctx, descriptor, container);
	},
	//______________________________________________
	if: function(context, descriptor, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__)
			ok = condition.output(context);
		else if (typeof condition === 'function')
			ok = condition.call(this, context);
		var sod = new SOD();
		if (ok)
			successTempl.toHTMLString(context, sod);
		else if (failTempl)
			failTempl.toHTMLString(context, sod);
		if (sod.children)
			descriptor.children += sod.children;
	},
	switch: function(context, descriptor, args) {
		var xpr = args[0],
			dico = args[1],
			value = xpr.output(context),
			templ = dico[value] || dico['default'];
		if (templ) {
			var sod = new SOD();
			templ.toHTMLString(context, sod);
			if (sod.children)
				descriptor.children += sod.children;
		}
	},
	//________________________________ TAGS
	tag: function(context, descriptor, originalArgs) {
		var name = originalArgs[0],
			template = originalArgs[1];
		var newDescriptor = new SOD();
		template.toHTMLString(context, newDescriptor);
		tagOutput(descriptor, newDescriptor, name);
	},
	text: function(context, descriptor, args) {
		var value = args[0];
		descriptor.children += value.__interpolable__ ? value.output(context) : value;
	},
	br: function(context, descriptor) {
		descriptor.children += '
';
	},
	//______________________________________________ ATTRIBUTES
	attr: function(context, descriptor, args) {
		var name = args[0],
			value = args[1];
		descriptor.attributes += ' ' + name + (value ? descriptor.attributes += '="' + (value.__interpolable__ ? value.output(context) : value) + '"' : '');
	},
	disabled: function(context, descriptor, args) {
		var value = args[0];
		if (value === undefined || context.get(value))
			descriptor.attributes += ' disabled';
	},
	val: function(context, descriptor, args) {
		var path = args[0],
			value = args[1];
		descriptor.attributes += ' value="' + (value.__interpolable__ ? value.output(context) : value) + '"';
	},
	setClass: function(context, descriptor, args) {
		var name = args[0],
			flag = args[1];
		if ((flag.__interpolable__ && flag.output(context)) || flag)
			descriptor.classes += ' ' + (name.__interpolable__ ? name.output(context) : name);
	},
	css: function(context, descriptor, args) {
		var prop = args[0],
			value = args[1];
		descriptor.style += prop + ':' + (value.__interpolable__ ? value.output(context) : value);
	},
	visible: function(context, descriptor, args) {
		var flag = args[0],
			val = flag.__interpolable__ ? flag.output(context) : flag;
		if (!val)
			descriptor.style += 'display:none;';
	},
	//_________________________________ EVENTS
	on: function() {},
	off: function() {},
	//_________________________________ CLIENT/SERVER
	client: function(context, descriptor, args) {
		if (context.env.data.isServer)
			return;
		args[0].toHTMLString(context, descriptor);
	},
	server: function(context, descriptor, args) {
		if (!context.env.data.isServer)
			return;
		args[0].toHTMLString(context, descriptor);
	},
	//_______________________________ SUSPEND RENDER
	suspendUntil: function(context, descriptor, args) {
		var xpr = args[0],
			index = args[1],
			templ = args[2],
			val = xpr.__interpolable__ ? xpr.output(context) : xpr,
			rest = new Template(templ._queue.slice(index));
		if (val)
			rest.toHTMLString(context, descriptor);
	}
};

View.prototype.toHTMLString = function(context, descriptor) {
	var sod = new SOD();
	Template.prototype.toHTMLString.call(this, context, sod);
	descriptor.children += sod.children;
	return descriptor.children;
};

Template.prototype.toHTMLString = function(context, descriptor) {
	context = context || new Context();
	descriptor = descriptor ||  new SOD();
	var handler = this._queue[0],
		index = 0,
		f;
	while (handler) {
		f = null;
		switch (handler.type) {
			case '*':
				f = methods[handler.handler];
				break;
			case 'string':
			case 'context':
				f = handler.handler;
				break;
			case 'custom':
				f = handler.handler.string;
				break;
		}
		if (!f) {
			handler = this._queue[++index];
			continue;
		}
		f(descriptor.context || context, descriptor, handler.args);
		if (handler.suspendAfter)
			break;
		handler = this._queue[++index];
	}
	return descriptor.children;
};

module.exports = methods;
<commit_msg>add fake once in string<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 */
var utils = require('../utils'),
	openTags = require('../parsers/open-tags'),
	strictTags = /span|script|meta/,
	Context = require('../context'),
	Template = require('../template'),
	View = require('../view');

// String Output Descriptor
function SOD() {
	this.attributes = '';
	this.classes = '';
	this.children = '';
	this.style = '';
}

function tagOutput(descriptor, innerDescriptor, name) {
	var out = '<' + name + innerDescriptor.attributes;
	if (innerDescriptor.style)
		out += ' style="' + innerDescriptor.style + '"';
	if (innerDescriptor.classes)
		out += ' class="' + innerDescriptor.classes + '"';
	if (innerDescriptor.children)
		descriptor.children += out + '>' + innerDescriptor.children + '</' + name + '>';
	else if (openTags.test(name))
		descriptor.children += out + '>';
	else if (strictTags.test(name))
		descriptor.children += out + '></' + name + '>';
	else
		descriptor.children += out + '/>';
}
utils.tagOutput = tagOutput;

var methods = {
	SOD: SOD,
	//_________________________________ local context management
	newContext: function(context, descriptor, args) {
		var data = args[0],
			parent = args[1] || context,
			path = args[2];
		descriptor.context = new Context(data, parent, path);
	},
	//_________________________________________ EACH
	each: function(context, descriptor, args) {
		var path = args[0],
			values = (typeof path === 'string') ? context.get(path) : path;
		if (values && values.length) {
			var template = args[1];
			for (var i = 0, len = values.length; i < len; ++i)
				template.toHTMLString(new Context(values[i], context), descriptor);
		} else if (args[2])
			args[2].toHTMLString(context, descriptor);
	},
	// ____________________________________ WITH
	with: function(context, descriptor, args) {
		var path = args[0],
			template = args[1];
		var ctx = new Context(typeof path === 'string' ? context.get(path) : path, context, path);
		template.toHTMLString(ctx, descriptor, container);
	},
	//______________________________________________
	if: function(context, descriptor, args) {
		var ok, condition = args[0],
			successTempl = args[1],
			failTempl = args[2];
		if (condition && condition.__interpolable__)
			ok = condition.output(context);
		else if (typeof condition === 'function')
			ok = condition.call(this, context);
		var sod = new SOD();
		if (ok)
			successTempl.toHTMLString(context, sod);
		else if (failTempl)
			failTempl.toHTMLString(context, sod);
		if (sod.children)
			descriptor.children += sod.children;
	},
	switch: function(context, descriptor, args) {
		var xpr = args[0],
			dico = args[1],
			value = xpr.output(context),
			templ = dico[value] || dico['default'];
		if (templ) {
			var sod = new SOD();
			templ.toHTMLString(context, sod);
			if (sod.children)
				descriptor.children += sod.children;
		}
	},
	//________________________________ TAGS
	tag: function(context, descriptor, originalArgs) {
		var name = originalArgs[0],
			template = originalArgs[1];
		var newDescriptor = new SOD();
		template.toHTMLString(context, newDescriptor);
		tagOutput(descriptor, newDescriptor, name);
	},
	text: function(context, descriptor, args) {
		var value = args[0];
		descriptor.children += value.__interpolable__ ? value.output(context) : value;
	},
	br: function(context, descriptor) {
		descriptor.children += '
';
	},
	//______________________________________________ ATTRIBUTES
	attr: function(context, descriptor, args) {
		var name = args[0],
			value = args[1];
		descriptor.attributes += ' ' + name + (value ? descriptor.attributes += '="' + (value.__interpolable__ ? value.output(context) : value) + '"' : '');
	},
	disabled: function(context, descriptor, args) {
		var value = args[0];
		if (value === undefined || context.get(value))
			descriptor.attributes += ' disabled';
	},
	val: function(context, descriptor, args) {
		var path = args[0],
			value = args[1];
		descriptor.attributes += ' value="' + (value.__interpolable__ ? value.output(context) : value) + '"';
	},
	setClass: function(context, descriptor, args) {
		var name = args[0],
			flag = args[1];
		if ((flag.__interpolable__ && flag.output(context)) || flag)
			descriptor.classes += ' ' + (name.__interpolable__ ? name.output(context) : name);
	},
	css: function(context, descriptor, args) {
		var prop = args[0],
			value = args[1];
		descriptor.style += prop + ':' + (value.__interpolable__ ? value.output(context) : value);
	},
	visible: function(context, descriptor, args) {
		var flag = args[0],
			val = flag.__interpolable__ ? flag.output(context) : flag;
		if (!val)
			descriptor.style += 'display:none;';
	},
	//_________________________________ EVENTS
	on: function() {},
	once: function() {},
	off: function() {},
	//_________________________________ CLIENT/SERVER
	client: function(context, descriptor, args) {
		if (context.env.data.isServer)
			return;
		args[0].toHTMLString(context, descriptor);
	},
	server: function(context, descriptor, args) {
		if (!context.env.data.isServer)
			return;
		args[0].toHTMLString(context, descriptor);
	},
	//_______________________________ SUSPEND RENDER
	suspendUntil: function(context, descriptor, args) {
		var xpr = args[0],
			index = args[1],
			templ = args[2],
			val = xpr.__interpolable__ ? xpr.output(context) : xpr,
			rest = new Template(templ._queue.slice(index));
		if (val)
			rest.toHTMLString(context, descriptor);
	}
};

View.prototype.toHTMLString = function(context, descriptor) {
	var sod = new SOD();
	Template.prototype.toHTMLString.call(this, context, sod);
	descriptor.children += sod.children;
	return descriptor.children;
};

Template.prototype.toHTMLString = function(context, descriptor) {
	context = context || new Context();
	descriptor = descriptor ||  new SOD();
	var handler = this._queue[0],
		index = 0,
		f;
	while (handler) {
		f = null;
		switch (handler.type) {
			case '*':
				f = methods[handler.handler];
				break;
			case 'string':
			case 'context':
				f = handler.handler;
				break;
			case 'custom':
				f = handler.handler.string;
				break;
		}
		if (!f) {
			handler = this._queue[++index];
			continue;
		}
		f(descriptor.context || context, descriptor, handler.args);
		if (handler.suspendAfter)
			break;
		handler = this._queue[++index];
	}
	return descriptor.children;
};

module.exports = methods;
<|endoftext|>


<commit_before>/*
@license https://github.com/t2ym/gulp-i18n-preprocess/blob/master/LICENSE.md
Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
*/
'use strict';

var chai = require('chai');
var assert = chai.assert;
var path = require('path');
var fs = require('fs');
var gutil = require('gulp-util');
var stream = require('stream');
var isStream = require('is-stream');
var gulp = require('gulp');
var debug = require('gulp-debug');

var through = require('through2');
var dom5 = require('dom5');
var JSONstringify = require('json-stringify-safe');

var i18nPreprocess = require('../');

chai.config.showDiff = true;

/*

`i18nPreprocess(options)`

### `options` object

- replacingText: Boolean, default: false - If true, UI texts are replaced with {{annotations}}
- jsonSpace: Number, default: 2 - JSON stringification parameter for formatting
- srcPath: String, default: 'app' - Path to source root
- force: Boolean, default: false - Force preprocessing even if i18n-behavior.html is not imported
- dropHtml: Boolean, default: false - If true, drop the preprocessed HTML for output
- constructAttributesRepository: Boolean, default: false - If true, construct localizable attributes repository
- attributesRepository: Object, default: {} - Input/Output - attributes respository object
- attributesRepositoryPath: String, default: null - Path to bower_components/i18n-behavior/i18n-attr-repo.html

*/

function convertToExpectedPath (file, srcBaseDir, expectedBaseDir) {
  if (file && file.path && srcBaseDir && expectedBaseDir) {
    srcBaseDir = srcBaseDir.replace(/\//g, path.sep);
    if (file.path.substr(0, srcBaseDir.length) === srcBaseDir) {
      file.path = path.join(expectedBaseDir.replace(/\//g, path.sep),
                            file.path.substr(srcBaseDir.length));
    }
    else {
      srcBaseDir = path.resolve(srcBaseDir);
      if (file.path.substr(0, srcBaseDir.length) === srcBaseDir) {
        file.path = path.join(expectedBaseDir.replace(/\//g, path.sep),
                              file.path.substr(srcBaseDir.length));
      }
    }
  }
  return file;
}

function n2h (target) {
  if (path.sep === '/') {
    return target;
  }
  if (target) {
    if (Array.isArray(target)) {
      return target.map(function (item) { return n2h(item); });
    }
    else if (typeof target === 'string') {
      return target.replace(/\//g, path.sep);
    }
    else {
      return target;
    }
  }
  else {
    return target;
  }
}

// Test suite inheritance utilities
var p = Object.setPrototypeOf || function (target, base) {
  var obj = Object.create(base);
  for (var p in target) {
    obj[p] = target[p];
  }
  return obj;
};
var _name = 'suite';
var suiteMap = {};
var s = function (name, baseName, extension) {
  if (suiteMap[name]) {
    throw new Error('duplicate suite name ' + name);
  }
  if (baseName && !suiteMap[baseName]) {
    throw new Error('inexistent base suite name ' + baseName);
  }
  extension[_name] = name;
  extension = p(extension, suiteMap[baseName] || {});
  suiteMap[name] = extension;
  return extension;
};

var attributesRepository_standard = {
  'input': {
    'placeholder': true
  },
  'paper-input': {
    'label': true,
    'error-message': true,
    'placeholder': true
  },
  'paper-textarea': {
    'label': true,
    'error-message': true,
    'placeholder': true
  },
  'paper-dropdown-menu': {
    'label': true
  },
  'paper-toast': {
    'text': true
  },
  'google-chart': {
    'options': true,
    'cols': true,
    'rows': true,
    'data': true
  },
  'platinum-push-messaging': {
    'title': true,
    'message': true
  },
  'json-data': {
    'any-attributes': true
  }
};

var attributesRepository_custom = p({
  'text-attribute-element': {
    'custom-text-attr1': true,
    'custom-text-attr2': true,
    'custom-text-attr3': true
  }
}, attributesRepository_standard);

var attributesRepository_saved;

var options_base = {
  replacingText: false,
  jsonSpace: 2,
  srcPath: 'test/src',
  force: false,
  dropHtml: false,
  constructAttributesRepository: false,
  attributesRepository: attributesRepository_standard,
  attributesRepositoryPath: null
};

var params_base = {
  suite: null,
  options: options_base,
  srcBaseDir: 'test/src',
  targets: [],
  expectedBaseDir: 'test/expected',
  expected: []
};

function appendJson (list) {
  if (list && Array.isArray(list)) {
    return list.map(function (item) {
      if (typeof item === 'string') {
        item = [ item, item.replace(/[.]html$/, '.json') ];
      }
      return item;
    }).reduce(function (prev, curr) {
      if (Array.isArray(curr)) {
        curr.forEach(function (item) {
          prev.push(item);
        });
      }
      else {
        prev.push(item);
      }
      return prev;
    }, []);
  }
  else {
    return list;
  }
}

function fromExpected (expectedBaseDir) {
  var buffer = fs.readFileSync(path.join(expectedBaseDir, 'attributes-repository.json'), 'utf8');
  return JSON.parse(buffer.toString());
}

var suites = [
  s(null, null, params_base),
  s('scan', null, {
    options: p({
      dropHtml: true,
      constructAttributesRepository: true,
      attributesRepository: {},
      attributesRepositoryPath: n2h('bower_components/i18n-behavior/i18n-attr-repo.html')
    }, options_base),
    targets: [ 'simple-text-element.html' ],
    attributesRepository: attributesRepository_standard
  }),
  s('gulp scan', 'scan', {
    gulp: true
  }),
  s('scan custom', 'scan', {
    targets: [ 'text-attribute-element.html' ],
    attributesRepository: attributesRepository_custom
  }),
  s('gulp scan custom', 'scan custom', {
    gulp: true
  }),
  s('simple-text-element', null, {
    options: p({
      replacingText: true,
      attributesRepository: attributesRepository_standard,
    }, options_base),
    targets: [ 'simple-text-element.html' ],
    expected: appendJson
  }),
  s('gulp simple-text-element', 'simple-text-element', {
    gulp: true
  }),
  s('i18n-dom-bind', 'simple-text-element', {
    options: p({
      replacingText: true,
      force: true,
      attributesRepository: attributesRepository_custom
    }, options_base),
    targets: [ 'basic-test.html' ],
    expected: [
      'basic-test.html',
      'simple-text-dom-bind.json',
      'simple-attribute-dom-bind.json',
      'compound-binding-dom-bind.json'
    ]
  }),
  s('gulp i18n-dom-bind', 'i18n-dom-bind', {
    gulp: true
  }),
  // test with i18n-behavior test fixtures
  // Note: Version of i18n-behavior must be carefully chosen in bower.json
  //       so that actual outputs can be checked against the preprocessed output
  //       from a STABLE and TEST-PASSING i18n-behavior release.  Otherwise,
  //       the following test suites would be meaningless because the expected outputs
  //       are actually just output by gulp-i18n-preprocess of an unstable version.
  s('gulp i18n-behavior/test/src scan', null, {
    gulp: true,
    options: p({
      srcPath: 'bower_components/i18n-behavior/test/src',
      dropHtml: true,
      constructAttributesRepository: true,
      attributesRepository: {},
      attributesRepositoryPath: n2h('bower_components/i18n-behavior/i18n-attr-repo.html')
    }, options_base),
    srcBaseDir: 'bower_components/i18n-behavior/test/src',
    targets: [ '**/*.html', '!**/*-test.html' ],
    expectedBaseDir: 'bower_components/i18n-behavior/test/preprocess',
    attributesRepository: fromExpected
  }),
  s('gulp i18n-behavior/test/src preprocess', null, {
    gulp: true,
    options: p({
      replacingText: true,
      srcPath: 'bower_components/i18n-behavior/test/src',
      dropHtml: false,
      constructAttributesRepository: false,
      attributesRepository: fromExpected
    }, options_base),
    srcBaseDir: 'bower_components/i18n-behavior/test/src',
    targets: [ '**/*.html', '!**/*-test.html' ],
    expectedBaseDir: 'bower_components/i18n-behavior/test/preprocess',
    expected: null
  }),
  s('gulp i18n-behavior/test/src/*-test.html preprocess', 'gulp i18n-behavior/test/src preprocess', {
    options: p({
      replacingText: true,
      srcPath: 'bower_components/i18n-behavior/test/src',
      force: true,
      dropHtml: false,
      constructAttributesRepository: false,
      attributesRepository: fromExpected
    }, options_base),
    targets: [ '**/*-test.html' ]
  })
];

suite('gulp-i18n-preprocess', function () {
  suites.forEach(function (params) {
    var preprocessor;
    var options = params.options;
    var inputs;
    var outputs;
    var expectedPaths;
    var expected;
    var attributesRepository;

    if (!params.suite) {
      return;
    }

    suite(params.suite, function () {
      suiteSetup(function () {
        if (params.gulp &&
          !params.options.constructAttributesRepository &&
          typeof params.options.attributesRepository === 'function') {
          options.attributesRepository = params.options.attributesRepository(params.expectedBaseDir);
        }
        preprocessor = i18nPreprocess(options);
        inputs = params.gulp ?
          params.targets.map(function (target) {
            return target.match(/^!/) ?
              '!' + [ params.srcBaseDir, target.substr(1) ].join('/') :
              [ params.srcBaseDir, target ].join('/')
          }) :
          params.targets.map(function (target) {
            return new gutil.File({
              cwd: __dirname,
              base: path.join(__dirname, n2h(target)),
              path: path.join(n2h(params.srcBaseDir), target),
              contents: fs.readFileSync(path.join(n2h(params.srcBaseDir), target))
            });
          });
        outputs = [];
        if (typeof params.expected === 'function') {
          params.expected = params.expected(params.targets);
        }
        expectedPaths = params.expected ?
          params.expected.map(function (outputPath) {
            return path.join(params.expectedBaseDir, n2h(outputPath));
          }) : null;
        expected = expectedPaths ?
          expectedPaths.map(function (target) {
            return new gutil.File({
              cwd: __dirname,
              base: path.join(__dirname, n2h(target)),
              path: target,
              contents: fs.readFileSync(target)
            })
          }) : null;
        if (params.attributesRepository &&
            params.options && params.options.constructAttributesRepository) {
          attributesRepository = {};
          params.options.attributesRepository = attributesRepository;
        }
      });

      test('get a duplex stream', function () {
        assert.ok(isStream.duplex(preprocessor), 'preprocessor is a duplex stream');
      });

      if (params.gulp) {
        test('preprocess in gulp', function (done) {
          gulp.task('preprocess', function () {
            return gulp.src(inputs, { base: params.srcBaseDir })
              .pipe(preprocessor)
              .pipe(through.obj(function (file, enc, callback) {
                assert.ok(file instanceof gutil.File, 'get a File instance for ' + file.path);
                convertToExpectedPath(file, params.srcBaseDir, params.expectedBaseDir);
                outputs.push(file);
                callback(null, file);
              }))
              .pipe(debug({ title: 'preprocess output:'}))
              .pipe(through.obj(function (file, enc, callback) {
                callback(null, null);
              }));
          });
          gulp.start.apply(gulp, [ 'preprocess', function () {
            gulp.reset();
            done();
          }]);
        });
      }
      else {
        test('get preprocessed files', function (done) {
          preprocessor.on('data', function (file) {
            assert.ok(file instanceof gutil.File, 'get a File instance for ' + file.path);
            convertToExpectedPath(file, params.srcBaseDir, params.expectedBaseDir);
            outputs.push(file);
          });

          preprocessor.on('end', done);

          inputs.forEach(function (file) {
            preprocessor.write(file);
          });

          preprocessor.end();
        });
      }

      if ((params.expected && params.expected.length > 0) ||
          !params.expected) {
        if (params.expected) {
          test('check preprocessed file list', function () {
            outputs.forEach(function (file, index) {
              assert.equal(file.path, expectedPaths[index], expectedPaths[index] + ' is output');
            });
            assert.equal(outputs.length, expectedPaths.length,
              'get expected ' + expectedPaths.length + ' files');
          });
        }

        test('check preprocessed file contents', function () {
          outputs.forEach(function (file, index) {
            var expectedFile = expected ? expected[index] : null;
            if (!expected) {
              expectedFile = new gutil.File({
                cwd: __dirname,
                base: file.base,
                path: file.path,
                contents: fs.readFileSync(file.path)
              });
            }
            if (file.contents.toString() !== expectedFile.contents.toString()) {
              console.log('file.path = ' + file.path);
              console.log('expected = ' + expectedFile.contents.toString());
              console.log('actual = ' + file.contents.toString());
            }
            assert.equal(file.contents.toString(), expectedFile.contents.toString(),
              'get expected file contents for ' + expectedFile.path);
          });
        });
      }
      else {
        test('no outputs', function () {
          assert.equal(outputs.length, 0, 'get no outputs');
        });
      }

      if (params.attributesRepository) {
        test('check attributesRepository', function () {
          var expectedAttributesRepository;
          if (typeof params.attributesRepository === 'function') {
            expectedAttributesRepository = params.attributesRepository(params.expectedBaseDir);
          }
          else {
            expectedAttributesRepository = params.attributesRepository;
          }
          assert.deepEqual(attributesRepository,
            expectedAttributesRepository,
            'get expected attributesRepository');
        });
      }

      suiteTeardown(function () {
      });
    });
  });
});
<commit_msg>test: Add check for gulp preprocessed output file list with expanded input file list<commit_after>/*
@license https://github.com/t2ym/gulp-i18n-preprocess/blob/master/LICENSE.md
Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
*/
'use strict';

var chai = require('chai');
var assert = chai.assert;
var path = require('path');
var fs = require('fs');
var gutil = require('gulp-util');
var stream = require('stream');
var isStream = require('is-stream');
var gulp = require('gulp');
var debug = require('gulp-debug');

var through = require('through2');
var dom5 = require('dom5');
var JSONstringify = require('json-stringify-safe');

var i18nPreprocess = require('../');

chai.config.showDiff = true;

/*

`i18nPreprocess(options)`

### `options` object

- replacingText: Boolean, default: false - If true, UI texts are replaced with {{annotations}}
- jsonSpace: Number, default: 2 - JSON stringification parameter for formatting
- srcPath: String, default: 'app' - Path to source root
- force: Boolean, default: false - Force preprocessing even if i18n-behavior.html is not imported
- dropHtml: Boolean, default: false - If true, drop the preprocessed HTML for output
- constructAttributesRepository: Boolean, default: false - If true, construct localizable attributes repository
- attributesRepository: Object, default: {} - Input/Output - attributes respository object
- attributesRepositoryPath: String, default: null - Path to bower_components/i18n-behavior/i18n-attr-repo.html

*/

function convertToExpectedPath (file, srcBaseDir, expectedBaseDir) {
  var target;
  if (file instanceof gutil.File) {
    target = file.path;
  }
  else {
    target = file;
  }
  if (target && srcBaseDir && expectedBaseDir) {
    srcBaseDir = srcBaseDir.replace(/\//g, path.sep);
    if (target.substr(0, srcBaseDir.length) === srcBaseDir) {
      target = path.join(expectedBaseDir.replace(/\//g, path.sep),
                        target.substr(srcBaseDir.length));
    }
    else {
      srcBaseDir = path.resolve(srcBaseDir);
      if (target.substr(0, srcBaseDir.length) === srcBaseDir) {
        target = path.join(expectedBaseDir.replace(/\//g, path.sep),
                          target.substr(srcBaseDir.length));
      }
    }
  }
  if (file instanceof gutil.File) {
    file.path = target;
  }
  else {
    file = target;
  }
  return file;
}

function n2h (target) {
  if (path.sep === '/') {
    return target;
  }
  if (target) {
    if (Array.isArray(target)) {
      return target.map(function (item) { return n2h(item); });
    }
    else if (typeof target === 'string') {
      return target.replace(/\//g, path.sep);
    }
    else {
      return target;
    }
  }
  else {
    return target;
  }
}

// Test suite inheritance utilities
var p = Object.setPrototypeOf || function (target, base) {
  var obj = Object.create(base);
  for (var p in target) {
    obj[p] = target[p];
  }
  return obj;
};
var _name = 'suite';
var suiteMap = {};
var s = function (name, baseName, extension) {
  if (suiteMap[name]) {
    throw new Error('duplicate suite name ' + name);
  }
  if (baseName && !suiteMap[baseName]) {
    throw new Error('inexistent base suite name ' + baseName);
  }
  extension[_name] = name;
  extension = p(extension, suiteMap[baseName] || {});
  suiteMap[name] = extension;
  return extension;
};

var attributesRepository_standard = {
  'input': {
    'placeholder': true
  },
  'paper-input': {
    'label': true,
    'error-message': true,
    'placeholder': true
  },
  'paper-textarea': {
    'label': true,
    'error-message': true,
    'placeholder': true
  },
  'paper-dropdown-menu': {
    'label': true
  },
  'paper-toast': {
    'text': true
  },
  'google-chart': {
    'options': true,
    'cols': true,
    'rows': true,
    'data': true
  },
  'platinum-push-messaging': {
    'title': true,
    'message': true
  },
  'json-data': {
    'any-attributes': true
  }
};

var attributesRepository_custom = p({
  'text-attribute-element': {
    'custom-text-attr1': true,
    'custom-text-attr2': true,
    'custom-text-attr3': true
  }
}, attributesRepository_standard);

var attributesRepository_saved;

var options_base = {
  replacingText: false,
  jsonSpace: 2,
  srcPath: 'test/src',
  force: false,
  dropHtml: false,
  constructAttributesRepository: false,
  attributesRepository: attributesRepository_standard,
  attributesRepositoryPath: null
};

var params_base = {
  suite: null,
  options: options_base,
  srcBaseDir: 'test/src',
  targets: [],
  expectedBaseDir: 'test/expected',
  expected: []
};

function appendJson (list) {
  if (list && Array.isArray(list)) {
    return list.map(function (item) {
      if (typeof item === 'string') {
        item = [ item, item.replace(/[.]html$/, '.json') ];
      }
      return item;
    }).reduce(function (prev, curr) {
      if (Array.isArray(curr)) {
        curr.forEach(function (item) {
          prev.push(item);
        });
      }
      else {
        prev.push(item);
      }
      return prev;
    }, []);
  }
  else {
    return list;
  }
}

function fromExpected (expectedBaseDir) {
  var buffer = fs.readFileSync(path.join(expectedBaseDir, 'attributes-repository.json'), 'utf8');
  return JSON.parse(buffer.toString());
}

var suites = [
  s(null, null, params_base),
  s('scan', null, {
    options: p({
      dropHtml: true,
      constructAttributesRepository: true,
      attributesRepository: {},
      attributesRepositoryPath: n2h('bower_components/i18n-behavior/i18n-attr-repo.html')
    }, options_base),
    targets: [ 'simple-text-element.html' ],
    attributesRepository: attributesRepository_standard
  }),
  s('gulp scan', 'scan', {
    gulp: true
  }),
  s('scan custom', 'scan', {
    targets: [ 'text-attribute-element.html' ],
    attributesRepository: attributesRepository_custom
  }),
  s('gulp scan custom', 'scan custom', {
    gulp: true
  }),
  s('simple-text-element', null, {
    options: p({
      replacingText: true,
      attributesRepository: attributesRepository_standard,
    }, options_base),
    targets: [ 'simple-text-element.html' ],
    expected: appendJson
  }),
  s('gulp simple-text-element', 'simple-text-element', {
    gulp: true
  }),
  s('i18n-dom-bind', 'simple-text-element', {
    options: p({
      replacingText: true,
      force: true,
      attributesRepository: attributesRepository_custom
    }, options_base),
    targets: [ 'basic-test.html' ],
    expected: [
      'basic-test.html',
      'simple-text-dom-bind.json',
      'simple-attribute-dom-bind.json',
      'compound-binding-dom-bind.json'
    ]
  }),
  s('gulp i18n-dom-bind', 'i18n-dom-bind', {
    gulp: true
  }),
  // test with i18n-behavior test fixtures
  // Note: Version of i18n-behavior must be carefully chosen in bower.json
  //       so that actual outputs can be checked against the preprocessed output
  //       from a STABLE and TEST-PASSING i18n-behavior release.  Otherwise,
  //       the following test suites would be meaningless because the expected outputs
  //       are actually just output by gulp-i18n-preprocess of an unstable version.
  s('gulp i18n-behavior/test/src scan', null, {
    gulp: true,
    options: p({
      srcPath: 'bower_components/i18n-behavior/test/src',
      dropHtml: true,
      constructAttributesRepository: true,
      attributesRepository: {},
      attributesRepositoryPath: n2h('bower_components/i18n-behavior/i18n-attr-repo.html')
    }, options_base),
    srcBaseDir: 'bower_components/i18n-behavior/test/src',
    targets: [ '**/*.html', '!**/*-test.html' ],
    expectedBaseDir: 'bower_components/i18n-behavior/test/preprocess',
    attributesRepository: fromExpected
  }),
  s('gulp i18n-behavior/test/src preprocess', null, {
    gulp: true,
    options: p({
      replacingText: true,
      srcPath: 'bower_components/i18n-behavior/test/src',
      dropHtml: false,
      constructAttributesRepository: false,
      attributesRepository: fromExpected
    }, options_base),
    srcBaseDir: 'bower_components/i18n-behavior/test/src',
    targets: [ '**/*.html', '!**/*-test.html' ],
    expectedBaseDir: 'bower_components/i18n-behavior/test/preprocess',
    expected: appendJson
  }),
  s('gulp i18n-behavior/test/src/*-test.html preprocess', 'gulp i18n-behavior/test/src preprocess', {
    options: p({
      replacingText: true,
      srcPath: 'bower_components/i18n-behavior/test/src',
      force: true,
      dropHtml: false,
      constructAttributesRepository: false,
      attributesRepository: fromExpected
    }, options_base),
    targets: [ '**/*-test.html' ],
    expected: [
      'basic-test.html',
      'simple-text-dom-bind.json',
      'simple-attribute-dom-bind.json',
      'compound-binding-dom-bind.json'
    ]
  })
];

suite('gulp-i18n-preprocess', function () {
  suites.forEach(function (params) {
    var preprocessor;
    var options = params.options;
    var inputs;
    var expandedInputPaths;
    var outputs;
    var expectedPaths;
    var expected;
    var attributesRepository;

    if (!params.suite) {
      return;
    }

    suite(params.suite, function () {
      suiteSetup(function () {
        if (params.gulp &&
          !params.options.constructAttributesRepository &&
          typeof params.options.attributesRepository === 'function') {
          options.attributesRepository = params.options.attributesRepository(params.expectedBaseDir);
        }
        preprocessor = i18nPreprocess(options);
        inputs = params.gulp ?
          params.targets.map(function (target) {
            return target.match(/^!/) ?
              '!' + [ params.srcBaseDir, target.substr(1) ].join('/') :
              [ params.srcBaseDir, target ].join('/')
          }) :
          params.targets.map(function (target) {
            return new gutil.File({
              cwd: __dirname,
              base: path.join(__dirname, n2h(target)),
              path: path.join(n2h(params.srcBaseDir), target),
              contents: fs.readFileSync(path.join(n2h(params.srcBaseDir), target))
            });
          });
        outputs = [];
        if (params.expected) {
          expectedPaths = undefined;
          if (!params.gulp &&
            typeof params.expected === 'function') {
            expectedPaths = params.expected(params.targets).map(function (outputPath) {
                return path.join(params.expectedBaseDir, n2h(outputPath));
              });
          }
          else if (Array.isArray(params.expected)) {
            expectedPaths = params.expected.map(function (outputPath) {
                return path.join(params.expectedBaseDir, n2h(outputPath));
              });
          }
          expected = expectedPaths ?
            expectedPaths.map(function (target) {
              return new gutil.File({
                cwd: __dirname,
                base: path.join(__dirname, n2h(target)),
                path: target,
                contents: fs.readFileSync(target)
              })
            }) : null;
        }
        if (params.gulp) {
          expandedInputPaths = [];
        }
        if (params.attributesRepository &&
            params.options && params.options.constructAttributesRepository) {
          attributesRepository = {};
          params.options.attributesRepository = attributesRepository;
        }
      });

      test('get a duplex stream', function () {
        assert.ok(isStream.duplex(preprocessor), 'preprocessor is a duplex stream');
      });

      if (params.gulp) {
        test('preprocess in gulp', function (done) {
          gulp.task('preprocess', function () {
            return gulp.src(inputs, { base: params.srcBaseDir })
              .pipe(through.obj(function (file, enc, callback) {
                expandedInputPaths.push(file.path);
                callback(null, file);
              }))
              .pipe(preprocessor)
              .pipe(through.obj(function (file, enc, callback) {
                assert.ok(file instanceof gutil.File, 'get a File instance for ' + file.path);
                convertToExpectedPath(file, params.srcBaseDir, params.expectedBaseDir);
                outputs.push(file);
                callback(null, file);
              }))
              .pipe(debug({ title: 'preprocess output:'}))
              .pipe(through.obj(function (file, enc, callback) {
                callback(null, null);
              }));
          });
          gulp.start.apply(gulp, [ 'preprocess', function () {
            gulp.reset();
            done();
          }]);
        });
      }
      else {
        test('get preprocessed files', function (done) {
          preprocessor.on('data', function (file) {
            assert.ok(file instanceof gutil.File, 'get a File instance for ' + file.path);
            convertToExpectedPath(file, params.srcBaseDir, params.expectedBaseDir);
            outputs.push(file);
          });

          preprocessor.on('end', done);

          inputs.forEach(function (file) {
            preprocessor.write(file);
          });

          preprocessor.end();
        });
      }

      if ((params.expected && params.expected.length > 0) ||
          !params.expected) {
        if (params.expected) {
          test('check preprocessed file list', function () {
            if (params.gulp) {
              if (typeof params.expected === 'function' &&
                  expandedInputPaths) {
                expectedPaths = params.expected(expandedInputPaths).map(function (target) {
                  var result = convertToExpectedPath(target, params.srcBaseDir, params.expectedBaseDir);
                  return result;
                });
              }
              else if (Array.isArray(params.expected)) {
                expectedPaths = params.expected.map(function (target) {
                  return path.join(params.expectedBaseDir, target);
                });
              }
            }
            outputs.forEach(function (file, index) {
              assert.equal(file.path, expectedPaths[index], expectedPaths[index] + ' is output');
            });
            assert.equal(outputs.length, expectedPaths.length,
              'get expected ' + expectedPaths.length + ' files');
          });
        }

        test('check preprocessed file contents', function () {
          outputs.forEach(function (file, index) {
            var expectedFile = expected ? expected[index] : null;
            if (!expected) {
              expectedFile = new gutil.File({
                cwd: __dirname,
                base: file.base,
                path: file.path,
                contents: fs.readFileSync(file.path)
              });
            }
            if (file.contents.toString() !== expectedFile.contents.toString()) {
              console.log('file.path = ' + file.path);
              console.log('expected = ' + expectedFile.contents.toString());
              console.log('actual = ' + file.contents.toString());
            }
            assert.equal(file.contents.toString(), expectedFile.contents.toString(),
              'get expected file contents for ' + expectedFile.path);
          });
        });
      }
      else {
        test('no outputs', function () {
          assert.equal(outputs.length, 0, 'get no outputs');
        });
      }

      if (params.attributesRepository) {
        test('check attributesRepository', function () {
          var expectedAttributesRepository;
          if (typeof params.attributesRepository === 'function') {
            expectedAttributesRepository = params.attributesRepository(params.expectedBaseDir);
          }
          else {
            expectedAttributesRepository = params.attributesRepository;
          }
          assert.deepEqual(attributesRepository,
            expectedAttributesRepository,
            'get expected attributesRepository');
        });
      }

      suiteTeardown(function () {
      });
    });
  });
});
<|endoftext|>


<commit_before>/* Environmental variables that help control this test:

FIREFOX_CHANNEL = empty (default NIGHTLY)
                  NIGHTLY
                  AURORA (often Developer Edition)
                  BETA
                  RELEASE

NO_CLOSE = if not empty then when the test is finished, the browser will not be closed

*/

const assert = require("assert");
const firefox = require("selenium-webdriver/firefox");
const webdriver = require("selenium-webdriver");
const { By, until } = webdriver;
// Uncomment the next line and others with `ServiceBuilder` to enable trace logs from Firefox and Geckodriver
// const { ServiceBuilder } = firefox;
const path = require("path");
const fs = require("fs");
const util = require("util");

const SHOOTER_BUTTON_ID = "pageAction-panel-screenshots";
// Applies to the old-style toolbar button:
const TOOLBAR_SHOOTER_BUTTON_ID = "screenshots_mozilla_org-browser-action";
const shooterSelector = By.css(`#${SHOOTER_BUTTON_ID}, #${TOOLBAR_SHOOTER_BUTTON_ID}`);
const SLIDE_IFRAME_ID = "firefox-screenshots-onboarding-iframe";
const PRESELECTION_IFRAME_ID = "firefox-screenshots-preselection-iframe";
const SELECTION_IFRAME_ID = "firefox-screenshots-selection-iframe";
const PREVIEW_IFRAME_ID = "firefox-screenshots-preview-iframe";
const backend = "http://localhost:10080";
const addonFileLocation = path.join(process.cwd(), "build", "screenshots-bootstrap.zip");
const downloadDir = path.join(process.cwd(), "test", "addon", ".artifacts");

function getDriver() {
  const channel = process.env.FIREFOX_CHANNEL || "NIGHTLY";
  if (!(channel in firefox.Channel)) {
    throw new Error(`Unknown channel: "${channel}"`);
  }

  // const servicebuilder = new ServiceBuilder().enableVerboseLogging(true).setStdio("inherit");

  const options = new firefox.Options()
    .setBinary(firefox.Channel[channel])
    .setPreference("extensions.legacy.enabled", true)
    .setPreference("xpinstall.signatures.required", false)
    .setPreference("browser.download.folderList", 2)
    .setPreference("browser.download.dir", downloadDir);

  // FIXME: should assert somehow that we have Firefox 54+

  const driver = new webdriver.Builder()
    // .setFirefoxService(servicebuilder)
    .withCapabilities({"moz:webdriverClick": true})
    .forBrowser("firefox")
    .setFirefoxOptions(options)
    .build();

  driver.installAddon(addonFileLocation);

  return driver;
}

function getChromeElement(driver, selector) {
  return driver.setContext(firefox.Context.CHROME)
    .then(() => driver.wait(until.elementLocated(selector)));
}

/** Calls finallyCallback() after the promise completes, successfully or not,
    returning the resolved or rejected promise as normal */
function promiseFinally(promise, finallyCallback) {
  return promise.then((result) => {
    finallyCallback();
    return result;
  }, (error) => {
    finallyCallback();
    throw error;
  });
}

/** This will start Screenshots, and return a promise that
    will be true if the onboarding slides are active, or false
    if not.  An error will be returned if it does not start
    successfully. */
function startScreenshots(driver) {
  return promiseFinally(
    getChromeElement(driver, shooterSelector).then((button) => {
      return button.click();
    }),
    () => {
      driver.setContext(firefox.Context.CONTENT);
    }
  ).then(() => {
    return driver.wait(() => {
      return Promise.all([
        driver.findElements(By.id(SLIDE_IFRAME_ID)),
        driver.findElements(By.id(PRESELECTION_IFRAME_ID))
      ]).then((results) => {
        return results[0].length || results[1].length;
      });
    });
  }).then(() => {
    return driver.findElements(By.id(SLIDE_IFRAME_ID));
  }).then((elements) => {
    return !!elements.length;
  });
}

function focusIframe(driver, iframeId) {
  return driver.switchTo().defaultContent().then(() => {
    return driver.findElement(By.id(iframeId))
  }).then((iframe) => {
    return driver.switchTo().frame(iframe);
  });
}

function closeTab(driver) {
  return driver.close()
  .then(() => driver.getAllWindowHandles())
  .then((tabs) => driver.switchTo().window(tabs[tabs.length - 1]))
  .then(() => driver.switchTo().defaultContent())
}

function skipOnboarding(driver) {
  return focusIframe(driver, SLIDE_IFRAME_ID).then(() => {
    return driver.findElement(By.id("skip"));
  }).then((skipLink) => {
    return skipLink.click();
  }).then(() => {
    return driver.switchTo().defaultContent();
  }).then(() => {
    return driver.wait(until.elementLocated(By.id(PRESELECTION_IFRAME_ID)));
  });
}

function startAutoSelectionShot(driver) {
  return driver.get(backend)
  .then(() => startScreenshots(driver))
  .then(() => driver.wait(until.ableToSwitchToFrame(By.id(PRESELECTION_IFRAME_ID))))
  .then(() => driver.wait(until.elementLocated(By.css(".visible"))))
  .then(() => driver.actions().move({x: 100, y: 100}).click().perform())
  .then(() => driver.switchTo().defaultContent())
  .then(() => driver.wait(until.ableToSwitchToFrame(By.id(SELECTION_IFRAME_ID))));
}

/** Waits when ready, calls creator to create the shot, waits for the resulting
    promise to complete, then watches for the
    new tab to open and load, and returns the shot URL.  The new tab
    will be switched to by the driver */
function expectCreatedShot(driver, creator) {
  // We keep track of how many tabs we start with, so we can detect when
  // a new tab is added (which signals that the saving worked)
  let startingTabCount;
  return driver.getAllWindowHandles().then((tabs) => {
    startingTabCount = tabs.length;
    return creator();
  }).then(() => {
    return driver.wait(() => {
      return driver.getAllWindowHandles().then((tabs) => {
        // On CircleCI there is consistently one weird tab with the id "22"
        // It's not a normal tab, so we ignore it:
        tabs = tabs.filter((t) => t !== "22");
        return tabs.length > startingTabCount;
      });
    });
  }).then(() => {
    return driver.getAllWindowHandles();
  }).then((tabs) => {
    tabs = tabs.filter((t) => t !== "22");
    if (tabs.length < startingTabCount) {
      throw new Error("New tab did not open");
    }
    return driver.switchTo().window(tabs[tabs.length - 1]);
  }).then(() => {
    return driver.wait(() => {
      return driver.getCurrentUrl().then((url) => {
        return url !== "about:blank" && !url.includes("/creating/")
      });
    });
  }).then(() => {
    return driver.getCurrentUrl();
  });
}

describe("Test Screenshots", function() {
  this.timeout(120000);
  let driver;

  before(function() {
    return getDriver().then((aDriver) => {
      driver = aDriver;
    });
  });

  after(function() {
    if (!process.env.NO_CLOSE) {
      return driver.quit();
    }
    console.info("Note: leaving browser open");
    return null;
  });

  it("should find the add-on button", function(done) {
    this.timeout(15000);
    promiseFinally(
      getChromeElement(driver, shooterSelector)
      .then((button) => button.getAttribute("label"))
      .then((label) => {
        if (label === "Take a Screenshot") {
          assert.equal(label, "Take a Screenshot");
        } else {
          assert.equal(label, "Firefox Screenshots");
        }
        done();
      }),
      () => {
        return driver.setContext(firefox.Context.CONTENT)
          .then(() => driver.getAllWindowHandles())
          .then((tabs) => driver.switchTo().window(tabs[tabs.length - 1]))
          .then(() => driver.switchTo().defaultContent());
      }).catch(done);
  });

  it("should take a shot", function(done) {
    driver.get(backend).then(() => {
      return startScreenshots(driver);
    }).then((onboarding) => {
      if (!onboarding) {
        throw new Error("Expected to get onboarding");
      }
      return skipOnboarding(driver);
    }).then(() => {
      return driver.wait(
        until.ableToSwitchToFrame(By.id(PRESELECTION_IFRAME_ID))
      );
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css(".visible"))
      );
    }).then((visibleButton) => {
      return visibleButton.click();
    }).then(() => {
      return driver.switchTo().defaultContent();
    }).then(() => {
      return driver.wait(
        until.ableToSwitchToFrame(By.id(PREVIEW_IFRAME_ID))
      );
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css(".preview-button-save"))
      );
    }).then((saveButton) => {
      return driver.wait(
        until.elementIsVisible(saveButton)
      );
    }).then((saveButton) => {
      return expectCreatedShot(driver, () => {
        saveButton.click();
      });
    }).then((shotUrl) => {
      assert(shotUrl.startsWith(backend), `Got url ${shotUrl} that doesn't start with ${backend}`);
      const restUrl = shotUrl.substr(backend.length);
      if (!/^\/[^/]+\/localhost$/.test(restUrl)) {
        throw new Error(`Unexpected URL: ${shotUrl}`);
      }
      done();
    }).catch(done);
  });

  it("should take an auto selection shot", function(done) {
    startAutoSelectionShot(driver).then(() => {
      return driver.wait(until.elementLocated(By.css(".highlight-button-save")));
    }).then((saveButton) => {
      return expectCreatedShot(driver, () => {
        saveButton.click();
      });
    }).then((shotUrl) => {
      assert(shotUrl.startsWith(backend), `Got url ${shotUrl} that doesn't start with ${backend}`);
      const restUrl = shotUrl.substr(backend.length);
      if (!/^\/[^/]+\/localhost$/.test(restUrl)) {
        throw new Error(`Unexpected URL: ${shotUrl}`);
      }
      done();
    }).catch(done);
  });

  it("should navigate to My Shots", function(done) {
    let currentTabs, startingTabCount;
    driver.getAllWindowHandles().then(tabs => {
      startingTabCount = tabs.length;
    }).then(() => {
      return driver.get(backend);
    }).then(() => {
      return startScreenshots(driver);
    }).then(() => {
      return driver.wait(
        until.ableToSwitchToFrame(By.id(PRESELECTION_IFRAME_ID))
      );
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css(".myshots-button"))
      );
    }).then(myShotsButton => {
      return myShotsButton.click();
    }).then(() => {
      return driver.wait(
        () => {
          return driver.getAllWindowHandles().then(tabs => {
            currentTabs = tabs;
            return currentTabs.length > startingTabCount;
          });
        }
      );
    }).then(() => {
      return driver.switchTo().window(currentTabs[currentTabs.length - 1]);
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css("#shot-index-page"))
      );
    }).then(() => {
      return driver.getCurrentUrl();
    }).then(url => {
      assert.equal(url, `${backend}/shots`, `Navigated to ${url} instead of My Shots at ${backend}/shots`);
      done();
    }).catch(done);
  });

  it("should download a shot", function(done) {
    const startingFileCount = fs.readdirSync(downloadDir).length;
    const filenameRegex = /^Screenshot.+ Firefox Screenshots\.png$/;
    let files;
    startAutoSelectionShot(driver)
    .then(() => driver.wait(until.elementLocated(By.css(".highlight-button-download"))))
    .then(downloadButton => downloadButton.click())
    .then(() => driver.wait(() => {
      return util.promisify(fs.readdir)(downloadDir).then(foundFiles => {
        files = foundFiles;
        return (files.length > startingFileCount);
      });
    }, 2000))
    .then(() => {
      // check for a file created within a couple seconds
      // @TODO maybe check the dimensions of the image if we wanna get fancy
      const matches = files.filter(filename => {
        if (!filenameRegex.test(filename)) {
          return false;
        }
        const stat = fs.statSync(path.join(downloadDir, filename));
        return ((stat.mtime.getTime() - Date.now()) < 2000);
      });
      assert(matches.length, `Shot was not downloaded to ${downloadDir}`);
      // clean up the dir
      const unlinkPromise = util.promisify(fs.unlink);
      files.forEach(filename => {
        filename !== ".gitignore" && unlinkPromise(path.join(downloadDir, filename));
      });
    })
    // Downloading seems to put the browser in a weird state that we can't reset
    // unless the tab is closed
    .then(() => closeTab(driver))
    .then(() => done())
    .catch(done);
  });

  it("should remain on original tab with UI overlay on save failure", function(done) {
    const badAddon = path.join(process.cwd(), "build", "screenshots-bootstrap-server-down.zip");
    driver.installAddon(badAddon)
    .then(() => startAutoSelectionShot(driver))
    .then(() => driver.wait(until.elementLocated(By.css(".highlight-button-save"))))
    .then((saveButton) => saveButton.click())
    .then(() => driver.getAllWindowHandles())
    .then((tabs) => driver.switchTo().window(tabs[tabs.length - 1]))
    .then(() => driver.switchTo().defaultContent())
    .then(() => driver.findElement(By.id(PRESELECTION_IFRAME_ID)))
    .then(selectionFrame => assert(selectionFrame.isDisplayed()))
    .then(() => driver.getCurrentUrl())
    .then((url) => {
      assert.equal(url, `${backend}/`, `Navigated away from ${backend}`);

      // Doing this in case there are tests after this one.
      driver.installAddon(addonFileLocation).then(() => done()).catch(done);
    }).catch(done);
  });
});
<commit_msg>Disable three tests temporarily. (#4240)<commit_after>/* Environmental variables that help control this test:

FIREFOX_CHANNEL = empty (default NIGHTLY)
                  NIGHTLY
                  AURORA (often Developer Edition)
                  BETA
                  RELEASE

NO_CLOSE = if not empty then when the test is finished, the browser will not be closed

*/

const assert = require("assert");
const firefox = require("selenium-webdriver/firefox");
const webdriver = require("selenium-webdriver");
const { By, until } = webdriver;
// Uncomment the next line and others with `ServiceBuilder` to enable trace logs from Firefox and Geckodriver
// const { ServiceBuilder } = firefox;
const path = require("path");
const fs = require("fs");
const util = require("util");

const SHOOTER_BUTTON_ID = "pageAction-panel-screenshots";
// Applies to the old-style toolbar button:
const TOOLBAR_SHOOTER_BUTTON_ID = "screenshots_mozilla_org-browser-action";
const shooterSelector = By.css(`#${SHOOTER_BUTTON_ID}, #${TOOLBAR_SHOOTER_BUTTON_ID}`);
const SLIDE_IFRAME_ID = "firefox-screenshots-onboarding-iframe";
const PRESELECTION_IFRAME_ID = "firefox-screenshots-preselection-iframe";
const SELECTION_IFRAME_ID = "firefox-screenshots-selection-iframe";
const PREVIEW_IFRAME_ID = "firefox-screenshots-preview-iframe";
const backend = "http://localhost:10080";
const addonFileLocation = path.join(process.cwd(), "build", "screenshots-bootstrap.zip");
const downloadDir = path.join(process.cwd(), "test", "addon", ".artifacts");

function getDriver() {
  const channel = process.env.FIREFOX_CHANNEL || "NIGHTLY";
  if (!(channel in firefox.Channel)) {
    throw new Error(`Unknown channel: "${channel}"`);
  }

  // const servicebuilder = new ServiceBuilder().enableVerboseLogging(true).setStdio("inherit");

  const options = new firefox.Options()
    .setBinary(firefox.Channel[channel])
    .setPreference("extensions.legacy.enabled", true)
    .setPreference("xpinstall.signatures.required", false)
    .setPreference("browser.download.folderList", 2)
    .setPreference("browser.download.dir", downloadDir);

  // FIXME: should assert somehow that we have Firefox 54+

  const driver = new webdriver.Builder()
    // .setFirefoxService(servicebuilder)
    .withCapabilities({"moz:webdriverClick": true})
    .forBrowser("firefox")
    .setFirefoxOptions(options)
    .build();

  driver.installAddon(addonFileLocation);

  return driver;
}

function getChromeElement(driver, selector) {
  return driver.setContext(firefox.Context.CHROME)
    .then(() => driver.wait(until.elementLocated(selector)));
}

/** Calls finallyCallback() after the promise completes, successfully or not,
    returning the resolved or rejected promise as normal */
function promiseFinally(promise, finallyCallback) {
  return promise.then((result) => {
    finallyCallback();
    return result;
  }, (error) => {
    finallyCallback();
    throw error;
  });
}

/** This will start Screenshots, and return a promise that
    will be true if the onboarding slides are active, or false
    if not.  An error will be returned if it does not start
    successfully. */
function startScreenshots(driver) {
  return promiseFinally(
    getChromeElement(driver, shooterSelector).then((button) => {
      return button.click();
    }),
    () => {
      driver.setContext(firefox.Context.CONTENT);
    }
  ).then(() => {
    return driver.wait(() => {
      return Promise.all([
        driver.findElements(By.id(SLIDE_IFRAME_ID)),
        driver.findElements(By.id(PRESELECTION_IFRAME_ID))
      ]).then((results) => {
        return results[0].length || results[1].length;
      });
    });
  }).then(() => {
    return driver.findElements(By.id(SLIDE_IFRAME_ID));
  }).then((elements) => {
    return !!elements.length;
  });
}

function focusIframe(driver, iframeId) {
  return driver.switchTo().defaultContent().then(() => {
    return driver.findElement(By.id(iframeId))
  }).then((iframe) => {
    return driver.switchTo().frame(iframe);
  });
}

function closeTab(driver) {
  return driver.close()
  .then(() => driver.getAllWindowHandles())
  .then((tabs) => driver.switchTo().window(tabs[tabs.length - 1]))
  .then(() => driver.switchTo().defaultContent())
}

function skipOnboarding(driver) {
  return focusIframe(driver, SLIDE_IFRAME_ID).then(() => {
    return driver.findElement(By.id("skip"));
  }).then((skipLink) => {
    return skipLink.click();
  }).then(() => {
    return driver.switchTo().defaultContent();
  }).then(() => {
    return driver.wait(until.elementLocated(By.id(PRESELECTION_IFRAME_ID)));
  });
}

function startAutoSelectionShot(driver) {
  return driver.get(backend)
  .then(() => startScreenshots(driver))
  .then(() => driver.wait(until.ableToSwitchToFrame(By.id(PRESELECTION_IFRAME_ID))))
  .then(() => driver.wait(until.elementLocated(By.css(".visible"))))
  .then(() => driver.actions().move({x: 100, y: 100}).click().perform())
  .then(() => driver.switchTo().defaultContent())
  .then(() => driver.wait(until.ableToSwitchToFrame(By.id(SELECTION_IFRAME_ID))));
}

/** Waits when ready, calls creator to create the shot, waits for the resulting
    promise to complete, then watches for the
    new tab to open and load, and returns the shot URL.  The new tab
    will be switched to by the driver */
function expectCreatedShot(driver, creator) {
  // We keep track of how many tabs we start with, so we can detect when
  // a new tab is added (which signals that the saving worked)
  let startingTabCount;
  return driver.getAllWindowHandles().then((tabs) => {
    startingTabCount = tabs.length;
    return creator();
  }).then(() => {
    return driver.wait(() => {
      return driver.getAllWindowHandles().then((tabs) => {
        // On CircleCI there is consistently one weird tab with the id "22"
        // It's not a normal tab, so we ignore it:
        tabs = tabs.filter((t) => t !== "22");
        return tabs.length > startingTabCount;
      });
    });
  }).then(() => {
    return driver.getAllWindowHandles();
  }).then((tabs) => {
    tabs = tabs.filter((t) => t !== "22");
    if (tabs.length < startingTabCount) {
      throw new Error("New tab did not open");
    }
    return driver.switchTo().window(tabs[tabs.length - 1]);
  }).then(() => {
    return driver.wait(() => {
      return driver.getCurrentUrl().then((url) => {
        return url !== "about:blank" && !url.includes("/creating/")
      });
    });
  }).then(() => {
    return driver.getCurrentUrl();
  });
}

describe("Test Screenshots", function() {
  this.timeout(120000);
  let driver;

  before(function() {
    return getDriver().then((aDriver) => {
      driver = aDriver;
    });
  });

  after(function() {
    if (!process.env.NO_CLOSE) {
      return driver.quit();
    }
    console.info("Note: leaving browser open");
    return null;
  });

  it("should find the add-on button", function(done) {
    this.timeout(15000);
    promiseFinally(
      getChromeElement(driver, shooterSelector)
      .then((button) => button.getAttribute("label"))
      .then((label) => {
        if (label === "Take a Screenshot") {
          assert.equal(label, "Take a Screenshot");
        } else {
          assert.equal(label, "Firefox Screenshots");
        }
        done();
      }),
      () => {
        return driver.setContext(firefox.Context.CONTENT)
          .then(() => driver.getAllWindowHandles())
          .then((tabs) => driver.switchTo().window(tabs[tabs.length - 1]))
          .then(() => driver.switchTo().defaultContent());
      }).catch(done);
  });

  it("should take a shot", function(done) {
    driver.get(backend).then(() => {
      return startScreenshots(driver);
    }).then((onboarding) => {
      if (!onboarding) {
        throw new Error("Expected to get onboarding");
      }
      return skipOnboarding(driver);
    }).then(() => {
      return driver.wait(
        until.ableToSwitchToFrame(By.id(PRESELECTION_IFRAME_ID))
      );
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css(".visible"))
      );
    }).then((visibleButton) => {
      return visibleButton.click();
    }).then(() => {
      return driver.switchTo().defaultContent();
    }).then(() => {
      return driver.wait(
        until.ableToSwitchToFrame(By.id(PREVIEW_IFRAME_ID))
      );
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css(".preview-button-save"))
      );
    }).then((saveButton) => {
      return driver.wait(
        until.elementIsVisible(saveButton)
      );
    }).then((saveButton) => {
      return expectCreatedShot(driver, () => {
        saveButton.click();
      });
    }).then((shotUrl) => {
      assert(shotUrl.startsWith(backend), `Got url ${shotUrl} that doesn't start with ${backend}`);
      const restUrl = shotUrl.substr(backend.length);
      if (!/^\/[^/]+\/localhost$/.test(restUrl)) {
        throw new Error(`Unexpected URL: ${shotUrl}`);
      }
      done();
    }).catch(done);
  });

  // Temporarily disabled.  See https://github.com/mozilla-services/screenshots/issues/4240
  xit("should take an auto selection shot", function(done) {
    startAutoSelectionShot(driver).then(() => {
      return driver.wait(until.elementLocated(By.css(".highlight-button-save")));
    }).then((saveButton) => {
      return expectCreatedShot(driver, () => {
        saveButton.click();
      });
    }).then((shotUrl) => {
      assert(shotUrl.startsWith(backend), `Got url ${shotUrl} that doesn't start with ${backend}`);
      const restUrl = shotUrl.substr(backend.length);
      if (!/^\/[^/]+\/localhost$/.test(restUrl)) {
        throw new Error(`Unexpected URL: ${shotUrl}`);
      }
      done();
    }).catch(done);
  });

  it("should navigate to My Shots", function(done) {
    let currentTabs, startingTabCount;
    driver.getAllWindowHandles().then(tabs => {
      startingTabCount = tabs.length;
    }).then(() => {
      return driver.get(backend);
    }).then(() => {
      return startScreenshots(driver);
    }).then(() => {
      return driver.wait(
        until.ableToSwitchToFrame(By.id(PRESELECTION_IFRAME_ID))
      );
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css(".myshots-button"))
      );
    }).then(myShotsButton => {
      return myShotsButton.click();
    }).then(() => {
      return driver.wait(
        () => {
          return driver.getAllWindowHandles().then(tabs => {
            currentTabs = tabs;
            return currentTabs.length > startingTabCount;
          });
        }
      );
    }).then(() => {
      return driver.switchTo().window(currentTabs[currentTabs.length - 1]);
    }).then(() => {
      return driver.wait(
        until.elementLocated(By.css("#shot-index-page"))
      );
    }).then(() => {
      return driver.getCurrentUrl();
    }).then(url => {
      assert.equal(url, `${backend}/shots`, `Navigated to ${url} instead of My Shots at ${backend}/shots`);
      done();
    }).catch(done);
  });

  // Temporarily disabled.  See https://github.com/mozilla-services/screenshots/issues/4240
  xit("should download a shot", function(done) {
    const startingFileCount = fs.readdirSync(downloadDir).length;
    const filenameRegex = /^Screenshot.+ Firefox Screenshots\.png$/;
    let files;
    startAutoSelectionShot(driver)
    .then(() => driver.wait(until.elementLocated(By.css(".highlight-button-download"))))
    .then(downloadButton => downloadButton.click())
    .then(() => driver.wait(() => {
      return util.promisify(fs.readdir)(downloadDir).then(foundFiles => {
        files = foundFiles;
        return (files.length > startingFileCount);
      });
    }, 2000))
    .then(() => {
      // check for a file created within a couple seconds
      // @TODO maybe check the dimensions of the image if we wanna get fancy
      const matches = files.filter(filename => {
        if (!filenameRegex.test(filename)) {
          return false;
        }
        const stat = fs.statSync(path.join(downloadDir, filename));
        return ((stat.mtime.getTime() - Date.now()) < 2000);
      });
      assert(matches.length, `Shot was not downloaded to ${downloadDir}`);
      // clean up the dir
      const unlinkPromise = util.promisify(fs.unlink);
      files.forEach(filename => {
        filename !== ".gitignore" && unlinkPromise(path.join(downloadDir, filename));
      });
    })
    // Downloading seems to put the browser in a weird state that we can't reset
    // unless the tab is closed
    .then(() => closeTab(driver))
    .then(() => done())
    .catch(done);
  });

  // Temporarily disabled.  See https://github.com/mozilla-services/screenshots/issues/4240
  xit("should remain on original tab with UI overlay on save failure", function(done) {
    const badAddon = path.join(process.cwd(), "build", "screenshots-bootstrap-server-down.zip");
    driver.installAddon(badAddon)
    .then(() => startAutoSelectionShot(driver))
    .then(() => driver.wait(until.elementLocated(By.css(".highlight-button-save"))))
    .then((saveButton) => saveButton.click())
    .then(() => driver.getAllWindowHandles())
    .then((tabs) => driver.switchTo().window(tabs[tabs.length - 1]))
    .then(() => driver.switchTo().defaultContent())
    .then(() => driver.findElement(By.id(PRESELECTION_IFRAME_ID)))
    .then(selectionFrame => assert(selectionFrame.isDisplayed()))
    .then(() => driver.getCurrentUrl())
    .then((url) => {
      assert.equal(url, `${backend}/`, `Navigated away from ${backend}`);

      // Doing this in case there are tests after this one.
      driver.installAddon(addonFileLocation).then(() => done()).catch(done);
    }).catch(done);
  });
});
<|endoftext|>


<commit_before>function fakeAjax(options) { jasmine.FakeAjax.initContext(options); }
function clearContext() { fakeAjax({}); }
function loadTestData(selector, url) { return jasmine.FakeAjax.loadTestData(selector, url); }
function latestAjax() { return jasmine.FakeAjax.latestAjax(); }
function latestAjaxWithUrlMatching(partialUrl) { return jasmine.FakeAjax.latestAjaxWithUrlMatching(partialUrl); }

afterEach(clearContext);

(function($, jasmine) {
  jasmine.FakeAjax = {
    realAjax: $.ajax,
    initContext: initContext,
    loadTestData: loadTestData,
    latestAjax: latestAjax,
    latestAjaxWithUrlMatching: latestAjaxWithUrlMatching,
    log: new Logger()
  };

  $.ajax = function(options) {
    jasmine.FakeAjax.recordedSession.addAjaxCall(options);
    var urls = jasmine.FakeAjax.urls;
    if (!urls) {
      jasmine.FakeAjax.log.warn("There are no ajax url mappings defined.");
    } else if (!urls[options.url]) {
      jasmine.FakeAjax.log.warn("Applying default success data for url '" + options.url + "'.");
      if (!options.success) {
        jasmine.FakeAjax.log.error("Ajax success handler is not defined in system under test for url '" + options.url + "'. See firebug script stack for more info.");
      } else {
        options.success("default success data");
      }
    } else if (urls[options.url].successData) {
      options.success(urls[options.url].successData);
    } else if (urls[options.url].errorMessage) {
      options.error({responseText: urls[options.url].errorMessage});
    } else {
      jasmine.FakeAjax.log.error("Unknown mapping value for url '" + options.url + "'. Expected either successData or errorMessage.");
    }
  };

  function initContext(options) {
    this.urls = options.urls;
    this.recordedSession = new RecordedSession();
  }

  function loadTestData(selector, url) {
    var fixture;
    jasmine.FakeAjax.realAjax({
      url: url,
      async: false,
      success: function(data) {
        fixture = data;
      },
      error: function() {
        jasmine.FakeAjax.log.error("Failed loading test data by url '" + url + "'.");
      }
    });
    var testDataContainer = $(fixture).find(selector);
    if (testDataContainer.length > 0) {
      return testDataContainer.html();
    } else {
      jasmine.FakeAjax.log.error("Failed loading test data by selector: '" + selector + "' from url: '" + url + "'. Whole fixture: " + fixture);
      return undefined;
    }
  }

  function latestAjax() {
    return lastDecoded(jasmine.FakeAjax.recordedSession.ajaxCalls);
  }

  function latestAjaxWithUrlMatching(partialUrl) {
    return lastDecoded(jasmine.FakeAjax.recordedSession.ajaxCalls.filter(function(ajaxOptions) {
      return ajaxOptions.url.match(partialUrl);
    }));
  }

  function lastDecoded(list) {
    return $.URLDecode(list[list.length - 1]);
  }

  function RecordedSession() {
    this.ajaxCalls = [];

    this.addAjaxCall = function(ajaxOptions) {
      this.ajaxCalls.push(ajaxOptions);
    }
  }

  function Logger() {
    function error(message) {
      withFirebugConsole(function(c) {
        c.error(message);
        debugger;
      });
    }

    function warn(message) {
      withFirebugConsole(function(c) {
        c.warn(message);
      });
    }

    function withFirebugConsole(callback) {
      if (window.console) {
        callback(window.console);
      }
    }
  }
})(jQuery, jasmine);
<commit_msg>Enhance cross browser compliance by using jquery's (instead of native) .filter.<commit_after>function fakeAjax(options) { jasmine.FakeAjax.initContext(options); }
function clearContext() { fakeAjax({}); }
function loadTestData(selector, url) { return jasmine.FakeAjax.loadTestData(selector, url); }
function latestAjax() { return jasmine.FakeAjax.latestAjax(); }
function latestAjaxWithUrlMatching(partialUrl) { return jasmine.FakeAjax.latestAjaxWithUrlMatching(partialUrl); }

afterEach(clearContext);

(function($, jasmine) {
  jasmine.FakeAjax = {
    realAjax: $.ajax,
    initContext: initContext,
    loadTestData: loadTestData,
    latestAjax: latestAjax,
    latestAjaxWithUrlMatching: latestAjaxWithUrlMatching,
    log: new Logger()
  };

  $.ajax = function(options) {
    jasmine.FakeAjax.recordedSession.addAjaxCall(options);
    var urls = jasmine.FakeAjax.urls;
    if (!urls) {
      jasmine.FakeAjax.log.warn("There are no ajax url mappings defined.");
    } else if (!urls[options.url]) {
      jasmine.FakeAjax.log.warn("Applying default success data for url '" + options.url + "'.");
      if (!options.success) {
        jasmine.FakeAjax.log.error("Ajax success handler is not defined in system under test for url '" + options.url + "'. See firebug script stack for more info.");
      } else {
        options.success("default success data");
      }
    } else if (urls[options.url].successData) {
      options.success(urls[options.url].successData);
    } else if (urls[options.url].errorMessage) {
      options.error({responseText: urls[options.url].errorMessage});
    } else {
      jasmine.FakeAjax.log.error("Unknown mapping value for url '" + options.url + "'. Expected either successData or errorMessage.");
    }
  };

  function initContext(options) {
    this.urls = options.urls;
    this.recordedSession = new RecordedSession();
  }

  function loadTestData(selector, url) {
    var fixture;
    jasmine.FakeAjax.realAjax({
      url: url,
      async: false,
      success: function(data) {
        fixture = data;
      },
      error: function() {
        jasmine.FakeAjax.log.error("Failed loading test data by url '" + url + "'.");
      }
    });
    var testDataContainer = $(fixture).find(selector);
    if (testDataContainer.length > 0) {
      return testDataContainer.html();
    } else {
      jasmine.FakeAjax.log.error("Failed loading test data by selector: '" + selector + "' from url: '" + url + "'. Whole fixture: " + fixture);
      return undefined;
    }
  }

  function latestAjax() {
    return lastDecoded(jasmine.FakeAjax.recordedSession.ajaxCalls);
  }

  function latestAjaxWithUrlMatching(partialUrl) {
    return lastDecoded($(jasmine.FakeAjax.recordedSession.ajaxCalls).filter(function(index, ajaxOptions) {
      return ajaxOptions.url.match(partialUrl);
    }));
  }

  function lastDecoded(list) {
    return $.URLDecode(list[list.length - 1]);
  }

  function RecordedSession() {
    this.ajaxCalls = [];

    this.addAjaxCall = function(ajaxOptions) {
      this.ajaxCalls.push(ajaxOptions);
    }
  }

  function Logger() {
    function error(message) {
      withFirebugConsole(function(c) {
        c.error(message);
        debugger;
      });
    }

    function warn(message) {
      withFirebugConsole(function(c) {
        c.warn(message);
      });
    }

    function withFirebugConsole(callback) {
      if (window.console) {
        callback(window.console);
      }
    }
  }
})(jQuery, jasmine);
<|endoftext|>


<commit_before>const winston = require('winston');
const j79 = require('j79-utils');

const settings = require('./settings');

function logFormatter(options) {
	return j79.rawNowISODate() + ' [' + options.level.toUpperCase() + '] ' + (options.message ? options.message : '');
}

function init() {
	// removing existing console transport
	winston.remove(winston.transports.Console);

	// add new console transport
	winston.add(winston.transports.Console, {
		formatter: logFormatter
	});

	// loading log setting
	const logFile = settings.get(settings.LOG_FILE);
	const rollingSize = settings.get(settings.LOG_ROLLING_SIZE_KB); // 0 by default
	const maxLogFiles = settings.get(settings.MAX_LOG_FILES); // 999 by default
	const logLevel = settings.get(settings.LOG_LEVEL); // info by default

	// adding file transport
	winston.add(winston.transports.File, {
		filename: logFile,
		formatter: logFormatter,
		json: false,
		tailable: rollingSize > 0,
		maxsize: rollingSize * 1024,
		maxFiles: maxLogFiles
	});

	// setting up log level
	winston.level = logLevel;

	winston.debug('Log is set up');
}

function isLogLevel(level) {
	return winston.levels[winston.level] >= winston.levels[level];
}

function getAvailLevels() {
	return Object.keys(winston.levels);
}

function logHttpRequest(req, res, next) {
	winston.debug("[%s] request is accepted. [url=%s], [clientHost=%s]", req.method.toUpperCase(), req.url, req.connection.remoteAddress);
	next();
}

// --------------------------------------------------------------------------------
module.exports.init = init;
module.exports.log = winston;
module.exports.logHttpRequest = logHttpRequest;
module.exports.isLogLevel = isLogLevel;
module.exports.getAvailLevels = getAvailLevels;
// --------------------------------------------------------------------------------<commit_msg>- removed redundant comments<commit_after>const winston = require('winston');
const j79 = require('j79-utils');

const settings = require('./settings');

function logFormatter(options) {
	return j79.rawNowISODate() + ' [' + options.level.toUpperCase() + '] ' + (options.message ? options.message : '');
}

function init() {
	// removing existing console transport
	winston.remove(winston.transports.Console);

	// add new console transport
	winston.add(winston.transports.Console, {
		formatter: logFormatter
	});

	// loading log setting
	const logFile = settings.get(settings.LOG_FILE);
	const rollingSize = settings.get(settings.LOG_ROLLING_SIZE_KB);
	const maxLogFiles = settings.get(settings.MAX_LOG_FILES);
	const logLevel = settings.get(settings.LOG_LEVEL);

	// adding file transport
	winston.add(winston.transports.File, {
		filename: logFile,
		formatter: logFormatter,
		json: false,
		tailable: rollingSize > 0,
		maxsize: rollingSize * 1024,
		maxFiles: maxLogFiles
	});

	// setting up log level
	winston.level = logLevel;

	winston.debug('Log is set up');
}

function isLogLevel(level) {
	return winston.levels[winston.level] >= winston.levels[level];
}

function getAvailLevels() {
	return Object.keys(winston.levels);
}

function logHttpRequest(req, res, next) {
	winston.debug("[%s] request is accepted. [url=%s], [clientHost=%s]", req.method.toUpperCase(), req.url, req.connection.remoteAddress);
	next();
}

// --------------------------------------------------------------------------------
module.exports.init = init;
module.exports.log = winston;
module.exports.logHttpRequest = logHttpRequest;
module.exports.isLogLevel = isLogLevel;
module.exports.getAvailLevels = getAvailLevels;
// --------------------------------------------------------------------------------<|endoftext|>