<commit_before>define(
  'ephox.darwin.navigation.BrTags',

  [
    'ephox.fussy.api.SelectionRange',
    'ephox.fussy.api.Situ',
    'ephox.oath.proximity.Awareness',
    'ephox.peanut.Fun',
    'ephox.perhaps.Option',
    'ephox.phoenix.api.dom.DomGather',
    'ephox.sugar.api.Node',
    'ephox.sugar.api.Text',
    'ephox.sugar.api.Traverse'
  ],

  function (SelectionRange, Situ, Awareness, Fun, Option, DomGather, Node, Text, Traverse) {
    var isBr = function (elem) {
      return Node.name(elem) === 'br';
    };

    var gatherer = function (cand, gather, isRoot) {
      return gather(cand, isRoot).bind(function (target) {
        return Node.isText(target) && Text.get(target).trim().length === 0 ? gatherer(target, gather, isRoot) : Option.some(target);
      });
    };

    var locate = function (element) {
      return Traverse.parent(element).bind(function (parent) {
        return Traverse.findIndex(element).map(function (index) {
          return {
            parent: Fun.constant(parent),
            index: Fun.constant(index)
          };
        });
      });
    };

    var handleBr = function (isRoot, element, traverse, gather, relative) {
      // 1. Has a neighbouring sibling ... position relative to neighbouring element
      // 2. Has no neighbouring sibling ... position relative to gathered element
      return traverse(element).orThunk(function () {
        return gatherer(element, gather, isRoot);
      }).map(relative);
    };

    var findBr = function (element, offset) {
      return Traverse.child(element, offset).filter(isBr).orThunk(function () {
        // Can be either side of the br, and still be a br.
        return Traverse.child(element, offset-1).filter(isBr);
      });
    };

    var handleParent = function (isRoot, element, offset, traverse, gather, relative) {
      // 1. Has no neighbouring sibling, position relative to gathered element
      // 2. Has a neighbouring sibling, position at the neighbouring sibling with respect to parent
      return findBr(element, offset).bind(function (br) {
        return locate(br).bind(function (info) {
          return traverse(br).fold(function () {
            return gatherer(br, gather, isRoot).map(relative);
          }, function (_) {
            return Option.some(Situ.on(info.parent(), info.index()));
          });
        });
      });
    };

    var tryBr = function (win, isRoot, element, offset, traverse, gather, situ) {
      // Three different situations
      // 1. the br is the child, and it has a previous sibling. Use parent, index-1)
      // 2. the br is the child and it has no previous sibling, set to before the previous gather result
      // 3. the br is the element and it has a previous sibling, use parent index-1)
      // 4. the br is the element and it has no previous sibling, set to before the previous gather result.
      // 2. the element is the br itself,
      var target = isBr(element) ? handleBr(isRoot, element, traverse, gather, situ) : handleParent(isRoot, element, offset, traverse, gather, situ);
      return target.map(function (tgt) {
        return SelectionRange.write(tgt, tgt);
      });
    };

    var tryBrDown = function (win, isRoot, element, offset) {
      return tryBr(win, isRoot, element, offset, Traverse.nextSibling, DomGather.after, Situ.before);
    };

    var tryBrUp = function (win, isRoot, element, offset) {
      return tryBr(win, isRoot, element, offset, Traverse.prevSibling, DomGather.before, Situ.after);
    };

    var process = function (analysis) {
      return analysis.fold(
        function (message) {
          console.log('>> br.none => browser (' + message + ')');
          return Option.none('BR ADT: none');
        },
        function () {
          console.log('>> br.success => browser');
          return Option.none();
        },
        function (cell) {
          console.log('>> br.failedUp => box-hitting');
          return Option.some({ element: Fun.constant(cell), offset: Fun.constant(0) });
        },
        function (cell) {
          console.log('>> br.failedUp => box-hitting');
          return Option.some({ element: Fun.constant(cell), offset: Fun.constant(Awareness.getEnd(cell)) });
        },
        function (section) {
          console.log('>> br.upSection => browser');
          return Option.none();
        }, function (section) {
          console.log('>> br.downSection => browser');
          return Option.none();
        }
      );
    };

    return {
      tryBrDown: tryBrDown,
      tryBrUp: tryBrUp,
      process: process
    };
  }
);<commit_msg>TBIO-2087: cleanup<commit_after>define(
  'ephox.darwin.navigation.BrTags',

  [
    'ephox.fussy.api.SelectionRange',
    'ephox.fussy.api.Situ',
    'ephox.oath.proximity.Awareness',
    'ephox.peanut.Fun',
    'ephox.perhaps.Option',
    'ephox.phoenix.api.dom.DomGather',
    'ephox.sugar.api.Node',
    'ephox.sugar.api.Text',
    'ephox.sugar.api.Traverse'
  ],

  function (SelectionRange, Situ, Awareness, Fun, Option, DomGather, Node, Text, Traverse) {
    var isBr = function (elem) {
      return Node.name(elem) === 'br';
    };

    var gatherer = function (cand, gather, isRoot) {
      return gather(cand, isRoot).bind(function (target) {
        return Node.isText(target) && Text.get(target).trim().length === 0 ? gatherer(target, gather, isRoot) : Option.some(target);
      });
    };

    var locate = function (element) {
      return Traverse.parent(element).bind(function (parent) {
        return Traverse.findIndex(element).map(function (index) {
          return {
            parent: Fun.constant(parent),
            index: Fun.constant(index)
          };
        });
      });
    };

    var handleBr = function (isRoot, element, traverse, gather, relative) {
      // 1. Has a neighbouring sibling ... position relative to neighbouring element
      // 2. Has no neighbouring sibling ... position relative to gathered element
      return traverse(element).orThunk(function () {
        return gatherer(element, gather, isRoot);
      }).map(relative);
    };

    var findBr = function (element, offset) {
      return Traverse.child(element, offset).filter(isBr).orThunk(function () {
        // Can be either side of the br, and still be a br.
        return Traverse.child(element, offset-1).filter(isBr);
      });
    };

    var handleParent = function (isRoot, element, offset, traverse, gather, relative) {
      // 1. Has no neighbouring sibling, position relative to gathered element
      // 2. Has a neighbouring sibling, position at the neighbouring sibling with respect to parent
      return findBr(element, offset).bind(function (br) {
        return traverse(br).fold(function () {
          return gatherer(br, gather, isRoot).map(relative);
        }, function (adjacent) {
          return locate(adjacent).map(function (info) {
            return Situ.on(info.parent(), info.index());
          });
        });
      });
    };

    var tryBr = function (win, isRoot, element, offset, traverse, gather, situ) {
      // Three different situations
      // 1. the br is the child, and it has a previous sibling. Use parent, index-1)
      // 2. the br is the child and it has no previous sibling, set to before the previous gather result
      // 3. the br is the element and it has a previous sibling, use parent index-1)
      // 4. the br is the element and it has no previous sibling, set to before the previous gather result.
      // 2. the element is the br itself,
      var target = isBr(element) ? handleBr(isRoot, element, traverse, gather, situ) : handleParent(isRoot, element, offset, traverse, gather, situ);
      return target.map(function (tgt) {
        return SelectionRange.write(tgt, tgt);
      });
    };

    var tryBrDown = function (win, isRoot, element, offset) {
      return tryBr(win, isRoot, element, offset, Traverse.nextSibling, DomGather.after, Situ.before);
    };

    var tryBrUp = function (win, isRoot, element, offset) {
      return tryBr(win, isRoot, element, offset, Traverse.prevSibling, DomGather.before, Situ.after);
    };

    var process = function (analysis) {
      return analysis.fold(
        function (message) {
          console.log('>> br.none => browser (' + message + ')');
          return Option.none('BR ADT: none');
        },
        function () {
          console.log('>> br.success => browser');
          return Option.none();
        },
        function (cell) {
          console.log('>> br.failedUp => box-hitting');
          return Option.some({ element: Fun.constant(cell), offset: Fun.constant(0) });
        },
        function (cell) {
          console.log('>> br.failedUp => box-hitting');
          return Option.some({ element: Fun.constant(cell), offset: Fun.constant(Awareness.getEnd(cell)) });
        },
        function (section) {
          console.log('>> br.upSection => browser');
          return Option.none();
        }, function (section) {
          console.log('>> br.downSection => browser');
          return Option.none();
        }
      );
    };

    return {
      tryBrDown: tryBrDown,
      tryBrUp: tryBrUp,
      process: process
    };
  }
);<|endoftext|>


<commit_before>CLI.registerCommand('hello-world', function(opts) {
  console.info("Hello world from spacejamio:mcli!");
});
<commit_msg>Add stderr option to hello-world command<commit_after>CLI.registerCommand('hello-world', function(options) {
  if(options.stderr)
    console.error(options.prefix + string);
  else
    console.info(options.prefix + string);
});
<|endoftext|>


