<commit_before>import RSVP from 'rsvp';
import EmberObject from '@ember/object';
import { setupRenderingTest } from 'ember-qunit';
import { findAll, click, find } from '@ember/test-helpers';
import { module, test } from 'qunit';
import hbs from 'htmlbars-inline-precompile';
import { setupIntl } from 'ember-intl/test-support';

const { resolve } = RSVP;

module('Integration | Component | curriculum inventory sequence block session list', function(hooks) {
  setupRenderingTest(hooks);
  setupIntl(hooks);

  test('it renders', async function(assert) {
    assert.expect(31);

    const offering1 = EmberObject.create({id: 1});
    const offering2 = EmberObject.create({id: 2});
    const offering3 = EmberObject.create({id: 3});

    const offerings1 = [ offering1, offering2 ];
    const offerings2 = [ offering3 ];
    const offerings3 = [];
    const offerings4 = [];

    const sessionType1 = EmberObject.create({ title: 'Lecture'});
    const sessionType2 = EmberObject.create({ title: 'Ceremony'});
    const sessionType3 = EmberObject.create({ title: 'Small Group'});
    const sessionType4 = EmberObject.create({ title: 'Rocket Surgery'});

    const totalTime1 = (30).toFixed(2);
    const totalTime2 = (15).toFixed(2);
    const totalTime3 = (0).toFixed(2);
    const totalTime4 = (0).toFixed(2);

    const session1 = EmberObject.create({
      id: 1,
      title: 'Aardvark',
      offerings: resolve(offerings1),
      sessionType: resolve(sessionType1),
      isIndependentLearning: false,
      maxDuration: resolve(totalTime1)
    });

    const session2 = EmberObject.create({
      id: 2,
      title: 'Bluebird',
      offerings: resolve(offerings2),
      sessionType: resolve(sessionType2),
      isIndependentLearning: false,
      totalSumDuration: resolve(totalTime2)
    });

    const session3 = EmberObject.create({
      id: 3,
      title: 'Zeppelin',
      offerings: resolve(offerings3),
      sessionType: resolve(sessionType3),
      isIndependentLearning: false,
      maxDuration: resolve(totalTime3)
    });

    const session4 = EmberObject.create({
      id: 4,
      title: 'Zwickzange',
      offerings: resolve(offerings4),
      sessionType: resolve(sessionType4),
      isIndependentLearning: true,
      totalSumDuration: resolve(totalTime4)
    });

    const sessions = [session1, session2, session3, session4];

    const block = EmberObject.create({
      id: 1,
      sessions: resolve([session1, session3]),
      excludedSessions: resolve([session2]),
    });

    this.set('sessions', resolve(sessions));
    this.set('sequenceBlock', block);
    this.set('sortBy', 'title');
    this.set('setSortBy', function(){});
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    assert.dom('thead th').hasText('Count as one offering', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[1]).hasText('Exclude', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[2]).hasText('Session Title', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[3]).hasText('Session Type', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[4]).hasText('Total time', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[5]).hasText('Offerings', 'Column header is labeled correctly.');

    assert.dom('tbody tr:nth-of-type(1) td').hasText('Yes', 'All offerings in session are counted as one.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[1]).hasText('No', 'Excluded value is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[2]).hasText(session1.get('title'), 'Session title is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[3]).hasText(sessionType1.get('title'), 'Session type title is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[4]).hasText(totalTime1, 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[5]).hasText(offerings1.length.toString(), 'Number of offerings is shown.');

    assert.dom('tbody tr:nth-of-type(2) td').hasText('No', 'All offerings are counted individually.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[1]).hasText('Yes', 'Excluded value is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[2]).hasText(session2.get('title'), 'Title is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[3]).hasText(sessionType2.get('title'), 'Session type is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[4]).hasText(totalTime2, 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[5]).hasText(offerings2.length.toString(), 'Number of offerings is shown.');

    assert.dom('tbody tr:nth-of-type(3) td').hasText('Yes', 'All offerings in session are counted as one.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[1]).hasText('No', 'Excluded value is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[2]).hasText(session3.get('title'), 'Title is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[3]).hasText(sessionType3.get('title'), 'Session type is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[4]).hasText(totalTime3, 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[5]).hasText(offerings3.length.toString(), 'Number of offerings is shown.');

    assert.dom('tbody tr:nth-of-type(4) td').hasText('No', 'All offerings are counted individually.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[1]).hasText('No', 'Excluded value is shown.');
    assert.ok(find(findAll('tbody tr:nth-of-type(4) td')[2]).textContent.trim().startsWith('(ILM)'), 'ILMs is labeled as such.');
    assert.ok(find(findAll('tbody tr:nth-of-type(4) td')[2]).textContent.trim().endsWith(session4.get('title')), 'Title is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[3]).hasText(sessionType4.get('title'), 'Session type is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[4]).hasText(totalTime4, 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[5]).hasText(offerings4.length.toString(), 'Number of offerings is shown.');
  });

  test('empty list', async function(assert) {
    assert.expect(2);

    const block = EmberObject.create({
      id: 1,
      sessions: resolve([]),
    });

    this.set('sessions', resolve([]));
    this.set('sequenceBlock', block);
    this.set('sortBy', 'title');
    this.set('setSortBy', function(){});
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    assert.dom('thead tr').exists({ count: 1 }, 'Table header is visible,');
    assert.dom('tbody tr').doesNotExist('but table body is empty.');
  });

  test('sort by title', async function(assert) {
    assert.expect(1);
    const session = EmberObject.create({
      id: 1,
      title: 'Zeppelin',
      offerings: resolve([]),
      sessionType: resolve(EmberObject.create({ title: 'Lecture'})),
      maxDuration: resolve(0)
    });

    const block = EmberObject.create({
      id: 1,
      sessions: resolve([ session ]),
    });

    this.set('sessions', resolve([ session ]));
    this.set('sequenceBlock', block);
    this.set('sortBy', 'id');
    this.set('setSortBy', function(what){
      assert.equal(what, 'title', "Sorting callback gets called for session titles.");
    });
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    await click(findAll('thead th')[2]);
  });

  test('sort by session type', async function(assert) {
    assert.expect(1);
    const session = EmberObject.create({
      id: 1,
      title: 'Zeppelin',
      offerings: resolve([]),
      sessionType: resolve(EmberObject.create({ title: 'Lecture'})),
      maxDuration: resolve(0)
    });

    const block = EmberObject.create({
      id: 1,
      sessions: resolve([ session ]),
    });

    this.set('sessions', resolve([ session ]));
    this.set('sequenceBlock', block);
    this.set('sortBy', 'id');
    this.set('setSortBy', function(what){
      assert.equal(what, 'sessionType.title', "Sorting callback gets called for session type titles.");
    });
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    await click(findAll('thead th')[3]);
  });

  test('sort by offerings total', async function(assert) {
    assert.expect(1);
    const session = EmberObject.create({
      id: 1,
      title: 'Zeppelin',
      offerings: resolve([]),
      sessionType: resolve(EmberObject.create({ title: 'Lecture'})),
      maxDuration: resolve(0)
    });

    const block = EmberObject.create({
      id: 1,
      sessions: resolve([ session ]),
    });

    this.set('sessions', resolve([ session ]));
    this.set('sequenceBlock', block);
    this.set('sortBy', 'id');
    this.set('setSortBy', function(what){
      assert.equal(what, 'offerings.length', "Sorting callback gets called for offerings length.");
    });
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    await click(findAll('thead th')[5]);
  });
});
<commit_msg>Update Test to use mirage and real models<commit_after>import { setupRenderingTest } from 'ember-qunit';
import { findAll, click, find } from '@ember/test-helpers';
import { module, test } from 'qunit';
import hbs from 'htmlbars-inline-precompile';
import { setupIntl } from 'ember-intl/test-support';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import moment from 'moment';

module('Integration | Component | curriculum inventory sequence block session list', function(hooks) {
  setupRenderingTest(hooks);
  setupIntl(hooks);
  setupMirage(hooks);

  test('it renders', async function(assert) {
    assert.expect(31);
    const now = moment().toDate();
    const in15Hours = moment().add(15, 'hours').toDate();
    const in30Hours = moment().add(30, 'hours').toDate();

    const offering1 = this.server.create('offering', {
      startDate: now,
      endDate: in30Hours
    });
    const offering2 = this.server.create('offering', {
      startDate: now,
      endDate: in15Hours
    });
    const offering3 = this.server.create('offering', {
      startDate: now,
      endDate: in15Hours
    });

    const sessionType1 = this.server.create('session-type', { title: 'Lecture'});
    const sessionType2 = this.server.create('session-type', { title: 'Ceremony'});
    const sessionType3 = this.server.create('session-type', { title: 'Small Group'});
    const sessionType4 = this.server.create('session-type', { title: 'Rocket Surgery'});

    const session1 = this.server.create('session', {
      title: 'Aardvark',
      offerings: [offering1, offering2],
      sessionType: sessionType1,
    });

    const session2 = this.server.create('session', {
      title: 'Bluebird',
      offerings: [offering3],
      sessionType: sessionType2,
    });

    const session3 = this.server.create('session', {
      title: 'Zeppelin',
      sessionType: sessionType3,
    });
    const ilmSession = this.server.create('ilm-session', {
      hours: 0,
    });
    const session4 = this.server.create('session', {
      title: 'Zwickzange',
      sessionType: sessionType4,
      ilmSession,
    });

    const block = this.server.create('curriculum-inventory-sequence-block', {
      sessions: [session1, session3],
      excludedSessions: [session2],
    });
    const blockModel = await this.owner.lookup('service:store').find('curriculum-inventory-sequence-block', block.id);
    const sessionModels = await this.owner.lookup('service:store').findAll('session');

    this.set('sessions', sessionModels);
    this.set('sequenceBlock', blockModel);
    this.set('sortBy', 'title');
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{noop}}
      @setSortBy={{setSortBy}}
    />`);
    assert.dom('thead th').hasText('Count as one offering', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[1]).hasText('Exclude', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[2]).hasText('Session Title', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[3]).hasText('Session Type', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[4]).hasText('Total time', 'Column header is labeled correctly.');
    assert.dom(findAll('thead th')[5]).hasText('Offerings', 'Column header is labeled correctly.');

    assert.dom('tbody tr:nth-of-type(1) td').hasText('Yes', 'All offerings in session are counted as one.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[1]).hasText('No', 'Excluded value is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[2]).hasText(session1.title, 'Session title is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[3]).hasText(sessionType1.title, 'Session type title is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[4]).hasText('30.00', 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(1) td')[5]).hasText('2', 'Number of offerings is shown.');

    assert.dom('tbody tr:nth-of-type(2) td').hasText('No', 'All offerings are counted individually.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[1]).hasText('Yes', 'Excluded value is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[2]).hasText(session2.title, 'Title is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[3]).hasText(sessionType2.title, 'Session type is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[4]).hasText('15.00', 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(2) td')[5]).hasText('1', 'Number of offerings is shown.');

    assert.dom('tbody tr:nth-of-type(3) td').hasText('Yes', 'All offerings in session are counted as one.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[1]).hasText('No', 'Excluded value is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[2]).hasText(session3.title, 'Title is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[3]).hasText(sessionType3.title, 'Session type is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[4]).hasText('0', 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(3) td')[5]).hasText('0', 'Number of offerings is shown.');

    assert.dom('tbody tr:nth-of-type(4) td').hasText('No', 'All offerings are counted individually.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[1]).hasText('No', 'Excluded value is shown.');
    assert.ok(find(findAll('tbody tr:nth-of-type(4) td')[2]).textContent.trim().startsWith('(ILM)'), 'ILMs is labeled as such.');
    assert.ok(find(findAll('tbody tr:nth-of-type(4) td')[2]).textContent.trim().endsWith(session4.title), 'Title is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[3]).hasText(sessionType4.title, 'Session type is visible.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[4]).hasText('0', 'Total time is shown.');
    assert.dom(findAll('tbody tr:nth-of-type(4) td')[5]).hasText('0', 'Number of offerings is shown.');
  });

  test('empty list', async function(assert) {
    assert.expect(2);

    const block = this.server.create('curriculum-inventory-sequence-block');
    const blockModel = await this.owner.lookup('service:store').find('curriculum-inventory-sequence-block', block.id);
    const sessionModels = await this.owner.lookup('service:store').findAll('session');

    this.set('sessions', sessionModels);
    this.set('sequenceBlock', blockModel);
    this.set('sortBy', 'title');
    this.set('setSortBy', function(){});
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    assert.dom('thead tr').exists({ count: 1 }, 'Table header is visible,');
    assert.dom('tbody tr').doesNotExist('but table body is empty.');
  });

  test('sort by title', async function(assert) {
    assert.expect(1);

    const session = this.server.create('session', {
      title: 'Zeppelin',
      sessionType: this.server.create('session-type', { title: 'Lecture'}),
    });
    const block = this.server.create('curriculum-inventory-sequence-block', {
      sessions: [session],
    });
    const blockModel = await this.owner.lookup('service:store').find('curriculum-inventory-sequence-block', block.id);
    const sessionModels = await this.owner.lookup('service:store').findAll('session');

    this.set('sessions', sessionModels);
    this.set('sequenceBlock', blockModel);
    this.set('sortBy', 'id');
    this.set('setSortBy', function(what){
      assert.equal(what, 'title', "Sorting callback gets called for session titles.");
    });
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    await click(findAll('thead th')[2]);
  });

  test('sort by session type', async function(assert) {
    assert.expect(1);
    const session = this.server.create('session', {
      title: 'Zeppelin',
      sessionType: this.server.create('session-type', { title: 'Lecture'}),
    });
    const block = this.server.create('curriculum-inventory-sequence-block', {
      sessions: [session],
    });
    const blockModel = await this.owner.lookup('service:store').find('curriculum-inventory-sequence-block', block.id);
    const sessionModels = await this.owner.lookup('service:store').findAll('session');

    this.set('sessions', sessionModels);
    this.set('sequenceBlock', blockModel);
    this.set('sortBy', 'id');
    this.set('setSortBy', function(what){
      assert.equal(what, 'sessionType.title', "Sorting callback gets called for session type titles.");
    });
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    await click(findAll('thead th')[3]);
  });

  test('sort by offerings total', async function(assert) {
    assert.expect(1);
    const session = this.server.create('session', {
      title: 'Zeppelin',
      sessionType: this.server.create('session-type', { title: 'Lecture'}),
    });
    const block = this.server.create('curriculum-inventory-sequence-block', {
      sessions: [session],
    });
    const blockModel = await this.owner.lookup('service:store').find('curriculum-inventory-sequence-block', block.id);
    const sessionModels = await this.owner.lookup('service:store').findAll('session');

    this.set('sessions', sessionModels);
    this.set('sequenceBlock', blockModel);
    this.set('sortBy', 'id');
    this.set('setSortBy', function(what){
      assert.equal(what, 'offerings.length', "Sorting callback gets called for offerings length.");
    });
    await this.render(hbs`<CurriculumInventorySequenceBlockSessionList
      @sessions={{await sessions}}
      @sequenceBlock={{sequenceBlock}}
      @sortBy={{sortBy}}
      @setSortBy={{setSortBy}}
    />`);
    await click(findAll('thead th')[5]);
  });
});
<|endoftext|>


<commit_before>define(
    [
        'jquery',
        'ko',
        'Omise_Payment/js/view/payment/omise-offsite-method-renderer',
        'Magento_Checkout/js/view/payment/default',
        'Magento_Checkout/js/model/quote',
        'Magento_Catalog/js/price-utils'
    ],
    function (
        $,
        ko,
        Base,
        Component,
        quote,
        priceUtils
    ) {
        'use strict';
        const INSTALLMENT_MIN_PURCHASE_AMOUNT = 3000;

        return Component.extend(Base).extend({
            defaults: {
                template: 'Omise_Payment/payment/offsite-installment-form'
            },

            code: 'omise_offsite_installment',
            restrictedToCurrencies: ['thb'],

            /**
             * Initiate observable fields
             *
             * @return this
             */
            initObservable: function () {
                this._super()
                    .observe([
                        'omiseOffsite',
                        'installmentTermsFC',
                        'installmentTermsKTC',
                        'installmentTermsKBank',
                        'installmentTermsBBL',
                        'installmentTermsBAY',
                        'installmentTermsSCB',
                    ]);

                return this;
            },

            /**
             * Format Price
             *
             * @param {float} amount - Amount to be formatted
             * @return {string}
             */
            getFormattedAmount: function (amount) {
                return priceUtils.formatPrice(amount, quote.getPriceFormat());
            },

            /**
             * Get formatted message about installment value limitation
             *
             * NOTE: this value should be taken directly from capability object when it is fully implemented.
             *
             * @return {string}
             */
            getMinimumOrderText: function () {
                return $.mage.__('Minimum order value is %amount').replace('%amount', this.getFormattedAmount(INSTALLMENT_MIN_PURCHASE_AMOUNT));
            },

            /**
             * Get Installment minimum
             * this function respects info from: https://www.omise.co/installment-payment
             *
             * NOTE: in the future this function should return data from capabilities object.
             *
             * @param {string} id - Bank ID
             * @return {integer}
             */
            getInstallmentMinimum: function (id) {
                return {
                    'kbank'         : 500,
                    'bbl'           : 500,
                    'bay'           : 300,
                    'first_choice'  : 300,
                    'ktc'           : 300,
                    'scb'           : 500
                }[id];
            },

            /**
             * Get Installment monthly interest rate
             *
             * NOTE: in the future this function should return data from capabilities object.
             *
             * @param {string} id - Bank id
             * @return {float}
             */
            getInstallmentInterestRate: function (id) {
                return {
                    'kbank'         : 0.0065,
                    'bbl'           : 0.008,
                    'bay'           : 0.008,
                    'first_choice'  : 0.013,
                    'ktc'           : 0.008,
                    'scb'           : 0.0074
                }[id];
            },

            /**
             * Get zero interest setting
             *
             * @return {boolean}
             */
            isZeroInterest: function () {
                return window.checkoutConfig.is_zero_interest;
            },

            /**
             * Calculates single installment amount
             *
             * @param {string} id - Bank ID
             * @param {integer} terms - number of monthly installments
             * @return {integer}
             */
            calculateSingleInstallmentAmount: function (id, terms) {
                const total = this.getTotal();

                if (this.isZeroInterest()) {
                    //merchant pays interest
                    return (total / terms).toFixed(2)
                }

                const rate = this.getInstallmentInterestRate(id);
                const interest = rate * terms * total;

                return + (((total + interest) / terms).toFixed(2));
            },

            /**
             * Get total amount of an order
             *
             * @return {integer}
             */
            getTotal: function () {
                return + window.checkoutConfig.quoteData.grand_total;
            },

            /**
             * Get installment terms
             *
             * @return {string|null}
             */
            getTerms: function () {
                return this.installmentTermsBBL() || this.installmentTermsKBank() || this.installmentTermsFC() || this.installmentTermsKTC() || this.installmentTermsBAY() || this.installmentTermsSCB();
            },

            /**
             * Reset selected terms
             */
            resetTerms: function () {
                this.installmentTermsBBL(null);
                this.installmentTermsKBank(null);
                this.installmentTermsFC(null);
                this.installmentTermsKTC(null);
                this.installmentTermsBAY(null);
                this.installmentTermsSCB(null);
            },

            /**
             * Get a checkout form data
             *
             * @return {Object}
             */
            getData: function () {
                return {
                    'method': this.item.method,
                    'additional_data': {
                        'offsite': this.omiseOffsite(),
                        'terms': this.getTerms()
                    }
                };
            },

            /**
             * Returns Installment Terms
             * @param {string} id - Bank id
             * @return {array}
             */
            getInstallmentTerms: function (id) {
                const installmentBackends = checkoutConfig.installment_backends;
                const templateLabel = $.mage.__('%terms months (%amount / month)');

                for (const key in installmentBackends) {
                    if (installmentBackends[key]._id !== 'installment_' + id) {
                        continue;
                    }

                    let dispTerms = [];
                    const terms = installmentBackends[key].allowed_installment_terms;
                    const minSingleInstallment = this.getInstallmentMinimum(id);

                    for (let i = 0; i < terms.length; i++) {
                        const amount = this.calculateSingleInstallmentAmount(id, terms[i]);

                        if (amount >= minSingleInstallment) {
                            dispTerms.push({
                                label: templateLabel.replace('%terms', terms[i]).replace('%amount', this.getFormattedAmount(amount)),
                                key: terms[i]
                            });
                        }
                    }

                    return ko.observableArray(
                        dispTerms
                    );
                }
            },

            /**
             * Check if order value meets minimum requirement
             *
             * @return {boolean}
             */
            orderValueTooLow: function () {
                return this.getTotal() < INSTALLMENT_MIN_PURCHASE_AMOUNT;
            }

        });
    }
);
<commit_msg>Changed min-purchase amount from 3000 to 2000<commit_after>define(
    [
        'jquery',
        'ko',
        'Omise_Payment/js/view/payment/omise-offsite-method-renderer',
        'Magento_Checkout/js/view/payment/default',
        'Magento_Checkout/js/model/quote',
        'Magento_Catalog/js/price-utils'
    ],
    function (
        $,
        ko,
        Base,
        Component,
        quote,
        priceUtils
    ) {
        'use strict';
        const INSTALLMENT_MIN_PURCHASE_AMOUNT = 2000;

        return Component.extend(Base).extend({
            defaults: {
                template: 'Omise_Payment/payment/offsite-installment-form'
            },

            code: 'omise_offsite_installment',
            restrictedToCurrencies: ['thb'],

            /**
             * Initiate observable fields
             *
             * @return this
             */
            initObservable: function () {
                this._super()
                    .observe([
                        'omiseOffsite',
                        'installmentTermsFC',
                        'installmentTermsKTC',
                        'installmentTermsKBank',
                        'installmentTermsBBL',
                        'installmentTermsBAY',
                        'installmentTermsSCB',
                    ]);

                return this;
            },

            /**
             * Format Price
             *
             * @param {float} amount - Amount to be formatted
             * @return {string}
             */
            getFormattedAmount: function (amount) {
                return priceUtils.formatPrice(amount, quote.getPriceFormat());
            },

            /**
             * Get formatted message about installment value limitation
             *
             * NOTE: this value should be taken directly from capability object when it is fully implemented.
             *
             * @return {string}
             */
            getMinimumOrderText: function () {
                return $.mage.__('Minimum order value is %amount').replace('%amount', this.getFormattedAmount(INSTALLMENT_MIN_PURCHASE_AMOUNT));
            },

            /**
             * Get Installment minimum
             * this function respects info from: https://www.omise.co/installment-payment
             *
             * NOTE: in the future this function should return data from capabilities object.
             *
             * @param {string} id - Bank ID
             * @return {integer}
             */
            getInstallmentMinimum: function (id) {
                return {
                    'kbank'         : 500,
                    'bbl'           : 500,
                    'bay'           : 300,
                    'first_choice'  : 300,
                    'ktc'           : 300,
                    'scb'           : 500
                }[id];
            },

            /**
             * Get Installment monthly interest rate
             *
             * NOTE: in the future this function should return data from capabilities object.
             *
             * @param {string} id - Bank id
             * @return {float}
             */
            getInstallmentInterestRate: function (id) {
                return {
                    'kbank'         : 0.0065,
                    'bbl'           : 0.008,
                    'bay'           : 0.008,
                    'first_choice'  : 0.013,
                    'ktc'           : 0.008,
                    'scb'           : 0.0074
                }[id];
            },

            /**
             * Get zero interest setting
             *
             * @return {boolean}
             */
            isZeroInterest: function () {
                return window.checkoutConfig.is_zero_interest;
            },

            /**
             * Calculates single installment amount
             *
             * @param {string} id - Bank ID
             * @param {integer} terms - number of monthly installments
             * @return {integer}
             */
            calculateSingleInstallmentAmount: function (id, terms) {
                const total = this.getTotal();

                if (this.isZeroInterest()) {
                    //merchant pays interest
                    return (total / terms).toFixed(2)
                }

                const rate = this.getInstallmentInterestRate(id);
                const interest = rate * terms * total;

                return + (((total + interest) / terms).toFixed(2));
            },

            /**
             * Get total amount of an order
             *
             * @return {integer}
             */
            getTotal: function () {
                return + window.checkoutConfig.quoteData.grand_total;
            },

            /**
             * Get installment terms
             *
             * @return {string|null}
             */
            getTerms: function () {
                return this.installmentTermsBBL() || this.installmentTermsKBank() || this.installmentTermsFC() || this.installmentTermsKTC() || this.installmentTermsBAY() || this.installmentTermsSCB();
            },

            /**
             * Reset selected terms
             */
            resetTerms: function () {
                this.installmentTermsBBL(null);
                this.installmentTermsKBank(null);
                this.installmentTermsFC(null);
                this.installmentTermsKTC(null);
                this.installmentTermsBAY(null);
                this.installmentTermsSCB(null);
            },

            /**
             * Get a checkout form data
             *
             * @return {Object}
             */
            getData: function () {
                return {
                    'method': this.item.method,
                    'additional_data': {
                        'offsite': this.omiseOffsite(),
                        'terms': this.getTerms()
                    }
                };
            },

            /**
             * Returns Installment Terms
             * @param {string} id - Bank id
             * @return {array}
             */
            getInstallmentTerms: function (id) {
                const installmentBackends = checkoutConfig.installment_backends;
                const templateLabel = $.mage.__('%terms months (%amount / month)');

                for (const key in installmentBackends) {
                    if (installmentBackends[key]._id !== 'installment_' + id) {
                        continue;
                    }

                    let dispTerms = [];
                    const terms = installmentBackends[key].allowed_installment_terms;
                    const minSingleInstallment = this.getInstallmentMinimum(id);

                    for (let i = 0; i < terms.length; i++) {
                        const amount = this.calculateSingleInstallmentAmount(id, terms[i]);

                        if (amount >= minSingleInstallment) {
                            dispTerms.push({
                                label: templateLabel.replace('%terms', terms[i]).replace('%amount', this.getFormattedAmount(amount)),
                                key: terms[i]
                            });
                        }
                    }

                    return ko.observableArray(
                        dispTerms
                    );
                }
            },

            /**
             * Check if order value meets minimum requirement
             *
             * @return {boolean}
             */
            orderValueTooLow: function () {
                return this.getTotal() < INSTALLMENT_MIN_PURCHASE_AMOUNT;
            }

        });
    }
);
<|endoftext|>


<commit_before>var assert        = require('../support/assert');
var _             = require('underscore');
var redis         = require('redis');
var th            = require('../support/test_helper');
var Windshaft     = require('../../lib/windshaft');
var ServerOptions = require('../support/server_options');

suite('multilayer', function() {

    var server = new Windshaft.Server(ServerOptions);
    var redisClient = redis.createClient(ServerOptions.redis.port);

    before(function(done) {
        // Check that we start with an empty redis db
        redisClient.keys("*", function(err, matches) {
            assert.equal(matches.length, 0, "redis keys present at setup time:\n" + matches.join("\n"));
            done();
        });
    });

    function layerType(layer) {
        return layer.type;
    }

    function testInteractivityLayersOrderScenario(testScenario) {
        test('interactivity layers order – ' + testScenario.desc, function(done) {
            var layergroup =  {
                version: '1.3.0',
                layers: testScenario.layers
            };

            server.afterLayergroupCreateCalls = 0;

            assert.response(server,
                {
                    url: '/database/windshaft_test/layergroup',
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    data: JSON.stringify(layergroup)
                },
                {
                    //status: 200, don't use status here to have a more meaningful error message
                    headers: {
                        'content-type': 'application/json; charset=utf-8'
                    }
                },
                function(response) {
                    assert.equal(
                        response.statusCode,
                        200,
                            'Expected status code 200, got ' + response.statusCode +
                            '\n\tResponse body: ' + response.body +
                            '\n\tLayer types: ' + layergroup.layers.map(layerType).join(', ')
                    );

                    assert.equal(server.afterLayergroupCreateCalls, 1);

                    var layergroupResponse = JSON.parse(response.body);
                    assert.ok(layergroupResponse);

                    var layergroupId = layergroupResponse.layergroupid;
                    assert.ok(layergroupId);
                    assert.equal(layergroupResponse.layercount, layergroup.layers.length);

                    redisClient.exists("map_cfg|" +  layergroupId, function(err, exists) {
                        if (err) {
                            return done(err);
                        }
                        assert.ok(exists, "Missing expected token " + layergroupId + " from redis");
                        redisClient.del("map_cfg|" +  layergroupId, function(err) {
                            done(err);
                        });
                    });
                }
            );
        });
    }

    var cartocssVersion = '2.3.0';
    var cartocss = '#layer { line-width:16; }';
    var sql = "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom";
    var sqlWadus = "select 1 as wadus, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom";

    var httpLayer = {
        type: 'http',
        options: {
            urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png',
            subdomains: ['a','b','c']
        }
    };

    var torqueLayer = {
        type: 'torque',
        options: {
            sql: "select 1 id, '1970-01-02'::date d, 'POINT(0 0)'::geometry the_geom_webmercator",
            cartocss: [
                "Map {",
                    "-torque-frame-count:2;",
                    "-torque-resolution:3;",
                    "-torque-time-attribute:d;",
                    "-torque-aggregation-function:'count(id)';",
                "}"
            ].join(' '),
            cartocss_version: '2.0.1'
        }
    };

    var mapnikLayer = {
        type: 'mapnik',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss
        }
    };

    var mapnikInteractivityLayer = {
        type: 'mapnik',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'i'
        }
    };

    var cartodbLayer = {
        type: 'cartodb',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss
        }
    };

    var cartodbInteractivityLayer = {
        type: 'cartodb',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'i'
        }
    };

    var cartodbWadusInteractivityLayer = {
        type: 'cartodb',
        options: {
            sql: sqlWadus,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'wadus'
        }
    };

    var noTypeLayer = {
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss
        }
    };

    var noTypeInteractivityLayer = {
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'i'
        }
    };

    var allLayers = [
        httpLayer,
        torqueLayer,
        mapnikLayer,
        mapnikInteractivityLayer,
        cartodbLayer,
        cartodbInteractivityLayer,
        cartodbWadusInteractivityLayer,
        noTypeLayer,
        noTypeInteractivityLayer
    ];

    var testScenarios = [
        {
            desc: 'one layer, no interactivity',
            layers: [cartodbLayer]
        },
        {
            desc: 'one layer with interactivity',
            layers: [cartodbInteractivityLayer]
        },
        {
            desc: 'two layers, interactivity mix',
            layers: [
                cartodbLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'two layers, different interactivity columns',
            layers: [
                cartodbWadusInteractivityLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'mix of no interactivity with interactivity',
            layers: [
                cartodbInteractivityLayer,
                cartodbLayer,
                cartodbWadusInteractivityLayer
            ]
        },
        {
            desc: 'interactivity layers + torque',
            layers: [
                cartodbWadusInteractivityLayer,
                cartodbInteractivityLayer,
                torqueLayer
            ]
        },
        {
            desc: 'torque + interactivity layers',
            layers: [
                torqueLayer,
                cartodbWadusInteractivityLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'interactivity + torque + interactivity',
            layers: [
                cartodbInteractivityLayer,
                torqueLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'http + mix of [no] interactivity layers',
            layers: [
                httpLayer,
                cartodbInteractivityLayer,
                cartodbLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'http + interactivity + torque + interactivity',
            layers: [
                httpLayer,
                cartodbInteractivityLayer,
                torqueLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'http + interactivity + torque + no interactivity + torque + interactivity',
            layers: [
                httpLayer,
                cartodbInteractivityLayer,
                torqueLayer,
                cartodbLayer,
                torqueLayer,
                cartodbWadusInteractivityLayer
            ]
        },
        {
            desc: 'mapnik type – two layers, interactivity mix',
            layers: [
                mapnikLayer,
                mapnikInteractivityLayer
            ]
        },
        {
            desc: 'mapnik type – mix of no interactivity with interactivity',
            layers: [
                cartodbInteractivityLayer,
                cartodbLayer,
                mapnikInteractivityLayer
            ]
        },
        {
            desc: 'mapnik type – interactivity layers + torque',
            layers: [
                mapnikInteractivityLayer,
                cartodbInteractivityLayer,
                torqueLayer
            ]
        },
        {
            desc: 'mapnik type – http + interactivity + torque + interactivity',
            layers: [
                httpLayer,
                mapnikInteractivityLayer,
                torqueLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'no type – two layers, interactivity mix',
            layers: [
                noTypeLayer,
                noTypeInteractivityLayer
            ]
        },
        {
            desc: 'no type – mix of no interactivity with interactivity',
            layers: [
                noTypeInteractivityLayer,
                noTypeLayer,
                mapnikInteractivityLayer
            ]
        },
        {
            desc: 'no type – interactivity layers + torque',
            layers: [
                noTypeLayer,
                noTypeInteractivityLayer,
                torqueLayer
            ]
        },
        {
            desc: 'no type – http + interactivity + torque + interactivity',
            layers: [
                httpLayer,
                noTypeInteractivityLayer,
                torqueLayer,
                noTypeInteractivityLayer
            ]
        }
    ];

    var chaosScenariosSize = 25;
    var chaosScenarios = [];
    for (var i = 0; i < chaosScenariosSize; i++) {
        // Underscore.js' sample method uses Fisher-Yates shuffle internally, see http://bost.ocks.org/mike/shuffle/
        var randomLayers = _.sample(allLayers, _.random(1, allLayers.length));
        chaosScenarios.push({
            desc: 'chaos scenario – layer types: ' + randomLayers.map(layerType).join(', '),
            layers: randomLayers
        })
    }

    testScenarios.forEach(testInteractivityLayersOrderScenario);
    chaosScenarios.forEach(testInteractivityLayersOrderScenario);

    ////////////////////////////////////////////////////////////////////
    //
    // TEARDOWN
    //
    ////////////////////////////////////////////////////////////////////

    after(function(done) {
        // Check that we left the redis db empty
        redisClient.keys("*", function(err, keys) {
            if (err) {
                return done(err);
            }

            assert.equal(keys.length, 0, "Left over redis keys:\n" + keys.join("\n"));

            done();
        });

    });

});

<commit_msg>Change suite name<commit_after>var assert        = require('../support/assert');
var _             = require('underscore');
var redis         = require('redis');
var th            = require('../support/test_helper');
var Windshaft     = require('../../lib/windshaft');
var ServerOptions = require('../support/server_options');

suite('multilayer interactivity and layers order', function() {

    var server = new Windshaft.Server(ServerOptions);
    var redisClient = redis.createClient(ServerOptions.redis.port);

    before(function(done) {
        // Check that we start with an empty redis db
        redisClient.keys("*", function(err, matches) {
            assert.equal(matches.length, 0, "redis keys present at setup time:\n" + matches.join("\n"));
            done();
        });
    });

    function layerType(layer) {
        return layer.type;
    }

    function testInteractivityLayersOrderScenario(testScenario) {
        test(testScenario.desc, function(done) {
            var layergroup =  {
                version: '1.3.0',
                layers: testScenario.layers
            };

            server.afterLayergroupCreateCalls = 0;

            assert.response(server,
                {
                    url: '/database/windshaft_test/layergroup',
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    data: JSON.stringify(layergroup)
                },
                {
                    //status: 200, don't use status here to have a more meaningful error message
                    headers: {
                        'content-type': 'application/json; charset=utf-8'
                    }
                },
                function(response) {
                    assert.equal(
                        response.statusCode,
                        200,
                            'Expected status code 200, got ' + response.statusCode +
                            '\n\tResponse body: ' + response.body +
                            '\n\tLayer types: ' + layergroup.layers.map(layerType).join(', ')
                    );

                    assert.equal(server.afterLayergroupCreateCalls, 1);

                    var layergroupResponse = JSON.parse(response.body);
                    assert.ok(layergroupResponse);

                    var layergroupId = layergroupResponse.layergroupid;
                    assert.ok(layergroupId);
                    assert.equal(layergroupResponse.layercount, layergroup.layers.length);

                    redisClient.exists("map_cfg|" +  layergroupId, function(err, exists) {
                        if (err) {
                            return done(err);
                        }
                        assert.ok(exists, "Missing expected token " + layergroupId + " from redis");
                        redisClient.del("map_cfg|" +  layergroupId, function(err) {
                            done(err);
                        });
                    });
                }
            );
        });
    }

    var cartocssVersion = '2.3.0';
    var cartocss = '#layer { line-width:16; }';
    var sql = "select 1 as i, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom";
    var sqlWadus = "select 1 as wadus, st_setsrid('LINESTRING(0 0, 1 0)'::geometry, 4326) as the_geom";

    var httpLayer = {
        type: 'http',
        options: {
            urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png',
            subdomains: ['a','b','c']
        }
    };

    var torqueLayer = {
        type: 'torque',
        options: {
            sql: "select 1 id, '1970-01-02'::date d, 'POINT(0 0)'::geometry the_geom_webmercator",
            cartocss: [
                "Map {",
                    "-torque-frame-count:2;",
                    "-torque-resolution:3;",
                    "-torque-time-attribute:d;",
                    "-torque-aggregation-function:'count(id)';",
                "}"
            ].join(' '),
            cartocss_version: '2.0.1'
        }
    };

    var mapnikLayer = {
        type: 'mapnik',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss
        }
    };

    var mapnikInteractivityLayer = {
        type: 'mapnik',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'i'
        }
    };

    var cartodbLayer = {
        type: 'cartodb',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss
        }
    };

    var cartodbInteractivityLayer = {
        type: 'cartodb',
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'i'
        }
    };

    var cartodbWadusInteractivityLayer = {
        type: 'cartodb',
        options: {
            sql: sqlWadus,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'wadus'
        }
    };

    var noTypeLayer = {
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss
        }
    };

    var noTypeInteractivityLayer = {
        options: {
            sql: sql,
            cartocss_version: cartocssVersion,
            cartocss: cartocss,
            interactivity: 'i'
        }
    };

    var allLayers = [
        httpLayer,
        torqueLayer,
        mapnikLayer,
        mapnikInteractivityLayer,
        cartodbLayer,
        cartodbInteractivityLayer,
        cartodbWadusInteractivityLayer,
        noTypeLayer,
        noTypeInteractivityLayer
    ];

    var testScenarios = [
        {
            desc: 'one layer, no interactivity',
            layers: [cartodbLayer]
        },
        {
            desc: 'one layer with interactivity',
            layers: [cartodbInteractivityLayer]
        },
        {
            desc: 'two layers, interactivity mix',
            layers: [
                cartodbLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'two layers, different interactivity columns',
            layers: [
                cartodbWadusInteractivityLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'mix of no interactivity with interactivity',
            layers: [
                cartodbInteractivityLayer,
                cartodbLayer,
                cartodbWadusInteractivityLayer
            ]
        },
        {
            desc: 'interactivity layers + torque',
            layers: [
                cartodbWadusInteractivityLayer,
                cartodbInteractivityLayer,
                torqueLayer
            ]
        },
        {
            desc: 'torque + interactivity layers',
            layers: [
                torqueLayer,
                cartodbWadusInteractivityLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'interactivity + torque + interactivity',
            layers: [
                cartodbInteractivityLayer,
                torqueLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'http + mix of [no] interactivity layers',
            layers: [
                httpLayer,
                cartodbInteractivityLayer,
                cartodbLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'http + interactivity + torque + interactivity',
            layers: [
                httpLayer,
                cartodbInteractivityLayer,
                torqueLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'http + interactivity + torque + no interactivity + torque + interactivity',
            layers: [
                httpLayer,
                cartodbInteractivityLayer,
                torqueLayer,
                cartodbLayer,
                torqueLayer,
                cartodbWadusInteractivityLayer
            ]
        },
        {
            desc: 'mapnik type – two layers, interactivity mix',
            layers: [
                mapnikLayer,
                mapnikInteractivityLayer
            ]
        },
        {
            desc: 'mapnik type – mix of no interactivity with interactivity',
            layers: [
                cartodbInteractivityLayer,
                cartodbLayer,
                mapnikInteractivityLayer
            ]
        },
        {
            desc: 'mapnik type – interactivity layers + torque',
            layers: [
                mapnikInteractivityLayer,
                cartodbInteractivityLayer,
                torqueLayer
            ]
        },
        {
            desc: 'mapnik type – http + interactivity + torque + interactivity',
            layers: [
                httpLayer,
                mapnikInteractivityLayer,
                torqueLayer,
                cartodbInteractivityLayer
            ]
        },
        {
            desc: 'no type – two layers, interactivity mix',
            layers: [
                noTypeLayer,
                noTypeInteractivityLayer
            ]
        },
        {
            desc: 'no type – mix of no interactivity with interactivity',
            layers: [
                noTypeInteractivityLayer,
                noTypeLayer,
                mapnikInteractivityLayer
            ]
        },
        {
            desc: 'no type – interactivity layers + torque',
            layers: [
                noTypeLayer,
                noTypeInteractivityLayer,
                torqueLayer
            ]
        },
        {
            desc: 'no type – http + interactivity + torque + interactivity',
            layers: [
                httpLayer,
                noTypeInteractivityLayer,
                torqueLayer,
                noTypeInteractivityLayer
            ]
        }
    ];

    var chaosScenariosSize = 25;
    var chaosScenarios = [];
    for (var i = 0; i < chaosScenariosSize; i++) {
        // Underscore.js' sample method uses Fisher-Yates shuffle internally, see http://bost.ocks.org/mike/shuffle/
        var randomLayers = _.sample(allLayers, _.random(1, allLayers.length));
        chaosScenarios.push({
            desc: 'chaos scenario – layer types: ' + randomLayers.map(layerType).join(', '),
            layers: randomLayers
        })
    }

    testScenarios.forEach(testInteractivityLayersOrderScenario);
    chaosScenarios.forEach(testInteractivityLayersOrderScenario);

    ////////////////////////////////////////////////////////////////////
    //
    // TEARDOWN
    //
    ////////////////////////////////////////////////////////////////////

    after(function(done) {
        // Check that we left the redis db empty
        redisClient.keys("*", function(err, keys) {
            if (err) {
                return done(err);
            }

            assert.equal(keys.length, 0, "Left over redis keys:\n" + keys.join("\n"));

            done();
        });

    });

});

<|endoftext|>


<commit_before>/* @flow */
import test from 'ava'
import useGitHub from 'create-npm/test/helpers/useGitHub'
import useGitHubRepository from 'create-npm/test/helpers/useGitHubRepository'
import { getGitHubRepositoryName } from 'create-npm/src/actions'

useGitHub()
const localPath = useGitHubRepository('test-create-npm/existing-repo')

test('reading the name of a GitHub repository', async t => {
  t.is(
    await getGitHubRepositoryName(localPath),
    'test-create-npm/existing-repo'
  )
})
<commit_msg>Use git ssh key when cloning<commit_after>/* @flow */
import test from 'ava'
import useGitHub from 'create-npm/test/helpers/useGitHub'
import useGitHubRepository from 'create-npm/test/helpers/useGitHubRepository'
import useGitSshKey from 'create-npm/test/helpers/useGitSshKey'
import { getGitHubRepositoryName } from 'create-npm/src/actions'

useGitHub()
useGitSshKey()
const localPath = useGitHubRepository('test-create-npm/existing-repo')

test('reading the name of a GitHub repository', async t => {
  t.is(
    await getGitHubRepositoryName(localPath),
    'test-create-npm/existing-repo'
  )
})
<|endoftext|>


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

describe('Grid Dom Binders', function() {

  var table, columns, data;

  beforeEach(function() {
    table = document.createElement('table');

    columns = [
      { id: 'id', sortable: false },
      { id: 'firstName', editable: true },
      { id: 'lastName' }
    ];

    data = [
      { id: 1, firstName: 'foo1', lastName: 'bar1' },
      { id: 2, firstName: 'foo2', lastName: 'bar2' },
      { id: 3, firstName: 'foo2', lastName: 'bar3' }
    ];
  });

  describe('with headers and footers', function() {
    var grid;

    beforeEach(function() {
      grid = new Grid(table, {
        data: data,
        columns: columns,
        view: {
          thead: true,
          tfoot: true
        }
      });

      // Reset events for tests
      grid.$$events = {};

      spyOn(grid.$thead, 'on');
      spyOn(grid.$tfoot, 'on');
      spyOn(grid.$tbody, 'on');
      spyOn(grid.$table, 'on');

      spyOn(grid.$thead, 'off');
      spyOn(grid.$tfoot, 'off');
      spyOn(grid.$tbody, 'off');
      spyOn(grid.$table, 'off');
    });

    it('should bind resize event', function() {
      var jq = $.fn || $.prototype;
      spyOn(jq, 'on');

      GridDomBinders.bindResize(grid);

      expect(grid.$$events).toEqual({
        onResize: jasmine.any(Function)
      });

      expect(jq.on).toHaveBeenCalledWith('resize', grid.$$events.onResize);

      // It should not bind twice
      jq.on.calls.reset();

      GridDomBinders.bindResize(grid);

      expect(jq.on).not.toHaveBeenCalled();
    });

    it('should bind input events', function() {
      spyOn($sniffer, 'hasEvent').and.returnValue(true);

      GridDomBinders.bindEdition(grid);

      expect(grid.$$events).toEqual({
        onInputTbody: {
          events: 'input change',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$table.on).not.toHaveBeenCalled();
      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).toHaveBeenCalledWith('input change', grid.$$events.onInputTbody.handler);

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindEdition(grid);

      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind input events', function() {
      spyOn($sniffer, 'hasEvent').and.returnValue(true);

      GridDomBinders.bindEdition(grid);

      var onInputTbody = grid.$$events.onInputTbody.handler;

      GridDomBinders.unbindEdition(grid);

      expect(grid.$table.off).not.toHaveBeenCalled();
      expect(grid.$thead.off).not.toHaveBeenCalled();
      expect(grid.$tfoot.off).not.toHaveBeenCalled();
      expect(grid.$tbody.off).toHaveBeenCalledWith('input change', onInputTbody);
      expect(grid.$$events.onInputTbody).toBeNull();
    });

    it('should bind selection events', function() {
      GridDomBinders.bindSelection(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTbody: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);
      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);
      expect(grid.$tbody.on).toHaveBeenCalledWith('click', grid.$$events.onClickTbody.handler);
      expect(grid.$table.on).not.toHaveBeenCalled();

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSelection(grid);

      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind selection events', function() {
      GridDomBinders.bindSelection(grid);

      var onClickThead = grid.$$events.onClickThead.handler;
      var onClickTfoot = grid.$$events.onClickTfoot.handler;
      var onClickTbody = grid.$$events.onClickTbody.handler;

      GridDomBinders.unbindSelection(grid);

      expect(grid.$thead.off).toHaveBeenCalledWith('click', onClickThead);
      expect(grid.$tfoot.off).toHaveBeenCalledWith('click', onClickTfoot);
      expect(grid.$tbody.off).toHaveBeenCalledWith('click', onClickTbody);
      expect(grid.$table.off).not.toHaveBeenCalled();

      expect(grid.$$events.onClickThead).toBeNull();
      expect(grid.$$events.onClickTfoot).toBeNull();
      expect(grid.$$events.onClickTbody).toBeNull();
    });

    it('should bind sort events', function() {
      GridDomBinders.bindSort(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);
      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);
      expect(grid.$tbody.on).not.toHaveBeenCalled();
      expect(grid.$table.on).not.toHaveBeenCalled();

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSort(grid);

      expect(grid.$table.on).not.toHaveBeenCalled();
      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind sort events', function() {
      GridDomBinders.bindSort(grid);

      var onClickThead = grid.$$events.onClickThead.handler;
      var onClickTfoot = grid.$$events.onClickTfoot.handler;

      GridDomBinders.unbindSort(grid);

      expect(grid.$thead.off).toHaveBeenCalledWith('click', onClickThead);
      expect(grid.$tfoot.off).toHaveBeenCalledWith('click', onClickTfoot);
      expect(grid.$tbody.off).not.toHaveBeenCalled();
      expect(grid.$table.off).not.toHaveBeenCalled();
      expect(grid.$$events.onClickThead).toBeNull();
      expect(grid.$$events.onClickTfoot).toBeNull();
    });

    it('should bind drag & drop events', function() {
      GridDomBinders.bindDragDrop(grid);

      expect(grid.$$events).toEqual({
        onDragStart: {
          events: 'dragstart',
          handler: jasmine.any(Function)
        },
        onDragOver: {
          events: 'dragover',
          handler: jasmine.any(Function)
        },
        onDragEnd: {
          events: 'dragend',
          handler: jasmine.any(Function)
        },
        onDragLeave: {
          events: 'dragleave',
          handler: jasmine.any(Function)
        },
        onDragEnter: {
          events: 'dragenter',
          handler: jasmine.any(Function)
        },
        onDragDrop: {
          events: 'drop',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();

      expect(grid.$table.on).toHaveBeenCalledWith('dragstart', grid.$$events.onDragStart.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragover', grid.$$events.onDragOver.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragend', grid.$$events.onDragEnd.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragleave', grid.$$events.onDragLeave.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragenter', grid.$$events.onDragEnter.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('drop', grid.$$events.onDragDrop.handler);

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindDragDrop(grid);

      expect(grid.$table.on).not.toHaveBeenCalled();
      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind drag & drop events', function() {
      GridDomBinders.bindDragDrop(grid);

      var onDragStart = grid.$$events.onDragStart.handler;
      var onDragOver = grid.$$events.onDragOver.handler;
      var onDragEnd = grid.$$events.onDragEnd.handler;
      var onDragLeave = grid.$$events.onDragLeave.handler;
      var onDragEnter = grid.$$events.onDragEnter.handler;
      var onDragDrop = grid.$$events.onDragDrop.handler;

      GridDomBinders.unbindDragDrop(grid);

      expect(grid.$table.off).toHaveBeenCalledWith('dragstart', onDragStart);
      expect(grid.$table.off).toHaveBeenCalledWith('dragover', onDragOver);
      expect(grid.$table.off).toHaveBeenCalledWith('dragend', onDragEnd);
      expect(grid.$table.off).toHaveBeenCalledWith('dragleave', onDragLeave);
      expect(grid.$table.off).toHaveBeenCalledWith('dragenter', onDragEnter);
      expect(grid.$table.off).toHaveBeenCalledWith('drop', onDragDrop);
    });
  });

  describe('without footer', function() {
    var grid;

    beforeEach(function() {
      grid = new Grid(table, {
        data: data,
        columns: columns,
        view: {
          thead: true,
          tfoot: false
        }
      });

      // Reset events for tests
      grid.$$events = {};

      spyOn(grid.$thead, 'on');
      spyOn(grid.$tbody, 'on');

      spyOn(grid.$thead, 'off');
      spyOn(grid.$tbody, 'off');
    });

    it('should bind selection events', function() {
      GridDomBinders.bindSelection(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTbody: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);
      expect(grid.$tbody.on).toHaveBeenCalledWith('click', grid.$$events.onClickTbody.handler);

      // It should not bind twice
      grid.$thead.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSelection(grid);

      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should bind sort events', function() {
      GridDomBinders.bindSort(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);

      // It should not bind twice
      grid.$thead.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSort(grid);

      expect(grid.$thead.on).not.toHaveBeenCalled();
    });
  });

  describe('without header', function() {
    var grid;

    beforeEach(function() {
      grid = new Grid(table, {
        data: data,
        columns: columns,
        view: {
          thead: false,
          tfoot: true
        }
      });

      // Reset events for tests
      grid.$$events = {};

      spyOn(grid.$tfoot, 'on');
      spyOn(grid.$tbody, 'on');

      spyOn(grid.$tfoot, 'off');
      spyOn(grid.$tbody, 'off');
    });

    it('should bind selection events', function() {
      GridDomBinders.bindSelection(grid);

      expect(grid.$$events).toEqual({
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTbody: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);
      expect(grid.$tbody.on).toHaveBeenCalledWith('click', grid.$$events.onClickTbody.handler);

      // It should not bind twice
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSelection(grid);

      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should bind sort events', function() {
      GridDomBinders.bindSort(grid);

      expect(grid.$$events).toEqual({
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);

      // It should not bind twice
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSort(grid);

      expect(grid.$tfoot.on).not.toHaveBeenCalled();
    });
  });
});
<commit_msg>refactor(test): migrate grid-dom-binders-spec to es6<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

describe('Grid Dom Binders', () => {

  let table, columns, data;

  beforeEach(() => {
    table = document.createElement('table');

    columns = [
      { id: 'id', sortable: false },
      { id: 'firstName', editable: true },
      { id: 'lastName' }
    ];

    data = [
      { id: 1, firstName: 'foo1', lastName: 'bar1' },
      { id: 2, firstName: 'foo2', lastName: 'bar2' },
      { id: 3, firstName: 'foo2', lastName: 'bar3' }
    ];
  });

  describe('with headers and footers', () => {
    let grid;

    beforeEach(() => {
      grid = new Grid(table, {
        data: data,
        columns: columns,
        view: {
          thead: true,
          tfoot: true
        }
      });

      // Reset events for tests
      grid.$$events = {};

      spyOn(grid.$thead, 'on');
      spyOn(grid.$tfoot, 'on');
      spyOn(grid.$tbody, 'on');
      spyOn(grid.$table, 'on');

      spyOn(grid.$thead, 'off');
      spyOn(grid.$tfoot, 'off');
      spyOn(grid.$tbody, 'off');
      spyOn(grid.$table, 'off');
    });

    it('should bind resize event', () => {
      const jq = $.fn || $.prototype;
      spyOn(jq, 'on');

      GridDomBinders.bindResize(grid);

      expect(grid.$$events).toEqual({
        onResize: jasmine.any(Function)
      });

      expect(jq.on).toHaveBeenCalledWith('resize', grid.$$events.onResize);

      // It should not bind twice
      jq.on.calls.reset();

      GridDomBinders.bindResize(grid);

      expect(jq.on).not.toHaveBeenCalled();
    });

    it('should bind input events', () => {
      spyOn($sniffer, 'hasEvent').and.returnValue(true);

      GridDomBinders.bindEdition(grid);

      expect(grid.$$events).toEqual({
        onInputTbody: {
          events: 'input change',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$table.on).not.toHaveBeenCalled();
      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).toHaveBeenCalledWith('input change', grid.$$events.onInputTbody.handler);

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindEdition(grid);

      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind input events', () => {
      spyOn($sniffer, 'hasEvent').and.returnValue(true);

      GridDomBinders.bindEdition(grid);

      const onInputTbody = grid.$$events.onInputTbody.handler;

      GridDomBinders.unbindEdition(grid);

      expect(grid.$table.off).not.toHaveBeenCalled();
      expect(grid.$thead.off).not.toHaveBeenCalled();
      expect(grid.$tfoot.off).not.toHaveBeenCalled();
      expect(grid.$tbody.off).toHaveBeenCalledWith('input change', onInputTbody);
      expect(grid.$$events.onInputTbody).toBeNull();
    });

    it('should bind selection events', () => {
      GridDomBinders.bindSelection(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTbody: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);
      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);
      expect(grid.$tbody.on).toHaveBeenCalledWith('click', grid.$$events.onClickTbody.handler);
      expect(grid.$table.on).not.toHaveBeenCalled();

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSelection(grid);

      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind selection events', () => {
      GridDomBinders.bindSelection(grid);

      const onClickThead = grid.$$events.onClickThead.handler;
      const onClickTfoot = grid.$$events.onClickTfoot.handler;
      const onClickTbody = grid.$$events.onClickTbody.handler;

      GridDomBinders.unbindSelection(grid);

      expect(grid.$thead.off).toHaveBeenCalledWith('click', onClickThead);
      expect(grid.$tfoot.off).toHaveBeenCalledWith('click', onClickTfoot);
      expect(grid.$tbody.off).toHaveBeenCalledWith('click', onClickTbody);
      expect(grid.$table.off).not.toHaveBeenCalled();

      expect(grid.$$events.onClickThead).toBeNull();
      expect(grid.$$events.onClickTfoot).toBeNull();
      expect(grid.$$events.onClickTbody).toBeNull();
    });

    it('should bind sort events', () => {
      GridDomBinders.bindSort(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);
      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);
      expect(grid.$tbody.on).not.toHaveBeenCalled();
      expect(grid.$table.on).not.toHaveBeenCalled();

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSort(grid);

      expect(grid.$table.on).not.toHaveBeenCalled();
      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind sort events', () => {
      GridDomBinders.bindSort(grid);

      const onClickThead = grid.$$events.onClickThead.handler;
      const onClickTfoot = grid.$$events.onClickTfoot.handler;

      GridDomBinders.unbindSort(grid);

      expect(grid.$thead.off).toHaveBeenCalledWith('click', onClickThead);
      expect(grid.$tfoot.off).toHaveBeenCalledWith('click', onClickTfoot);
      expect(grid.$tbody.off).not.toHaveBeenCalled();
      expect(grid.$table.off).not.toHaveBeenCalled();
      expect(grid.$$events.onClickThead).toBeNull();
      expect(grid.$$events.onClickTfoot).toBeNull();
    });

    it('should bind drag & drop events', () => {
      GridDomBinders.bindDragDrop(grid);

      expect(grid.$$events).toEqual({
        onDragStart: {
          events: 'dragstart',
          handler: jasmine.any(Function)
        },
        onDragOver: {
          events: 'dragover',
          handler: jasmine.any(Function)
        },
        onDragEnd: {
          events: 'dragend',
          handler: jasmine.any(Function)
        },
        onDragLeave: {
          events: 'dragleave',
          handler: jasmine.any(Function)
        },
        onDragEnter: {
          events: 'dragenter',
          handler: jasmine.any(Function)
        },
        onDragDrop: {
          events: 'drop',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();

      expect(grid.$table.on).toHaveBeenCalledWith('dragstart', grid.$$events.onDragStart.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragover', grid.$$events.onDragOver.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragend', grid.$$events.onDragEnd.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragleave', grid.$$events.onDragLeave.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('dragenter', grid.$$events.onDragEnter.handler);
      expect(grid.$table.on).toHaveBeenCalledWith('drop', grid.$$events.onDragDrop.handler);

      // It should not bind twice
      grid.$table.on.calls.reset();
      grid.$thead.on.calls.reset();
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindDragDrop(grid);

      expect(grid.$table.on).not.toHaveBeenCalled();
      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should unbind drag & drop events', () => {
      GridDomBinders.bindDragDrop(grid);

      const onDragStart = grid.$$events.onDragStart.handler;
      const onDragOver = grid.$$events.onDragOver.handler;
      const onDragEnd = grid.$$events.onDragEnd.handler;
      const onDragLeave = grid.$$events.onDragLeave.handler;
      const onDragEnter = grid.$$events.onDragEnter.handler;
      const onDragDrop = grid.$$events.onDragDrop.handler;

      GridDomBinders.unbindDragDrop(grid);

      expect(grid.$table.off).toHaveBeenCalledWith('dragstart', onDragStart);
      expect(grid.$table.off).toHaveBeenCalledWith('dragover', onDragOver);
      expect(grid.$table.off).toHaveBeenCalledWith('dragend', onDragEnd);
      expect(grid.$table.off).toHaveBeenCalledWith('dragleave', onDragLeave);
      expect(grid.$table.off).toHaveBeenCalledWith('dragenter', onDragEnter);
      expect(grid.$table.off).toHaveBeenCalledWith('drop', onDragDrop);
    });
  });

  describe('without footer', () => {
    let grid;

    beforeEach(() => {
      grid = new Grid(table, {
        data: data,
        columns: columns,
        view: {
          thead: true,
          tfoot: false
        }
      });

      // Reset events for tests
      grid.$$events = {};

      spyOn(grid.$thead, 'on');
      spyOn(grid.$tbody, 'on');

      spyOn(grid.$thead, 'off');
      spyOn(grid.$tbody, 'off');
    });

    it('should bind selection events', () => {
      GridDomBinders.bindSelection(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTbody: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);
      expect(grid.$tbody.on).toHaveBeenCalledWith('click', grid.$$events.onClickTbody.handler);

      // It should not bind twice
      grid.$thead.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSelection(grid);

      expect(grid.$thead.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should bind sort events', () => {
      GridDomBinders.bindSort(grid);

      expect(grid.$$events).toEqual({
        onClickThead: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$thead.on).toHaveBeenCalledWith('click', grid.$$events.onClickThead.handler);

      // It should not bind twice
      grid.$thead.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSort(grid);

      expect(grid.$thead.on).not.toHaveBeenCalled();
    });
  });

  describe('without header', () => {
    let grid;

    beforeEach(() => {
      grid = new Grid(table, {
        data: data,
        columns: columns,
        view: {
          thead: false,
          tfoot: true
        }
      });

      // Reset events for tests
      grid.$$events = {};

      spyOn(grid.$tfoot, 'on');
      spyOn(grid.$tbody, 'on');

      spyOn(grid.$tfoot, 'off');
      spyOn(grid.$tbody, 'off');
    });

    it('should bind selection events', () => {
      GridDomBinders.bindSelection(grid);

      expect(grid.$$events).toEqual({
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        },
        onClickTbody: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);
      expect(grid.$tbody.on).toHaveBeenCalledWith('click', grid.$$events.onClickTbody.handler);

      // It should not bind twice
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSelection(grid);

      expect(grid.$tfoot.on).not.toHaveBeenCalled();
      expect(grid.$tbody.on).not.toHaveBeenCalled();
    });

    it('should bind sort events', () => {
      GridDomBinders.bindSort(grid);

      expect(grid.$$events).toEqual({
        onClickTfoot: {
          events: 'click',
          handler: jasmine.any(Function)
        }
      });

      expect(grid.$tfoot.on).toHaveBeenCalledWith('click', grid.$$events.onClickTfoot.handler);

      // It should not bind twice
      grid.$tfoot.on.calls.reset();
      grid.$tbody.on.calls.reset();

      GridDomBinders.bindSort(grid);

      expect(grid.$tfoot.on).not.toHaveBeenCalled();
    });
  });
});
<|endoftext|>


<commit_before>/*jshint node: true, -W106 */
'use strict';

/*
* Name : pageListModelSpec.js
* Module : UnitTest
* Location : /test/dataTier
*
* History :
*
* Version   Date         Programmer         Description
* =========================================================
* 0.0.1     2015-05-11   Filippo Rampado    Initial code
* =========================================================
*/

var PageListModel = require('../../../lib/dataTier/pageList/pageListModel.js');
//var assert = require('chai').assert;
var assert = require('assert');

describe('PageListModel', function() {
    it('returns null when passed a non-valid string', function() {
        //assert.equal(new PageListModel(12), {});
        //assert.equal(new PageListModel(' '), {});
        assert.isNull(new PageListModel(12), 'no PageListModel defined');
        assert.isNull(new PageListModel(' '), 'no PageListModel defined');
    });

    var pageList1 = new PageListModel('name');

    it('create object with the right name', function() {
        assert.equal(pageList1._name, 'name');
    });

    var page1={
        getData: function(){
            return 'testData1';
        },
        getProperties: function(){
            return 'testProp1';
        }
    };
    var page2={
        getData: function(){
            return 'testData2';
        },
        getProperties: function(){
            return 'testProp2';
        }
    };

    describe('#addPage', function() {
        it('returns true and pushes the page if page is valid', function() {
            assert.equal(pageList1.addPage(page1), true);
            assert.equal(pageList1._pages.length, 1);
        });
        it('returns false if page is invalid', function() {
            assert.equal(pageList1.addPage(2), false);
        });
    });

    describe('#getName', function() {
        it('returns the right name', function() {
            assert.equal(pageList1.getName(), 'name');
        });
    });

    describe('#getData', function() {
        var pageList2=new PageListModel('name');
        it('returns empty json if it has no pages', function() {
            assert.equal(pageList2.getData().length, 0);
        });
        console.dir(pageList2);
        console.dir(page2);
        pageList2.addPage(page1);
        it('returns json with one page', function() {
            var data=pageList2.getData();
            assert.equal(data.length, 1);
            assert.equal(data[0].properties, 'testProd1');
            assert.equal(data[0].data, 'testData1');
        });
        pageList2.addPage(page2);
        it('returns json with two pages', function() {
            var data=pageList2.getData();
            assert.equal(data.length, 2);
            assert.equal(data[0].properties, 'testProd1');
            assert.equal(data[0].data, 'testData1');
            assert.equal(data[1].properties, 'testProd2');
            assert.equal(data[1].data, 'testData2');
        });
    });

});<commit_msg>another attempt<commit_after>/*jshint node: true, -W106 */
'use strict';

/*
* Name : pageListModelSpec.js
* Module : UnitTest
* Location : /test/dataTier
*
* History :
*
* Version   Date         Programmer         Description
* =========================================================
* 0.0.1     2015-05-11   Filippo Rampado    Initial code
* =========================================================
*/

var PageListModel = require('../../../lib/dataTier/pageList/pageListModel.js');
//var assert = require('chai').assert;
var assert = require('assert');

describe('PageListModel', function() {
    it('returns null when passed a non-valid string', function() {
        //assert.equal(new PageListModel(12), {});
        //assert.equal(new PageListModel(' '), {});
        var a=new PageListModel(12);
        assert.isNull(a, 'no PageListModel defined');
        var b=new PageListModel(' ');
        assert.isNull(b, 'no PageListModel defined');
    });

    var pageList1 = new PageListModel('name');

    it('create object with the right name', function() {
        assert.equal(pageList1._name, 'name');
    });

    var page1={
        getData: function(){
            return 'testData1';
        },
        getProperties: function(){
            return 'testProp1';
        }
    };
    var page2={
        getData: function(){
            return 'testData2';
        },
        getProperties: function(){
            return 'testProp2';
        }
    };

    describe('#addPage', function() {
        it('returns true and pushes the page if page is valid', function() {
            assert.equal(pageList1.addPage(page1), true);
            assert.equal(pageList1._pages.length, 1);
        });
        it('returns false if page is invalid', function() {
            assert.equal(pageList1.addPage(2), false);
        });
    });

    describe('#getName', function() {
        it('returns the right name', function() {
            assert.equal(pageList1.getName(), 'name');
        });
    });

    describe('#getData', function() {
        var pageList2=new PageListModel('name');
        it('returns empty json if it has no pages', function() {
            assert.equal(pageList2.getData().length, 0);
        });
        console.dir(pageList2);
        console.dir(page2);
        pageList2.addPage(page1);
        it('returns json with one page', function() {
            var data=pageList2.getData();
            assert.equal(data.length, 1);
            assert.equal(data[0].properties, 'testProd1');
            assert.equal(data[0].data, 'testData1');
        });
        pageList2.addPage(page2);
        it('returns json with two pages', function() {
            var data=pageList2.getData();
            assert.equal(data.length, 2);
            assert.equal(data[0].properties, 'testProd1');
            assert.equal(data[0].data, 'testData1');
            assert.equal(data[1].properties, 'testProd2');
            assert.equal(data[1].data, 'testData2');
        });
    });

});<|endoftext|>