<commit_before>(function () {
  'use strict';

  // Setting up route
  angular
    .module('users.routes')
    .config(routeConfig);

  routeConfig.$inject = ['$stateProvider'];

  function routeConfig($stateProvider) {
    // Users state routing
    $stateProvider
      .state('settings', {
        abstract: true,
        url: '/settings',
        templateUrl: '/modules/users/client/views/settings/settings.client.view.html',
        controller: 'SettingsController',
        controllerAs: 'vm',
        data: {
          roles: ['user', 'admin']
        }
      })
      .state('settings.profile', {
        url: '/profile',
        templateUrl: '/modules/users/client/views/settings/edit-profile.client.view.html',
        controller: 'EditProfileController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Settings'
        }
      })
      .state('settings.password', {
        url: '/password',
        templateUrl: '/modules/users/client/views/settings/change-password.client.view.html',
        controller: 'ChangePasswordController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Settings password'
        }
      })
      .state('settings.accounts', {
        url: '/accounts',
        templateUrl: '/modules/users/client/views/settings/manage-social-accounts.client.view.html',
        controller: 'SocialAccountsController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Settings accounts'
        }
      })
      // .state('settings.picture', {
      //   url: '/picture',
      //   templateUrl: '/modules/users/client/views/settings/change-profile-picture.client.view.html',
      //   controller: 'ChangeProfilePictureController',
      //   controllerAs: 'vm',
      //   data: {
      //     pageTitle: 'Settings picture'
      //   }
      // })
      .state('authentication', {
        abstract: true,
        url: '/authentication',
        templateUrl: '/modules/users/client/views/authentication/authentication.client.view.html',
        controller: 'AuthenticationController',
        controllerAs: 'vm'
      })
      .state('authentication.signup', {
        url: '/signup',
        templateUrl: '/modules/users/client/views/authentication/signup.client.view.html',
        controller: 'AuthenticationController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Signup'
        }
      })
      .state('authentication.signin', {
        url: '/signin?err',
        templateUrl: '/modules/users/client/views/authentication/signin.client.view.html',
        controller: 'AuthenticationController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Signin'
        }
      })
      .state('password', {
        abstract: true,
        url: '/password',
        template: '<ui-view/>'
      })
      .state('password.forgot', {
        url: '/forgot',
        templateUrl: '/modules/users/client/views/password/forgot-password.client.view.html',
        controller: 'PasswordController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Password forgot'
        }
      })
      .state('password.reset', {
        abstract: true,
        url: '/reset',
        template: '<ui-view/>'
      })
      .state('password.reset.invalid', {
        url: '/invalid',
        templateUrl: '/modules/users/client/views/password/reset-password-invalid.client.view.html',
        data: {
          pageTitle: 'Password reset invalid'
        }
      })
      .state('password.reset.success', {
        url: '/success',
        templateUrl: '/modules/users/client/views/password/reset-password-success.client.view.html',
        data: {
          pageTitle: 'Password reset success'
        }
      })
      .state('password.reset.form', {
        url: '/:token',
        templateUrl: '/modules/users/client/views/password/reset-password.client.view.html',
        controller: 'PasswordController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Password reset form'
        }
      });
  }
}());
<commit_msg>Update users.client.routes.js<commit_after>(function () {
  'use strict';

  // Setting up route
  angular
    .module('users.routes')
    .config(routeConfig);

  routeConfig.$inject = ['$stateProvider'];

  function routeConfig($stateProvider) {
    // Users state routing
    $stateProvider
      .state('settings', {
        abstract: true,
        url: '/settings',
        templateUrl: '/modules/users/client/views/settings/settings.client.view.html',
        controller: 'SettingsController',
        controllerAs: 'vm',
        data: {
          roles: ['user', 'admin']
        }
      })
      .state('settings.profile', {
        url: '/profile',
        templateUrl: '/modules/users/client/views/settings/edit-profile.client.view.html',
        controller: 'EditProfileController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Settings'
        }
      })
      .state('settings.password', {
        url: '/password',
        templateUrl: '/modules/users/client/views/settings/change-password.client.view.html',
        controller: 'ChangePasswordController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Settings password'
        }
      })
      .state('settings.accounts', {
        url: '/accounts',
        templateUrl: '/modules/users/client/views/settings/manage-social-accounts.client.view.html',
        controller: 'SocialAccountsController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Settings accounts'
        }
      })
      // .state('settings.picture', {
      //   url: '/picture',
      //   templateUrl: '/modules/users/client/views/settings/change-profile-picture.client.view.html',
      //   controller: 'ChangeProfilePictureController',
      //   controllerAs: 'vm',
      //   data: {
      //     pageTitle: 'Settings picture'
      //   }
      // })
      .state('authentication', {
        abstract: true,
        url: '/authentication',
        templateUrl: '/modules/users/client/views/authentication/authentication.client.view.html',
        controller: 'AuthenticationController',
        controllerAs: 'vm'
      })
      .state('authentication.signup', {
        url: '/signup',
        templateUrl: '/modules/users/client/views/authentication/signup.client.view.html',
        controller: 'AuthenticationController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Signup'
        }
      })
      .state('authentication.signin', {
        url: '/signin?err',
        templateUrl: '/modules/users/client/views/authentication/signin.client.view.html',
        controller: 'AuthenticationController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Signin'
        }
      })
    .state('consent-form', {
        url: '/authentication/consent-form',
        templateUrl: '/modules/users/client/views/authentication/consent.view.html',
        controller: 'ConsentFormController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Consent'
        }
      })
      .state('password', {
        abstract: true,
        url: '/password',
        template: '<ui-view/>'
      })
      .state('password.forgot', {
        url: '/forgot',
        templateUrl: '/modules/users/client/views/password/forgot-password.client.view.html',
        controller: 'PasswordController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Password forgot'
        }
      })
      .state('password.reset', {
        abstract: true,
        url: '/reset',
        template: '<ui-view/>'
      })
      .state('password.reset.invalid', {
        url: '/invalid',
        templateUrl: '/modules/users/client/views/password/reset-password-invalid.client.view.html',
        data: {
          pageTitle: 'Password reset invalid'
        }
      })
      .state('password.reset.success', {
        url: '/success',
        templateUrl: '/modules/users/client/views/password/reset-password-success.client.view.html',
        data: {
          pageTitle: 'Password reset success'
        }
      })
      .state('password.reset.form', {
        url: '/:token',
        templateUrl: '/modules/users/client/views/password/reset-password.client.view.html',
        controller: 'PasswordController',
        controllerAs: 'vm',
        data: {
          pageTitle: 'Password reset form'
        }
      });
  }
}());
<|endoftext|>


<commit_before>const InputValueService = require('../../../../js/repeater/InputValueService');
const $ = require('jquery');

describe('InputValueService', () => {
    let inputValueService;

    beforeEach(() => {
        inputValueService = new InputValueService();
    });

    describe('getValue', () => {
        let $checkbox;
        let $multiSelect;
        let $radio;
        let $input;

        beforeEach(() => {
            $input = $('<input type="text" value="foo"/>');
            $checkbox = $('<input type="checkbox" value="foo"/>');
            $radio = $('<input type="radio" name="foo" value="foo"/>');
            $multiSelect = $(`
                <select multiple="true">
                    <option value="foo" selected></option>
                    <option value="bar" selected></option>
                    <option value="baz"></option>
                </select>
            `);
        });

        it('should get values from checkboxes', () => {
            expect(inputValueService.getValue($checkbox[0])).to.deep.equal({
                value: 'foo', selected: false
            });
        });

        it('should get values from multi-select boxes', () => {
            expect(inputValueService.getValue($multiSelect[0])).to.deep.equal([
                { value: 'foo', selected: true },
                { value: 'bar', selected: true },
                { value: 'baz', selected: false }
            ]);
        });

        it('should get values from radio buttons', () => {
            expect(inputValueService.getValue($radio[0])).to.deep.equal({
                value: 'foo', selected: false
            });
        });

        it('should get values from inputs that do not require manual intervention', () => {
            expect(inputValueService.getValue($input[0])).to.deep.equal({
                value: 'foo', selected: true
            });
        });
    });

    describe('setValue', () => {
        let $checkbox;
        let $multiSelect;
        let $radio;
        let $input;

        beforeEach(() => {
            $input = $('<input type="text" value="foo"/>');
            $checkbox = $('<input type="checkbox" value="foo"/>');
            $radio = $('<input type="radio" name="foo" value="foo"/>');
            $multiSelect = $(`
                <select multiple="true">
                    <option value="foo" selected></option>
                    <option value="bar" selected></option>
                    <option value="baz"></option>
                </select>
            `);
        });

        it('should set the values of checkboxes', () => {
            inputValueService.setValue($checkbox[0], true, {});

            expect($checkbox.prop('checked')).to.equal(true);
        });

        it('should set the value of radio inputs', () => {
            inputValueService.setValue($radio[0], 'bar', { selected: true });

            expect($radio.val()).to.equal('bar');
            expect($radio.prop('checked')).to.equal(true);
        });

        it('should set the value of multi-select boxes', () => {
            inputValueService.setValue($multiSelect[0], 'baz', { selected: true });

            expect($multiSelect.find(':selected').toArray().map(e => e.value).join(','))
                .to.equal('foo,bar,baz');
        });

        it('should set the value of inputs that do not require manual intervention', () => {
            inputValueService.setValue($input[0], 'bar', {});

            expect($input.val()).to.equal('bar');
        });
    });

    describe('printValue', () => {
        let $password;
        let $multiSelect;
        let $select;
        let $input;

        beforeEach(() => {
            $password = $('<input type="password" value="password"/>');
            $multiSelect = $(`
                <select multiple="true">
                    <option value="foo" selected>foo</option>
                    <option value="bar" selected>bar</option>
                    <option value="baz">baz</option>
                </select>
            `);
            $select = $(`
                <select>
                    <option value="foo" selected>foo</option>
                    <option value="bar">bar</option>
                    <option value="baz">baz</option>
                </select>
            `);
            $input = $('<input type="text" value="foo"/>');
        });

        it('should print password values', () => {
            expect(inputValueService.printValue($password[0], 'password', {})).to.equal('********');
        });

        it('should print single select values', () => {
            expect(inputValueService.printValue($select[0], 'foo', {})).to.equal('foo');
        });

        it('should print multi select values', () => {
            expect(inputValueService.printValue($multiSelect[0], 'foo', {})).to.equal('foo');
        });

        it('should print value that do not require manual intervention', () => {
            expect(inputValueService.printValue($input[0], 'foo')).to.equal('foo');
        });
    });

    describe('getSelected', () => {
        let $checkbox;
        let $radio;
        let $input;

        beforeEach(() => {
            $input = $('<input type="text" value="foo"/>');
            $checkbox = $('<input type="checkbox" value="foo"/>')
            $radio = $('<input type="radio" value="foo" name="radio"/>');
        });

        it('should return the checked value for a checkbox', () => {
            expect(inputValueService.getSelected($checkbox[0])).to.be.false;

            $checkbox.click();

            expect(inputValueService.getSelected($checkbox[0])).to.be.true;
        });

        it('should return the checked value for a radio', () => {
            expect(inputValueService.getSelected($radio[0])).to.be.false;

            $radio.click();

            expect(inputValueService.getSelected($radio[0])).to.be.true;
        });

        it('should return true for inputs that do not have a selected property', () => {
            expect(inputValueService.getSelected($input[0])).to.be.true;
        });
    });

    describe('getCheckboxValue', () => {
        let $checkbox;

        beforeEach(() => {
            $checkbox = $('<input type="checkbox" value="foo">');
        });

        it('should return the checkbox value if it is checked', () => {
            $checkbox.click();

            expect(inputValueService.getCheckboxValue($checkbox[0])).to.deep.equal({
                value: 'foo', selected: true
            });
        });

        it('should return false if the checkbox is not checked', () => {
            expect(inputValueService.getCheckboxValue($checkbox[0])).to.deep.equal({
                value: 'foo', selected: false
            });
        });
    });

    describe('setCheckboxValue', () => {
        let $checkbox;

        beforeEach(() => {
            $checkbox = $('<input type="checkbox" value="foo">');
        });

        it('should check the checkbox if the value is truthy', () => {
            inputValueService.setCheckboxValue($checkbox[0], 'yolo');

            expect($checkbox.prop('checked')).to.be.true;
        });

        it('should not check the checkbox if the value is falsy', () => {
            inputValueService.setCheckboxValue($checkbox[0], '');

            expect($checkbox.prop('checked')).to.be.false;
        });
    });
});
<commit_msg>fix odd coverage result, was down to a lower-case require statement<commit_after>const InputValueService = require('../../../../js/Repeater/InputValueService');
const $ = require('jquery');