<commit_before>steal('can/util/can.js', function (can) {
	// Given a list of elements, check if they are in the dom, if they
	// are in the dom, trigger inserted on them.
	can.inserted = function (elems) {
		// prevent mutations from changing the looping
		elems = can.makeArray(elems);
		var inDocument = false,
			// Not all browsers implement document.contains (Android)
			doc = can.$(document.contains ? document : document.body),
			children;
		for (var i = 0, elem;
			(elem = elems[i]) !== undefined; i++) {
			if (!inDocument) {
				if (elem.getElementsByTagName) {
					if (can.has(doc, elem)
						.length) {
						inDocument = true;
					} else {
						return;
					}
				} else {
					continue;
				}
			}

			if (inDocument && elem.getElementsByTagName) {
				children = can.makeArray(elem.getElementsByTagName("*"));
				can.trigger(elem, "inserted", [], false);
				for (var j = 0, child;
					(child = children[j]) !== undefined; j++) {
					// Trigger the destroyed event
					can.trigger(child, "inserted", [], false);
				}
			}
		}
	};

	can.appendChild = function (el, child) {
		var children;
		if (child.nodeType === 11) {
			children = can.makeArray(child.childNodes);
		} else {
			children = [child];
		}
		el.appendChild(child);
		can.inserted(children);
	};
	can.insertBefore = function (el, child, ref) {
		var children;
		if (child.nodeType === 11) {
			children = can.makeArray(child.childNodes);
		} else {
			children = [child];
		}
		el.insertBefore(child, ref);
		can.inserted(children);
	};

});
<commit_msg>Inline documentation for can.inserted<commit_after>steal('can/util/can.js', function (can) {
	// # can.inserted
	// Given a list of elements, check if they are in the dom, if they
	// are in the dom, trigger the `inserted` event on them.
	can.inserted = function (elems) {
		// Prevent mutations from changing the looping
		elems = can.makeArray(elems);
		var inDocument = false,
			// Not all browsers implement document.contains (Android)
			doc = can.$(document.contains ? document : document.body),
			children;
		// Go through `elems` and trigger the `inserted` event.
		// If the first element is not in the document (a Document Fragment)
		// exit the function.
		for (var i = 0, elem;
			(elem = elems[i]) !== undefined; i++) {
			// If we haven't already found an element in the document
			if (!inDocument) {
				if (elem.getElementsByTagName) {
					// If it is in the document
					if (can.has(doc, elem)
						.length) {
						inDocument = true;
					} else {
						// Document Fragment, exit the function
						return;
					}
				} else {
					// Continue on to the next element
					continue;
				}
			}

			if (inDocument && elem.getElementsByTagName) {
				// We've found an element in the document and will now
				// trigger `inserted` for `elem` and all of its children.
				children = can.makeArray(elem.getElementsByTagName("*"));
				can.trigger(elem, "inserted", [], false);
				for (var j = 0, child;
					(child = children[j]) !== undefined; j++) {
					// Trigger the inserted event
					can.trigger(child, "inserted", [], false);
				}
			}
		}
	};

	// ## Create can.appendChild and can.insertBefore
	can.appendChild = function (el, child) {
		var children;
		// Document Fragment
		if (child.nodeType === 11) {
			children = can.makeArray(child.childNodes);
		} else {
			children = [child];
		}
		el.appendChild(child);
		// Trigger the inserted event on the children
		can.inserted(children);
	};
	can.insertBefore = function (el, child, ref) {
		var children;
		// Document Fragment
		if (child.nodeType === 11) {
			children = can.makeArray(child.childNodes);
		} else {
			children = [child];
		}
		el.insertBefore(child, ref);
		// Trigger the inserted event on the children
		can.inserted(children);
	};
});
<|endoftext|>


<commit_before>import React from 'react';

import { storiesOf } from '@kadira/storybook';

// eslint-disable-next-line max-len
import Tooltip from '../../../../src/components/trends/common/Tooltip';

const props = {
  title: 'Title',
  content: Some Content,
  position: { top: 200, left: 200 },
};

const refDiv = (
);

storiesOf('Tooltip', module)
  .add('defaults', () => (

      {refDiv}
      <Tooltip {...props} />

  ))
  .add('offset -5,-5', () => (

      {refDiv}
      <Tooltip {...props} offset={{ top: -5, left: -5 }} />

  ))
  .add('borderColor', () => (

      {refDiv}
      <Tooltip {...props} borderColor={'blue'} />

  ))
  .add('borderWidth', () => (

      {refDiv}
      <Tooltip {...props} borderWidth={3} />

  ))
  .add('tailWidth', () => (

      {refDiv}
      <Tooltip {...props} tailWidth={10} />

  ))
  .add('tailHeight', () => (

      {refDiv}
      <Tooltip {...props} tailHeight={4} />

  ))
  .add('no content', () => (

      {refDiv}
      <Tooltip {...props} content={null} />

  ))
  .add('no title', () => (

      {refDiv}
      <Tooltip {...props} title={null} />

  ))
  .add('no tail', () => (

      {refDiv}
      <Tooltip {...props} tail={false} />

  ))
  .add('no tail, no title', () => (

      {refDiv}
      <Tooltip {...props} tail={false} title={null} />

  ))
  .add('no tail, no title, offset -10,0', () => (

      {refDiv}
      <Tooltip {...props} tail={false} title={null} offset={{ left: -10, top: 0 }} />

  ))
  .add('no tail, on right', () => (

      {refDiv}
      <Tooltip {...props} tail={false} side={'right'} />

  ))
  .add('tail, on right', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} />

  ))
  .add('tail, on right, offset 5,5', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} offset={{ top: 5, left: 5 }} />

  ))
  .add('tail, on right, no content', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} content={null} />

  ))
  .add('tail, on right, no title', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} title={null} />

  ))
  .add('top, no tail', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} />

  ))
  .add('top, no tail, no title', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} title={null} />

  ))
  .add('top, no tail, no title, offset 0,-10', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} title={null} offset={{ left: 0, top: -10 }} />

  ))
  .add('top, no tail, no content', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} content={null} />

  ))
  .add('bottom, no tail', () => (

      {refDiv}
      <Tooltip {...props} side={'bottom'} tail={false} />

  ))
  .add('bottom, no tail, no title', () => (

      {refDiv}
      <Tooltip {...props} side={'bottom'} tail={false} title={null} />

  ))
  .add('bottom, no tail, no content', () => (

      {refDiv}
      <Tooltip {...props} side={'bottom'} tail={false} content={null} />

  ));
<commit_msg>fix tooltip storybook<commit_after>import React from 'react';

import { storiesOf } from '@kadira/storybook';

// eslint-disable-next-line max-len
import Tooltip from '../../../../src/components/trends/common/Tooltip';

const props = {
  title: Title,
  content: Some Content,
  position: { top: 200, left: 200 },
};

const refDiv = (
);

storiesOf('Tooltip', module)
  .add('defaults', () => (

      {refDiv}
      <Tooltip {...props} />

  ))
  .add('offset -5,-5', () => (

      {refDiv}
      <Tooltip {...props} offset={{ top: -5, left: -5 }} />

  ))
  .add('borderColor', () => (

      {refDiv}
      <Tooltip {...props} borderColor={'blue'} />

  ))
  .add('borderWidth', () => (

      {refDiv}
      <Tooltip {...props} borderWidth={3} />

  ))
  .add('tailWidth', () => (

      {refDiv}
      <Tooltip {...props} tailWidth={10} />

  ))
  .add('tailHeight', () => (

      {refDiv}
      <Tooltip {...props} tailHeight={4} />

  ))
  .add('no content', () => (

      {refDiv}
      <Tooltip {...props} content={null} />

  ))
  .add('no title', () => (

      {refDiv}
      <Tooltip {...props} title={null} />

  ))
  .add('no tail', () => (

      {refDiv}
      <Tooltip {...props} tail={false} />

  ))
  .add('no tail, no title', () => (

      {refDiv}
      <Tooltip {...props} tail={false} title={null} />

  ))
  .add('no tail, no title, offset -10,0', () => (

      {refDiv}
      <Tooltip {...props} tail={false} title={null} offset={{ left: -10, top: 0 }} />

  ))
  .add('no tail, on right', () => (

      {refDiv}
      <Tooltip {...props} tail={false} side={'right'} />

  ))
  .add('tail, on right', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} />

  ))
  .add('tail, on right, offset 5,5', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} offset={{ top: 5, left: 5 }} />

  ))
  .add('tail, on right, no content', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} content={null} />

  ))
  .add('tail, on right, no title', () => (

      {refDiv}
      <Tooltip {...props} side={'right'} title={null} />

  ))
  .add('top, no tail', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} />

  ))
  .add('top, no tail, no title', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} title={null} />

  ))
  .add('top, no tail, no title, offset 0,-10', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} title={null} offset={{ left: 0, top: -10 }} />

  ))
  .add('top, no tail, no content', () => (

      {refDiv}
      <Tooltip {...props} side={'top'} tail={false} content={null} />

  ))
  .add('bottom, no tail', () => (

      {refDiv}
      <Tooltip {...props} side={'bottom'} tail={false} />

  ))
  .add('bottom, no tail, no title', () => (

      {refDiv}
      <Tooltip {...props} side={'bottom'} tail={false} title={null} />

  ))
  .add('bottom, no tail, no content', () => (

      {refDiv}
      <Tooltip {...props} side={'bottom'} tail={false} content={null} />

  ));
<|endoftext|>


<commit_before>function getMonzo() {
  return {
    // general
    name: "Monzo Account",
    provider: "monzo",

    // auth
    authType: "oauth2",
    accessToken: null,
    accessExpires: -1,
    // variables below used while auth is being negotiated
    clientId: null,
    clientSecret: null,
    state: null,
    redirectUri: null,

    // other variables
    accountId: null,
    cardId: null
  };
}

// auth functions
function monzoAuth(monzo) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet auth was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet auth was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet auth was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet auth was called!");
  }
  window.location = "https://auth.getmondo.co.uk/?client_id=" + monzo.clientId + "&redirect_uri=" + monzo.redirectUri + "&response_type=code&state=" + monzo.state;
}

function monzoCallback(monzo, authCode) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet callback was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet callback was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet callback was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet callback was called!");
  }

  var request = new XMLHttpRequest();
  request.open("POST", "https://api.monzo.com/oauth2/token", false);
  request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  request.send("grant_type=authorization_code&client_id=" + monzo.clientId + "&client_secret=" + monzo.clientSecret + "&redirect_uri=" + monzo.redirectUri + "&code=" + authCode);
  if (request.status == 200) {
    monzo.accessToken = JSON.parse(request.responseText).access_token;
    monzo.accessExpires = Date.now() + JSON.parse(request.responseText).expires_in * 1000;
    // clear the variables we were using while getting an access token
    delete monzo["clientId"];
    delete monzo["clientSecret"];
    delete monzo["redirectUri"];
    delete monzo["state"];
    // get the account id
    var request = new XMLHttpRequest();
    request.open("GET", "https://api.monzo.com/accounts", false);
    request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
    request.send();
    monzo.accountId = JSON.parse(request.responseText).accounts[0].id;
    monzo.cardId = monzoGetCards(monzo).id;
  }
}

