<commit_before>var sqlite3 = require('sqlite3');
var assert = require('assert');

if (process.setMaxListeners) process.setMaxListeners(0);

exports['test scheduling a query after the database was closed'] = function(beforeExit) {
    var error = false;
    var db = new sqlite3.Database(':memory:');
    db.on('error', function(err) {
        error = true;
        assert.equal(err.message, "SQLITE_MISUSE: Database handle is closed");
    });

    db.close();
    db.run("CREATE TABLE foo (id int)");

    beforeExit(function() {
        assert.ok(error);
    });
};

exports['test scheduling a query with callback after the database was closed'] = function(beforeExit) {
    var error = false;
    var errorEvent = false;
    var db = new sqlite3.Database(':memory:');
    db.on('error', function(err) {
        errorEvent = true;
    });

    db.close();
    db.run("CREATE TABLE foo (id int)", function(err) {
        assert.ok(err.message, "SQLITE_MISUSE: Database handle is closed");
        error = true;
    });

    beforeExit(function() {
        assert.ok(error);
        assert.ok(!errorEvent);
    });
};

exports['test running a query after the database was closed'] = function(beforeExit) {
    var error = false;
    var db = new sqlite3.Database(':memory:');

    var stmt = db.prepare("SELECT * FROM sqlite_master", function(err) {
        if (err) throw err;
        db.close(function(err) {
            assert.ok(err);
            error = true;
            assert.equal(err.message, "SQLITE_BUSY: unable to close due to unfinalised statements");
            stmt.run();
        });
    });

    beforeExit(function() {
        assert.ok(error);
    });
};
<commit_msg>fix scheduling.test.js against variable sqlite3 versions - closes #122 (thanks @tomhughes for initial patch)<commit_after>var sqlite3 = require('sqlite3');
var assert = require('assert');

if (process.setMaxListeners) process.setMaxListeners(0);

exports['test scheduling a query after the database was closed'] = function(beforeExit) {
    var error = false;
    var db = new sqlite3.Database(':memory:');
    db.on('error', function(err) {
        error = true;
        assert.ok(err.message && err.message.indexOf("SQLITE_MISUSE: Database handle is closed") > -1);
    });

    db.close();
    db.run("CREATE TABLE foo (id int)");

    beforeExit(function() {
        assert.ok(error);
    });
};

exports['test scheduling a query with callback after the database was closed'] = function(beforeExit) {
    var error = false;
    var errorEvent = false;
    var db = new sqlite3.Database(':memory:');
    db.on('error', function(err) {
        errorEvent = true;
    });

    db.close();
    db.run("CREATE TABLE foo (id int)", function(err) {
        assert.ok(err.message && err.message.indexOf("SQLITE_MISUSE: Database handle is closed") > -1);
        error = true;
    });

    beforeExit(function() {
        assert.ok(error);
        assert.ok(!errorEvent);
    });
};

exports['test running a query after the database was closed'] = function(beforeExit) {
    var error = false;
    var db = new sqlite3.Database(':memory:');

    var stmt = db.prepare("SELECT * FROM sqlite_master", function(err) {
        if (err) throw err;
        db.close(function(err) {
            assert.ok(err);
            error = true;
            assert.ok(err.message && err.message.indexOf("SQLITE_BUSY: unable to close due to") > -1);
            stmt.run();
        });
    });

    beforeExit(function() {
        assert.ok(error);
    });
};
<|endoftext|>


<commit_before>const url = require('url');
const mimeTypes = require('mime-types');
const path = require('path');
const headFile = require('./head-file');
const getStatic = require('./get-static');
const getFile = require('./get-file');
const getFiles = require('./get-files');
const putFile = require('./put-file');
const deleteFile = require('./delete-file');
const deleteFiles = require('./delete-files');
const getAuthHandler = require('./get-auth');
const BlobbyClient = require('blobby-client');

module.exports = (argv, config) => {
  const client = new BlobbyClient(argv, config);

  if (typeof config.logger === 'function') {
    client.on('warn', msg => logger.warn(msg));
    client.on('error', msg => logger.error(msg));
  }

  return async (req, res) => {
    if (typeof config.httpHandler === 'function') {
      if (config.httpHandler(req, res) === false) return; // if handled by parent ignore request
    }
    const urlInfo = url.parse(req.url, true, true);
    let safePathname;
    try {
      safePathname = decodeURI(urlInfo.pathname).split('/').map(decodeURIComponent).join('/');
    } catch (ex) {
      client.emit('error', { message: `Cannot decodeURI ${urlInfo.pathname}`, stack: ex.stack || ex });

      res.writeHead(400); // bad request
      return void res.end();
    }
    const contentType = mimeTypes.lookup(path.extname(safePathname)) || 'binary/octet-stream';
    if (req.method === 'GET' && getStatic(argv, config, { req, res, urlInfo, contentType, client })) return; // handled by static handler
    const pathParts = safePathname.split('/');
    const storageId = pathParts[1];
    if (!storageId) { // root is healthcheck
      res.statusCode = 200;
      return void res.end();
    } else if (storageId === 'favicon.ico') { // benign, don't log
      res.statusCode = 404;
      return void res.end();
    }
    let storage;
    try {
      storage = client.getStorage(storageId);
    } catch (ex) {
      client.emit('warn', { message: 'Storage exception', stack: ex.stack || ex });

      res.statusMessage = 'Invalid storage';
      res.statusCode = 404;
      return void res.end();
    }

    const fileKey = pathParts.slice(2).join('/');
    const opts = { isAuthorized: true, argv, config, client, storage, fileKey, urlInfo, req, res, contentType, headers: req.headers || req.getAllHeaders() };
    try {
      const auth = getAuthHandler(opts);
      if (auth) {
        opts.isAuthorized = await auth;
      }
      switch (req.method) {
        case 'HEAD':
          await headFile(opts);
          break;
        case 'GET':
          if (pathParts[pathParts.length - 1] === '') await getFiles(opts); // if path ends in `/` it's a directory request
          else await getFile(opts);
          break;
        case 'PUT':
          await putFile(opts);
          break;
        case 'DELETE':
          if (pathParts[pathParts.length - 1] === '') await deleteFiles(opts); // if path ends in `/` it's a directory request
          else await deleteFile(opts);
          break;
        default:
          client.emit('warn', { status: 404, message: `Unsupported req.method ${req.method}` });
          res.writeHead(404);
          res.end();
          break;
      }
    } catch (err) {
      const status = err.statusCode || 500;
      client.emit(status >= 500 ? 'error' : 'warn', { status: status, message: `Error ${status}`, stack: err.stack || err });
      res.statusCode = status;
      return void res.end();
    }
  };
};
<commit_msg>fix logger<commit_after>const url = require('url');
const mimeTypes = require('mime-types');
const path = require('path');
const headFile = require('./head-file');
const getStatic = require('./get-static');
const getFile = require('./get-file');
const getFiles = require('./get-files');
const putFile = require('./put-file');
const deleteFile = require('./delete-file');
const deleteFiles = require('./delete-files');
const getAuthHandler = require('./get-auth');
const BlobbyClient = require('blobby-client');

module.exports = (argv, config) => {
  const client = new BlobbyClient(argv, config);

  if (typeof config.logger === 'object') {
    client.on('warn', msg => config.logger.warn(msg));
    client.on('error', msg => config.logger.error(msg));
  }

  return async (req, res) => {
    if (typeof config.httpHandler === 'function') {
      if (config.httpHandler(req, res) === false) return; // if handled by parent ignore request
    }
    const urlInfo = url.parse(req.url, true, true);
    let safePathname;
    try {
      safePathname = decodeURI(urlInfo.pathname).split('/').map(decodeURIComponent).join('/');
    } catch (ex) {
      client.emit('error', { message: `Cannot decodeURI ${urlInfo.pathname}`, stack: ex.stack || ex });

      res.writeHead(400); // bad request
      return void res.end();
    }
    const contentType = mimeTypes.lookup(path.extname(safePathname)) || 'binary/octet-stream';
    if (req.method === 'GET' && getStatic(argv, config, { req, res, urlInfo, contentType, client })) return; // handled by static handler
    const pathParts = safePathname.split('/');
    const storageId = pathParts[1];
    if (!storageId) { // root is healthcheck
      res.statusCode = 200;
      return void res.end();
    } else if (storageId === 'favicon.ico') { // benign, don't log
      res.statusCode = 404;
      return void res.end();
    }
    let storage;
    try {
      storage = client.getStorage(storageId);
    } catch (ex) {
      client.emit('warn', { message: 'Storage exception', stack: ex.stack || ex });

      res.statusMessage = 'Invalid storage';
      res.statusCode = 404;
      return void res.end();
    }

    const fileKey = pathParts.slice(2).join('/');
    const opts = { isAuthorized: true, argv, config, client, storage, fileKey, urlInfo, req, res, contentType, headers: req.headers || req.getAllHeaders() };
    try {
      const auth = getAuthHandler(opts);
      if (auth) {
        opts.isAuthorized = await auth;
      }
      switch (req.method) {
        case 'HEAD':
          await headFile(opts);
          break;
        case 'GET':
          if (pathParts[pathParts.length - 1] === '') await getFiles(opts); // if path ends in `/` it's a directory request
          else await getFile(opts);
          break;
        case 'PUT':
          await putFile(opts);
          break;
        case 'DELETE':
          if (pathParts[pathParts.length - 1] === '') await deleteFiles(opts); // if path ends in `/` it's a directory request
          else await deleteFile(opts);
          break;
        default:
          client.emit('warn', { status: 404, message: `Unsupported req.method ${req.method}` });
          res.writeHead(404);
          res.end();
          break;
      }
    } catch (err) {
      const status = err.statusCode || 500;
      client.emit(status >= 500 ? 'error' : 'warn', { status: status, message: `Error ${status}`, stack: err.stack || err });
      res.statusCode = status;
      return void res.end();
    }
  };
};
<|endoftext|>


<commit_before>/* jshint node:true */
/* global MergeXML, describe, it, before, after, beforeEach, afterEach, expect */
'use strict';

describe('Instantiating object ', function() {
    var merger;

    it('works', function() {
        merger = new MergeXML();

        expect(merger).to.be.an('object');
    });

});

describe('Adding source', function() {
    var merger, a, b;

    it('strings works', function() {
        merger = new MergeXML();
        a = '';
        b = '';

        expect(merger.AddSource(a)).to.not.equal(false);
        expect(merger.AddSource(b)).to.not.equal(false);
    });

});