describe('InputValueService', () => {
    let inputValueService;

    beforeEach(() => {
        inputValueService = new InputValueService();
    });

    describe('getValue', () => {
        let $checkbox;
        let $multiSelect;
        let $radio;
        let $input;

        beforeEach(() => {
            $input = $('<input type="text" value="foo"/>');
            $checkbox = $('<input type="checkbox" value="foo"/>');
            $radio = $('<input type="radio" name="foo" value="foo"/>');
            $multiSelect = $(`
                <select multiple="true">
                    <option value="foo" selected></option>
                    <option value="bar" selected></option>
                    <option value="baz"></option>
                </select>
            `);
        });

        it('should get values from checkboxes', () => {
            expect(inputValueService.getValue($checkbox[0])).to.deep.equal({
                value: 'foo', selected: false
            });
        });

        it('should get values from multi-select boxes', () => {
            expect(inputValueService.getValue($multiSelect[0])).to.deep.equal([
                { value: 'foo', selected: true },
                { value: 'bar', selected: true },
                { value: 'baz', selected: false }
            ]);
        });

        it('should get values from radio buttons', () => {
            expect(inputValueService.getValue($radio[0])).to.deep.equal({
                value: 'foo', selected: false
            });
        });

        it('should get values from inputs that do not require manual intervention', () => {
            expect(inputValueService.getValue($input[0])).to.deep.equal({
                value: 'foo', selected: true
            });
        });
    });

    describe('setValue', () => {
        let $checkbox;
        let $multiSelect;
        let $radio;
        let $input;

        beforeEach(() => {
            $input = $('<input type="text" value="foo"/>');
            $checkbox = $('<input type="checkbox" value="foo"/>');
            $radio = $('<input type="radio" name="foo" value="foo"/>');
            $multiSelect = $(`
                <select multiple="true">
                    <option value="foo" selected></option>
                    <option value="bar" selected></option>
                    <option value="baz"></option>
                </select>
            `);
        });

        it('should set the values of checkboxes', () => {
            inputValueService.setValue($checkbox[0], true, {});

            expect($checkbox.prop('checked')).to.equal(true);
        });

        it('should set the value of radio inputs', () => {
            inputValueService.setValue($radio[0], 'bar', { selected: true });

            expect($radio.val()).to.equal('bar');
            expect($radio.prop('checked')).to.equal(true);
        });

        it('should set the value of multi-select boxes', () => {
            inputValueService.setValue($multiSelect[0], 'baz', { selected: true });

            expect($multiSelect.find(':selected').toArray().map(e => e.value).join(','))
                .to.equal('foo,bar,baz');
        });

        it('should set the value of inputs that do not require manual intervention', () => {
            inputValueService.setValue($input[0], 'bar', {});

            expect($input.val()).to.equal('bar');
        });
    });

    describe('printValue', () => {
        let $password;
        let $multiSelect;
        let $select;
        let $input;

        beforeEach(() => {
            $password = $('<input type="password" value="password"/>');
            $multiSelect = $(`
                <select multiple="true">
                    <option value="foo" selected>foo</option>
                    <option value="bar" selected>bar</option>
                    <option value="baz">baz</option>
                </select>
            `);
            $select = $(`
                <select>
                    <option value="foo" selected>foo</option>
                    <option value="bar">bar</option>
                    <option value="baz">baz</option>
                </select>
            `);
            $input = $('<input type="text" value="foo"/>');
        });

        it('should print password values', () => {
            expect(inputValueService.printValue($password[0], 'password', {})).to.equal('********');
        });

        it('should print single select values', () => {
            expect(inputValueService.printValue($select[0], 'foo', {})).to.equal('foo');
        });

        it('should print multi select values', () => {
            expect(inputValueService.printValue($multiSelect[0], 'foo', {})).to.equal('foo');
        });

        it('should print value that do not require manual intervention', () => {
            expect(inputValueService.printValue($input[0], 'foo')).to.equal('foo');
        });
    });

    describe('getSelected', () => {
        let $checkbox;
        let $radio;
        let $input;

        beforeEach(() => {
            $input = $('<input type="text" value="foo"/>');
            $checkbox = $('<input type="checkbox" value="foo"/>')
            $radio = $('<input type="radio" value="foo" name="radio"/>');
        });

        it('should return the checked value for a checkbox', () => {
            expect(inputValueService.getSelected($checkbox[0])).to.be.false;

            $checkbox.click();

            expect(inputValueService.getSelected($checkbox[0])).to.be.true;
        });

        it('should return the checked value for a radio', () => {
            expect(inputValueService.getSelected($radio[0])).to.be.false;

            $radio.click();

            expect(inputValueService.getSelected($radio[0])).to.be.true;
        });

        it('should return true for inputs that do not have a selected property', () => {
            expect(inputValueService.getSelected($input[0])).to.be.true;
        });
    });

    describe('getCheckboxValue', () => {
        let $checkbox;

        beforeEach(() => {
            $checkbox = $('<input type="checkbox" value="foo">');
        });

        it('should return the checkbox value if it is checked', () => {
            $checkbox.click();

            expect(inputValueService.getCheckboxValue($checkbox[0])).to.deep.equal({
                value: 'foo', selected: true
            });
        });

        it('should return false if the checkbox is not checked', () => {
            expect(inputValueService.getCheckboxValue($checkbox[0])).to.deep.equal({
                value: 'foo', selected: false
            });
        });
    });

    describe('setCheckboxValue', () => {
        let $checkbox;

        beforeEach(() => {
            $checkbox = $('<input type="checkbox" value="foo">');
        });

        it('should check the checkbox if the value is truthy', () => {
            inputValueService.setCheckboxValue($checkbox[0], 'yolo');

            expect($checkbox.prop('checked')).to.be.true;
        });

        it('should not check the checkbox if the value is falsy', () => {
            inputValueService.setCheckboxValue($checkbox[0], '');

            expect($checkbox.prop('checked')).to.be.false;
        });
    });
});
<|endoftext|>


<commit_before>var Sinon = require('sinon');
var QUnit = require('qunit');
var TestUtils = require('test-utils');
var Youtube = require('../src/youtube-video');