// HTML functions
function monzoTransactionHTML(monzo, id) {
  // alasql
  try {
    alasql("drop table transactions")
  } catch(err) {
    console.log(err.message);
  }
  alasql('CREATE TABLE transactions (' +
    'id STRING PRIMARY KEY,' +
    'created Date,' +
    'settled Date,' +
    'is_load BOOLEAN,' +
    'merchant_id STRING,' +
    'description STRING,' +
    'currency STRING,' +
    'amount INT,' +
    'account_balance INT,' +
    'notes STRING);');
  alasql('CREATE TABLE merchants (' +
    'id STRING PRIMARY KEY,' +
    'name STRING,' +
    'address STRING,' +
    'city STRING,' +
    'region STRING,' +
    'country STRING,' +
    'postcode STRING,' +
    'latitude DOUBLE PRECISION,' +
    'longitude DOUBLE PRECISION,' +
    'zoom_level INT,' +
    'created Date,' +
    'group_id STRING,' +
    'logo STRING,' +
    'emoji STRING,' +
    'category STRING);');
  // create a fake merchant for top-ups
  alasql('INSERT INTO merchants VALUES("merch_monzo", "Monzo", null, null, null, null, null, null, null, null, null, null, null, null, null);');

  transactions = monzoGetTransactions(monzo, true);
  for (var i = 0; i < transactions.length; i++) {
    var merchantId;
    if (transactions[i].merchant == null) {
      merchantId = null;
      if (transactions[i].is_load) {
        merchantId = "merch_monzo";
      }
    } else {
      merchantId = transactions[i].merchant.id;
      if (alasql('SELECT id from merchants where id="' + merchantId + '"').length == 0) {
        // add merchant to alasql
        alasql('INSERT INTO merchants VALUES(' +
          '"' + transactions[i].merchant.id + '"' + ',' +
          '"' + transactions[i].merchant.name + '"' + ',' +
          '"' + transactions[i].merchant.address.address + '"' + ',' +
          '"' + transactions[i].merchant.address.city + '"' + ',' +
          '"' + transactions[i].merchant.address.region + '"' + ',' +
          '"' + transactions[i].merchant.address.country + '"' + ',' +
          '"' + transactions[i].merchant.address.postcode + '"' + ',' +
          transactions[i].merchant.address.latitude + ',' +
          transactions[i].merchant.address.longitude + ',' +
          transactions[i].merchant.address.zoom_level + ',' +
          '"' + transactions[i].merchant.created + '"' + ',' +
          '"' + transactions[i].merchant.group_id + '"' + ',' +
          '"' + transactions[i].merchant.logo + '"' + ',' +
          '"' + transactions[i].merchant.emoji + '"' + ',' +
          '"' + transactions[i].merchant.category + '");');
      }
    }
    alasql('INSERT INTO transactions VALUES(' +
      '"' + transactions[i].id + '"' + ',' +
      '"' + transactions[i].created + '"' + ',' +
      '"' + transactions[i].settled + '"' + ',' +
      transactions[i].is_load + ',' +
      '"' + merchantId + '"' + ',' +
      '"' + transactions[i].description + '"' + ',' +
      '"' + transactions[i].currency + '"' + ',' +
      transactions[i].amount + ',' +
      transactions[i].account_balance + ',' +
      '"' + transactions[i].notes + '"' + ');');
  }

  var HTML = "";
  HTML += "
" + monzo.name + "
";
  HTML += '<input id="sql"></input><button type="button" onclick="javascript:alasql(document.getElementById(\'sql\').value)"></button>';
  HTML += '

';
  return HTML;
}

function monzoDetailsHTML(monzo, id) {
  var HTML = "";
  var balance = monzoGetBalance(monzo);
  var card = monzoGetCards(monzo);
  HTML += "
Welcome, " + card.name + "!
";
  HTML += "
Balance: £" + (balance.balance*0.01).toFixed(2) + "
";
  HTML += "
You spent £" + (balance.spend_today*0.01).toFixed(2) + " today.
";
  if (card.status == "ACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently active.
";
    HTML += 'Freeze your card
';
  } else if (card.status == "INACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently frozen.
";
    HTML += 'Defrost your card
';
  } else {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") has unknown status!
";
  }
  return HTML;
}

// other functions
function monzoGetBalance(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/balance?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText);
}

function monzoGetCards(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/card/list?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).cards[0];
}

function monzoGetTransactions(monzo, expand) {
  if (typeof expand === "undefined") { expand = false; }
  var request = new XMLHttpRequest();
  if (expand) {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId + "&expand[]=merchant", false);
  } else {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId, false);
  }
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).transactions;
}

function monzoFreezeCard(monzo, targetStatus, id) {
  var request = new XMLHttpRequest();
  request.open("PUT", "https://api.monzo.com/card/toggle?card_id=" + monzo.cardId + "&status=" + targetStatus, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  document.getElementById("accountDetails").innerHTML = monzoDetailsHTML(monzo, id)
}<commit_msg>Changed sql input to an textarea<commit_after>function getMonzo() {
  return {
    // general
    name: "Monzo Account",
    provider: "monzo",

    // auth
    authType: "oauth2",
    accessToken: null,
    accessExpires: -1,
    // variables below used while auth is being negotiated
    clientId: null,
    clientSecret: null,
    state: null,
    redirectUri: null,

    // other variables
    accountId: null,
    cardId: null
  };
}

// auth functions
function monzoAuth(monzo) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet auth was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet auth was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet auth was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet auth was called!");
  }
  window.location = "https://auth.getmondo.co.uk/?client_id=" + monzo.clientId + "&redirect_uri=" + monzo.redirectUri + "&response_type=code&state=" + monzo.state;
}

function monzoCallback(monzo, authCode) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet callback was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet callback was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet callback was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet callback was called!");
  }

  var request = new XMLHttpRequest();
  request.open("POST", "https://api.monzo.com/oauth2/token", false);
  request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  request.send("grant_type=authorization_code&client_id=" + monzo.clientId + "&client_secret=" + monzo.clientSecret + "&redirect_uri=" + monzo.redirectUri + "&code=" + authCode);
  if (request.status == 200) {
    monzo.accessToken = JSON.parse(request.responseText).access_token;
    monzo.accessExpires = Date.now() + JSON.parse(request.responseText).expires_in * 1000;
    // clear the variables we were using while getting an access token
    delete monzo["clientId"];
    delete monzo["clientSecret"];
    delete monzo["redirectUri"];
    delete monzo["state"];
    // get the account id
    var request = new XMLHttpRequest();
    request.open("GET", "https://api.monzo.com/accounts", false);
    request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
    request.send();
    monzo.accountId = JSON.parse(request.responseText).accounts[0].id;
    monzo.cardId = monzoGetCards(monzo).id;
  }
}

// HTML functions
function monzoTransactionHTML(monzo, id) {
  // alasql
  try {
    alasql("drop table transactions")
  } catch(err) {
    console.log(err.message);
  }
  alasql('CREATE TABLE transactions (' +
    'id STRING PRIMARY KEY,' +
    'created Date,' +
    'settled Date,' +
    'is_load BOOLEAN,' +
    'merchant_id STRING,' +
    'description STRING,' +
    'currency STRING,' +
    'amount INT,' +
    'account_balance INT,' +
    'notes STRING);');
  alasql('CREATE TABLE merchants (' +
    'id STRING PRIMARY KEY,' +
    'name STRING,' +
    'address STRING,' +
    'city STRING,' +
    'region STRING,' +
    'country STRING,' +
    'postcode STRING,' +
    'latitude DOUBLE PRECISION,' +
    'longitude DOUBLE PRECISION,' +
    'zoom_level INT,' +
    'created Date,' +
    'group_id STRING,' +
    'logo STRING,' +
    'emoji STRING,' +
    'category STRING);');
  // create a fake merchant for top-ups
  alasql('INSERT INTO merchants VALUES("merch_monzo", "Monzo", null, null, null, null, null, null, null, null, null, null, null, null, null);');

  transactions = monzoGetTransactions(monzo, true);
  for (var i = 0; i < transactions.length; i++) {
    var merchantId;
    if (transactions[i].merchant == null) {
      merchantId = null;
      if (transactions[i].is_load) {
        merchantId = "merch_monzo";
      }
    } else {
      merchantId = transactions[i].merchant.id;
      if (alasql('SELECT id from merchants where id="' + merchantId + '"').length == 0) {
        // add merchant to alasql
        alasql('INSERT INTO merchants VALUES(' +
          '"' + transactions[i].merchant.id + '"' + ',' +
          '"' + transactions[i].merchant.name + '"' + ',' +
          '"' + transactions[i].merchant.address.address + '"' + ',' +
          '"' + transactions[i].merchant.address.city + '"' + ',' +
          '"' + transactions[i].merchant.address.region + '"' + ',' +
          '"' + transactions[i].merchant.address.country + '"' + ',' +
          '"' + transactions[i].merchant.address.postcode + '"' + ',' +
          transactions[i].merchant.address.latitude + ',' +
          transactions[i].merchant.address.longitude + ',' +
          transactions[i].merchant.address.zoom_level + ',' +
          '"' + transactions[i].merchant.created + '"' + ',' +
          '"' + transactions[i].merchant.group_id + '"' + ',' +
          '"' + transactions[i].merchant.logo + '"' + ',' +
          '"' + transactions[i].merchant.emoji + '"' + ',' +
          '"' + transactions[i].merchant.category + '");');
      }
    }
    alasql('INSERT INTO transactions VALUES(' +
      '"' + transactions[i].id + '"' + ',' +
      '"' + transactions[i].created + '"' + ',' +
      '"' + transactions[i].settled + '"' + ',' +
      transactions[i].is_load + ',' +
      '"' + merchantId + '"' + ',' +
      '"' + transactions[i].description + '"' + ',' +
      '"' + transactions[i].currency + '"' + ',' +
      transactions[i].amount + ',' +
      transactions[i].account_balance + ',' +
      '"' + transactions[i].notes + '"' + ');');
  }

  var HTML = "";
  HTML += "
" + monzo.name + "
";
  HTML += '<textarea id="sql"></textarea><button type="button" onclick="javascript:alasql(document.getElementById(\'sql\').value)">Search!</button>';
  HTML += '

';
  return HTML;
}