describe('Merging XML sources', function() {
    var merger, a, b;

    describe('with option join = undefined', function() {

        // TODO

    });

    describe('with option join = false', function() {

        it('succeeds if sources have a common root name', function() {
            merger = new MergeXML({
                join: false
            });
            a = '<r></r>';
            b = '<r></r>';
            merger.AddSource(a);
            merger.AddSource(b);
            expect(merger.Get(1).trim()).to.equal('<r></r>');
        });

        it('fails to merge second source if sources do not have a common root name', function() {
            merger = new MergeXML({
                join: false
            });
            a = '';
            b = '';
            merger.AddSource(a);
            merger.AddSource(b);

            expect(merger.Get(1).trim()).to.equal('');
        });

    });

    describe('with option updn = true or undefined', function() {
        var merger, a, b;

        it('merges sources by nodeName', function() {
            merger = new MergeXML({
                updn: true
            });
            a = '' +
                '<c>s1</c>' +
                '<c>s3</c>' +
                '';
            b = '' +
                '<c>s1</c>' +
                's2' +
                '<c>s4</c>' +
                '';
            merger.AddSource(a);
            merger.AddSource(b);
            expect(merger.Get(1).trim()).to.equal('<c>s1</c><c>s4</c>s2');

            merger = new MergeXML();
            merger.AddSource(a);
            merger.AddSource(b);

            expect(merger.Get(1).trim()).to.equal('<c>s1</c><c>s4</c>s2');
        });

    });

    describe('with option updn = false', function() {
        var merger, a, b;

        it('merges sources by node position, discarding nodeName', function() {
            merger = new MergeXML({
                updn: false
            });
            a = '' +
                '<c>s1</c>' +
                '<c>s3</c>' +
                '';
            b = '' +
                '<c>s1</c>' +
                's2' +
                '<c>s4</c>' +
                '';
            merger.AddSource(a);
            merger.AddSource(b);

            expect(merger.Get(1).trim()).to.equal('<c>s1</c><c>s2</c><c>s4</c>');
        });
    });

    describe('with namespaced attributes', function() {
        var merger;
        var ns = 'https://github.com/enketo/merge-xml';

        it('correctly adds namespaced attributes from second source', function() {
            merger = new MergeXML({
                join: false
            });
            a = '' +
                '<c>s1</c>' +
                '';
            b = '' +
                '<c enk:custom="something">s2</c>' +
                '';
            merger.AddSource(a);
            merger.AddSource(b);

            expect(merger.error.code).to.equal('');
            expect(merger.error.text).to.equal('');
            expect(merger.Get(1).trim()).to.equal('<c enk:custom="something">s2</c>');
            // in IE11 and below, merger.Get(0) returns an ActiveXObject we use the internal "Query" function
            expect(merger.Query('//c').attributes[0].localName).to.equal('custom'); // fails in IE because
            expect(merger.Query('//c').attributes[0].namespaceURI).to.equal(ns);
        })

    })

    describe('with sources that have and do not have a UTF encoding declaration', function() {
        var merger;
        var a = '<?xml version="1.0"?>' +
            '<c>s1</c>';
        var b = '<?xml version="1.0" encoding="UTF-8"?>' +
            '<c>s2</c>';

        it('undeclared and UTF-8', function() {
            merger = new MergeXML({
                join: false
            });
            merger.AddSource(a);
            merger.AddSource(b);

            expect(merger.error.code).to.equal('');
            expect(merger.error.text).to.equal('');
            expect(merger.Get(1)).to.contain('<c>s2</c>');
        });

        it('UTF8 and undeclared', function() {
            merger = new MergeXML({
                join: false
            });
            merger.AddSource(b);
            merger.AddSource(a);

            expect(merger.error.code).to.equal('');
            expect(merger.error.text).to.equal('');
            expect(merger.Get(1)).to.contain('<c>s1</c>');
        });

    });

});
<commit_msg>Delete merge.spec.js<commit_after><|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Controller.extend({
  intl: Ember.inject.service(),
  actualChartOptions: Ember.computed('intl.locale', function() {
    return {
      chart: {
        plotBackgroundColor: null,
        plotBorderWidth: null,
        plotShadow: false,
        type: 'column'
      },
      title: {
        text: ''
      },
      xAxis:{
        categories: [
          this.get('intl').t('index.actual.series.events'),
          this.get('intl').t('index.actual.series.family'),
          this.get('intl').t('index.actual.series.series'),
          this.get('intl').t('index.actual.series.culture'),
          this.get('intl').t('index.actual.series.music'),
          this.get('intl').t('index.actual.series.politics'),
          this.get('intl').t('index.actual.series.presenation'),
          this.get('intl').t('index.actual.series.quiz'),
          this.get('intl').t('index.actual.series.religion'),
          this.get('intl').t('index.actual.series.show'),
          this.get('intl').t('index.actual.series.movie'),
          this.get('intl').t('index.actual.series.sport'),
          this.get('intl').t('index.actual.series.spot'),
        ],
      },
      yAxis: {
        title: {
          text: this.get('intl').t('index.actual.yAxis'),
        }
      },
      tooltip: {
        pointFormat: '{point.y:.3f} Mio. €'
      },
    }
  }),
  actualChartData: Ember.computed('intl.locale', function() {
    return [{
      name:  this.get('intl').t('index.actual.name.dasErste'),
      color: '#1e5b9a',
      data: [ 0, 114.9923, 262.7471, 50.9954, 1.6636, 309.7525, 0, 0, 10.0774, 225.5548, 213.7767, 461.8339, 3.6481]
    },{
      name:  this.get('intl').t('index.actual.name.zdf'),
      color: '#fa7d19',
      data: [171.697, 36.490, 422.425, 86.055, 6.201, 172.130, 32.672, 32, 0, 160.639, 73.300, 368.039, 0]
    }];
  }),
});
<commit_msg>sort bar chart<commit_after>import Ember from 'ember';

export default Ember.Controller.extend({
  intl: Ember.inject.service(),
  actualChartOptions: Ember.computed('intl.locale', function() {
    return {
      chart: {
        plotBackgroundColor: null,
        plotBorderWidth: null,
        plotShadow: false,
        type: 'column'
      },
      title: {
        text: ''
      },
      xAxis:{
        categories: [
          this.get('intl').t('index.actual.series.quiz'),
          this.get('intl').t('index.actual.series.spot'),
          this.get('intl').t('index.actual.series.music'),
          this.get('intl').t('index.actual.series.religion'),
          this.get('intl').t('index.actual.series.presenation'),
          this.get('intl').t('index.actual.series.culture'),
          this.get('intl').t('index.actual.series.family'),
          this.get('intl').t('index.actual.series.events'),
          this.get('intl').t('index.actual.series.movie'),
          this.get('intl').t('index.actual.series.show'),
          this.get('intl').t('index.actual.series.politics'),
          this.get('intl').t('index.actual.series.series'),
          this.get('intl').t('index.actual.series.sport'),
        ],
      },
      yAxis: {
        title: {
          text: this.get('intl').t('index.actual.yAxis'),
        }
      },
      tooltip: {
        pointFormat: '{point.y:.3f} Mio. €'
      },
    }
  }),
  actualChartData: Ember.computed('intl.locale', function() {
    return [{
      name:  this.get('intl').t('index.actual.name.dasErste'),
      color: '#1e5b9a',
      data: [ 0, 3.6481, 1.6636, 10.0774, 0, 50.9954, 114.9923, 0, 213.7767, 225.5548, 309.7525, 262.7471, 461.8339 ]
    },{
      name:  this.get('intl').t('index.actual.name.zdf'),
      color: '#fa7d19',
      data: [ 0.03, 0, 6.20, 0, 32.67, 86.06, 36.49, 171.70, 73.30, 160.64, 172.13, 422.425, 368.04 ]
    }];
  }),
});
<|endoftext|>


<commit_before>describe("Saving sessions.", function() {

  var windowId;
  var bookmarks;
  var tabsInfo;

  beforeEach(function(done) {
    clearLocalStorageAndInitialise();
    // Necessary because it takes time to create Seshy folder.
    setTimeout(() => {
      chrome.windows.create({}, (newWindow) => {
        windowId = newWindow.id
        tabsInfo = getTabsOrBookmarksInfo(newWindow.id, false);
        createTabs(tabsInfo, done);
      });
    }, 1000);
  });

  it("Should be able to save a set of tabs as bookmarks in a folder.", function(done) {
    callTest(done);
  });

  it("Should delete all the bookmarks in the session folder before saving an existing session.", function(done) {
    saveTestSession(windowId, () => {
      callTest(done);
    });
  });

  xit("Saves a session if it is given a name and it is not already saved.", function(done) {
    console.log("Unimplemented test.");
    done();
  })

  xit("Puts the text field for the current session's name into edit mode ready to be saved when the session manager " +
  "is opened and the current session is not already saved.", function(done) {
    console.log("Unimplemented test.");
    done();
  });

  xit("Only saves sessions the user has flagged to be saved.", function(done) {
    console.log("Unimplemented test.");
    done();
  });

  afterEach(function(done) {
    cleanUp();
    // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
    setTimeout(done, 1000);
  });

  function callTest(done) {
    saveSession(windowId); // Method under test.
    setTimeout(getBookmarksFolder, 1000);

    function getBookmarksFolder() {
      var query = {
        'title': 'Test Session'
      }
      chrome.bookmarks.search(query, getBookmarks);
    }

    function getBookmarks(bookmarkSessionFolderSearchResults) {
      // Only one bookmark session folder with the correct saved tabs ensures that the original bookmarks were deleted.
      expect(bookmarkSessionFolderSearchResults.length).toEqual(1);

      chrome.bookmarks.getChildren(bookmarkSessionFolderSearchResults[0].id, function(bookmarkTreeNodes) {
        bookmarks = bookmarkTreeNodes;
        assertSavedBookmarks(bookmarks, tabsInfo);
      });
    }

    function assertSavedBookmarks(bookmarks, expectedTabsInfo) {
      for (var i = 0; i < bookmarks.length; i++) {
        var bookmark = bookmarks[i];
        var expectedTabInfo = expectedTabsInfo[i];
        expect(bookmark.index).toEqual(expectedTabInfo.index);
        expect(bookmark.url).toEqual(expectedTabInfo.url);
      }
      done();
    }
  }
});