module.exports = (function () {
    'use strict';

    QUnit.module('Youtube Video Tests');

    QUnit.test('loading a video', function () {
        QUnit.expect(11);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player776">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var loadSpy = Sinon.spy();
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {
            playVideo: function (){}
        };
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player776');
        var loadingCssClass = 'v-loading';
        var player = new Youtube({
            el: videoEl,
            loadingCssClass: loadingCssClass
        });
        // setup server
        player.load(loadSpy);
        QUnit.ok(player._container.classList.contains(loadingCssClass), 'after calling load(), loading css class was added to container');
        QUnit.equal(loadSpy.callCount, 0, 'load callback was not yet fired because javascript file hasnt finished loading yet');
        // trigger script loaded
        window.onYouTubeIframeAPIReady();
        QUnit.ok(!videoEl.parentNode, 'the original video element has been removed from the DOM');
        var ytPlayerConstructorOptions = ytPlayerStub.args[0][1];
        QUnit.equal(ytPlayerConstructorOptions.width, 640, 'YouTube player constructor was passed width of video element');
        QUnit.equal(ytPlayerConstructorOptions.height, 360, 'YouTube player constructor was passed height of video element');
        QUnit.equal(ytPlayerConstructorOptions.videoId, videoId, 'YouTube player constructor was passed correct video id');
        QUnit.equal(loadSpy.callCount, 0, 'load callback was STILL not fired yet because player hasnt finished loading');
        QUnit.ok(player._container.classList.contains(loadingCssClass), 'container still has loading css class');
        // trigger player ready
        ytPlayerConstructorOptions.events.onReady({target: stubbedPlayer});
        QUnit.deepEqual(loadSpy.args[0], [stubbedPlayer], 'after player is done loading, load callback was fired with the player instance as the first arg');
        QUnit.ok(!player._container.classList.contains(loadingCssClass), 'container no longer has loading css class');
        player.destroy();
        QUnit.equal(fixture.childNodes[0], videoEl, 'video element was put back in the DOM inside of its original parent');
        window.YT = origYT;
    });

    QUnit.test('script loading', function () {
        QUnit.expect(4);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player77">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        fixture.innerHTML = html;
        var videoEl = document.getElementById('player77');
        var player = new Youtube({el: videoEl});
        var scriptUrl = 'https://www.youtube.com/iframe_api';
        // setup server
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 0, 'script element has NOT been added to DOM because load() hasnt been called');
        player.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() is called, script element is added to DOM');
        QUnit.ok(document.querySelectorAll('script[src="' + scriptUrl + '"]')[0].async, 'script has truthy async value');
        player.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 0, 'after destroying last instance, script element is finally removed from the DOM');
        window.YT = origYT;
    });

    QUnit.test('script existence when there are multiple instances', function () {
        QUnit.expect(6);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player32">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        fixture.innerHTML = html;
        var videoEl = document.getElementById('player32');
        var firstPlayer = new Youtube({el: videoEl});
        var scriptUrl = 'https://www.youtube.com/iframe_api';
        // setup server
        firstPlayer.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() on first instance is called, script element is added to DOM');
        var secondPlayer = new Youtube({el: videoEl});
        secondPlayer.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() is called on a second instance, script element is NOT added to the DOM a second time');
        firstPlayer.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after destroying first instance, script element is still left hanging out in the DOM, even when it hasnt finished loading yet, because there is another instance present');
        var thirdPlayer = new Youtube({el: videoEl});
        thirdPlayer.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() is called on a third instance, script element is NOT added to the DOM a second time');
        window.onYouTubeIframeAPIReady(); // trigger script loaded
        secondPlayer.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after destroying second instance after script has loaded, script element is still left hanging out in the DOM because there is another instance present');
        thirdPlayer.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 0, 'after destroying last instance, script element is finally removed from the DOM');
        window.YT = origYT;
    });

    QUnit.test('when a video is played', function () {
        QUnit.expect(4);
        var html = '<video width="640" height="360" id="player45">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=nOEw9iiopwI" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var playingClass = 'vid-playing';
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {playVideo: Sinon.spy()};
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player45');

        var player = new Youtube({
            el: videoEl,
            playingCssClass: playingClass
        });
        // load player
        player.load();
        window.onYouTubeIframeAPIReady(); // trigger script loaded
        ytPlayerStub.args[0][1].events.onReady({target: stubbedPlayer}); // trigger player loaded
        // test
        QUnit.ok(!player._container.classList.contains(playingClass), 'initially there is no playing css class added to the video container element because the video isnt playing');
        var playSpy = Sinon.spy();
        videoEl.addEventListener('play', playSpy);
        QUnit.equal(playSpy.callCount, 0, 'play event on the video element hasnt been triggered yet');
        ytPlayerStub.args[0][1].events.onStateChange({data: 1}); // trigger play
        QUnit.ok(player._container.classList.contains(playingClass), 'when video is played, playing css class has been added to the video container element');
        QUnit.equal(playSpy.callCount, 1, 'play event on the video element has been triggered once');
        player.destroy();
        window.YT = origYT;
    });

    QUnit.test('extracting video id from a url that begins with a direct link', function () {
        QUnit.expect(1);
        var videoEl = document.createElement('video');
        var player = new Youtube({el: videoEl});
        var videoId = 'nOEw9iiopwI';
        QUnit.equal(player.getVideoId('http://www.youtube.com/watch?v=' + videoId), videoId, 'correct video id was returned');
        player.destroy();
    });

    QUnit.test('extracting video id from a youtube url that is a embed link', function () {
        QUnit.expect(1);
        var videoEl = document.createElement('video');
        // test url
        var player = new Youtube({el: videoEl});
        var videoId = 'nCJJdW20uZI';
        QUnit.equal(player.getVideoId('https://www.youtube.com/embed/' + videoId), videoId, 'correct video id was returned');
        player.destroy();
    });

    QUnit.test('query parameters from a url', function () {
        QUnit.expect(2);
        var videoEl = document.createElement('video');
        videoEl.innerHTML = '<source type="video/youtube" />';
        var fixture = document.getElementById('qunit-fixture');
        fixture.appendChild(videoEl);
        // test url
        videoEl.getElementsByTagName('source')[0].setAttribute('src', 'http://www.youtube.com/watch?v=nOEw9i3opwI&rel=0');
        var player = new Youtube({el: videoEl});
        QUnit.deepEqual(player.getPlayerVars(), {v: 'nOEw9i3opwI', rel: "0"}, 'correct video id was returned');
        player.destroy();
        // test url
        videoEl.getElementsByTagName('source')[0].setAttribute('src', 'https://www.youtube.com/embed/nCJJdW20uZI?autoplay=true&blah');
        var player = new Youtube({el: videoEl});
        QUnit.deepEqual(player.getPlayerVars(), {autoplay: 'true', blah: ''}, 'correct video id was returned');
        player.destroy();
    });

    QUnit.test('attempting to play/pause a video before player has loaded', function () {
        QUnit.expect(3);
        var html = '<video width="640" height="360" id="player89">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=nOEw9iiopwI" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var playingClass = 'vid-playing';
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {playVideo: Sinon.spy()};
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player89');
        var player = new Youtube({el: videoEl, playingCssClass: playingClass});
        var playSpy = Sinon.spy(player, 'play');
        var stopSpy = Sinon.spy(player, 'stop');
        var pauseSpy = Sinon.spy(player, 'pause');
        // load player
        player.load();
        player.play();
        QUnit.ok(!playSpy.threw('TypeError'), 'calling play() before player\'s script has loaded does NOT throw error');
        player.pause();
        QUnit.ok(!pauseSpy.threw('TypeError'), 'calling pause() before player\'s script has loaded does NOT throw error');
        player.stop();
        QUnit.ok(!stopSpy.threw('TypeError'), 'calling stop() before player\'s script has loaded does NOT throw error');
        // trigger script loaded
        window.onYouTubeIframeAPIReady();
        player.play();
        // trigger player loaded
        ytPlayerStub.args[0][1].events.onReady({target: stubbedPlayer});
        player.play();
        // test
        playSpy.restore();
        stopSpy.restore();
        pauseSpy.restore();
        player.destroy();
        window.YT = origYT;
    });

    QUnit.test('autoplay', function () {
        QUnit.expect(1);
        var html = '<video width="640" height="360" id="player87">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=nOEw9iiopwI" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {playVideo: Sinon.spy()};
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player87');
        videoEl.setAttribute('autoplay', 'true'); // add autoplay
        var player = new Youtube({el: videoEl});
        player.load(); // load player
        window.onYouTubeIframeAPIReady(); // trigger script loaded
        QUnit.equal(ytPlayerStub.args[0][1].playerVars.autoplay, 1, 'when video element has autoplay attribute, new Youtube Video constructor is passed playerVars.autoplay set to 1');
        player.destroy();
        window.YT = origYT;
    });

    QUnit.test('applying a custom wrapper class to video', function () {
        QUnit.expect(12);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player776">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var loadSpy = Sinon.spy();
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {
            playVideo: function (){}
        };
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player776');
        var loadingCssClass = 'v-loading';
        var customWrapperClass = 'v-wrapper';
        var player = new Youtube({
            el: videoEl,
            loadingCssClass: loadingCssClass,
            customWrapperClass: customWrapperClass
        });
        // setup server
        player.load(loadSpy);
        QUnit.ok(player._container.classList.contains(loadingCssClass), 'after calling load(), loading css class was added to container');
        QUnit.ok(player._container.classList.contains(customWrapperClass), 'after calling load(), custom wrapper css class was added to container');
        QUnit.equal(loadSpy.callCount, 0, 'load callback was not yet fired because javascript file hasnt finished loading yet');
        // trigger script loaded
        window.onYouTubeIframeAPIReady();
        QUnit.ok(!videoEl.parentNode, 'the original video element has been removed from the DOM');
        var ytPlayerConstructorOptions = ytPlayerStub.args[0][1];
        QUnit.equal(ytPlayerConstructorOptions.width, 640, 'YouTube player constructor was passed width of video element');
        QUnit.equal(ytPlayerConstructorOptions.height, 360, 'YouTube player constructor was passed height of video element');
        QUnit.equal(ytPlayerConstructorOptions.videoId, videoId, 'YouTube player constructor was passed correct video id');
        QUnit.equal(loadSpy.callCount, 0, 'load callback was STILL not fired yet because player hasnt finished loading');
        QUnit.ok(player._container.classList.contains(loadingCssClass), 'container still has loading css class');
        // trigger player ready
        ytPlayerConstructorOptions.events.onReady({target: stubbedPlayer});
        QUnit.deepEqual(loadSpy.args[0], [stubbedPlayer], 'after player is done loading, load callback was fired with the player instance as the first arg');
        QUnit.ok(!player._container.classList.contains(loadingCssClass), 'container no longer has loading css class');
        player.destroy();
        QUnit.equal(fixture.childNodes[0], videoEl, 'video element was put back in the DOM inside of its original parent');
        window.YT = origYT;
    });

})();