function monzoDetailsHTML(monzo, id) {
  var HTML = "";
  var balance = monzoGetBalance(monzo);
  var card = monzoGetCards(monzo);
  HTML += "
Welcome, " + card.name + "!
";
  HTML += "
Balance: £" + (balance.balance*0.01).toFixed(2) + "
";
  HTML += "
You spent £" + (balance.spend_today*0.01).toFixed(2) + " today.
";
  if (card.status == "ACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently active.
";
    HTML += 'Freeze your card
';
  } else if (card.status == "INACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently frozen.
";
    HTML += 'Defrost your card
';
  } else {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") has unknown status!
";
  }
  return HTML;
}

// other functions
function monzoGetBalance(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/balance?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText);
}

function monzoGetCards(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/card/list?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).cards[0];
}

function monzoGetTransactions(monzo, expand) {
  if (typeof expand === "undefined") { expand = false; }
  var request = new XMLHttpRequest();
  if (expand) {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId + "&expand[]=merchant", false);
  } else {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId, false);
  }
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).transactions;
}

function monzoFreezeCard(monzo, targetStatus, id) {
  var request = new XMLHttpRequest();
  request.open("PUT", "https://api.monzo.com/card/toggle?card_id=" + monzo.cardId + "&status=" + targetStatus, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  document.getElementById("accountDetails").innerHTML = monzoDetailsHTML(monzo, id)
}<|endoftext|>


<commit_before>'use strict';

describe('E2E testing: Signup app', function () {
  var constants = require('../../../../testConstants.json');
  var page      = require('../../../pages/signupPage.js');
  var loginPage = require('../../../pages/loginPage.js');
  var projectsPage = require('../../../pages/projectsPage.js');
  var expectedCondition = protractor.ExpectedConditions;
  var CONDITION_TIMEOUT = 3000;

  it('setup and contains a user form', function () {
    page.get();
    expect(page.signupForm).toBeDefined();
  });

  it('can verify required information filled', function () {
    page.get();
    expect(page.signupButton.isEnabled()).toBe(false);
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setInvalidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
  });

  it('cannot submit if email is invalid', function () {
    page.emailInput.clear();
    page.emailInput.sendKeys(constants.emailNoAt);
    page.captcha.setInvalidCaptcha();
    expect(page.emailInvalid.isDisplayed()).toBe(true);
    expect(page.signupButton.isEnabled()).toBe(false);
  });

  it('cannot submit if password too short', function () {
    page.emailInput.clear();
    page.emailInput.sendKeys(constants.unusedEmail);
    expect(page.signupButton.isEnabled()).toBe(true);
    page.passwordInput.clear();
    page.passwordInput.sendKeys(constants.passwordTooShort);
    page.captcha.setInvalidCaptcha();
    expect(page.passwordInvalid.isDisplayed()).toBe(true);
    expect(page.signupButton.isEnabled()).toBe(false);
  });

  it('can submit if password long enough', function () {
    page.passwordInput.clear();
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setInvalidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
  });

  it('can submit if password is showing and long enough', function () {
    page.showPassword.click();
    page.captcha.setInvalidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
  });

  it('cannot submit if captcha not selected', function () {
    page.get();
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    expect(page.signupButton.isEnabled()).toBe(false);
  });

  it('can submit a user registration request and captcha is invalid', function () {
    page.get();
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setInvalidCaptcha();
    page.signupButton.click();
    expect(page.captchaInvalid.isDisplayed()).toBe(true);
  });

  it('finds the admin user (case insensitive) already exists', function () {
    page.get();
    page.emailInput.sendKeys(constants.adminEmail.toUpperCase());
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setValidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
    page.signupButton.click();
    expect(page.emailTaken.isDisplayed()).toBe(true);
  });

  it('can prefill email address that can\'t be changed', function () {
    page.getPrefilledEmail(constants.unusedEmail);
    expect(page.emailInput.isEnabled()).toBe(false);
  });

  it('can prefill email address that already exists', function () {
    page.getPrefilledEmail(constants.adminEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setValidCaptcha();
    page.signupButton.click();
    expect(page.emailTaken.isDisplayed()).toBe(true);
  });

  it('can signup a new user', function () {
    page.get();
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setValidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
    page.signupButton.click();

    // Verify new user logged in and redirected to projects page
    browser.wait(expectedCondition.visibilityOf(projectsPage.createBtn),
      CONDITION_TIMEOUT);
    expect(projectsPage.createBtn.isDisplayed()).toBe(true);
  });

  it('redirects to projects page if already logged in', function () {
    loginPage.logout();
    loginPage.loginAsUser();
    page.get();
    browser.wait(expectedCondition.visibilityOf(projectsPage.createBtn),
      CONDITION_TIMEOUT);
    expect(projectsPage.createBtn.isDisplayed()).toBe(true);
  });
});
<commit_msg>E2E: logout before running signup tests <commit_after>'use strict';

describe('E2E testing: Signup app', function () {
  var constants = require('../../../../testConstants.json');
  var page      = require('../../../pages/signupPage.js');
  var loginPage = require('../../../pages/loginPage.js');
  var projectsPage = require('../../../pages/projectsPage.js');
  var expectedCondition = protractor.ExpectedConditions;
  var CONDITION_TIMEOUT = 3000;

  it('setup and contains a user form', function () {
    loginPage.logout();
    page.get();
    expect(page.signupForm).toBeDefined();
  });

  it('can verify required information filled', function () {
    page.get();
    expect(page.signupButton.isEnabled()).toBe(false);
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setInvalidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
  });

  it('cannot submit if email is invalid', function () {
    page.emailInput.clear();
    page.emailInput.sendKeys(constants.emailNoAt);
    page.captcha.setInvalidCaptcha();
    expect(page.emailInvalid.isDisplayed()).toBe(true);
    expect(page.signupButton.isEnabled()).toBe(false);
  });

  it('cannot submit if password too short', function () {
    page.emailInput.clear();
    page.emailInput.sendKeys(constants.unusedEmail);
    expect(page.signupButton.isEnabled()).toBe(true);
    page.passwordInput.clear();
    page.passwordInput.sendKeys(constants.passwordTooShort);
    page.captcha.setInvalidCaptcha();
    expect(page.passwordInvalid.isDisplayed()).toBe(true);
    expect(page.signupButton.isEnabled()).toBe(false);
  });

  it('can submit if password long enough', function () {
    page.passwordInput.clear();
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setInvalidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
  });

  it('can submit if password is showing and long enough', function () {
    page.showPassword.click();
    page.captcha.setInvalidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
  });

  it('cannot submit if captcha not selected', function () {
    page.get();
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    expect(page.signupButton.isEnabled()).toBe(false);
  });

  it('can submit a user registration request and captcha is invalid', function () {
    page.get();
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setInvalidCaptcha();
    page.signupButton.click();
    expect(page.captchaInvalid.isDisplayed()).toBe(true);
  });

  it('finds the admin user (case insensitive) already exists', function () {
    page.get();
    page.emailInput.sendKeys(constants.adminEmail.toUpperCase());
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setValidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
    page.signupButton.click();
    expect(page.emailTaken.isDisplayed()).toBe(true);
  });

  it('can prefill email address that can\'t be changed', function () {
    page.getPrefilledEmail(constants.unusedEmail);
    expect(page.emailInput.isEnabled()).toBe(false);
  });

  it('can prefill email address that already exists', function () {
    page.getPrefilledEmail(constants.adminEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setValidCaptcha();
    page.signupButton.click();
    expect(page.emailTaken.isDisplayed()).toBe(true);
  });

  it('can signup a new user', function () {
    page.get();
    page.emailInput.sendKeys(constants.unusedEmail);
    page.nameInput.sendKeys(constants.unusedName);
    page.passwordInput.sendKeys(constants.passwordValid);
    page.captcha.setValidCaptcha();
    expect(page.signupButton.isEnabled()).toBe(true);
    page.signupButton.click();

    // Verify new user logged in and redirected to projects page
    browser.wait(expectedCondition.visibilityOf(projectsPage.createBtn),
      CONDITION_TIMEOUT);
    expect(projectsPage.createBtn.isDisplayed()).toBe(true);
  });

  it('redirects to projects page if already logged in', function () {
    loginPage.logout();
    loginPage.loginAsUser();
    page.get();
    browser.wait(expectedCondition.visibilityOf(projectsPage.createBtn),
      CONDITION_TIMEOUT);
    expect(projectsPage.createBtn.isDisplayed()).toBe(true);
  });
});
<|endoftext|>


<commit_before>const { shouldFail, constants, expectEvent } = require('openzeppelin-test-helpers');
const { ZERO_ADDRESS } = constants;

function capitalize (str) {
  return str.replace(/\b\w/g, l => l.toUpperCase());
}

function shouldBehaveLikePublicRole (authorized, otherAuthorized, [anyone], rolename, manager) {
  rolename = capitalize(rolename);

  describe('should behave like public role', function () {
    beforeEach('check preconditions', async function () {
      (await this.contract[`is${rolename}`](authorized)).should.equal(true);
      (await this.contract[`is${rolename}`](otherAuthorized)).should.equal(true);
      (await this.contract[`is${rolename}`](anyone)).should.equal(false);
    });

    if (manager === undefined) { // Managed roles are only assigned by the manager, and none are set at construction
      it('emits events during construction', async function () {
        await expectEvent.inConstruction(this.contract, `${rolename}Added`, {
          account: authorized,
        });
      });
    }

    it('reverts when querying roles for the null account', async function () {
      await shouldFail.reverting(this.contract[`is${rolename}`](ZERO_ADDRESS));
    });

    describe('access control', function () {
      context('from authorized account', function () {
        const from = authorized;

        it('allows access', async function () {
          await this.contract[`only${rolename}Mock`]({ from });
        });
      });

      context('from unauthorized account', function () {
        const from = anyone;

        it('reverts', async function () {
          await shouldFail.reverting(this.contract[`only${rolename}Mock`]({ from }));
        });
      });
    });

    describe('add', function () {
      const from = manager === undefined ? authorized : manager;

      context(`from ${manager ? 'the manager' : 'a role-haver'} account`, function () {
        it('adds role to a new account', async function () {
          await this.contract[`add${rolename}`](anyone, { from });
          (await this.contract[`is${rolename}`](anyone)).should.equal(true);
        });

        it(`emits a ${rolename}Added event`, async function () {
          const { logs } = await this.contract[`add${rolename}`](anyone, { from });
          expectEvent.inLogs(logs, `${rolename}Added`, { account: anyone });
        });

        it('reverts when adding role to an already assigned account', async function () {
          await shouldFail.reverting(this.contract[`add${rolename}`](authorized, { from }));
        });

        it('reverts when adding role to the null account', async function () {
          await shouldFail.reverting(this.contract[`add${rolename}`](ZERO_ADDRESS, { from }));
        });
      });
    });

    describe('remove', function () {
      // Non-managed roles have no restrictions on the mocked '_remove' function (exposed via 'remove').
      const from = manager || anyone;

      context(`from ${manager ? 'the manager' : 'any'} account`, function () {
        it('removes role from an already assigned account', async function () {
          await this.contract[`remove${rolename}`](authorized, { from });
          (await this.contract[`is${rolename}`](authorized)).should.equal(false);
          (await this.contract[`is${rolename}`](otherAuthorized)).should.equal(true);
        });

        it(`emits a ${rolename}Removed event`, async function () {
          const { logs } = await this.contract[`remove${rolename}`](authorized, { from });
          expectEvent.inLogs(logs, `${rolename}Removed`, { account: authorized });
        });

        it('reverts when removing from an unassigned account', async function () {
          await shouldFail.reverting(this.contract[`remove${rolename}`](anyone), { from });
        });

        it('reverts when removing role from the null account', async function () {
          await shouldFail.reverting(this.contract[`remove${rolename}`](ZERO_ADDRESS), { from });
        });
      });
    });

    describe('renouncing roles', function () {
      it('renounces an assigned role', async function () {
        await this.contract[`renounce${rolename}`]({ from: authorized });
        (await this.contract[`is${rolename}`](authorized)).should.equal(false);
      });

      it(`emits a ${rolename}Removed event`, async function () {
        const { logs } = await this.contract[`renounce${rolename}`]({ from: authorized });
        expectEvent.inLogs(logs, `${rolename}Removed`, { account: authorized });
      });

      it('reverts when renouncing unassigned role', async function () {
        await shouldFail.reverting(this.contract[`renounce${rolename}`]({ from: anyone }));
      });
    });
  });
}

module.exports = {
  shouldBehaveLikePublicRole,
};
<commit_msg>Add some barebones PublicRole.behavior documentation.<commit_after>const { shouldFail, constants, expectEvent } = require('openzeppelin-test-helpers');
const { ZERO_ADDRESS } = constants;

function capitalize (str) {
  return str.replace(/\b\w/g, l => l.toUpperCase());
}

// Tests that a role complies with the standard role interface, that is:
//  * an onlyRole modifier
//  * an isRole function
//  * an addRole function, accessible to role havers
//  * a renounceRole function
//  * roleAdded and roleRemoved events
// Both the modifier and an additional internal remove function are tested through a mock contract that exposes them.
// This mock contract should be stored in this.contract.
//
// @param authorized an account that has the role
// @param otherAuthorized another account that also has the role
// @param anyone an account that doesn't have the role, passed inside an array for ergonomics
// @param rolename a string with the name of the role
// @param manager undefined for regular roles, or a manager account for managed roles. In these, only the manager
// account can create and remove new role bearers.
function shouldBehaveLikePublicRole (authorized, otherAuthorized, [anyone], rolename, manager) {
  rolename = capitalize(rolename);

  describe('should behave like public role', function () {
    beforeEach('check preconditions', async function () {
      (await this.contract[`is${rolename}`](authorized)).should.equal(true);
      (await this.contract[`is${rolename}`](otherAuthorized)).should.equal(true);
      (await this.contract[`is${rolename}`](anyone)).should.equal(false);
    });

    if (manager === undefined) { // Managed roles are only assigned by the manager, and none are set at construction
      it('emits events during construction', async function () {
        await expectEvent.inConstruction(this.contract, `${rolename}Added`, {
          account: authorized,
        });
      });
    }

    it('reverts when querying roles for the null account', async function () {
      await shouldFail.reverting(this.contract[`is${rolename}`](ZERO_ADDRESS));
    });

    describe('access control', function () {
      context('from authorized account', function () {
        const from = authorized;

        it('allows access', async function () {
          await this.contract[`only${rolename}Mock`]({ from });
        });
      });

      context('from unauthorized account', function () {
        const from = anyone;

        it('reverts', async function () {
          await shouldFail.reverting(this.contract[`only${rolename}Mock`]({ from }));
        });
      });
    });

    describe('add', function () {
      const from = manager === undefined ? authorized : manager;

      context(`from ${manager ? 'the manager' : 'a role-haver'} account`, function () {
        it('adds role to a new account', async function () {
          await this.contract[`add${rolename}`](anyone, { from });
          (await this.contract[`is${rolename}`](anyone)).should.equal(true);
        });

        it(`emits a ${rolename}Added event`, async function () {
          const { logs } = await this.contract[`add${rolename}`](anyone, { from });
          expectEvent.inLogs(logs, `${rolename}Added`, { account: anyone });
        });

        it('reverts when adding role to an already assigned account', async function () {
          await shouldFail.reverting(this.contract[`add${rolename}`](authorized, { from }));
        });

        it('reverts when adding role to the null account', async function () {
          await shouldFail.reverting(this.contract[`add${rolename}`](ZERO_ADDRESS, { from }));
        });
      });
    });

    describe('remove', function () {
      // Non-managed roles have no restrictions on the mocked '_remove' function (exposed via 'remove').
      const from = manager || anyone;

      context(`from ${manager ? 'the manager' : 'any'} account`, function () {
        it('removes role from an already assigned account', async function () {
          await this.contract[`remove${rolename}`](authorized, { from });
          (await this.contract[`is${rolename}`](authorized)).should.equal(false);
          (await this.contract[`is${rolename}`](otherAuthorized)).should.equal(true);
        });

        it(`emits a ${rolename}Removed event`, async function () {
          const { logs } = await this.contract[`remove${rolename}`](authorized, { from });
          expectEvent.inLogs(logs, `${rolename}Removed`, { account: authorized });
        });

        it('reverts when removing from an unassigned account', async function () {
          await shouldFail.reverting(this.contract[`remove${rolename}`](anyone), { from });
        });

        it('reverts when removing role from the null account', async function () {
          await shouldFail.reverting(this.contract[`remove${rolename}`](ZERO_ADDRESS), { from });
        });
      });
    });

    describe('renouncing roles', function () {
      it('renounces an assigned role', async function () {
        await this.contract[`renounce${rolename}`]({ from: authorized });
        (await this.contract[`is${rolename}`](authorized)).should.equal(false);
      });

      it(`emits a ${rolename}Removed event`, async function () {
        const { logs } = await this.contract[`renounce${rolename}`]({ from: authorized });
        expectEvent.inLogs(logs, `${rolename}Removed`, { account: authorized });
      });

      it('reverts when renouncing unassigned role', async function () {
        await shouldFail.reverting(this.contract[`renounce${rolename}`]({ from: anyone }));
      });
    });
  });
}

module.exports = {
  shouldBehaveLikePublicRole,
};
<|endoftext|>


<commit_before>import React, { Component } from "react"
import FontIcon from "material-ui/FontIcon"
import { Column, Cell } from "fixed-data-table-2"
import { NOMAD_WATCH_ALLOCATION_HEALTH, NOMAD_UNWATCH_ALLOCATION_HEALTH } from "../../sagas/event"
import { green500, red500, grey200 } from "material-ui/styles/colors"

const AllocationConsulHealthCell = ({ rowIndex, dispatch, allocationHealth, nodes, data, ...props }) => (
  <Cell rowIndex={rowIndex} data={data} {...props}>
    <AllocationConsulHealth dispatch={dispatch} allocation={data[rowIndex]} allocationHealth={allocationHealth} />
  </Cell>
)
export { AllocationConsulHealthCell }

class AllocationConsulHealth extends Component {
  componentDidMount() {
    this.watch(this.props)
  }

  componentWillUnmount() {
    this.unwatch(this.props)
  }

  componentWillReceiveProps(nextProps) {
    // if we get a new allocation, unsubscribe from the old and subscribe to the new
    if (this.props.allocation.ID != nextProps.allocation.ID) {
      this.unwatch(this.props)
      this.watch(nextProps)
      return
    }

    // if the current allocation changed from running to something else, unsubscribe
    if (this.props.allocation.ClientStatus == "running" && nextProps.allocation.ClientStatus != "running") {
      this.unwatch(this.props)
    }

    // if the current allocation changed anything to running, subscrube to health
    if (this.props.allocation.ClientStatus != "running" && nextProps.allocation.ClientStatus == "running") {
      this.watch(nextProps)
    }
  }

  unwatch(props) {
    if (props.allocation.ClientStatus != "running") {
      return
    }

    this.props.dispatch({
      type: NOMAD_UNWATCH_ALLOCATION_HEALTH,
      payload: {
        id: props.allocation.ID,
        client: props.allocation.NodeID
      }
    })
  }

  watch(props) {
    if (props.allocation.ClientStatus != "running") {
      return
    }

    this.props.dispatch({
      type: NOMAD_WATCH_ALLOCATION_HEALTH,
      payload: {
        id: props.allocation.ID,
        client: props.allocation.NodeID
      }
    })
  }

  render() {
    // can't be any health status for non-running jobs
    if (this.props.allocation.ClientStatus != "running") {
      return null
    }

    const allocID = this.props.allocation.ID
    const health = this.props.allocationHealth[allocID]

    if (!health) {
      return (
        <FontIcon color={grey200} className="material-icons">
          help_outline
        </FontIcon>
      )
    }

    let icon = ""

    if (health.Healthy) {
      icon = (
        <FontIcon color={green500} className="material-icons">
          {health.Total > 1 ? "done_all" : "done"}
        </FontIcon>
      )
    }

    if (health.Healthy == false) {
      icon = (
        <FontIcon color={red500} className="material-icons">
          clear
        </FontIcon>
      )
    }

    return {icon}
  }
}

export default AllocationConsulHealth
<commit_msg>improve allocation consul health performance<commit_after>import React, { Component } from "react"
import FontIcon from "material-ui/FontIcon"
import { Column, Cell } from "fixed-data-table-2"
import { NOMAD_WATCH_ALLOCATION_HEALTH, NOMAD_UNWATCH_ALLOCATION_HEALTH } from "../../sagas/event"
import { green500, red500, grey200 } from "material-ui/styles/colors"

const AllocationConsulHealthCell = ({ rowIndex, dispatch, allocationHealth, nodes, data, ...props }) => (
  <Cell rowIndex={rowIndex} data={data} {...props}>
    <AllocationConsulHealth
      dispatch={dispatch}
      allocation={data[rowIndex]}
      allocationHealth={allocationHealth[data[rowIndex].ID]}
    />
  </Cell>
)
export { AllocationConsulHealthCell }

class AllocationConsulHealth extends Component {
  componentDidMount() {
    this.watch(this.props)
  }

  componentWillUnmount() {
    this.unwatch(this.props)
  }

  componentWillReceiveProps(nextProps) {
    // if we get a new allocation, unsubscribe from the old and subscribe to the new
    if (this.props.allocation.ID != nextProps.allocation.ID) {
      this.unwatch(this.props)
      this.watch(nextProps)
      return
    }

    // if the current allocation changed from running to something else, unsubscribe
    if (this.props.allocation.ClientStatus == "running" && nextProps.allocation.ClientStatus != "running") {
      this.unwatch(this.props)
    }

    // if the current allocation changed anything to running, subscrube to health
    if (this.props.allocation.ClientStatus != "running" && nextProps.allocation.ClientStatus == "running") {
      this.watch(nextProps)
    }
  }

  unwatch(props) {
    this.props.dispatch({
      type: NOMAD_UNWATCH_ALLOCATION_HEALTH,
      payload: {
        id: props.allocation.ID,
        client: props.allocation.NodeID
      }
    })
  }

  watch(props) {
    this.props.dispatch({
      type: NOMAD_WATCH_ALLOCATION_HEALTH,
      payload: {
        id: props.allocation.ID,
        client: props.allocation.NodeID
      }
    })
  }

  render() {
    // can't be any health status for non-running jobs
    if (this.props.allocation.ClientStatus != "running") {
      return null
    }

    const health = this.props.allocationHealth

    if (!health) {
      return (
        <FontIcon title="Unknown Consul Health" color={grey200} className="material-icons">
          help_outline
        </FontIcon>
      )
    }

    let icon = ""

    if (health.Healthy) {
      icon = (
        <FontIcon title="All Consul Health checks OK" color={green500} className="material-icons">
          {health.Total > 1 ? "done_all" : "done"}
        </FontIcon>
      )
    }

    if (health.Healthy == false) {
      icon = (
        <FontIcon color={red500} className="material-icons">
          clear
        </FontIcon>
      )
    }

    return {icon}
  }
}

export default AllocationConsulHealth
<|endoftext|>


<commit_before>/**
 * @class Ext.ux.grid.property.Store
 * @extends Ext.grid.property.Store
 *
 * @author Harald Hanek (c) 2011-2012
 * @license http://harrydeluxe.mit-license.org
 */
Ext.define('Ext.ux.grid.property.Store', {
    extend: 'Ext.grid.property.Store',
    proxy: {
        type: 'memory',
        reader: {
            type: 'json'
        }
    },

    /**
     * Creates new property store.
     * @param {Ext.grid.Panel} grid The grid this store will be bound to
     * @param {Object} source The source data config object
     */
    constructor: function(grid, source)
    {
        var me = this;
        me.grid = grid;
        me.source = source;

        delete me.superclass.constructor;

        me.callParent([{
            data: source || [],
            model: Ext.ux.grid.property.Property,
            proxy: me.getProxy(),
            groupField: grid.groupField
        }]);
    },

    setValue: function(prop, value, create)
    {
        var me = this,
            rec = me.getRec(prop);

        if(rec)
        {
            rec.set('value', value);
            me.source[prop] = value;
        }
        else if(create)
        {
            // only create if specified.
            me.source[prop] = value;
            rec = new Ext.ux.grid.property.Property({
                name: prop,
                value: value
            }, prop);
            me.add(rec);
        }
    }
});<commit_msg>fix some problems with parent constructor<commit_after>/**
 * @class Ext.ux.grid.property.Store
 * @extends Ext.grid.property.Store
 *
 * @author Harald Hanek (c) 2011-2012
 * @license http://harrydeluxe.mit-license.org
 */
Ext.define('Ext.ux.grid.property.Store', {
    extend: 'Ext.grid.property.Store',

    uses: ['Ext.ux.grid.property.Property'],

    proxy: {
        type: 'memory',
        reader: {
            type: 'json'
        }
    },

    /**
     * Creates new property store.
     * @param {Ext.grid.Panel} grid The grid this store will be bound to
     * @param {Object} source The source data config object
     */
    constructor: function(grid, source)
    {
        var me = this,
            tmp = me.superclass.constructor; // stores temporary the parent constructor

        me.grid = grid;
        me.source = source;

        delete me.superclass.constructor;

        me.callParent([{
            data: source || [],
            model: Ext.ux.grid.property.Property,
            proxy: me.getProxy(),
            groupField: grid.groupField
        }]);

        me.superclass.constructor = tmp;
    },

    setValue: function(prop, value, create)
    {
        var me = this,
            rec = me.getRec(prop);

        if(rec)
        {
            rec.set('value', value);
            me.source[prop] = value;
        }
        else if(create)
        {
            // only create if specified.
            me.source[prop] = value;
            rec = new Ext.ux.grid.property.Property({
                name: prop,
                value: value
            }, prop);
            me.add(rec);
        }
    }
});<|endoftext|>


<commit_before>import React from 'react';
import {shallow} from 'enzyme';
import {QueryRenderer} from 'react-relay';

import IssueishDetailContainer from '../../lib/containers/issueish-detail-container';
import {cloneRepository, buildRepository} from '../helpers';
import {queryBuilder} from '../builder/graphql/query';
import {aggregatedReviewsBuilder} from '../builder/graphql/aggregated-reviews-builder';
import GithubLoginModel from '../../lib/models/github-login-model';
import RefHolder from '../../lib/models/ref-holder';
import {getEndpoint} from '../../lib/models/endpoint';
import {InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT} from '../../lib/shared/keytar-strategy';
import ObserveModel from '../../lib/views/observe-model';
import IssueishDetailItem from '../../lib/items/issueish-detail-item';
import IssueishDetailController from '../../lib/controllers/issueish-detail-controller';
import AggregatedReviewsContainer from '../../lib/containers/aggregated-reviews-container';

import rootQuery from '../../lib/containers/__generated__/issueishDetailContainerQuery.graphql';

describe('IssueishDetailContainer', function() {
  let atomEnv, loginModel, repository;

  beforeEach(async function() {
    atomEnv = global.buildAtomEnvironment();
    loginModel = new GithubLoginModel(InMemoryStrategy);
    repository = await buildRepository(await cloneRepository());
  });

  afterEach(function() {
    atomEnv.destroy();
  });

  function buildApp(override = {}) {
    const props = {
      endpoint: getEndpoint('github.com'),

      owner: 'atom',
      repo: 'github',
      issueishNumber: 123,

      selectedTab: 0,
      onTabSelected: () => {},
      onOpenFilesTab: () => {},

      repository,
      loginModel,

      workspace: atomEnv.workspace,
      commands: atomEnv.commands,
      keymaps: atomEnv.keymaps,
      tooltips: atomEnv.tooltips,
      config: atomEnv.config,

      switchToIssueish: () => {},
      onTitleChange: () => {},
      destroy: () => {},

      itemType: IssueishDetailItem,
      refEditor: new RefHolder(),

      ...override,
    };

    return <IssueishDetailContainer {...props} />;
  }

  it('renders a spinner while the token is being fetched', async function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')(null);

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    // Don't render the GraphQL query before the token is available
    assert.isTrue(repoWrapper.exists('LoadingView'));
  });

  it('renders a login prompt if the user is unauthenticated', function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: UNAUTHENTICATED});

    assert.isTrue(tokenWrapper.exists('GithubLoginView'));
  });

  it("renders a login prompt if the user's token has insufficient scopes", function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: INSUFFICIENT});

    assert.isTrue(tokenWrapper.exists('GithubLoginView'));
    assert.match(tokenWrapper.find('p').text(), /re-authenticate/);
  });

  it('renders an offline message if the user cannot connect to the Internet', function() {
    sinon.spy(loginModel, 'didUpdate');

    const wrapper = shallow(buildApp());
    const e = new Error('wat');
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: e});

    assert.isTrue(tokenWrapper.exists('QueryErrorView'));

    tokenWrapper.find('QueryErrorView').prop('retry')();
    assert.isTrue(loginModel.didUpdate.called);
  });

  it('passes the token to the login model on login', async function() {
    sinon.stub(loginModel, 'setToken').resolves();

    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: UNAUTHENTICATED});

    await tokenWrapper.find('GithubLoginView').prop('onLogin')('4321');
    assert.isTrue(loginModel.setToken.calledWith('https://github.enterprise.horse', '4321'));
  });

  it('passes an existing token from the login model', async function() {
    sinon.stub(loginModel, 'getToken').resolves('1234');

    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));
    assert.deepEqual(await wrapper.find(ObserveModel).prop('fetchData')(loginModel), {token: '1234'});
  });

  it('renders a spinner while repository data is being fetched', function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(null);

    const props = queryBuilder(rootQuery).build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    assert.isTrue(resultWrapper.exists('LoadingView'));
  });

  it('renders a spinner while the GraphQL query is being performed', async function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props: null, retry: () => {},
    });

    assert.isTrue(resultWrapper.exists('LoadingView'));
  });

  it('renders an error view if the GraphQL query fails', async function() {
    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const error = new Error('wat');
    error.rawStack = error.stack;
    const retry = sinon.spy();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error, props: null, retry,
    });

    const errorView = resultWrapper.find('QueryErrorView');
    assert.strictEqual(errorView.prop('error'), error);

    errorView.prop('retry')();
    assert.isTrue(retry.called);

    sinon.stub(loginModel, 'removeToken').resolves();
    await errorView.prop('logout')();
    assert.isTrue(loginModel.removeToken.calledWith('https://github.enterprise.horse'));

    sinon.stub(loginModel, 'setToken').resolves();
    await errorView.prop('login')('1234');
    assert.isTrue(loginModel.setToken.calledWith('https://github.enterprise.horse', '1234'));
  });

  it('renders an IssueishDetailContainer with GraphQL results for an issue', async function() {
    const wrapper = shallow(buildApp({
      owner: 'smashwilson',
      repo: 'pushbot',
      issueishNumber: 4000,
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const variables = repoWrapper.find(QueryRenderer).prop('variables');
    assert.strictEqual(variables.repoOwner, 'smashwilson');
    assert.strictEqual(variables.repoName, 'pushbot');
    assert.strictEqual(variables.issueishNumber, 4000);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.beIssue()))
      .build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    const controller = resultWrapper.find(IssueishDetailController);

    // GraphQL query results
    assert.strictEqual(controller.prop('repository'), props.repository);

    // Null data for aggregated comment threads
    assert.isFalse(controller.prop('reviewCommentsLoading'));
    assert.strictEqual(controller.prop('reviewCommentsTotalCount'), 0);
    assert.strictEqual(controller.prop('reviewCommentsResolvedCount'), 0);
    assert.lengthOf(controller.prop('reviewCommentThreads'), 0);

    // Requested repository attributes
    assert.strictEqual(controller.prop('branches'), repoData.branches);

    // The local repository, passed with a different name to not collide with the GraphQL result
    assert.strictEqual(controller.prop('localRepository'), repository);
    assert.strictEqual(controller.prop('workdirPath'), repository.getWorkingDirectoryPath());

    // The GitHub OAuth token
    assert.strictEqual(controller.prop('token'), '1234');
  });

  it('renders an IssueishDetailController while aggregating reviews for a pull request', async function() {
    const wrapper = shallow(buildApp({
      owner: 'smashwilson',
      repo: 'pushbot',
      issueishNumber: 4000,
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.bePullRequest()))
      .build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    const reviews = aggregatedReviewsBuilder().loading(true).build();
    assert.strictEqual(resultWrapper.find(AggregatedReviewsContainer).prop('pullRequest'), props.repository.issueish);
    const reviewsWrapper = resultWrapper.find(AggregatedReviewsContainer).renderProp('children')(reviews);

    const controller = reviewsWrapper.find(IssueishDetailController);

    // GraphQL query results
    assert.strictEqual(controller.prop('repository'), props.repository);

    // Null data for aggregated comment threads
    assert.isTrue(controller.prop('reviewCommentsLoading'));
    assert.strictEqual(controller.prop('reviewCommentsTotalCount'), 0);
    assert.strictEqual(controller.prop('reviewCommentsResolvedCount'), 0);
    assert.lengthOf(controller.prop('reviewCommentThreads'), 0);

    // Requested repository attributes
    assert.strictEqual(controller.prop('branches'), repoData.branches);

    // The local repository, passed with a different name to not collide with the GraphQL result
    assert.strictEqual(controller.prop('localRepository'), repository);
    assert.strictEqual(controller.prop('workdirPath'), repository.getWorkingDirectoryPath());

    // The GitHub OAuth token
    assert.strictEqual(controller.prop('token'), '1234');
  });

  it('renders an error view if the review aggregation fails', async function() {
    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.bePullRequest()))
      .build();
    const retry = sinon.spy();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry,
    });

    const reviews = aggregatedReviewsBuilder()
      .addError(new Error("It's not DNS"))
      .addError(new Error("There's no way it's DNS"))
      .addError(new Error('It was DNS'))
      .build();
    const reviewsWrapper = resultWrapper.find(AggregatedReviewsContainer).renderProp('children')(reviews);

    const errorView = reviewsWrapper.find('ErrorView');
    assert.strictEqual(errorView.prop('title'), 'Unable to fetch review comments');
    assert.deepEqual(errorView.prop('descriptions'), [
      "Error: It's not DNS",
      "Error: There's no way it's DNS",
      'Error: It was DNS',
    ]);

    errorView.prop('retry')();
    assert.isTrue(retry.called);

    sinon.stub(loginModel, 'removeToken').resolves();
    await errorView.prop('logout')();
    assert.isTrue(loginModel.removeToken.calledWith('https://github.enterprise.horse'));
  });

  it('passes GraphQL query results and aggregated reviews to its IssueishDetailController', async function() {
    const wrapper = shallow(buildApp({
      owner: 'smashwilson',
      repo: 'pushbot',
      issueishNumber: 4000,
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const variables = repoWrapper.find(QueryRenderer).prop('variables');
    assert.strictEqual(variables.repoOwner, 'smashwilson');
    assert.strictEqual(variables.repoName, 'pushbot');
    assert.strictEqual(variables.issueishNumber, 4000);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.bePullRequest()))
      .build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    const reviews = aggregatedReviewsBuilder()
      .addReviewThread(b => b.thread(t => t.isResolved(true)).addComment())
      .addReviewThread(b => b.thread(t => t.isResolved(false)).addComment().addComment())
      .addReviewThread(b => b.thread(t => t.isResolved(false)))
      .addReviewThread(b => b.thread(t => t.isResolved(false)).addComment())
      .addReviewThread(b => b.thread(t => t.isResolved(true)))
      .build();
    const reviewsWrapper = resultWrapper.find(AggregatedReviewsContainer).renderProp('children')(reviews);

    const controller = reviewsWrapper.find(IssueishDetailController);

    // GraphQL query results
    assert.strictEqual(controller.prop('repository'), props.repository);

    // Aggregated comment thread data
    assert.isFalse(controller.prop('reviewCommentsLoading'));
    assert.strictEqual(controller.prop('reviewCommentsTotalCount'), 3);
    assert.strictEqual(controller.prop('reviewCommentsResolvedCount'), 1);
    assert.lengthOf(controller.prop('reviewCommentThreads'), 3);

    // Requested repository attributes
    assert.strictEqual(controller.prop('branches'), repoData.branches);

    // The local repository, passed with a different name to not collide with the GraphQL result
    assert.strictEqual(controller.prop('localRepository'), repository);
    assert.strictEqual(controller.prop('workdirPath'), repository.getWorkingDirectoryPath());

    // The GitHub OAuth token
    assert.strictEqual(controller.prop('token'), '1234');
  });
});
<commit_msg>fix 'IssueDetailContainer' test warnings<commit_after>import React from 'react';
import {shallow} from 'enzyme';
import {QueryRenderer} from 'react-relay';