describe("Resuming sessions.", function() {

  describe("User restores a session from the session manager.", function() {

    var windowId;
    var sessionFolderId;
    var bookmarksInfo;

    beforeEach(function(done) {
      clearLocalStorageAndInitialise();
      // Necessary because it takes time to create Seshy folder.
      setTimeout(() => {
        chrome.windows.create({}, (newWindow) => {
          windowId = newWindow.id;
          bookmarksInfo = getTabsOrBookmarksInfo(newWindow.id, false);
          createTabs(bookmarksInfo, saveTestSessionAndCaptureSessionFolderId);
        });
      }, 1000);

      function saveTestSessionAndCaptureSessionFolderId() {
        saveTestSession(windowId, captureSessionFolderId);
      }

      function captureSessionFolderId(newSessionFolderId) {
        sessionFolderId = newSessionFolderId;
        chrome.windows.remove(windowId, () => {
          done();
        });
      }
    });

    it("Adds a window ID to session folder ID mapping in local storage.", function(done) {
      resumeSession(sessionFolderId, () => {
        chrome.storage.local.get(null, assertWindowToSessionFolderMappingAdded)
      });

      function assertWindowToSessionFolderMappingAdded(allLocalStorageObject) {
        var allLocalStorageKeys = Object.keys(allLocalStorageObject);

        var matchingLocalStorageKey;
        var matchingLocalStorageKeyValue;

        for (var i = 0; i < allLocalStorageKeys.length; i++) {
          var localStorageKey = allLocalStorageKeys[i];
          if (localStorageKey == windowId) {
            matchingLocalStorageKey = localStorageKey;
            matchingLocalStorageKeyValue = allLocalStorageObject[windowId.toString()]
          }
        }
        expect(matchingLocalStorageKey).toBe(windowId.toString());
        expect(matchingLocalStorageKeyValue).toBe(sessionFolderId);
        done();
      }
    });

    it("Opens a window with all the tabs as they were when the session was saved.", function(done) {
      resumeSession(sessionFolderId, (newWindow) => {
        assertSessionRestored(newWindow, bookmarksInfo);
      });

      function assertSessionRestored(newWindow, bookmarksInfo) {
        var tabs = newWindow.tabs;

        var expectedTabsNumber = bookmarksInfo.length;
        expect(tabs.length).toBe(expectedTabsNumber);

        var allTabsEqualToBookmarks = true;
        for (var i = 0; i++; i < tabs.length) {
          var tab = tabs[i];
          var bookmark = bookmarksInfo[i];
          if (tabEqualToBookmark(tab, bookmark)) {
            allTabsEqualBookmarks = false;
          }
        }
        expect(allTabsEqualToBookmarks).toBe(true);
        done();
      }
    });

    xit("Focuses the appropriate window if the session is already open.", function(done) {
      console.log("Unimplemented test.");
      done();
    });

    afterEach(function(done) {
      cleanUp();
      // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
      setTimeout(done, 1000);
    });
  })

  describe("Identifying existing session and prompting to resume.", function() {

    // TODO set variables on `this` instead.
    var expectedSessionFolderId;
    var windowToCheck;
    var bookmarksInfo;
    var actualSessionFolderId;

    beforeEach(function(done) {
      clearLocalStorageAndInitialise();
      // Necessary because it takes time to create Seshy folder.
      setTimeout(() => {
        getSeshyFolder(createSessionBookmarksFolderThenBookmarks);
      }, 1000);

      function createSessionBookmarksFolderThenBookmarks(bookmarkTreeNodes) {
        createSessionBookmarksFolder(bookmarkTreeNodes, createBookmarks);
      }

      function createBookmarks(sessionBookmarksFolder) {
        expectedSessionFolderId = sessionBookmarksFolder.id;
        var asBookmarks = true;
        bookmarksInfo = getTabsOrBookmarksInfo(expectedSessionFolderId, asBookmarks);

        chrome.bookmarks.create(bookmarksInfo[0]);
        chrome.bookmarks.create(bookmarksInfo[1]);
        chrome.bookmarks.create(bookmarksInfo[2]);
        chrome.bookmarks.create(bookmarksInfo[3], createWindow);
      }

      function createWindow(bookmarkTreeNode) {
        chrome.windows.create({}, createTabs);
      }

      function createTabs(newWindow) {
        windowToCheck = newWindow;
        var tabsInfo = getTabsOrBookmarksInfo(windowToCheck.id);

        chrome.tabs.create(tabsInfo[0]);
        chrome.tabs.create(tabsInfo[1]);
        chrome.tabs.create(tabsInfo[2], getWindow);
        // Don't create new tab as the new window creates that for us.
      }

      function getWindow() {
        chrome.windows.get(windowToCheck.id, {'populate': true}, callTest);
      }

      function callTest(uptodateWindowToCheck) {
        windowToCheck = uptodateWindowToCheck;
        getSession(windowToCheck, captureExistingSession); // Method under test.
      }

      function captureExistingSession(actualSessionFolder) {
        actualSessionFolderId = actualSessionFolder === null ? null : actualSessionFolder.id;
        done();
      }
    });

    afterEach(function(done) {
      cleanUp();
      // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
      setTimeout(done, 1000);
    });

    it("Should recognise when a set of opened tabs represents an existing session.", function() {
      expect(expectedSessionFolderId).toEqual(actualSessionFolderId);
    });
  });
});

describe("Ending sessions.", function() {

  var windowId;

  beforeEach(function(done) {
    clearLocalStorageAndInitialise();
    // Necessary because it takes time to create Seshy folder.
    setTimeout(() => {
      chrome.windows.create({}, addWindowToSessionMapping);
    }, 1000);

    function addWindowToSessionMapping(newWindow) {
      windowId = newWindow.id;
      var fakeSessionFolderId = 1;
      var items = {};
      items[newWindow.id.toString()] = fakeSessionFolderId;
      chrome.storage.local.set(items, done);
    }
  });

  it("Removes any window to session folder mapping from local storage.", function(done) {
    removeWindowToSessionFolderMapping(windowId, () => {
      getAllLocalStorage(assertWindowToSessionFolderMappingRemoved);
    });

    function assertWindowToSessionFolderMappingRemoved(allLocalStorageObject) {
      var allLocalStorageKeys = Object.keys(allLocalStorageObject);

      var matchingLocalStorageKey = false;
      var windowIdString = windowId.toString();

      for (var i = 0; i < allLocalStorageKeys.length; i++) {
        var localStorageKey = allLocalStorageKeys[i];
        if (localStorageKey == windowIdString) {
          matchingLocalStorageKey = true;
        }
      }
      expect(matchingLocalStorageKey).toBe(false);
      done();
    }
  });

  afterEach(function(done) {
    cleanUp();
    // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
    setTimeout(done, 1000);
  });
});

describe("Deleting sessions.", function() {

  var windowId;
  var expectedDeletedSessionFolderId;

  beforeEach(function(done) {
    clearLocalStorageAndInitialise();
    // Necessary because it takes time to create Seshy folder.
    setTimeout(() => {
      chrome.windows.create({}, (newWindow) => {
        windowId = newWindow.id;
        tabsInfo = getTabsOrBookmarksInfo(newWindow.id, false);
        createTabs(tabsInfo, saveTestSessionAndCaptureSessionFolderId);
      });
    }, 1000);

    function saveTestSessionAndCaptureSessionFolderId() {
      saveTestSession(windowId, captureSessionFolderId);

      function captureSessionFolderId(sessionFolderId) {
        expectedDeletedSessionFolderId = sessionFolderId;
        done();
      }
    }
  });

  it("Deletes the session folder.", function(done) {
    deleteSession(expectedDeletedSessionFolderId, tryGetSessionFolder); // Method under test.

    function tryGetSessionFolder(sessionFolderId) {
      chrome.bookmarks.get(sessionFolderId.toString(), assertSessionFolderDeleted);
      var sessionFolderDeleted = false;

      function assertSessionFolderDeleted(sessionFolderId) {
        if (chrome.runtime.lastError) {
          sessionFolderDeleted = true;
        }
        expect(sessionFolderDeleted).toBe(true);
        done();
      }
    }
  })

  afterEach(function(done) {
    cleanUp();
    // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
    setTimeout(done, 1000);
  });
});

//---===~ Functions ~===------------------------------------------------------------------------------------------------
function createTabs(tabsInfo, callback) {
  chrome.tabs.create(tabsInfo[0]);
  chrome.tabs.create(tabsInfo[1]);
  if (typeof callback != 'undefined') {
    chrome.tabs.create(tabsInfo[2], callback);
  }
  else {
    chrome.tabs.create(tabsInfo[2]);
  }
}

function getTabsOrBookmarksInfo(windowOrParentId, asBookmarks, tabSetNumber) {
  var tabsInfo1 = [
    {
      'index': 0,
      'url': 'chrome://extensions/'
    },
    {
      'index': 1,
      'url': 'chrome://settings/'
    },
    {
      'index': 2,
      'url': 'chrome://about/'
    },
    {
      'index': 3,
      'url': 'chrome://newtab/'
    }
  ]
  var tabsInfo2 = [
    {
      'index': 0,
      'url': 'chrome://apps/'
    },
    {
      'index': 1,
      'url': 'chrome://downloads/'
    },
    {
      'index': 2,
      'url': 'chrome://history/'
    },
    {
      'index': 3,
      'url': 'chrome://newtab/'
    }
  ]

  if (tabSetNumber === 2) {
    var tabsInfo = tabsInfo2;
  }
  else {
    var tabsInfo = tabsInfo1;
  }

  for (var i = 0; i < tabsInfo.length; i++) {
    var tabInfo = tabsInfo[i];
    if (asBookmarks === true) {
      tabInfo.parentId = windowOrParentId;
    }
    else {
      tabInfo.windowId = windowOrParentId;
    }
  }
  return tabsInfo;
}

function saveTestSession(windowId, callback) {
  var expectedSessionFolderId;

  getSeshyFolder((seshyFolder) => {
    createSessionBookmarksFolder(seshyFolder, createBookmarksThenSaveMapping);
  });

  function createBookmarksThenSaveMapping(sessionBookmarksFolder) {
    expectedSessionFolderId = sessionBookmarksFolder.id;

    createBookmarks(sessionBookmarksFolder, () => {
      addWindowToSessionMapping(windowId, expectedSessionFolderId, returnSessionFolderId);
    })
  }

  function returnSessionFolderId() {
    callback(expectedSessionFolderId);
  }
}

function createSessionBookmarksFolder(bookmarkTreeNodes, callback) {
  var seshyFolder = bookmarkTreeNodes[0];
  var options = {
    'parentId': seshyFolder.id, // From seshy.js
    'title': 'Test Session'
  }
  chrome.bookmarks.create(options, callback);
}

function createBookmarks(sessionBookmarksFolder, callback) {
  var asBookmarks = true;
  var sessionFolderId = sessionBookmarksFolder.id;
  var bookmarksInfo = getTabsOrBookmarksInfo(sessionFolderId, asBookmarks, 2);

  chrome.bookmarks.create(bookmarksInfo[0]);
  chrome.bookmarks.create(bookmarksInfo[1]);
  chrome.bookmarks.create(bookmarksInfo[2]);

  // TODO Properly identify if function.
  if (typeof callback != 'undefined') {
    chrome.bookmarks.create(bookmarksInfo[3], () => {
      callback(bookmarksInfo);
    });
  }
  else {
    chrome.bookmarks.create(bookmarksInfo[3]);
  }
}

function addWindowToSessionMapping(windowId, expectedSessionFolderId, callback) {
  var items = {};
  items[windowId.toString()] = expectedSessionFolderId;
  chrome.storage.local.set(items, () => {
    callback();
  });
}

function cleanUp() {
  getSeshyFolder(removeBookmarksFolder);
}

function getSeshyFolder(callback) {
  var query = {
    'title': 'Seshy'
  }
  chrome.bookmarks.search(query, callback);
}

function removeBookmarksFolder(bookmarkTreeNodes) {
  bookmarksFolder = bookmarkTreeNodes[0];
  chrome.bookmarks.removeTree(bookmarksFolder.id, getAllWindows);
}

function getAllWindows() {
  chrome.windows.getAll({}, removeWindows);
}

function removeWindows(windows) {
  // Don't remove first window because it will have Jasmine test results.
  for (var i = 1; i < windows.length; i++) {
    var window = windows[i];
    chrome.windows.remove(window.id);
  }
}

function clearLocalStorageAndInitialise() {
  chrome.storage.local.clear(initialise);
}