<commit_msg>unit test cleanup<commit_after>var Sinon = require('sinon');
var QUnit = require('qunit');
var TestUtils = require('test-utils');
var Youtube = require('../src/youtube-video');

module.exports = (function () {
    'use strict';

    QUnit.module('Youtube Video Tests');

    QUnit.test('loading a video', function () {
        QUnit.expect(11);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player776">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var loadSpy = Sinon.spy();
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {
            playVideo: function (){}
        };
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player776');
        var loadingCssClass = 'v-loading';
        var player = new Youtube({
            el: videoEl,
            loadingCssClass: loadingCssClass
        });
        // setup server
        player.load(loadSpy);
        QUnit.ok(player._container.classList.contains(loadingCssClass), 'after calling load(), loading css class was added to container');
        QUnit.equal(loadSpy.callCount, 0, 'load callback was not yet fired because javascript file hasnt finished loading yet');
        // trigger script loaded
        window.onYouTubeIframeAPIReady();
        QUnit.ok(!videoEl.parentNode, 'the original video element has been removed from the DOM');
        var ytPlayerConstructorOptions = ytPlayerStub.args[0][1];
        QUnit.equal(ytPlayerConstructorOptions.width, 640, 'YouTube player constructor was passed width of video element');
        QUnit.equal(ytPlayerConstructorOptions.height, 360, 'YouTube player constructor was passed height of video element');
        QUnit.equal(ytPlayerConstructorOptions.videoId, videoId, 'YouTube player constructor was passed correct video id');
        QUnit.equal(loadSpy.callCount, 0, 'load callback was STILL not fired yet because player hasnt finished loading');
        QUnit.ok(player._container.classList.contains(loadingCssClass), 'container still has loading css class');
        // trigger player ready
        ytPlayerConstructorOptions.events.onReady({target: stubbedPlayer});
        QUnit.deepEqual(loadSpy.args[0], [stubbedPlayer], 'after player is done loading, load callback was fired with the player instance as the first arg');
        QUnit.ok(!player._container.classList.contains(loadingCssClass), 'container no longer has loading css class');
        player.destroy();
        QUnit.equal(fixture.childNodes[0], videoEl, 'video element was put back in the DOM inside of its original parent');
        window.YT = origYT;
    });

    QUnit.test('script loading', function () {
        QUnit.expect(4);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player77">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        fixture.innerHTML = html;
        var videoEl = document.getElementById('player77');
        var player = new Youtube({el: videoEl});
        var scriptUrl = 'https://www.youtube.com/iframe_api';
        // setup server
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 0, 'script element has NOT been added to DOM because load() hasnt been called');
        player.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() is called, script element is added to DOM');
        QUnit.ok(document.querySelectorAll('script[src="' + scriptUrl + '"]')[0].async, 'script has truthy async value');
        player.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 0, 'after destroying last instance, script element is finally removed from the DOM');
        window.YT = origYT;
    });

    QUnit.test('script existence when there are multiple instances', function () {
        QUnit.expect(6);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player32">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        fixture.innerHTML = html;
        var videoEl = document.getElementById('player32');
        var firstPlayer = new Youtube({el: videoEl});
        var scriptUrl = 'https://www.youtube.com/iframe_api';
        // setup server
        firstPlayer.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() on first instance is called, script element is added to DOM');
        var secondPlayer = new Youtube({el: videoEl});
        secondPlayer.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() is called on a second instance, script element is NOT added to the DOM a second time');
        firstPlayer.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after destroying first instance, script element is still left hanging out in the DOM, even when it hasnt finished loading yet, because there is another instance present');
        var thirdPlayer = new Youtube({el: videoEl});
        thirdPlayer.load();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after load() is called on a third instance, script element is NOT added to the DOM a second time');
        window.onYouTubeIframeAPIReady(); // trigger script loaded
        secondPlayer.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 1, 'after destroying second instance after script has loaded, script element is still left hanging out in the DOM because there is another instance present');
        thirdPlayer.destroy();
        QUnit.equal(document.querySelectorAll('script[src="' + scriptUrl + '"]').length, 0, 'after destroying last instance, script element is finally removed from the DOM');
        window.YT = origYT;
    });

    QUnit.test('when a video is played', function () {
        QUnit.expect(4);
        var html = '<video width="640" height="360" id="player45">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=nOEw9iiopwI" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var playingClass = 'vid-playing';
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {playVideo: Sinon.spy()};
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player45');

        var player = new Youtube({
            el: videoEl,
            playingCssClass: playingClass
        });
        // load player
        player.load();
        window.onYouTubeIframeAPIReady(); // trigger script loaded
        ytPlayerStub.args[0][1].events.onReady({target: stubbedPlayer}); // trigger player loaded
        // test
        QUnit.ok(!player._container.classList.contains(playingClass), 'initially there is no playing css class added to the video container element because the video isnt playing');
        var playSpy = Sinon.spy();
        videoEl.addEventListener('play', playSpy);
        QUnit.equal(playSpy.callCount, 0, 'play event on the video element hasnt been triggered yet');
        ytPlayerStub.args[0][1].events.onStateChange({data: 1}); // trigger play
        QUnit.ok(player._container.classList.contains(playingClass), 'when video is played, playing css class has been added to the video container element');
        QUnit.equal(playSpy.callCount, 1, 'play event on the video element has been triggered once');
        player.destroy();
        window.YT = origYT;
    });

    QUnit.test('extracting video id from a url that begins with a direct link', function () {
        QUnit.expect(1);
        var videoEl = document.createElement('video');
        var player = new Youtube({el: videoEl});
        var videoId = 'nOEw9iiopwI';
        QUnit.equal(player.getVideoId('http://www.youtube.com/watch?v=' + videoId), videoId, 'correct video id was returned');
        player.destroy();
    });

    QUnit.test('extracting video id from a youtube url that is a embed link', function () {
        QUnit.expect(1);
        var videoEl = document.createElement('video');
        // test url
        var player = new Youtube({el: videoEl});
        var videoId = 'nCJJdW20uZI';
        QUnit.equal(player.getVideoId('https://www.youtube.com/embed/' + videoId), videoId, 'correct video id was returned');
        player.destroy();
    });

    QUnit.test('query parameters from a url', function () {
        QUnit.expect(2);
        var videoEl = document.createElement('video');
        videoEl.innerHTML = '<source type="video/youtube" />';
        var fixture = document.getElementById('qunit-fixture');
        fixture.appendChild(videoEl);
        // test url
        videoEl.getElementsByTagName('source')[0].setAttribute('src', 'http://www.youtube.com/watch?v=nOEw9i3opwI&rel=0');
        var player = new Youtube({el: videoEl});
        QUnit.deepEqual(player.getPlayerVars(), {v: 'nOEw9i3opwI', rel: "0"}, 'correct video id was returned');
        player.destroy();
        // test url
        videoEl.getElementsByTagName('source')[0].setAttribute('src', 'https://www.youtube.com/embed/nCJJdW20uZI?autoplay=true&blah');
        var player = new Youtube({el: videoEl});
        QUnit.deepEqual(player.getPlayerVars(), {autoplay: 'true', blah: ''}, 'correct video id was returned');
        player.destroy();
    });

    QUnit.test('attempting to play/pause a video before player has loaded', function () {
        QUnit.expect(3);
        var html = '<video width="640" height="360" id="player89">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=nOEw9iiopwI" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var playingClass = 'vid-playing';
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {playVideo: Sinon.spy()};
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player89');
        var player = new Youtube({el: videoEl, playingCssClass: playingClass});
        var playSpy = Sinon.spy(player, 'play');
        var stopSpy = Sinon.spy(player, 'stop');
        var pauseSpy = Sinon.spy(player, 'pause');
        // load player
        player.load();
        player.play();
        QUnit.ok(!playSpy.threw('TypeError'), 'calling play() before player\'s script has loaded does NOT throw error');
        player.pause();
        QUnit.ok(!pauseSpy.threw('TypeError'), 'calling pause() before player\'s script has loaded does NOT throw error');
        player.stop();
        QUnit.ok(!stopSpy.threw('TypeError'), 'calling stop() before player\'s script has loaded does NOT throw error');
        // trigger script loaded
        window.onYouTubeIframeAPIReady();
        player.play();
        // trigger player loaded
        ytPlayerStub.args[0][1].events.onReady({target: stubbedPlayer});
        player.play();
        // test
        playSpy.restore();
        stopSpy.restore();
        pauseSpy.restore();
        player.destroy();
        window.YT = origYT;
    });

    QUnit.test('autoplay', function () {
        QUnit.expect(1);
        var html = '<video width="640" height="360" id="player87">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=nOEw9iiopwI" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {playVideo: Sinon.spy()};
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player87');
        videoEl.setAttribute('autoplay', 'true'); // add autoplay
        var player = new Youtube({el: videoEl});
        player.load(); // load player
        window.onYouTubeIframeAPIReady(); // trigger script loaded
        QUnit.equal(ytPlayerStub.args[0][1].playerVars.autoplay, 1, 'when video element has autoplay attribute, new Youtube Video constructor is passed playerVars.autoplay set to 1');
        player.destroy();
        window.YT = origYT;
    });

    QUnit.test('applying a custom wrapper class to video', function () {
        QUnit.expect(1);
        var videoId = 'nOEw9iiopwI';
        var html = '<video width="640" height="360" id="player776">' +
            '<source type="video/youtube" src="http://www.youtube.com/watch?v=' + videoId + '" />' +
            '</video>';
        var fixture = document.getElementById('qunit-fixture');
        fixture.innerHTML = html;
        var loadSpy = Sinon.spy();
        var origYT = window.YT;
        var ytPlayerStub = Sinon.stub();
        window.YT = {Player: ytPlayerStub};
        var stubbedPlayer = {
            playVideo: function (){}
        };
        ytPlayerStub.returns(stubbedPlayer);
        var videoEl = document.getElementById('player776');
        var customWrapperClass = 'v-wrapper';
        var player = new Youtube({
            el: videoEl,
            customWrapperClass: customWrapperClass
        });
        // setup server
        player.load(loadSpy);
        QUnit.ok(player._container.classList.contains(customWrapperClass), 'after calling load(), custom wrapper css class was added to container');
        // trigger script loaded
        window.onYouTubeIframeAPIReady();
        var ytPlayerConstructorOptions = ytPlayerStub.args[0][1];
        // trigger player ready
        ytPlayerConstructorOptions.events.onReady({target: stubbedPlayer});
        player.destroy();
        window.YT = origYT;
    });

})();