import IssueishDetailContainer from '../../lib/containers/issueish-detail-container';
import {cloneRepository, buildRepository} from '../helpers';
import {queryBuilder} from '../builder/graphql/query';
import {aggregatedReviewsBuilder} from '../builder/graphql/aggregated-reviews-builder';
import GithubLoginModel from '../../lib/models/github-login-model';
import RefHolder from '../../lib/models/ref-holder';
import {getEndpoint} from '../../lib/models/endpoint';
import {InMemoryStrategy, UNAUTHENTICATED, INSUFFICIENT} from '../../lib/shared/keytar-strategy';
import ObserveModel from '../../lib/views/observe-model';
import IssueishDetailItem from '../../lib/items/issueish-detail-item';
import IssueishDetailController from '../../lib/controllers/issueish-detail-controller';
import AggregatedReviewsContainer from '../../lib/containers/aggregated-reviews-container';

import rootQuery from '../../lib/containers/__generated__/issueishDetailContainerQuery.graphql';

describe('IssueishDetailContainer', function() {
  let atomEnv, loginModel, repository;

  beforeEach(async function() {
    atomEnv = global.buildAtomEnvironment();
    loginModel = new GithubLoginModel(InMemoryStrategy);
    repository = await buildRepository(await cloneRepository());
  });

  afterEach(function() {
    atomEnv.destroy();
  });

  function buildApp(override = {}) {
    const props = {
      endpoint: getEndpoint('github.com'),

      owner: 'atom',
      repo: 'github',
      issueishNumber: 123,

      selectedTab: 0,
      onTabSelected: () => {},
      onOpenFilesTab: () => {},

      repository,
      loginModel,

      workspace: atomEnv.workspace,
      commands: atomEnv.commands,
      keymaps: atomEnv.keymaps,
      tooltips: atomEnv.tooltips,
      config: atomEnv.config,

      switchToIssueish: () => {},
      onTitleChange: () => {},
      destroy: () => {},
      reportRelayError: () => {},

      itemType: IssueishDetailItem,
      refEditor: new RefHolder(),

      ...override,
    };

    return <IssueishDetailContainer {...props} />;
  }

  it('renders a spinner while the token is being fetched', async function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')(null);

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    // Don't render the GraphQL query before the token is available
    assert.isTrue(repoWrapper.exists('LoadingView'));
  });

  it('renders a login prompt if the user is unauthenticated', function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: UNAUTHENTICATED});

    assert.isTrue(tokenWrapper.exists('GithubLoginView'));
  });

  it("renders a login prompt if the user's token has insufficient scopes", function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: INSUFFICIENT});

    assert.isTrue(tokenWrapper.exists('GithubLoginView'));
    assert.match(tokenWrapper.find('p').text(), /re-authenticate/);
  });

  it('renders an offline message if the user cannot connect to the Internet', function() {
    sinon.spy(loginModel, 'didUpdate');

    const wrapper = shallow(buildApp());
    const e = new Error('wat');
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: e});

    assert.isTrue(tokenWrapper.exists('QueryErrorView'));

    tokenWrapper.find('QueryErrorView').prop('retry')();
    assert.isTrue(loginModel.didUpdate.called);
  });

  it('passes the token to the login model on login', async function() {
    sinon.stub(loginModel, 'setToken').resolves();

    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: UNAUTHENTICATED});

    await tokenWrapper.find('GithubLoginView').prop('onLogin')('4321');
    assert.isTrue(loginModel.setToken.calledWith('https://github.enterprise.horse', '4321'));
  });

  it('passes an existing token from the login model', async function() {
    sinon.stub(loginModel, 'getToken').resolves('1234');

    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));
    assert.deepEqual(await wrapper.find(ObserveModel).prop('fetchData')(loginModel), {token: '1234'});
  });

  it('renders a spinner while repository data is being fetched', function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(null);

    const props = queryBuilder(rootQuery).build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    assert.isTrue(resultWrapper.exists('LoadingView'));
  });

  it('renders a spinner while the GraphQL query is being performed', async function() {
    const wrapper = shallow(buildApp());
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props: null, retry: () => {},
    });

    assert.isTrue(resultWrapper.exists('LoadingView'));
  });

  it('renders an error view if the GraphQL query fails', async function() {
    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));
    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const error = new Error('wat');
    error.rawStack = error.stack;
    const retry = sinon.spy();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error, props: null, retry,
    });

    const errorView = resultWrapper.find('QueryErrorView');
    assert.strictEqual(errorView.prop('error'), error);

    errorView.prop('retry')();
    assert.isTrue(retry.called);

    sinon.stub(loginModel, 'removeToken').resolves();
    await errorView.prop('logout')();
    assert.isTrue(loginModel.removeToken.calledWith('https://github.enterprise.horse'));

    sinon.stub(loginModel, 'setToken').resolves();
    await errorView.prop('login')('1234');
    assert.isTrue(loginModel.setToken.calledWith('https://github.enterprise.horse', '1234'));
  });

  it('renders an IssueishDetailContainer with GraphQL results for an issue', async function() {
    const wrapper = shallow(buildApp({
      owner: 'smashwilson',
      repo: 'pushbot',
      issueishNumber: 4000,
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const variables = repoWrapper.find(QueryRenderer).prop('variables');
    assert.strictEqual(variables.repoOwner, 'smashwilson');
    assert.strictEqual(variables.repoName, 'pushbot');
    assert.strictEqual(variables.issueishNumber, 4000);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.beIssue()))
      .build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    const controller = resultWrapper.find(IssueishDetailController);

    // GraphQL query results
    assert.strictEqual(controller.prop('repository'), props.repository);

    // Null data for aggregated comment threads
    assert.isFalse(controller.prop('reviewCommentsLoading'));
    assert.strictEqual(controller.prop('reviewCommentsTotalCount'), 0);
    assert.strictEqual(controller.prop('reviewCommentsResolvedCount'), 0);
    assert.lengthOf(controller.prop('reviewCommentThreads'), 0);

    // Requested repository attributes
    assert.strictEqual(controller.prop('branches'), repoData.branches);

    // The local repository, passed with a different name to not collide with the GraphQL result
    assert.strictEqual(controller.prop('localRepository'), repository);
    assert.strictEqual(controller.prop('workdirPath'), repository.getWorkingDirectoryPath());

    // The GitHub OAuth token
    assert.strictEqual(controller.prop('token'), '1234');
  });

  it('renders an IssueishDetailController while aggregating reviews for a pull request', async function() {
    const wrapper = shallow(buildApp({
      owner: 'smashwilson',
      repo: 'pushbot',
      issueishNumber: 4000,
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.bePullRequest()))
      .build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    const reviews = aggregatedReviewsBuilder().loading(true).build();
    assert.strictEqual(resultWrapper.find(AggregatedReviewsContainer).prop('pullRequest'), props.repository.issueish);
    const reviewsWrapper = resultWrapper.find(AggregatedReviewsContainer).renderProp('children')(reviews);

    const controller = reviewsWrapper.find(IssueishDetailController);

    // GraphQL query results
    assert.strictEqual(controller.prop('repository'), props.repository);

    // Null data for aggregated comment threads
    assert.isTrue(controller.prop('reviewCommentsLoading'));
    assert.strictEqual(controller.prop('reviewCommentsTotalCount'), 0);
    assert.strictEqual(controller.prop('reviewCommentsResolvedCount'), 0);
    assert.lengthOf(controller.prop('reviewCommentThreads'), 0);

    // Requested repository attributes
    assert.strictEqual(controller.prop('branches'), repoData.branches);

    // The local repository, passed with a different name to not collide with the GraphQL result
    assert.strictEqual(controller.prop('localRepository'), repository);
    assert.strictEqual(controller.prop('workdirPath'), repository.getWorkingDirectoryPath());

    // The GitHub OAuth token
    assert.strictEqual(controller.prop('token'), '1234');
  });

  it('renders an error view if the review aggregation fails', async function() {
    const wrapper = shallow(buildApp({
      endpoint: getEndpoint('github.enterprise.horse'),
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.bePullRequest()))
      .build();
    const retry = sinon.spy();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry,
    });

    const reviews = aggregatedReviewsBuilder()
      .addError(new Error("It's not DNS"))
      .addError(new Error("There's no way it's DNS"))
      .addError(new Error('It was DNS'))
      .build();
    const reviewsWrapper = resultWrapper.find(AggregatedReviewsContainer).renderProp('children')(reviews);

    const errorView = reviewsWrapper.find('ErrorView');
    assert.strictEqual(errorView.prop('title'), 'Unable to fetch review comments');
    assert.deepEqual(errorView.prop('descriptions'), [
      "Error: It's not DNS",
      "Error: There's no way it's DNS",
      'Error: It was DNS',
    ]);

    errorView.prop('retry')();
    assert.isTrue(retry.called);

    sinon.stub(loginModel, 'removeToken').resolves();
    await errorView.prop('logout')();
    assert.isTrue(loginModel.removeToken.calledWith('https://github.enterprise.horse'));
  });

  it('passes GraphQL query results and aggregated reviews to its IssueishDetailController', async function() {
    const wrapper = shallow(buildApp({
      owner: 'smashwilson',
      repo: 'pushbot',
      issueishNumber: 4000,
    }));

    const tokenWrapper = wrapper.find(ObserveModel).renderProp('children')({token: '1234'});

    const repoData = await tokenWrapper.find(ObserveModel).prop('fetchData')(
      tokenWrapper.find(ObserveModel).prop('model'),
    );
    const repoWrapper = tokenWrapper.find(ObserveModel).renderProp('children')(repoData);

    const variables = repoWrapper.find(QueryRenderer).prop('variables');
    assert.strictEqual(variables.repoOwner, 'smashwilson');
    assert.strictEqual(variables.repoName, 'pushbot');
    assert.strictEqual(variables.issueishNumber, 4000);

    const props = queryBuilder(rootQuery)
      .repository(r => r.issueish(i => i.bePullRequest()))
      .build();
    const resultWrapper = repoWrapper.find(QueryRenderer).renderProp('render')({
      error: null, props, retry: () => {},
    });

    const reviews = aggregatedReviewsBuilder()
      .addReviewThread(b => b.thread(t => t.isResolved(true)).addComment())
      .addReviewThread(b => b.thread(t => t.isResolved(false)).addComment().addComment())
      .addReviewThread(b => b.thread(t => t.isResolved(false)))
      .addReviewThread(b => b.thread(t => t.isResolved(false)).addComment())
      .addReviewThread(b => b.thread(t => t.isResolved(true)))
      .build();
    const reviewsWrapper = resultWrapper.find(AggregatedReviewsContainer).renderProp('children')(reviews);

    const controller = reviewsWrapper.find(IssueishDetailController);

    // GraphQL query results
    assert.strictEqual(controller.prop('repository'), props.repository);

    // Aggregated comment thread data
    assert.isFalse(controller.prop('reviewCommentsLoading'));
    assert.strictEqual(controller.prop('reviewCommentsTotalCount'), 3);
    assert.strictEqual(controller.prop('reviewCommentsResolvedCount'), 1);
    assert.lengthOf(controller.prop('reviewCommentThreads'), 3);

    // Requested repository attributes
    assert.strictEqual(controller.prop('branches'), repoData.branches);

    // The local repository, passed with a different name to not collide with the GraphQL result
    assert.strictEqual(controller.prop('localRepository'), repository);
    assert.strictEqual(controller.prop('workdirPath'), repository.getWorkingDirectoryPath());

    // The GitHub OAuth token
    assert.strictEqual(controller.prop('token'), '1234');
  });
});
<|endoftext|>