function getAllLocalStorage(callback) {
  chrome.storage.local.get(null, callback);
}
<commit_msg>Fixed test.<commit_after>describe("Saving sessions.", function() {

  var windowId;
  var bookmarks;
  var tabsInfo;

  beforeEach(function(done) {
    clearLocalStorageAndInitialise();
    // Necessary because it takes time to create Seshy folder.
    setTimeout(() => {
      chrome.windows.create({}, (newWindow) => {
        windowId = newWindow.id
        tabsInfo = getTabsOrBookmarksInfo(newWindow.id, false);
        createTabs(tabsInfo, done);
      });
    }, 1000);
  });

  it("Should be able to save a set of tabs as bookmarks in a folder.", function(done) {
    callTest(done);
  });

  it("Should delete all the bookmarks in the session folder before saving an existing session.", function(done) {
    saveTestSession(windowId, () => {
      callTest(done);
    });
  });

  xit("Saves a session if it is given a name and it is not already saved.", function(done) {
    console.log("Unimplemented test.");
    done();
  })

  xit("Puts the text field for the current session's name into edit mode ready to be saved when the session manager " +
  "is opened and the current session is not already saved.", function(done) {
    console.log("Unimplemented test.");
    done();
  });

  xit("Only saves sessions the user has flagged to be saved.", function(done) {
    console.log("Unimplemented test.");
    done();
  });

  afterEach(function(done) {
    cleanUp();
    // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
    setTimeout(done, 1000);
  });

  function callTest(done) {
    saveSession(windowId); // Method under test.
    setTimeout(getBookmarksFolder, 1000);

    function getBookmarksFolder() {
      var query = {
        'title': 'Test Session'
      }
      chrome.bookmarks.search(query, getBookmarks);
    }

    function getBookmarks(bookmarkSessionFolderSearchResults) {
      // Only one bookmark session folder with the correct saved tabs ensures that the original bookmarks were deleted.
      expect(bookmarkSessionFolderSearchResults.length).toEqual(1);

      chrome.bookmarks.getChildren(bookmarkSessionFolderSearchResults[0].id, function(bookmarkTreeNodes) {
        bookmarks = bookmarkTreeNodes;
        assertSavedBookmarks(bookmarks, tabsInfo);
      });
    }

    function assertSavedBookmarks(bookmarks, expectedTabsInfo) {
      for (var i = 0; i < bookmarks.length; i++) {
        var bookmark = bookmarks[i];
        var expectedTabInfo = expectedTabsInfo[i];
        expect(bookmark.index).toEqual(expectedTabInfo.index);
        expect(bookmark.url).toEqual(expectedTabInfo.url);
      }
      done();
    }
  }
});

describe("Resuming sessions.", function() {

  describe("User restores a session from the session manager.", function() {

    var windowId;
    var sessionFolderId;
    var bookmarksInfo;

    beforeEach(function(done) {
      clearLocalStorageAndInitialise();
      // Necessary because it takes time to create Seshy folder.
      setTimeout(() => {
        chrome.windows.create({}, (newWindow) => {
          windowId = newWindow.id;
          bookmarksInfo = getTabsOrBookmarksInfo(newWindow.id, false);
          createTabs(bookmarksInfo, saveTestSessionAndCaptureSessionFolderId);
        });
      }, 1000);

      function saveTestSessionAndCaptureSessionFolderId() {
        saveTestSession(windowId, captureSessionFolderId);
      }

      function captureSessionFolderId(newSessionFolderId) {
        sessionFolderId = newSessionFolderId;
        chrome.windows.remove(windowId, () => {
          done();
        });
      }
    });

    it("Adds a window ID to session folder ID mapping in local storage.", function(done) {
      resumeSession(sessionFolderId, (newWindow) => {
        windowId = newWindow.id;
        chrome.storage.local.get(null, assertWindowToSessionFolderMappingAdded)
      });

      function assertWindowToSessionFolderMappingAdded(allLocalStorageObject) {
        var allLocalStorageKeys = Object.keys(allLocalStorageObject);

        var matchingLocalStorageKey;
        var matchingLocalStorageKeyValue;

        for (var i = 0; i < allLocalStorageKeys.length; i++) {
          var localStorageKey = allLocalStorageKeys[i];
          if (localStorageKey == windowId) {
            matchingLocalStorageKey = localStorageKey;
            matchingLocalStorageKeyValue = allLocalStorageObject[windowId.toString()]
          }
        }
        expect(matchingLocalStorageKey).toBe(windowId.toString());
        expect(matchingLocalStorageKeyValue).toBe(sessionFolderId);
        done();
      }
    });

    it("Opens a window with all the tabs as they were when the session was saved.", function(done) {
      resumeSession(sessionFolderId, (newWindow) => {
        assertSessionRestored(newWindow, bookmarksInfo);
      });

      function assertSessionRestored(newWindow, bookmarksInfo) {
        var tabs = newWindow.tabs;

        var expectedTabsNumber = bookmarksInfo.length;
        expect(tabs.length).toBe(expectedTabsNumber);

        var allTabsEqualToBookmarks = true;
        for (var i = 0; i++; i < tabs.length) {
          var tab = tabs[i];
          var bookmark = bookmarksInfo[i];
          if (tabEqualToBookmark(tab, bookmark)) {
            allTabsEqualBookmarks = false;
          }
        }
        expect(allTabsEqualToBookmarks).toBe(true);
        done();
      }
    });

    xit("Focuses the appropriate window if the session is already open.", function(done) {
      console.log("Unimplemented test.");
      done();
    });

    afterEach(function(done) {
      cleanUp();
      // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
      setTimeout(done, 1000);
    });
  })

  describe("Identifying existing session and prompting to resume.", function() {

    // TODO set variables on `this` instead.
    var expectedSessionFolderId;
    var windowToCheck;
    var bookmarksInfo;
    var actualSessionFolderId;

    beforeEach(function(done) {
      clearLocalStorageAndInitialise();
      // Necessary because it takes time to create Seshy folder.
      setTimeout(() => {
        getSeshyFolder(createSessionBookmarksFolderThenBookmarks);
      }, 1000);

      function createSessionBookmarksFolderThenBookmarks(bookmarkTreeNodes) {
        createSessionBookmarksFolder(bookmarkTreeNodes, createBookmarks);
      }

      function createBookmarks(sessionBookmarksFolder) {
        expectedSessionFolderId = sessionBookmarksFolder.id;
        var asBookmarks = true;
        bookmarksInfo = getTabsOrBookmarksInfo(expectedSessionFolderId, asBookmarks);

        chrome.bookmarks.create(bookmarksInfo[0]);
        chrome.bookmarks.create(bookmarksInfo[1]);
        chrome.bookmarks.create(bookmarksInfo[2]);
        chrome.bookmarks.create(bookmarksInfo[3], createWindow);
      }

      function createWindow(bookmarkTreeNode) {
        chrome.windows.create({}, createTabs);
      }

      function createTabs(newWindow) {
        windowToCheck = newWindow;
        var tabsInfo = getTabsOrBookmarksInfo(windowToCheck.id);

        chrome.tabs.create(tabsInfo[0]);
        chrome.tabs.create(tabsInfo[1]);
        chrome.tabs.create(tabsInfo[2], getWindow);
        // Don't create new tab as the new window creates that for us.
      }

      function getWindow() {
        chrome.windows.get(windowToCheck.id, {'populate': true}, callTest);
      }

      function callTest(uptodateWindowToCheck) {
        windowToCheck = uptodateWindowToCheck;
        getSession(windowToCheck, captureExistingSession); // Method under test.
      }

      function captureExistingSession(actualSessionFolder) {
        actualSessionFolderId = actualSessionFolder === null ? null : actualSessionFolder.id;
        done();
      }
    });

    afterEach(function(done) {
      cleanUp();
      // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
      setTimeout(done, 1000);
    });

    it("Should recognise when a set of opened tabs represents an existing session.", function() {
      expect(expectedSessionFolderId).toEqual(actualSessionFolderId);
    });
  });
});

describe("Ending sessions.", function() {

  var windowId;

  beforeEach(function(done) {
    clearLocalStorageAndInitialise();
    // Necessary because it takes time to create Seshy folder.
    setTimeout(() => {
      chrome.windows.create({}, addWindowToSessionMapping);
    }, 1000);

    function addWindowToSessionMapping(newWindow) {
      windowId = newWindow.id;
      var fakeSessionFolderId = 1;
      var items = {};
      items[newWindow.id.toString()] = fakeSessionFolderId;
      chrome.storage.local.set(items, done);
    }
  });

  it("Removes any window to session folder mapping from local storage.", function(done) {
    removeWindowToSessionFolderMapping(windowId, () => {
      getAllLocalStorage(assertWindowToSessionFolderMappingRemoved);
    });

    function assertWindowToSessionFolderMappingRemoved(allLocalStorageObject) {
      var allLocalStorageKeys = Object.keys(allLocalStorageObject);

      var matchingLocalStorageKey = false;
      var windowIdString = windowId.toString();

      for (var i = 0; i < allLocalStorageKeys.length; i++) {
        var localStorageKey = allLocalStorageKeys[i];
        if (localStorageKey == windowIdString) {
          matchingLocalStorageKey = true;
        }
      }
      expect(matchingLocalStorageKey).toBe(false);
      done();
    }
  });

  afterEach(function(done) {
    cleanUp();
    // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
    setTimeout(done, 1000);
  });
});

describe("Deleting sessions.", function() {

  var windowId;
  var expectedDeletedSessionFolderId;

  beforeEach(function(done) {
    clearLocalStorageAndInitialise();
    // Necessary because it takes time to create Seshy folder.
    setTimeout(() => {
      chrome.windows.create({}, (newWindow) => {
        windowId = newWindow.id;
        tabsInfo = getTabsOrBookmarksInfo(newWindow.id, false);
        createTabs(tabsInfo, saveTestSessionAndCaptureSessionFolderId);
      });
    }, 1000);

    function saveTestSessionAndCaptureSessionFolderId() {
      saveTestSession(windowId, captureSessionFolderId);

      function captureSessionFolderId(sessionFolderId) {
        expectedDeletedSessionFolderId = sessionFolderId;
        done();
      }
    }
  });

  it("Deletes the session folder.", function(done) {
    deleteSession(expectedDeletedSessionFolderId, tryGetSessionFolder); // Method under test.

    function tryGetSessionFolder(sessionFolderId) {
      chrome.bookmarks.get(sessionFolderId.toString(), assertSessionFolderDeleted);
      var sessionFolderDeleted = false;

      function assertSessionFolderDeleted(sessionFolderId) {
        if (chrome.runtime.lastError) {
          sessionFolderDeleted = true;
        }
        expect(sessionFolderDeleted).toBe(true);
        done();
      }
    }
  })

  afterEach(function(done) {
    cleanUp();
    // Necessary because it takes time to delete Seshy folder in cleanup of previous test.
    setTimeout(done, 1000);
  });
});

//---===~ Functions ~===------------------------------------------------------------------------------------------------
function createTabs(tabsInfo, callback) {
  chrome.tabs.create(tabsInfo[0]);
  chrome.tabs.create(tabsInfo[1]);
  if (typeof callback != 'undefined') {
    chrome.tabs.create(tabsInfo[2], callback);
  }
  else {
    chrome.tabs.create(tabsInfo[2]);
  }
}

function getTabsOrBookmarksInfo(windowOrParentId, asBookmarks, tabSetNumber) {
  var tabsInfo1 = [
    {
      'index': 0,
      'url': 'chrome://extensions/'
    },
    {
      'index': 1,
      'url': 'chrome://settings/'
    },
    {
      'index': 2,
      'url': 'chrome://about/'
    },
    {
      'index': 3,
      'url': 'chrome://newtab/'
    }
  ]
  var tabsInfo2 = [
    {
      'index': 0,
      'url': 'chrome://apps/'
    },
    {
      'index': 1,
      'url': 'chrome://downloads/'
    },
    {
      'index': 2,
      'url': 'chrome://history/'
    },
    {
      'index': 3,
      'url': 'chrome://newtab/'
    }
  ]

  if (tabSetNumber === 2) {
    var tabsInfo = tabsInfo2;
  }
  else {
    var tabsInfo = tabsInfo1;
  }

  for (var i = 0; i < tabsInfo.length; i++) {
    var tabInfo = tabsInfo[i];
    if (asBookmarks === true) {
      tabInfo.parentId = windowOrParentId;
    }
    else {
      tabInfo.windowId = windowOrParentId;
    }
  }
  return tabsInfo;
}