<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* File to handle Google's Auth API requests
*/

const PHONE_NUMBER_LENGTH = 10;
const TUTORIAL_FILENAME = 'home';

// Call to Auth servlet to get user log information
/** @param {string} fileName */
function getLogStatus(fileName) {
  fetch('/log-status').then(response => response.json()).then((logStatus) => {
    if (!logStatus.isRegistered && logStatus.isLogged) {
      showRegistrationForm(logStatus.isRegistered);
    }

    if (fileName === TUTORIAL_FILENAME) {
      handleTutorialContent(logStatus.isLogged);
    }

    handleLogForm(logStatus);
  });
}

/** @param {boolean} isRegistered */
function showRegistrationForm(isRegistered) {
  $('#registration-modal').load('common/registration.html', () => {
    setUploadedImaged();
    setIconClickEvent();
    if (isRegistered) {
      getUserInformation();
    }
    $('#exampleModalCenter').modal('show');
  });
}

function getUserInformation() {
  fetch('/get-vendor', {method: 'POST'}).then(
    response => {
      if (response.status === 401) {
        response.text().then((error) => {
          $('#log-button').trigger('click');
          alert(error);
          return;
        });
      } else if (response.status === 200) {
        response.json()
        .then((vendorInformation) => {
          setVendorInformationInModal(vendorInformation);
        });
      }
    }
  );
}

function setIconClickEvent() {
  $(".upload-button").on('click', function() {
      $("#imageFile").click();
  });
}

function setUploadedImaged() {
  $("#imageFile").change(function () {
    if (this.files && this.files[0]) {
      const reader = new FileReader();
      reader.onload = function (e) {
        $('#profile-picture').attr('src', e.target.result);
      }
      reader.readAsDataURL(this.files[0]);
    } else {
      $('#profile-picture').attr('src', 'images/placeholderImage.png');
    }
  });
}

function setVendorInformationInModal(vendorInformation) {
  const firstName = document.getElementById('first_name');
  const lastName = document.getElementById('last_name');
  const phoneNumber = document.getElementById('phone_number');
  const blobKey = document.getElementById('blobKey');
  const registerButton = document.getElementById('registerButton');

  firstName.value = vendorInformation.firstName;
  lastName.value = vendorInformation.lastName;
  phoneNumber.value = vendorInformation.phoneNumber;
  registerButton.innerHTML = 'Update Account'

  if (vendorInformation.profilePic){
    const profilePic = document.getElementById('profile-picture');
    const altText = document.getElementById('altText');

    blobKey.value = vendorInformation.profilePic.blobKey.blobKey;
    profilePic.src = `/serve-blob?blobKey=${blobKey.value}`;
    altText.value = vendorInformation.profilePic.altText;
  }
}

// Sets the dropdown menu or URL link
/** @param {{url:string, isLogged:boolean, isRegistered:boolean}} logStatus */
function handleLogForm(logStatus) {
  if (logStatus.isLogged) {
    setDropdownMenuInDOM(logStatus.url);
  } else {
    setLogURL(logStatus.url);
  }
}

// Sets the log URL link on the DOM
/** @param {string} logURL */
function setLogURL(logURL) {
  const logButton = document.getElementById('log-button');
  logButton.href = logURL;
}

// Valids that the user inputs are in the right format
function validateRegistrationFormInputs() {
  const firstName = document.getElementById('first_name').value;
  const lastName = document.getElementById('last_name').value;
  const phoneNumber = document.getElementById('phone_number').value;
  const profilePictureFile = document.getElementById('imageFile');
  const blobKey = document.getElementById('blobKey').value;
  const altText = document.getElementById('altText').value;

  if (!firstName || !lastName || !isValidInput(firstName, true) || !isValidInput(lastName, true)) {
    alert('Names can\'t be empty or have special characters');
    return;
  }

  if (!phoneNumber || phoneNumber.length !== PHONE_NUMBER_LENGTH || !isValidInput(phoneNumber, false)) {
    alert(`Phone Number can't be empty, have spaces or have more than ${PHONE_NUMBER_LENGTH} numbers`);
    return;
  }

  if (!altText) {
    alert('Alt text can\'t be empty');
    return;
  }

  handleRegistration(firstName, lastName, phoneNumber,profilePictureFile.files[0], blobKey, altText);
}

// Checks if input is valid
/**
* @param {string} vendorInput
* @param {boolean} isNameInput
* @return {boolean}
*/
function isValidInput(vendorInput, isNameInput) {
  // Regex for Valid Characters i.e. Alphabets, Numbers and Space
  const validCharacters = /^[A-Za-z0-9 ]+$/;
  // Regex for Valid Numbers
  const validNumbers = /^[0-9]+$/;

  const regexCheck = (isNameInput) ? validCharacters : validNumbers;

  // Returns true if the input is clean of special characters
  return regexCheck.test(vendorInput);
}

// Fetch vendor data to add it to datastore
/**
* @param {string} firstName
* @param {string} lastName
* @param {string} phoneNumber
* @param {file} profilePictureImg
* @return {void}
*/
async function handleRegistration(firstName, lastName, phoneNumber, profilePictureImg, blobKey, altText) {
  const blobURL = await getBlobstoreURL();
  const vendorsParams = new FormData();

  vendorsParams.append('firstName', firstName);
  vendorsParams.append('lastName', lastName);
  vendorsParams.append('phoneNumber', phoneNumber);
  vendorsParams.append('imageFile', profilePictureImg);
  vendorsParams.append('blobKey', blobKey);
  vendorsParams.append('altText', altText);

  await fetch(blobURL, {method: 'POST', body: vendorsParams})
  .then(response => {
    // If the registration is complete then hide the modal
    if(response.redirected) {
      alert('Successful Registration');
      $('#exampleModalCenter').modal('hide');
      return;
    }

    // If an error ocurred, alert it
    response.text().then((error) => {
      alert(error);
    });
  });
}

async function getBlobstoreURL() {
  let blobURL;
  await fetch('/blobstore-upload-url?formHandler=/update-vendor')
    .then((response) => {
      return response.text();
    }).then((formUrl) => {
      blobURL = formUrl;
    });
  return blobURL;
}
<commit_msg>Fix code style issues<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* File to handle Google's Auth API requests
*/

const PHONE_NUMBER_LENGTH = 10;
const TUTORIAL_FILENAME = 'home';

// Call to Auth servlet to get user log information
/** @param {string} fileName */
function getLogStatus(fileName) {
  fetch('/log-status').then(response => response.json()).then((logStatus) => {
    if (!logStatus.isRegistered && logStatus.isLogged) {
      showRegistrationForm(logStatus.isRegistered);
    }

    if (fileName === TUTORIAL_FILENAME) {
      handleTutorialContent(logStatus.isLogged);
    }

    handleLogForm(logStatus);
  });
}

/** @param {boolean} isRegistered */
function showRegistrationForm(isRegistered) {
  $('#registration-modal').load('common/registration.html', () => {
    setUploadedImaged();
    setIconClickEvent();
    if (isRegistered) {
      getUserInformation();
    }
    $('#exampleModalCenter').modal('show');
  });
}

// Retrieves the user information to set it in the registration form
function getUserInformation() {
  fetch('/get-vendor', {method: 'POST'}).then(
    response => {
      if (response.status === 401) {
        response.text().then((error) => {
          $('#log-button').trigger('click');
          alert(error);
          return;
        });
      } else if (response.status === 200) {
        response.json()
        .then((vendorInformation) => {
          setVendorInformationInModal(vendorInformation);
        });
      }
    }
  );
}

// Sets the input event on the profile picture icon.
function setIconClickEvent() {
  $(".upload-button").on('click', function() {
      $("#imageFile").click();
  });
}

// Checks for uploaded files by the user to set the image or a placeholder
function setUploadedImaged() {
  $("#imageFile").change(function () {
    if (this.files && this.files[0]) {
      const reader = new FileReader();
      reader.onload = function (e) {
        $('#profile-picture').attr('src', e.target.result);
      }
      reader.readAsDataURL(this.files[0]);
    } else {
      $('#profile-picture').attr('src', 'images/placeholderImage.png');
    }
  });
}

// Sets the dropdown menu or URL link
/** @param {{firstName:string, lastName:string, phoneNumber:string, blobKey:string, altText:string}} logStatus */
function setVendorInformationInModal(vendorInformation) {
  const firstName = document.getElementById('first_name');
  const lastName = document.getElementById('last_name');
  const phoneNumber = document.getElementById('phone_number');
  const blobKey = document.getElementById('blobKey');
  const registerButton = document.getElementById('registerButton');

  firstName.value = vendorInformation.firstName;
  lastName.value = vendorInformation.lastName;
  phoneNumber.value = vendorInformation.phoneNumber;
  registerButton.innerHTML = 'Update Account'

  if (vendorInformation.profilePic) {
    const profilePic = document.getElementById('profile-picture');
    const altText = document.getElementById('altText');

    blobKey.value = vendorInformation.profilePic.blobKey.blobKey;
    profilePic.src = `/serve-blob?blobKey=${blobKey.value}`;
    altText.value = vendorInformation.profilePic.altText;
  }
}

// Sets the dropdown menu or URL link
/** @param {{url:string, isLogged:boolean, isRegistered:boolean}} logStatus */
function handleLogForm(logStatus) {
  if (logStatus.isLogged) {
    setDropdownMenuInDOM(logStatus.url);
  } else {
    setLogURL(logStatus.url);
  }
}

// Sets the log URL link on the DOM
/** @param {string} logURL */
function setLogURL(logURL) {
  const logButton = document.getElementById('log-button');
  logButton.href = logURL;
}

// Valids that the user inputs are in the right format
function validateRegistrationFormInputs() {
  const firstName = document.getElementById('first_name').value;
  const lastName = document.getElementById('last_name').value;
  const phoneNumber = document.getElementById('phone_number').value;
  const profilePictureFile = document.getElementById('imageFile');
  const blobKey = document.getElementById('blobKey').value;
  const altText = document.getElementById('altText').value;

  if (!firstName || !lastName || !isValidInput(firstName, true) || !isValidInput(lastName, true)) {
    alert('Names can\'t be empty or have special characters');
    return;
  }

  if (!phoneNumber || phoneNumber.length !== PHONE_NUMBER_LENGTH || !isValidInput(phoneNumber, false)) {
    alert(`Phone Number can't be empty, have spaces or have more than ${PHONE_NUMBER_LENGTH} numbers`);
    return;
  }

  if (!altText) {
    alert('Alt text can\'t be empty');
    return;
  }

  handleRegistration(firstName, lastName, phoneNumber,profilePictureFile.files[0], blobKey, altText);
}

// Checks if input is valid
/**
* @param {string} vendorInput
* @param {boolean} isNameInput
* @return {boolean}
*/
function isValidInput(vendorInput, isNameInput) {
  // Regex for Valid Characters i.e. Alphabets, Numbers and Space
  const validCharacters = /^[A-Za-z0-9 ]+$/;
  // Regex for Valid Numbers
  const validNumbers = /^[0-9]+$/;

  const regexCheck = (isNameInput) ? validCharacters : validNumbers;

  // Returns true if the input is clean of special characters
  return regexCheck.test(vendorInput);
}

// Fetch vendor data to add it to datastore
/**
* @param {string} firstName
* @param {string} lastName
* @param {string} phoneNumber
* @param {file} profilePictureImg
* @return {void}
*/
async function handleRegistration(firstName, lastName, phoneNumber, profilePictureImg, blobKey, altText) {
  const blobURL = await getBlobstoreURL();
  const vendorsParams = new FormData();

  vendorsParams.append('firstName', firstName);
  vendorsParams.append('lastName', lastName);
  vendorsParams.append('phoneNumber', phoneNumber);
  vendorsParams.append('imageFile', profilePictureImg);
  vendorsParams.append('blobKey', blobKey);
  vendorsParams.append('altText', altText);

  await fetch(blobURL, {method: 'POST', body: vendorsParams})
  .then(response => {
    // If the registration is complete then hide the modal
    if (response.redirected) {
      alert('Successful Registration');
      $('#exampleModalCenter').modal('hide');
      return;
    }

    // If an error ocurred, alert it
    response.text().then((error) => {
      alert(error);
    });
  });
}

async function getBlobstoreURL() {
  let blobURL;
  await fetch('/blobstore-upload-url?formHandler=/update-vendor')
    .then((response) => {
      return response.text();
    }).then((formUrl) => {
      blobURL = formUrl;
    });
  return blobURL;
}
<|endoftext|>


<commit_before>/**
 * Test scenario
 * =============
 * The virtual DOM enviroment provided by Jest + JSDOM is a `window` sized 1024x768.
 * By placing anchor at different places on the virtual window,
 * we can know if `anchored()` is doing its job of deciding position.
 *
 *           1024
 * ┌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┐
 * ╎  ┌╌╌╌╌┐ Anchored       ╎
 * ╎  └╌╌╌╌┘ Component      ╎
 * ╎                        ╎ 768
 * ╎      □ Anchor          ╎
 * ╎                        ╎
 * └╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┘
 */

import React, { PropTypes, PureComponent } from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';

import anchored, { ANCHORED_PLACEMENT } from '../anchored';

// --------------------
//  Mocking components
// --------------------

const ANCHOR_SIZE = 20;
const BOX_SIZE = 100;

// <Anchor> needs to be a React Component so it has an backing instance.
// eslint-disable-next-line react/prefer-stateless-function
class Anchor extends PureComponent {
    static propTypes = {
        top: PropTypes.number.isRequired,
        left: PropTypes.number.isRequired,
    };

    render() {
        const { top, left } = this.props;
        const style = {
            width: ANCHOR_SIZE,
            height: ANCHOR_SIZE,
            position: 'absolute',
            top,
            left,
        };
        return
;
    }
}

function Box({ style }) {
    const boxStyle = {
        ...style,
        width: BOX_SIZE,
        height: BOX_SIZE,
    };
    return
;
}
const AnchoredBoxBottom = anchored()(Box);
const AnchoredBoxTop = anchored({ defaultPlacement: ANCHORED_PLACEMENT.TOP })(Box);

/**
 * Overrides the one shiped with `jsdom`, since it always return 0.
 */
HTMLElement.prototype.getBoundingClientRect = function getBoundingClientRect() {
    if (!this.style) {
        return {
            bottom: 0,
            height: 0,
            left: 0,
            right: 0,
            top: 0,
            width: 0,
        };
    }

    const rect = {
        width: parseInt(this.style.width, 10),
        height: parseInt(this.style.height, 10),
        top: parseInt(this.style.top, 10) || 0,
        left: parseInt(this.style.left, 10) || 0,
    };

    rect.bottom = rect.top + rect.height;
    rect.right = rect.left + rect.width;

    return rect;
};

// --------------------
//  Prepare env
// --------------------
/**
 * Prepare different containers for each component, since `mount({ attachTo: node })` method
 * will wipe out everything in that `node`, replacing the formerly-rendered content.
 */
const anchorRoot = document.createElement('div');
const boxRoot = document.createElement('div');

document.body.appendChild(anchorRoot);
document.body.appendChild(boxRoot);

// --------------------
//  Test cases
// --------------------

it('renders without crashing', () => {
    const div = document.createElement('div');
    const element = <AnchoredBoxBottom />;

    ReactDOM.render(element, div);
});

it('renders on top of anchor when possible or needed', () => {
    const anchorWrapper = mount(<Anchor top={700} left={100} />, { attachTo: anchorRoot });

    let boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.TOP);
    expect(boxWrapper.prop('style').top).toBe(700 - BOX_SIZE);

    boxWrapper = mount(
        <AnchoredBoxBottom anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.TOP);
    expect(boxWrapper.prop('style').top).toBe(700 - BOX_SIZE);
});

it('renders below anchor when possible or needed', () => {
    const anchorWrapper = mount(<Anchor top={50} left={100} />, { attachTo: anchorRoot });

    let boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.BOTTOM);
    expect(boxWrapper.prop('style').top).toBe(50 + ANCHOR_SIZE);

    boxWrapper = mount(
        <AnchoredBoxBottom anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.BOTTOM);
    expect(boxWrapper.prop('style').top).toBe(50 + ANCHOR_SIZE);
});

it('renders and aligns to the center line of anchor', () => {
    const anchorWrapper = mount(<Anchor top={20} left={100} />, { attachTo: anchorRoot });
    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(
        // The center line of <Box>
        boxWrapper.prop('style').left + (BOX_SIZE / 2)
    ).toBe(
        // The center line of <Anchor>
        100 + (ANCHOR_SIZE / 2)
    );
});

it('renders on the left side of anchor when not enough space on the right', () => {
    const anchorWrapper = mount(<Anchor top={20} left={1000} />, { attachTo: anchorRoot });
    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(
        // The center line of <Box>
        boxWrapper.prop('style').left + (BOX_SIZE / 2)
    ).toBeLessThan(
        // The center line of <Anchor>
        1000 + (ANCHOR_SIZE / 2)
    );
});

it('renders on the right side of anchor when not enough space on the left', () => {
    const anchorWrapper = mount(<Anchor top={20} left={10} />, { attachTo: anchorRoot });
    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(
        // The center line of <Box>
        boxWrapper.prop('style').left + (BOX_SIZE / 2)
    ).toBeGreaterThan(
        // The center line of <Anchor>
        10 + (ANCHOR_SIZE / 2)
    );
});

it('can take an HTMLElement as anchor', () => {
    mount(<Anchor top={10} left={10} />, { attachTo: anchorRoot });
    const anchorNode = document.getElementById('anchor');

    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorNode} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.exists()).toBeTruthy();
});