function saveTestSession(windowId, callback) {
  var expectedSessionFolderId;

  getSeshyFolder((seshyFolder) => {
    createSessionBookmarksFolder(seshyFolder, createBookmarksThenSaveMapping);
  });

  function createBookmarksThenSaveMapping(sessionBookmarksFolder) {
    expectedSessionFolderId = sessionBookmarksFolder.id;

    createBookmarks(sessionBookmarksFolder, () => {
      addWindowToSessionMapping(windowId, expectedSessionFolderId, returnSessionFolderId);
    })
  }

  function returnSessionFolderId() {
    callback(expectedSessionFolderId);
  }
}

function createSessionBookmarksFolder(bookmarkTreeNodes, callback) {
  var seshyFolder = bookmarkTreeNodes[0];
  var options = {
    'parentId': seshyFolder.id, // From seshy.js
    'title': 'Test Session'
  }
  chrome.bookmarks.create(options, callback);
}

function createBookmarks(sessionBookmarksFolder, callback) {
  var asBookmarks = true;
  var sessionFolderId = sessionBookmarksFolder.id;
  var bookmarksInfo = getTabsOrBookmarksInfo(sessionFolderId, asBookmarks, 2);

  chrome.bookmarks.create(bookmarksInfo[0]);
  chrome.bookmarks.create(bookmarksInfo[1]);
  chrome.bookmarks.create(bookmarksInfo[2]);

  // TODO Properly identify if function.
  if (typeof callback != 'undefined') {
    chrome.bookmarks.create(bookmarksInfo[3], () => {
      callback(bookmarksInfo);
    });
  }
  else {
    chrome.bookmarks.create(bookmarksInfo[3]);
  }
}

function addWindowToSessionMapping(windowId, expectedSessionFolderId, callback) {
  var items = {};
  items[windowId.toString()] = expectedSessionFolderId;
  chrome.storage.local.set(items, () => {
    callback();
  });
}

function cleanUp() {
  getSeshyFolder(removeBookmarksFolder);
}

function getSeshyFolder(callback) {
  var query = {
    'title': 'Seshy'
  }
  chrome.bookmarks.search(query, callback);
}

function removeBookmarksFolder(bookmarkTreeNodes) {
  bookmarksFolder = bookmarkTreeNodes[0];
  chrome.bookmarks.removeTree(bookmarksFolder.id, getAllWindows);
}

function getAllWindows() {
  chrome.windows.getAll({}, removeWindows);
}

function removeWindows(windows) {
  // Don't remove first window because it will have Jasmine test results.
  for (var i = 1; i < windows.length; i++) {
    var window = windows[i];
    chrome.windows.remove(window.id);
  }
}

function clearLocalStorageAndInitialise() {
  chrome.storage.local.clear(initialise);
}

function getAllLocalStorage(callback) {
  chrome.storage.local.get(null, callback);
}
<|endoftext|>


<commit_before>import { h, cleanDocumentBody, IDENTIFIER } from '../utils'
import { defaultProps } from '../../src/props'
import * as Utils from '../../src/utils'

afterEach(cleanDocumentBody)

describe('isBareVirtualElement', () => {
  it('returns true for a plain object', () => {
    expect(Utils.isBareVirtualElement({})).toBe(true)
  })

  it('returns false for other object types', () => {
    expect(Utils.isBareVirtualElement([])).toBe(false)
    expect(Utils.isBareVirtualElement(function() {})).toBe(false)
    expect(Utils.isBareVirtualElement(h('div')))
  })

  it('returns false for primitive values', () => {
    expect(Utils.isBareVirtualElement('')).toBe(false)
    expect(Utils.isBareVirtualElement(Symbol())).toBe(false)
    expect(Utils.isBareVirtualElement(0)).toBe(false)
    expect(Utils.isBareVirtualElement(undefined)).toBe(false)
    expect(Utils.isBareVirtualElement(null)).toBe(false)
    expect(Utils.isBareVirtualElement(true)).toBe(false)
  })
})

describe('getArrayOfElements', () => {
  it('returns an empty array with no arguments', () => {
    expect(Array.isArray(Utils.getArrayOfElements())).toBe(true)
  })

  it('returns the same array if given an array', () => {
    const arr = []
    expect(Utils.getArrayOfElements(arr)).toBe(arr)
  })

  it('returns an array of elements when given a valid selector string', () => {
    ;[...Array(10)].map(() => h())
    const allAreElements = Utils.getArrayOfElements(IDENTIFIER).every(
      value => value instanceof Element,
    )
    expect(allAreElements).toBe(true)
  })

  it('returns an empty array when given an invalid selector string', () => {
    const arr = Utils.getArrayOfElements('😎')
    expect(Array.isArray(arr)).toBe(true)
    expect(arr.length).toBe(0)
  })

  it('returns an array of length 1 if the value is a DOM element', () => {
    const ref = h()
    const arr = Utils.getArrayOfElements(ref)
    expect(arr[0]).toBe(ref)
    expect(arr.length).toBe(1)
  })

  it('returns an array of length 1 if the value is a polyfilled virtual element', () => {
    const ref = { isVirtual: true }
    const arr = Utils.getArrayOfElements(ref)
    expect(arr[0]).toBe(ref)
    expect(arr.length).toBe(1)
  })

  it('returns an array if given a NodeList', () => {
    const ref = h()
    const arr = Utils.getArrayOfElements(
      document.querySelectorAll(`.${IDENTIFIER}`),
    )
    expect(arr[0]).toBe(ref)
    expect(Array.isArray(arr)).toBe(true)
  })

  it('returns an empty array for an invalid selector', () => {
    const arr = Utils.getArrayOfElements('+')
    expect(Array.isArray(arr)).toBe(true)
    expect(arr.length).toBe(0)
  })
})

describe('hasOwnProperty', () => {
  it('works for plain objects', () => {
    expect(Utils.hasOwnProperty({ prop: true }, 'prop')).toBe(true)
    expect(Utils.hasOwnProperty({}, 'toString')).toBe(false)
  })

  it('works for prototypeless objects', () => {
    const o = Object.create(null)
    o.prop = true
    expect(Utils.hasOwnProperty(o, 'prop')).toBe(true)
  })
})

describe('getValue', () => {
  it('returns the value if not an array', () => {
    expect(Utils.getValue('unique', 0)).toBe('unique')
    expect(Utils.getValue('unique', 1)).toBe('unique')
    expect(Utils.getValue(true, 1)).toBe(true)
  })

  it('returns the value at the specified index if an array', () => {
    expect(Utils.getValue([-100, -200], 0)).toBe(-100)
    expect(Utils.getValue([-100, -200], 1)).toBe(-200)
    expect(Utils.getValue(['x', 'y'], 0)).toBe('x')
    expect(Utils.getValue(['x', 'y'], 1)).toBe('y')
  })

  it('uses the default duration if the value is null', () => {
    expect(Utils.getValue([null, 5], 0, defaultProps.duration[0])).toBe(
      defaultProps.duration[0],
    )
    expect(Utils.getValue([5, null], 1, defaultProps.duration[1])).toBe(
      defaultProps.duration[1],
    )
    expect(Utils.getValue([null, 5], 0, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
    expect(Utils.getValue([5, null], 1, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
  })

  it('uses the default duration if the value is undefined', () => {
    expect(Utils.getValue([undefined, 5], 0, defaultProps.duration[0])).toBe(
      defaultProps.duration[0],
    )
    expect(Utils.getValue([5, undefined], 1, defaultProps.duration[1])).toBe(
      defaultProps.duration[1],
    )
    expect(Utils.getValue([undefined, 5], 0, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
    expect(Utils.getValue([5, undefined], 1, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
  })
})

describe('debounce', () => {
  it('works as expected', done => {
    const fn = jest.fn()
    const debouncedFn = Utils.debounce(fn, 50)
    debouncedFn()
    expect(fn.mock.calls.length).toBe(0)
    setTimeout(() => {
      expect(fn.mock.calls.length).toBe(0)
      debouncedFn()
      setTimeout(() => {
        expect(fn.mock.calls.length).toBe(0)
        setTimeout(() => {
          expect(fn.mock.calls.length).toBe(1)
          done()
        }, 51)
      }, 20)
    }, 40)
  })
})

describe('getModifier', () => {
  it('returns an object nested in `modifiers` object without errors', () => {
    expect(Utils.getModifier({}, 'flip')).toBe(undefined)
    expect(Utils.getModifier({ modifiers: {} }, 'flip')).toBe(undefined)
    expect(
      Utils.getModifier(
        {
          modifiers: {
            flip: {
              enabled: true,
            },
          },
        },
        'flip',
      ),
    ).toEqual({ enabled: true })
  })
})

describe('includes', () => {
  it('includes(string, string)', () => {
    expect(Utils.includes('test', 'es')).toBe(true)
    expect(Utils.includes('$128', '$12')).toBe(true)
    expect(Utils.includes('test', 'tesst')).toBe(false)
    expect(Utils.includes('$128', '$$')).toBe(false)
  })

  it('includes(Array, string)', () => {
    expect(Utils.includes(['test', 'other'], 'other')).toBe(true)
    expect(Utils.includes(['test', 'other'], 'test')).toBe(true)
    expect(Utils.includes(['test', 'other'], 'othr')).toBe(false)
    expect(Utils.includes(['test', 'other'], 'tst')).toBe(false)
  })
})

describe('setFlipModifierEnabled', () => {
  it('sets it correctly', () => {
    const modifiers = [{ name: 'x' }, { name: 'flip', enabled: true }]
    Utils.setFlipModifierEnabled(modifiers, false)
    expect(modifiers[1].enabled).toBe(false)
    Utils.setFlipModifierEnabled(modifiers, true)
    expect(modifiers[1].enabled).toBe(true)
  })
})

describe('canReceiveFocus', () => {
  it('returns true for a[href]', () => {
    const a = h('a')
    a.href = '#'
    expect(Utils.canReceiveFocus(a)).toBe(true)
  })

  it('returns true for area[href]', () => {
    const area = h('area')
    area.href = '#'
    expect(Utils.canReceiveFocus(area)).toBe(true)
  })

  it('returns true for input', () => {
    const input = h('input')
    expect(Utils.canReceiveFocus(input)).toBe(true)
  })

  it('returns true for textarea', () => {
    const textarea = h('textarea')
    expect(Utils.canReceiveFocus(textarea)).toBe(true)
  })

  it('returns true for select', () => {
    const select = h('select')
    expect(Utils.canReceiveFocus(select)).toBe(true)
  })

  it('returns true for iframe', () => {
    const iframe = h('iframe')
    expect(Utils.canReceiveFocus(iframe)).toBe(true)
  })

  it('returns true for [tabindex]', () => {
    const div = h('div')
    div.tabIndex = '0'
    expect(Utils.canReceiveFocus(div)).toBe(true)
  })

  it('returns false for [disabled]', () => {
    const ref = h('div')
    ref.setAttribute('disabled', 'disabled')
    expect(Utils.canReceiveFocus(ref)).toBe(false)
  })

  it('returns false for other elements', () => {
    const other = h('span')
    expect(Utils.canReceiveFocus(other)).toBe(false)
  })

  it('does not throw an error if given a virtual reference', () => {
    const ref = {}
    expect(Utils.canReceiveFocus(ref)).toBe(true)
  })
})

describe('div', () => {
  it('creates and returns a div element', () => {
    const d = Utils.div()
    expect(d.nodeName).toBe('DIV')
  })
})

describe('evaluateProps', () => {
  it('sets `animateFill` option to false if `arrow` is true', () => {
    const props = { animateFill: true, arrow: true }
    expect(Utils.evaluateProps(h(), props)).toEqual({
      animateFill: false,
      arrow: true,
    })
  })

  it('sets `animateFill` option to false if `arrow` is true (data attribute)', () => {
    const ref = h()
    ref.setAttribute('data-tippy-arrow', 'true')
    expect(Utils.evaluateProps(ref, { animateFill: true })).toEqual({
      arrow: true,
      animateFill: false,
    })
  })

  it('ignores attributes if `ignoreAttributes: true`', () => {
    const props = { animation: 'scale', ignoreAttributes: true }
    const reference = h()
    reference.setAttribute('data-tippy-animation', 'fade')
    expect(Utils.evaluateProps(reference, props)).toEqual({
      animation: 'scale',
      ignoreAttributes: true,
    })
  })

  it('does not ignore attributes if `ignoreAttributes: false`', () => {
    const props = { animation: 'scale', ignoreAttributes: false }
    const reference = h()
    reference.setAttribute('data-tippy-animation', 'fade')
    expect(Utils.evaluateProps(reference, props)).toEqual({
      animation: 'fade',
      ignoreAttributes: false,
    })
  })
})

describe('validateOptions', () => {
  it('does nothing if valid options were passed', () => {
    expect(() =>
      Utils.validateOptions(
        { arrow: true, arrowType: 'round' },
        { arrow: false, arrowType: 'sharp' },
      ),
    ).not.toThrow()
  })

  it('throws with the correct message if invalid options were passed', () => {
    expect(() =>
      Utils.validateOptions({ intractive: true }, { interactive: false }),
    ).toThrow('[tippy]: `intractive` is not a valid option')
  })
})

describe('setTransitionDuration', () => {
  it('sets the `transition-duration` property on a list of elements with the value specified', () => {
    const els = [h(), h(), null, h()]
    Utils.setTransitionDuration(els, 1298)
    expect(els[0].style.transitionDuration).toBe('1298ms')
    expect(els[1].style.transitionDuration).toBe('1298ms')
    expect(els[3].style.transitionDuration).toBe('1298ms')
  })
})

describe('setVisibilityState', () => {
  it('sets the `data-state` attribute on a list of elements with the value specified', () => {
    const els = [h(), h(), null, h()]
    Utils.setVisibilityState(els, 'visible')
    expect(els[0].getAttribute('data-state')).toBe('visible')
    expect(els[1].getAttribute('data-state')).toBe('visible')
    expect(els[3].getAttribute('data-state')).toBe('visible')
    Utils.setVisibilityState(els, 'hidden')
    expect(els[0].getAttribute('data-state')).toBe('hidden')
    expect(els[1].getAttribute('data-state')).toBe('hidden')
    expect(els[3].getAttribute('data-state')).toBe('hidden')
  })
})
<commit_msg>Mock timers for debounce test<commit_after>import { h, cleanDocumentBody, IDENTIFIER } from '../utils'
import { defaultProps } from '../../src/props'
import * as Utils from '../../src/utils'

jest.useFakeTimers()

afterEach(cleanDocumentBody)

describe('isBareVirtualElement', () => {
  it('returns true for a plain object', () => {
    expect(Utils.isBareVirtualElement({})).toBe(true)
  })

  it('returns false for other object types', () => {
    expect(Utils.isBareVirtualElement([])).toBe(false)
    expect(Utils.isBareVirtualElement(function() {})).toBe(false)
    expect(Utils.isBareVirtualElement(h('div')))
  })

  it('returns false for primitive values', () => {
    expect(Utils.isBareVirtualElement('')).toBe(false)
    expect(Utils.isBareVirtualElement(Symbol())).toBe(false)
    expect(Utils.isBareVirtualElement(0)).toBe(false)
    expect(Utils.isBareVirtualElement(undefined)).toBe(false)
    expect(Utils.isBareVirtualElement(null)).toBe(false)
    expect(Utils.isBareVirtualElement(true)).toBe(false)
  })
})

describe('getArrayOfElements', () => {
  it('returns an empty array with no arguments', () => {
    expect(Array.isArray(Utils.getArrayOfElements())).toBe(true)
  })

  it('returns the same array if given an array', () => {
    const arr = []
    expect(Utils.getArrayOfElements(arr)).toBe(arr)
  })

  it('returns an array of elements when given a valid selector string', () => {
    ;[...Array(10)].map(() => h())
    const allAreElements = Utils.getArrayOfElements(IDENTIFIER).every(
      value => value instanceof Element,
    )
    expect(allAreElements).toBe(true)
  })

  it('returns an empty array when given an invalid selector string', () => {
    const arr = Utils.getArrayOfElements('😎')
    expect(Array.isArray(arr)).toBe(true)
    expect(arr.length).toBe(0)
  })

  it('returns an array of length 1 if the value is a DOM element', () => {
    const ref = h()
    const arr = Utils.getArrayOfElements(ref)
    expect(arr[0]).toBe(ref)
    expect(arr.length).toBe(1)
  })

  it('returns an array of length 1 if the value is a polyfilled virtual element', () => {
    const ref = { isVirtual: true }
    const arr = Utils.getArrayOfElements(ref)
    expect(arr[0]).toBe(ref)
    expect(arr.length).toBe(1)
  })

  it('returns an array if given a NodeList', () => {
    const ref = h()
    const arr = Utils.getArrayOfElements(
      document.querySelectorAll(`.${IDENTIFIER}`),
    )
    expect(arr[0]).toBe(ref)
    expect(Array.isArray(arr)).toBe(true)
  })

  it('returns an empty array for an invalid selector', () => {
    const arr = Utils.getArrayOfElements('+')
    expect(Array.isArray(arr)).toBe(true)
    expect(arr.length).toBe(0)
  })
})

describe('hasOwnProperty', () => {
  it('works for plain objects', () => {
    expect(Utils.hasOwnProperty({ prop: true }, 'prop')).toBe(true)
    expect(Utils.hasOwnProperty({}, 'toString')).toBe(false)
  })

  it('works for prototypeless objects', () => {
    const o = Object.create(null)
    o.prop = true
    expect(Utils.hasOwnProperty(o, 'prop')).toBe(true)
  })
})

describe('getValue', () => {
  it('returns the value if not an array', () => {
    expect(Utils.getValue('unique', 0)).toBe('unique')
    expect(Utils.getValue('unique', 1)).toBe('unique')
    expect(Utils.getValue(true, 1)).toBe(true)
  })

  it('returns the value at the specified index if an array', () => {
    expect(Utils.getValue([-100, -200], 0)).toBe(-100)
    expect(Utils.getValue([-100, -200], 1)).toBe(-200)
    expect(Utils.getValue(['x', 'y'], 0)).toBe('x')
    expect(Utils.getValue(['x', 'y'], 1)).toBe('y')
  })

  it('uses the default duration if the value is null', () => {
    expect(Utils.getValue([null, 5], 0, defaultProps.duration[0])).toBe(
      defaultProps.duration[0],
    )
    expect(Utils.getValue([5, null], 1, defaultProps.duration[1])).toBe(
      defaultProps.duration[1],
    )
    expect(Utils.getValue([null, 5], 0, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
    expect(Utils.getValue([5, null], 1, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
  })

  it('uses the default duration if the value is undefined', () => {
    expect(Utils.getValue([undefined, 5], 0, defaultProps.duration[0])).toBe(
      defaultProps.duration[0],
    )
    expect(Utils.getValue([5, undefined], 1, defaultProps.duration[1])).toBe(
      defaultProps.duration[1],
    )
    expect(Utils.getValue([undefined, 5], 0, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
    expect(Utils.getValue([5, undefined], 1, defaultProps.delay)).toBe(
      defaultProps.delay,
    )
  })
})

describe('debounce', () => {
  it('works as expected', () => {
    const fn = jest.fn()
    const debouncedFn = Utils.debounce(fn, 50)
    debouncedFn()
    expect(fn).toHaveBeenCalledTimes(0)
    jest.advanceTimersByTime(40)
    expect(fn).toHaveBeenCalledTimes(0)
    debouncedFn()
    jest.advanceTimersByTime(40)
    expect(fn).toHaveBeenCalledTimes(0)
    jest.advanceTimersByTime(10)
    expect(fn).toHaveBeenCalledTimes(1)
  })
})

describe('getModifier', () => {
  it('returns an object nested in `modifiers` object without errors', () => {
    expect(Utils.getModifier({}, 'flip')).toBe(undefined)
    expect(Utils.getModifier({ modifiers: {} }, 'flip')).toBe(undefined)
    expect(
      Utils.getModifier(
        {
          modifiers: {
            flip: {
              enabled: true,
            },
          },
        },
        'flip',
      ),
    ).toEqual({ enabled: true })
  })
})

describe('includes', () => {
  it('includes(string, string)', () => {
    expect(Utils.includes('test', 'es')).toBe(true)
    expect(Utils.includes('$128', '$12')).toBe(true)
    expect(Utils.includes('test', 'tesst')).toBe(false)
    expect(Utils.includes('$128', '$$')).toBe(false)
  })

  it('includes(Array, string)', () => {
    expect(Utils.includes(['test', 'other'], 'other')).toBe(true)
    expect(Utils.includes(['test', 'other'], 'test')).toBe(true)
    expect(Utils.includes(['test', 'other'], 'othr')).toBe(false)
    expect(Utils.includes(['test', 'other'], 'tst')).toBe(false)
  })
})

describe('setFlipModifierEnabled', () => {
  it('sets it correctly', () => {
    const modifiers = [{ name: 'x' }, { name: 'flip', enabled: true }]
    Utils.setFlipModifierEnabled(modifiers, false)
    expect(modifiers[1].enabled).toBe(false)
    Utils.setFlipModifierEnabled(modifiers, true)
    expect(modifiers[1].enabled).toBe(true)
  })
})

describe('canReceiveFocus', () => {
  it('returns true for a[href]', () => {
    const a = h('a')
    a.href = '#'
    expect(Utils.canReceiveFocus(a)).toBe(true)
  })

  it('returns true for area[href]', () => {
    const area = h('area')
    area.href = '#'
    expect(Utils.canReceiveFocus(area)).toBe(true)
  })

  it('returns true for input', () => {
    const input = h('input')
    expect(Utils.canReceiveFocus(input)).toBe(true)
  })

  it('returns true for textarea', () => {
    const textarea = h('textarea')
    expect(Utils.canReceiveFocus(textarea)).toBe(true)
  })

  it('returns true for select', () => {
    const select = h('select')
    expect(Utils.canReceiveFocus(select)).toBe(true)
  })

  it('returns true for iframe', () => {
    const iframe = h('iframe')
    expect(Utils.canReceiveFocus(iframe)).toBe(true)
  })

  it('returns true for [tabindex]', () => {
    const div = h('div')
    div.tabIndex = '0'
    expect(Utils.canReceiveFocus(div)).toBe(true)
  })

  it('returns false for [disabled]', () => {
    const ref = h('div')
    ref.setAttribute('disabled', 'disabled')
    expect(Utils.canReceiveFocus(ref)).toBe(false)
  })

  it('returns false for other elements', () => {
    const other = h('span')
    expect(Utils.canReceiveFocus(other)).toBe(false)
  })

  it('does not throw an error if given a virtual reference', () => {
    const ref = {}
    expect(Utils.canReceiveFocus(ref)).toBe(true)
  })
})

describe('div', () => {
  it('creates and returns a div element', () => {
    const d = Utils.div()
    expect(d.nodeName).toBe('DIV')
  })
})

describe('evaluateProps', () => {
  it('sets `animateFill` option to false if `arrow` is true', () => {
    const props = { animateFill: true, arrow: true }
    expect(Utils.evaluateProps(h(), props)).toEqual({
      animateFill: false,
      arrow: true,
    })
  })

  it('sets `animateFill` option to false if `arrow` is true (data attribute)', () => {
    const ref = h()
    ref.setAttribute('data-tippy-arrow', 'true')
    expect(Utils.evaluateProps(ref, { animateFill: true })).toEqual({
      arrow: true,
      animateFill: false,
    })
  })

  it('ignores attributes if `ignoreAttributes: true`', () => {
    const props = { animation: 'scale', ignoreAttributes: true }
    const reference = h()
    reference.setAttribute('data-tippy-animation', 'fade')
    expect(Utils.evaluateProps(reference, props)).toEqual({
      animation: 'scale',
      ignoreAttributes: true,
    })
  })

  it('does not ignore attributes if `ignoreAttributes: false`', () => {
    const props = { animation: 'scale', ignoreAttributes: false }
    const reference = h()
    reference.setAttribute('data-tippy-animation', 'fade')
    expect(Utils.evaluateProps(reference, props)).toEqual({
      animation: 'fade',
      ignoreAttributes: false,
    })
  })
})

describe('validateOptions', () => {
  it('does nothing if valid options were passed', () => {
    expect(() =>
      Utils.validateOptions(
        { arrow: true, arrowType: 'round' },
        { arrow: false, arrowType: 'sharp' },
      ),
    ).not.toThrow()
  })

  it('throws with the correct message if invalid options were passed', () => {
    expect(() =>
      Utils.validateOptions({ intractive: true }, { interactive: false }),
    ).toThrow('[tippy]: `intractive` is not a valid option')
  })
})

describe('setTransitionDuration', () => {
  it('sets the `transition-duration` property on a list of elements with the value specified', () => {
    const els = [h(), h(), null, h()]
    Utils.setTransitionDuration(els, 1298)
    expect(els[0].style.transitionDuration).toBe('1298ms')
    expect(els[1].style.transitionDuration).toBe('1298ms')
    expect(els[3].style.transitionDuration).toBe('1298ms')
  })
})

describe('setVisibilityState', () => {
  it('sets the `data-state` attribute on a list of elements with the value specified', () => {
    const els = [h(), h(), null, h()]
    Utils.setVisibilityState(els, 'visible')
    expect(els[0].getAttribute('data-state')).toBe('visible')
    expect(els[1].getAttribute('data-state')).toBe('visible')
    expect(els[3].getAttribute('data-state')).toBe('visible')
    Utils.setVisibilityState(els, 'hidden')
    expect(els[0].getAttribute('data-state')).toBe('hidden')
    expect(els[1].getAttribute('data-state')).toBe('hidden')
    expect(els[3].getAttribute('data-state')).toBe('hidden')
  })
})
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009 Nicholas C. Zakas
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
/*
	mousewheel (deprecated) -> IE6.0, Chrome, Opera, Safari
	DOMMouseScroll (deprecated) -> Firefox 1.0
	wheel (standard) -> Chrome 31, Firefox 17, IE9, Firefox Mobile 17.0

	//No need to use, use DOMMouseScroll
	MozMousePixelScroll -> Firefox 3.5, Firefox Mobile 1.0

	//Events
	WheelEvent -> see wheel
	MouseWheelEvent -> see mousewheel
	MouseScrollEvent -> Firefox 3.5, Firefox Mobile 1.0
*/
( function( $ ) {

$.idleTimer = function( firstParam, elem ) {
    var opts;
    if (typeof firstParam === "object") {
        opts = firstParam;
        firstParam = null;
    } else if (typeof firstParam === "number") {
        opts = { timeout: firstParam };
        firstParam = null;
    }

	// defaults that are to be stored as instance props on the elem
	opts = $.extend( {
		idle: false,              //indicates if the user is idle
		timeout: 30000,           //the amount of time (ms) before the user is considered idle
		events: "mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove" // activity is one of these events
	}, opts );

	elem = elem || document;

	var jqElem = $( elem ),
		obj = jqElem.data("idleTimerObj") || {},

		/* (intentionally not documented)
		 * Toggles the idle state and fires an appropriate event.
		 * @return {void}
		 */
		toggleIdleState = function( myelem ) {

		    var obj = $.data(elem, "idleTimerObj") || {};

		    // toggle the state
		    obj.idle = !obj.idle;

		    // store toggle state date time
		    obj.olddate = +new Date();

		    // create a custom event, with state and name space
		    var event = $.Event((obj.idle ? "idle" : "active") + ".idleTimer");

		    // trigger event on object with elem and copy of obj
		    $(elem).trigger(event, [elem, $.extend({}, obj), e]);
		},

        /**
        * Handle event triggers
        * @return {void}
        * @method event
        * @static
        */
        handleEvent = function (e) {

            var obj = $.data(elem, "idleTimerObj") || {};

            // this is already paused, ignore events for now
            if (obj.remaining != null) { return; }

            /*
            mousemove is kinda buggy, it can be triggered when it should be idle.
            Typically is happening between 115 - 150 milliseconds after idle triggered.
            @psyafter & @kaellis report "always triggered if using modal (jQuery ui, with overlay)"
            @thorst has similar issues on ios7 "after $.scrollTop() on text area"
            */
            if (e.type === "mousemove") {
                // if coord are same, it didn't move
                if (e.pageX === obj.pageX && e.pageY === obj.pageY) {
                    return;
                }
                // if coord don't exist how could it move
                if (typeof e.pageX === "undefined" && typeof e.pageY === "undefined") {
                    return;
                }
                // under 200 ms is hard to do, and you would have to stop, as continuous activity will bypass this
                var elapsed = (+new Date()) - obj.olddate;
                if (elapsed < 200) {
                    return;
                }
            }

            // clear any existing timeout
            clearTimeout(obj.tId);

            // if the idle timer is enabled, flip
            if (obj.idle) {
                toggleIdleState(e);
            }

            // store when user was last active
            obj.lastActive = +new Date();

            // update mouse coord
            obj.pageX = e.pageX;
            obj.pageY = e.pageY;

            // set a new timeout
            obj.tId = setTimeout(toggleIdleState, obj.timeout);

        },

        /**
        * Restore initial settings and restart timer
        * @return {void}
        * @method reset
        * @static
        */
        reset = function () {

            var obj = $.data(elem, "idleTimerObj") || {};

            // reset settings
            obj.idle = obj.idleBackup;
            obj.olddate = +new Date();
            obj.lastActive = obj.olddate;
            obj.remaining = null;

            // reset Timers
            clearTimeout(obj.tId);
            if (!obj.idle) {
                obj.tId = setTimeout(toggleIdleState, obj.timeout);
            }

        },

        /**
        * Store remaining time, stop timer
        * You can pause from an idle OR active state
        * @return {void}
        * @method pause
        * @static
        */
        pause = function () {

            var obj = $.data(elem, "idleTimerObj") || {};

            // this is already paused
            if (obj.remaining != null) { return; }

            // define how much is left on the timer
            obj.remaining = obj.timeout - ((+new Date()) - obj.olddate);

            // clear any existing timeout
            clearTimeout(obj.tId);
        },

        /**
        * Start timer with remaining value
        * @return {void}
        * @method resume
        * @static
        */
        resume = function () {

            var obj = $.data(elem, "idleTimerObj") || {};

            // this isn't paused yet
            if (obj.remaining == null) { return; }

            // start timer
            if (!obj.idle) {
                obj.tId = setTimeout(toggleIdleState, obj.remaining);
            }

            // clear remaining
            obj.remaining = null;
        },

		/**
		 * Stops the idle timer. This removes appropriate event handlers
		 * and cancels any pending timeouts.
		 * @return {void}
		 * @method stop
		 * @static
		 */
		stop = function( jqElem ) {

			var obj = jqElem.data("idleTimerObj") || {};

			//set to disabled
			obj.enabled = false;

			//clear any pending timeouts
			clearTimeout( obj.tId );

			//detach the event handlers
			jqElem.off(".idleTimer");
		};

	obj.olddate = obj.olddate || +new Date();

    // determine which function to call
	if (firstParam === null && typeof obj.idle !== "undefined") {
	    // they think they want to init, but it already is, just reset
	    reset();
	    return jqElem;
	} else if (firstParam === null) {
	    // they want to init
	} else if (firstParam !== null && typeof obj.idle === "undefined") {
	    // they want to do something, but it isnt init
	    // not sure the best way to handle this
	    return false;
	} else if ( firstParam === "destroy" ) {
		stop( jqElem );
		return this;
	} else if (firstParam === "pause") {
	    pause();
	    return jqElem;
	} else if (firstParam === "resume") {
	    resume();
	    return jqElem;
	} else if (firstParam === "reset") {
	    reset();
	    return jqElem;
	} else if ( firstParam === "getElapsedTime" ) {
		return ( +new Date() ) - obj.olddate;
	}

	/* (intentionally not documented)
	 * Handles a user event indicating that the user isn't idle.
	 * @param {Event} event A DOM2-normalized event object.
	 * @return {void}
	 */
	jqElem.on( $.trim( ( opts.events + " " ).split(" ").join("._idleTimer ") ), function(e) {
	    handleEvent(e);
	});

	obj.idle = opts.idle;
	obj.enabled = opts.enabled;
	obj.timeout = opts.timeout;

	//set a timeout to toggle state. May wish to omit this in some situations
	if ( opts.startImmediately ) {
		obj.tId = setTimeout( toggleIdleState, obj.timeout );
	}

	// assume the user is active for the first x seconds.
	jqElem.data( "idleTimer", "active" );

	// store our instance on the object
	jqElem.data("idleTimerObj", obj);

	return jqElem;
};

$.fn.idleTimer = function( firstParam ) {

	if ( this[0] ){
		return $.idleTimer( firstParam, this[0] );
	}

	return this;
};

})( jQuery );
<commit_msg>stop renamed destroy<commit_after>/*
 * Copyright (c) 2009 Nicholas C. Zakas
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
/*
	mousewheel (deprecated) -> IE6.0, Chrome, Opera, Safari
	DOMMouseScroll (deprecated) -> Firefox 1.0
	wheel (standard) -> Chrome 31, Firefox 17, IE9, Firefox Mobile 17.0

	//No need to use, use DOMMouseScroll
	MozMousePixelScroll -> Firefox 3.5, Firefox Mobile 1.0

	//Events
	WheelEvent -> see wheel
	MouseWheelEvent -> see mousewheel
	MouseScrollEvent -> Firefox 3.5, Firefox Mobile 1.0
*/
( function( $ ) {

$.idleTimer = function( firstParam, elem ) {
    var opts;
    if (typeof firstParam === "object") {
        opts = firstParam;
        firstParam = null;
    } else if (typeof firstParam === "number") {
        opts = { timeout: firstParam };
        firstParam = null;
    }

	// defaults that are to be stored as instance props on the elem
	opts = $.extend( {
		idle: false,              //indicates if the user is idle
		timeout: 30000,           //the amount of time (ms) before the user is considered idle
		events: "mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove" // activity is one of these events
	}, opts );

	elem = elem || document;

	var jqElem = $( elem ),
		obj = jqElem.data("idleTimerObj") || {},

		/* (intentionally not documented)
		 * Toggles the idle state and fires an appropriate event.
		 * @return {void}
		 */
		toggleIdleState = function( myelem ) {

		    var obj = $.data(elem, "idleTimerObj") || {};

		    // toggle the state
		    obj.idle = !obj.idle;

		    // store toggle state date time
		    obj.olddate = +new Date();

		    // create a custom event, with state and name space
		    var event = $.Event((obj.idle ? "idle" : "active") + ".idleTimer");

		    // trigger event on object with elem and copy of obj
		    $(elem).trigger(event, [elem, $.extend({}, obj), e]);
		},

        /**
        * Handle event triggers
        * @return {void}
        * @method event
        * @static
        */
        handleEvent = function (e) {

            var obj = $.data(elem, "idleTimerObj") || {};

            // this is already paused, ignore events for now
            if (obj.remaining != null) { return; }

            /*
            mousemove is kinda buggy, it can be triggered when it should be idle.
            Typically is happening between 115 - 150 milliseconds after idle triggered.
            @psyafter & @kaellis report "always triggered if using modal (jQuery ui, with overlay)"
            @thorst has similar issues on ios7 "after $.scrollTop() on text area"
            */
            if (e.type === "mousemove") {
                // if coord are same, it didn't move
                if (e.pageX === obj.pageX && e.pageY === obj.pageY) {
                    return;
                }
                // if coord don't exist how could it move
                if (typeof e.pageX === "undefined" && typeof e.pageY === "undefined") {
                    return;
                }
                // under 200 ms is hard to do, and you would have to stop, as continuous activity will bypass this
                var elapsed = (+new Date()) - obj.olddate;
                if (elapsed < 200) {
                    return;
                }
            }

            // clear any existing timeout
            clearTimeout(obj.tId);

            // if the idle timer is enabled, flip
            if (obj.idle) {
                toggleIdleState(e);
            }

            // store when user was last active
            obj.lastActive = +new Date();

            // update mouse coord
            obj.pageX = e.pageX;
            obj.pageY = e.pageY;

            // set a new timeout
            obj.tId = setTimeout(toggleIdleState, obj.timeout);

        },

        /**
        * Restore initial settings and restart timer
        * @return {void}
        * @method reset
        * @static
        */
        reset = function () {

            var obj = $.data(elem, "idleTimerObj") || {};

            // reset settings
            obj.idle = obj.idleBackup;
            obj.olddate = +new Date();
            obj.lastActive = obj.olddate;
            obj.remaining = null;

            // reset Timers
            clearTimeout(obj.tId);
            if (!obj.idle) {
                obj.tId = setTimeout(toggleIdleState, obj.timeout);
            }

        },

        /**
        * Store remaining time, stop timer
        * You can pause from an idle OR active state
        * @return {void}
        * @method pause
        * @static
        */
        pause = function () {

            var obj = $.data(elem, "idleTimerObj") || {};

            // this is already paused
            if (obj.remaining != null) { return; }

            // define how much is left on the timer
            obj.remaining = obj.timeout - ((+new Date()) - obj.olddate);

            // clear any existing timeout
            clearTimeout(obj.tId);
        },

        /**
        * Start timer with remaining value
        * @return {void}
        * @method resume
        * @static
        */
        resume = function () {

            var obj = $.data(elem, "idleTimerObj") || {};

            // this isn't paused yet
            if (obj.remaining == null) { return; }

            // start timer
            if (!obj.idle) {
                obj.tId = setTimeout(toggleIdleState, obj.remaining);
            }

            // clear remaining
            obj.remaining = null;
        },

		/**
		 * Stops the idle timer. This removes appropriate event handlers
		 * and cancels any pending timeouts.
		 * @return {void}
		 * @method stop
		 * @static
		 */
		destroy = function (jqElem) {

			var obj = jqElem.data("idleTimerObj") || {};

			//set to disabled
			obj.enabled = false;

			//clear any pending timeouts
			clearTimeout( obj.tId );

			//detach the event handlers
			jqElem.off(".idleTimer");
		};

	obj.olddate = obj.olddate || +new Date();

    // determine which function to call
	if (firstParam === null && typeof obj.idle !== "undefined") {
	    // they think they want to init, but it already is, just reset
	    reset();
	    return jqElem;
	} else if (firstParam === null) {
	    // they want to init
	} else if (firstParam !== null && typeof obj.idle === "undefined") {
	    // they want to do something, but it isnt init
	    // not sure the best way to handle this
	    return false;
	} else if ( firstParam === "destroy" ) {
	    destroy(jqElem);
		return this;
	} else if (firstParam === "pause") {
	    pause();
	    return jqElem;
	} else if (firstParam === "resume") {
	    resume();
	    return jqElem;
	} else if (firstParam === "reset") {
	    reset();
	    return jqElem;
	} else if ( firstParam === "getElapsedTime" ) {
		return ( +new Date() ) - obj.olddate;
	}

	/* (intentionally not documented)
	 * Handles a user event indicating that the user isn't idle.
	 * @param {Event} event A DOM2-normalized event object.
	 * @return {void}
	 */
	jqElem.on( $.trim( ( opts.events + " " ).split(" ").join("._idleTimer ") ), function(e) {
	    handleEvent(e);
	});

	obj.idle = opts.idle;
	obj.enabled = opts.enabled;
	obj.timeout = opts.timeout;

	//set a timeout to toggle state. May wish to omit this in some situations
	if ( opts.startImmediately ) {
		obj.tId = setTimeout( toggleIdleState, obj.timeout );
	}

	// assume the user is active for the first x seconds.
	jqElem.data( "idleTimer", "active" );

	// store our instance on the object
	jqElem.data("idleTimerObj", obj);

	return jqElem;
};

$.fn.idleTimer = function( firstParam ) {

	if ( this[0] ){
		return $.idleTimer( firstParam, this[0] );
	}

	return this;
};

})( jQuery );
<|endoftext|>


<commit_before>/*
* Name :  PagesList.js
* Module : UnitTest
* Location : /frontend/test/unit/Model
*
* History :
* Version       Date        Programmer                  Description
* =================================================================================================
* 0.1.0			2015-05-14	Francesco Rossetto			Codifica del test sul Model Graph.js
*
* 0.0.1			2015-05-14	Francesco Rossetto			Creazione file
* =================================================================================================
*
*/

describe('Graph', function(){
	'use strict';

	var Graph;
	var Legend;
	var Flow;

	beforeEach(module('app'));

	beforeEach(inject(function(_Graph_, $injector){
		Graph = _Graph_;
		Legend = $injector.get('Legend');
		Flow = $injector.get('Flow');
	}));

	describe('Constructor', function(){

		var json = {
			"title" : "grafico1",
			"URLSocket" : "http://localhost/page1/grafico1"
		};

		beforeEach(function(){
			Graph = new Graph(json);
		});

		it('constructor create the graph with the correct title', function(){
			expect(Graph.getTitle()).toBeEqual("grafico1");
		});
		it('constructor create the graph with the correct url', function(){
			expect(Graph.getUrl()).toBeEqual("http://localhost/page1/grafico1");
		});

	});

	/*describe('updateParameters', function(){
		var json = {
			"title" : "graficoNuovo",
			"height" : 300,
			"width" : 300,
			"enabledLegend" : true,
			"legend" : {},
			"horizontalGrid" : true,
			"verticalGrid" : true
		};

		beforeEach(function(){
			Graph.updateParameters(json);
		});

		spyOn(Legend.prototype, "Legend").and.returnValue({});

		it('graph updated with the correct name', function(){
			expect(PagesList.getTitle()).toBeEqual("graficoNuovo");
		});
		it('graph updated with the correct name', function(){
			expect(PagesList.getTitle()).toBeEqual("graficoNuovo");
		});
		it('graph updated with the correct name', function(){
			expect(PagesList.getTitle()).toBeEqual("graficoNuovo");
		});

	});*/

});<commit_msg>test: modify Graph.js<commit_after>/*
* Name :  PagesList.js
* Module : UnitTest
* Location : /frontend/test/unit/Model
*
* History :
* Version       Date        Programmer                  Description
* =================================================================================================
* 0.1.0			2015-05-14	Francesco Rossetto			Codifica del test sul Model Graph.js
*
* 0.0.1			2015-05-14	Francesco Rossetto			Creazione file
* =================================================================================================
*
*/

describe('Graph', function(){
	'use strict';

	var Graph;
	var Legend;
	var Flow;

	beforeEach(module('app'));

	beforeEach(inject(function(_Graph_, $injector){
		Graph = _Graph_;
		Legend = $injector.get('Legend');
		Flow = $injector.get('Flow');
	}));

	describe('Constructor', function(){

		var json = {
			"title" : "grafico1",
			"URLSocket" : "http://localhost/page1/grafico1"
		};

		beforeEach(function(){
			Graph = new Graph(json);
		});

		it('constructor create the graph with the correct title', function(){
			expect(Graph.getTitle()).toBeEqual("grafico1");
		});
		it('constructor create the graph with the correct url', function(){
			expect(Graph.getUrl()).toBeEqual("http://localhost/page1/grafico1");
		});

	});

	describe('updateParameters', function(){
		var json = {
			"title" : "graficoNuovo",
			"height" : 300,
			"width" : 300,
			"enabledLegend" : true,
			"legend" : {},
			"horizontalGrid" : true,
			"verticalGrid" : true
		};

		beforeEach(function(){
			Graph.prototype.updateParameters(json);
		});

		spyOn(Legend.prototype, "Legend").and.returnValue({});

		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getTitle()).toBeEqual("graficoNuovo");
		});
		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getHeight()).toBeEqual(300);
		});
		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getWidth()).toBeEqual(300));
		});
		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getEnabledLegend()).toBeEqual(true));
		});
		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getLegend()).toBeEqual({}));
		});
		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getHorizontalGrid()).toBeEqual(true));
		});
		it('graph updated with the correct name', function(){
			expect(Graph.prototype.getVerticalGrid()).toBeEqual(true));
		});

	});

	describe('addFlow', function(){

		var json = {

		};

		beforeEach(function(){
			Graph.prototype.addflow();
		});

		it('', function(){
			expect(Graph.prototype.getFlowList().length).toBeEqual(1);
		});

	});

});<|endoftext|>