it('re-adjusts position when assigned with another anchor', () => {
    let anchorWrapper = mount(<Anchor top={20} left={10} />, { attachTo: anchorRoot });
    const wrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    );

    expect(wrapper.find(Box).prop('placement')).toBe(ANCHORED_PLACEMENT.BOTTOM);

    anchorWrapper = mount(<Anchor top={200} left={10} />, { attachTo: anchorRoot });
    wrapper.setProps({ anchor: anchorWrapper.instance() });

    expect(wrapper.find(Box).prop('placement')).toBe(ANCHORED_PLACEMENT.TOP);
});
<commit_msg>Revise test descriptions for anchored()<commit_after>/**
 * Test scenario
 * =============
 * The virtual DOM enviroment provided by Jest + JSDOM is a `window` sized 1024x768.
 * By placing anchor at different places on the virtual window,
 * we can know if `anchored()` is doing its job of deciding position.
 *
 *           1024
 * ┌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┐
 * ╎  ┌╌╌╌╌┐ Anchored       ╎
 * ╎  └╌╌╌╌┘ Component      ╎
 * ╎                        ╎ 768
 * ╎      □ Anchor          ╎
 * ╎                        ╎
 * └╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┘
 */

import React, { PropTypes, PureComponent } from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';

import anchored, { ANCHORED_PLACEMENT } from '../anchored';

// --------------------
//  Mocking components
// --------------------

const ANCHOR_SIZE = 20;
const BOX_SIZE = 100;

// <Anchor> needs to be a React Component so it has an backing instance.
// eslint-disable-next-line react/prefer-stateless-function
class Anchor extends PureComponent {
    static propTypes = {
        top: PropTypes.number.isRequired,
        left: PropTypes.number.isRequired,
    };

    render() {
        const { top, left } = this.props;
        const style = {
            width: ANCHOR_SIZE,
            height: ANCHOR_SIZE,
            position: 'absolute',
            top,
            left,
        };
        return
;
    }
}

function Box({ style }) {
    const boxStyle = {
        ...style,
        width: BOX_SIZE,
        height: BOX_SIZE,
    };
    return
;
}
const AnchoredBoxBottom = anchored()(Box);
const AnchoredBoxTop = anchored({ defaultPlacement: ANCHORED_PLACEMENT.TOP })(Box);

/**
 * Overrides the one shiped with `jsdom`, since it always return 0.
 */
HTMLElement.prototype.getBoundingClientRect = function getBoundingClientRect() {
    if (!this.style) {
        return {
            bottom: 0,
            height: 0,
            left: 0,
            right: 0,
            top: 0,
            width: 0,
        };
    }

    const rect = {
        width: parseInt(this.style.width, 10),
        height: parseInt(this.style.height, 10),
        top: parseInt(this.style.top, 10) || 0,
        left: parseInt(this.style.left, 10) || 0,
    };

    rect.bottom = rect.top + rect.height;
    rect.right = rect.left + rect.width;

    return rect;
};

// --------------------
//  Prepare env
// --------------------
/**
 * Prepare different containers for each component, since `mount({ attachTo: node })` method
 * will wipe out everything in that `node`, replacing the formerly-rendered content.
 */
const anchorRoot = document.createElement('div');
const boxRoot = document.createElement('div');

document.body.appendChild(anchorRoot);
document.body.appendChild(boxRoot);

// --------------------
//  Test cases
// --------------------

it('renders without crashing', () => {
    const div = document.createElement('div');
    const element = <AnchoredBoxBottom />;

    ReactDOM.render(element, div);
});

it('renders above when anchor placed near bottom of viewport', () => {
    const anchorWrapper = mount(<Anchor top={700} left={100} />, { attachTo: anchorRoot });

    let boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.TOP);
    expect(boxWrapper.prop('style').top).toBe(700 - BOX_SIZE);

    boxWrapper = mount(
        <AnchoredBoxBottom anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.TOP);
    expect(boxWrapper.prop('style').top).toBe(700 - BOX_SIZE);
});

it('renders below when anchor placed near top of viewport', () => {
    const anchorWrapper = mount(<Anchor top={50} left={100} />, { attachTo: anchorRoot });

    let boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.BOTTOM);
    expect(boxWrapper.prop('style').top).toBe(50 + ANCHOR_SIZE);

    boxWrapper = mount(
        <AnchoredBoxBottom anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.prop('placement')).toBe(ANCHORED_PLACEMENT.BOTTOM);
    expect(boxWrapper.prop('style').top).toBe(50 + ANCHOR_SIZE);
});

it('renders and aligns to the center line of anchor', () => {
    const anchorWrapper = mount(<Anchor top={20} left={100} />, { attachTo: anchorRoot });
    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(
        // The center line of <Box>
        boxWrapper.prop('style').left + (BOX_SIZE / 2)
    ).toBe(
        // The center line of <Anchor>
        100 + (ANCHOR_SIZE / 2)
    );
});

it('renders on the left when anchor placed on the right of viewport', () => {
    const anchorWrapper = mount(<Anchor top={20} left={1000} />, { attachTo: anchorRoot });
    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(
        // The center line of <Box>
        boxWrapper.prop('style').left + (BOX_SIZE / 2)
    ).toBeLessThan(
        // The center line of <Anchor>
        1000 + (ANCHOR_SIZE / 2)
    );
});

it('renders on the right when anchor placed on the left of viewport', () => {
    const anchorWrapper = mount(<Anchor top={20} left={10} />, { attachTo: anchorRoot });
    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(
        // The center line of <Box>
        boxWrapper.prop('style').left + (BOX_SIZE / 2)
    ).toBeGreaterThan(
        // The center line of <Anchor>
        10 + (ANCHOR_SIZE / 2)
    );
});

it('can take an HTMLElement as anchor', () => {
    mount(<Anchor top={10} left={10} />, { attachTo: anchorRoot });
    const anchorNode = document.getElementById('anchor');

    const boxWrapper = mount(
        <AnchoredBoxTop anchor={anchorNode} />,
        { attachTo: boxRoot }
    ).find(Box);

    expect(boxWrapper.exists()).toBeTruthy();
});

it('re-adjusts position when assigned with another anchor', () => {
    let anchorWrapper = mount(<Anchor top={20} left={10} />, { attachTo: anchorRoot });
    const wrapper = mount(
        <AnchoredBoxTop anchor={anchorWrapper.instance()} />,
        { attachTo: boxRoot }
    );

    expect(wrapper.find(Box).prop('placement')).toBe(ANCHORED_PLACEMENT.BOTTOM);

    anchorWrapper = mount(<Anchor top={200} left={10} />, { attachTo: anchorRoot });
    wrapper.setProps({ anchor: anchorWrapper.instance() });

    expect(wrapper.find(Box).prop('placement')).toBe(ANCHORED_PLACEMENT.TOP);
});
<|endoftext|>


<commit_before>import {style, inline, Node} from "../model"
import {splitAt, joinPoint, liftableRange, wrappableRange, insertNode} from "../transform"
import {elt} from "../edit/dom"

export class Item {
  constructor(icon, title) {
    this.icon = icon
    this.title = title
  }
  active() { return false }
  select() { return true }
}

export class LiftItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Move out of block")
  }
  select(pm) {
    let sel = pm.selection
    return liftableRange(pm.doc, sel.from, sel.to)
  }
  apply(pm) {
    let sel = pm.selection
    let range = liftableRange(pm.doc, sel.from, sel.to)
    pm.apply(range)
  }
}

export class JoinItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Join with above block")
  }
  select(pm) {
    return joinPoint(pm.doc, pm.selection.head)
  }
  apply(pm) {
    let point = joinPoint(pm.doc, pm.selection.head)
    if (point) pm.apply(point)
  }
}

export class SubmenuItem extends Item {
  constructor(icon, title, submenu) {
    super(icon, title)
    this.submenu = submenu
  }
  select(pm) { return this.submenu.some(i => i.select(pm)) }
  apply(pm) { return this.submenu.filter(i => i.select(pm)) }
}

export class BlockTypeItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply({name: "setType", pos: sel.from, end: sel.to, type: this.type, attrs: this.attrs})
  }
}

export class InsertBlockItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  select(pm) {
    let sel = pm.selection
    return sel.empty && pm.doc.path(sel.head.path).type.type == Node.types[this.type].type
  }
  apply(pm) {
    let sel = pm.selection
    if (sel.head.offset) {
      pm.apply(splitAt(pm.doc, sel.head))
      sel = pm.selection
    }
    pm.apply(insertNode(pm.doc, sel.head.shorten(), {type: this.type, attrs: this.attrs}))
  }
}

export class WrapItem extends Item {
  constructor(icon, title, type) {
    super(icon, title)
    this.type = type
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply(wrappableRange(pm.doc, sel.from, sel.to, this.type))
  }
}

export class InlineStyleItem extends Item {
  constructor(icon, title, style, dialog) {
    super(icon, title)
    this.style = typeof style == "string" ? {type: style} : style
    this.dialog = dialog
  }
  active(pm) {
    let sel = pm.selection
    return inline.rangeHasInlineStyle(pm.doc, sel.from, sel.to, this.style.type)
  }
  apply(pm) {
    let sel = pm.selection
    if (this.active(pm))
      pm.apply({name: "removeStyle", pos: sel.from, end: sel.to, style: this.style.type})
    else if (this.dialog)
      return this.dialog
    else
      pm.apply({name: "addStyle", pos: sel.from, end: sel.to, style: this.style})
  }
}

export class ImageItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Insert image")
  }
  apply(pm) { return new ImageDialog }
}

export class Dialog {
  constructor() {
    this.id = Math.floor(Math.random() * 0xffffff).toString(16)
  }

  focus(form) {
    let input = form.querySelector("input")
    if (input) input.focus()
  }

  buildForm(pm) {
    let form = this.form(pm)
    form.appendChild(elt("button", {type: "submit", style: "display: none"}))
    return form
  }
}

export class LinkDialog extends Dialog {
  form() {
    return elt("form", null,
               elt("div", null, elt("input", {name: "href", type: "text", placeholder: "Target URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autocomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.href.value) return
    let sel = pm.selection
    pm.apply({name: "addStyle", pos: sel.from, end: sel.to,
              style: style.link(elts.href.value, elts.title.value)})
  }
}

export class ImageDialog extends Dialog {
  form(pm) {
    let alt = pm.selectedText
    return elt("form", null,
               elt("div", null, elt("input", {name: "src", type: "text", placeholder: "Image URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "alt", type: "text", value: alt, autocomplete: "off",
                                              placeholder: "Description / alternative text", size: 40})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autcomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.src.value) return
    let sel = pm.selection
    pm.apply({name: "replace", pos: sel.from, end: sel.to})
    let attrs = {src: elts.src.value, alt: elts.alt.value, title: elts.title.value}
    pm.apply(insertNode(pm.doc, sel.from, {type: "image", attrs: attrs}))
  }
}
<commit_msg>Replace join with a replace frontend<commit_after>import {style, inline, Node} from "../model"
import {splitAt, joinNodes, liftableRange, wrappableRange, insertNode} from "../transform"
import {elt} from "../edit/dom"

export class Item {
  constructor(icon, title) {
    this.icon = icon
    this.title = title
  }
  active() { return false }
  select() { return true }
}

export class LiftItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Move out of block")
  }
  select(pm) {
    let sel = pm.selection
    return liftableRange(pm.doc, sel.from, sel.to)
  }
  apply(pm) {
    let sel = pm.selection
    let range = liftableRange(pm.doc, sel.from, sel.to)
    pm.apply(range)
  }
}

export class JoinItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Join with above block")
  }
  select(pm) {
    return joinNodes(pm.doc, pm.selection.head)
  }
  apply(pm) {
    let point = joinNodes(pm.doc, pm.selection.head)
    if (point) pm.apply(point)
  }
}

export class SubmenuItem extends Item {
  constructor(icon, title, submenu) {
    super(icon, title)
    this.submenu = submenu
  }
  select(pm) { return this.submenu.some(i => i.select(pm)) }
  apply(pm) { return this.submenu.filter(i => i.select(pm)) }
}

export class BlockTypeItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply({name: "setType", pos: sel.from, end: sel.to, type: this.type, attrs: this.attrs})
  }
}

export class InsertBlockItem extends Item {
  constructor(icon, title, type, attrs) {
    super(icon, title)
    this.type = type
    this.attrs = attrs
  }
  select(pm) {
    let sel = pm.selection
    return sel.empty && pm.doc.path(sel.head.path).type.type == Node.types[this.type].type
  }
  apply(pm) {
    let sel = pm.selection
    if (sel.head.offset) {
      pm.apply(splitAt(pm.doc, sel.head))
      sel = pm.selection
    }
    pm.apply(insertNode(pm.doc, sel.head.shorten(), {type: this.type, attrs: this.attrs}))
  }
}

export class WrapItem extends Item {
  constructor(icon, title, type) {
    super(icon, title)
    this.type = type
  }
  apply(pm) {
    let sel = pm.selection
    pm.apply(wrappableRange(pm.doc, sel.from, sel.to, this.type))
  }
}

export class InlineStyleItem extends Item {
  constructor(icon, title, style, dialog) {
    super(icon, title)
    this.style = typeof style == "string" ? {type: style} : style
    this.dialog = dialog
  }
  active(pm) {
    let sel = pm.selection
    return inline.rangeHasInlineStyle(pm.doc, sel.from, sel.to, this.style.type)
  }
  apply(pm) {
    let sel = pm.selection
    if (this.active(pm))
      pm.apply({name: "removeStyle", pos: sel.from, end: sel.to, style: this.style.type})
    else if (this.dialog)
      return this.dialog
    else
      pm.apply({name: "addStyle", pos: sel.from, end: sel.to, style: this.style})
  }
}

export class ImageItem extends Item {
  constructor(icon, title) {
    super(icon, title || "Insert image")
  }
  apply(pm) { return new ImageDialog }
}

export class Dialog {
  constructor() {
    this.id = Math.floor(Math.random() * 0xffffff).toString(16)
  }

  focus(form) {
    let input = form.querySelector("input")
    if (input) input.focus()
  }

  buildForm(pm) {
    let form = this.form(pm)
    form.appendChild(elt("button", {type: "submit", style: "display: none"}))
    return form
  }
}

export class LinkDialog extends Dialog {
  form() {
    return elt("form", null,
               elt("div", null, elt("input", {name: "href", type: "text", placeholder: "Target URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autocomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.href.value) return
    let sel = pm.selection
    pm.apply({name: "addStyle", pos: sel.from, end: sel.to,
              style: style.link(elts.href.value, elts.title.value)})
  }
}

export class ImageDialog extends Dialog {
  form(pm) {
    let alt = pm.selectedText
    return elt("form", null,
               elt("div", null, elt("input", {name: "src", type: "text", placeholder: "Image URL",
                                              size: 40, autocomplete: "off"})),
               elt("div", null, elt("input", {name: "alt", type: "text", value: alt, autocomplete: "off",
                                              placeholder: "Description / alternative text", size: 40})),
               elt("div", null, elt("input", {name: "title", type: "text", placeholder: "Title",
                                              size: 40, autcomplete: "off"})))
  }

  apply(form, pm) {
    let elts = form.elements
    if (!elts.src.value) return
    let sel = pm.selection
    pm.apply({name: "replace", pos: sel.from, end: sel.to})
    let attrs = {src: elts.src.value, alt: elts.alt.value, title: elts.title.value}
    pm.apply(insertNode(pm.doc, sel.from, {type: "image", attrs: attrs}))
  }
}
<|endoftext|>


<commit_before>function getCapabilitiesFor(browserName, version) {
  var base = {
    'tunnel-identifier' : process.env.TRAVIS_JOB_NUMBER,
    'name': browserName + version + '-' + process.env.TRAVIS_BRANCH + '-' +
      process.env.TRAVIS_PULL_REQUEST,
    'build': process.env.TRAVIS_BUILD_NUMBER,
    'prerun': {
      'executable': 'http://localhost:5000/plugin-installer/SauceLabsInstaller.exe',
      'background': false,
      'timeout': 120
    }
  };
  // Sauce Labs Supports IE 10 on Windows 8 and IE 11 on Windows 8.1
  base.platform = version === '10' ? 'Windows 8' : 'Windows 8.1';
  base.browserName = browserName === 'ie' ? 'internet explorer' : browserName;
  base.version = version;
  return base;
}

var config = {
  allScriptsTimeout: 30000,
  specs: [
    'integration/example.js'
  ],
  baseUrl: 'http://localhost:5000/',
  framework: 'jasmine',
  jasmineNodeOpts: {
    defaultTimeoutInterval: 90000
  }
};

switch(process.env.BROWSER) {
  case 'ie':
    config.sauceUser = process.env.SAUCE_USERNAME;
    config.sauceKey = process.env.SAUCE_ACCESS_KEY;
    config.capabilities = getCapabilitiesFor(process.env.BROWSER, process.env.BVER);
  break;
  case 'firefox':
    var helper = require('./firefox-helper.js');
    config.getMultiCapabilities = helper.getFirefoxProfile;
    config.seleniumAddress = 'http://hub.browserstack.com/wd/hub';
  break;
  default:
  case 'chrome':
    config.capabilities = {
        'browserName': 'chrome',
        'chromeOptions': {
          'args': ['auto-select-desktop-capture-source="Entire screen"',
            'use-fake-device-for-media-stream',
            'use-fake-ui-for-media-stream'],
          'binary': process.env.BROWSERBIN
        }
      };
    config.directConnect = true;
  break;
}
exports.config = config;
<commit_msg>Try windows 10<commit_after>function getCapabilitiesFor(browserName, version) {
  var base = {
    'tunnel-identifier' : process.env.TRAVIS_JOB_NUMBER,
    'name': browserName + version + '-' + process.env.TRAVIS_BRANCH + '-' +
      process.env.TRAVIS_PULL_REQUEST,
    'build': process.env.TRAVIS_BUILD_NUMBER,
    'prerun': {
      'executable': 'http://localhost:5000/plugin-installer/SauceLabsInstaller.exe',
      'background': false,
      'timeout': 120
    }
  };
  // Sauce Labs Supports IE 10 on Windows 8 and IE 11 on Windows 8.1
  base.platform = version === '10' ? 'Windows 8' : 'Windows 10';
  base.browserName = browserName === 'ie' ? 'internet explorer' : browserName;
  base.version = version;
  return base;
}

var config = {
  allScriptsTimeout: 30000,
  specs: [
    'integration/example.js'
  ],
  baseUrl: 'http://localhost:5000/',
  framework: 'jasmine',
  jasmineNodeOpts: {
    defaultTimeoutInterval: 90000
  }
};

switch(process.env.BROWSER) {
  case 'ie':
    config.sauceUser = process.env.SAUCE_USERNAME;
    config.sauceKey = process.env.SAUCE_ACCESS_KEY;
    config.capabilities = getCapabilitiesFor(process.env.BROWSER, process.env.BVER);
  break;
  case 'firefox':
    var helper = require('./firefox-helper.js');
    config.getMultiCapabilities = helper.getFirefoxProfile;
    config.seleniumAddress = 'http://hub.browserstack.com/wd/hub';
  break;
  default:
  case 'chrome':
    config.capabilities = {
        'browserName': 'chrome',
        'chromeOptions': {
          'args': ['auto-select-desktop-capture-source="Entire screen"',
            'use-fake-device-for-media-stream',
            'use-fake-ui-for-media-stream'],
          'binary': process.env.BROWSERBIN
        }
      };
    config.directConnect = true;
  break;
}
exports.config = config;
<|endoftext|>