// import Service from '@ember/service'; import hbs from 'htmlbars-inline-precompile'; import moment from 'moment'; import sinon from 'sinon'; import {blur, click, fillIn, find, focus, render, triggerKeyEvent, typeIn} from '@ember/test-helpers'; import {datepickerSelect} from 'ember-power-datepicker/test-support'; import {describe, it} from 'mocha'; import {expect} from 'chai'; import {setupRenderingTest} from 'ember-mocha'; // class SettingsStub extends Service { // timezone = 'Etc/UTC'; // get(key) { // if (key === 'timezone') { // return this.timezone; // } // } // } describe('Integration: Component: gh-date-picker', function () { setupRenderingTest(); let clock; // beforeEach(async function () { // this.owner.register('service:settings', SettingsStub); // }); afterEach(function () { clock?.restore(); }); it('renders', async function () { await render(hbs``); expect(find('[data-test-date-picker-trigger]'), 'datepicker trigger').to.exist; expect(find('[data-test-date-picker-input]'), 'datepicker input').to.exist; }); it('defaults to now when @value is empty', async function () { clock = sinon.useFakeTimers({ now: moment('2022-02-22 22:22:22.000Z').toDate() }); await render(hbs``); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-22'); }); it('shows passed in @value value', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); await render(hbs``); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-22'); }); it('updates date via input blur', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-28'); await blur('[data-test-date-picker-input]'); expect(changeSpy.callCount).to.equal(1); expect(changeSpy.firstCall.args[0]).to.be.an.instanceof(Date); expect(changeSpy.firstCall.args[0].toISOString()).to.equal(moment('2022-02-28T00:00:00.000Z').toISOString()); }); it('updates date via input Enter keydown', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-28'); await triggerKeyEvent('[data-test-date-picker-input]', 'keydown', 'Enter'); expect(changeSpy.callCount).to.equal(1); expect(changeSpy.firstCall.args[0]).to.be.an.instanceof(Date); expect(changeSpy.firstCall.args[0].toISOString()).to.equal(moment('2022-02-28T00:00:00.000Z').toISOString()); }); it('updates date via datepicker selection', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const onChange = (newDate) => { this.set('date', newDate); }; const changeSpy = sinon.spy(onChange); this.set('onChange', changeSpy); await render(hbs``); await datepickerSelect('[data-test-date-picker-trigger]', moment('2022-02-27T13:00:00.000Z').toDate()); expect(find('[data-test-date-picker-input]')).to.have.value('2022-02-27'); expect(changeSpy.callCount).to.equal(1); expect(changeSpy.firstCall.args[0]).to.be.an.instanceof(Date); expect(changeSpy.firstCall.args[0].toISOString()).to.equal(moment('2022-02-27T00:00:00.000Z').toISOString()); }); it('updates when @value is changed externally', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); await render(hbs``); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-22'); this.set('date', moment('2022-02-28 10:00:00.000Z')).toDate(); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-28'); }); it('updates when @value is changed externally when we have a scratch date', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); await render(hbs``); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-22'); await fillIn('[data-test-date-picker-input]', '2022-02-27'); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-27'); this.set('date', moment('2022-02-28 10:00:00.000Z')).toDate(); expect(find('[data-test-date-picker-input]'), 'date input').to.have.value('2022-02-28'); }); it('calls @onInput on input events', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const inputSpy = sinon.spy(); this.set('onInput', inputSpy); await render(hbs``); await typeIn('[data-test-date-picker-input]', 'lo'); expect(inputSpy.callCount).to.equal(2); expect(inputSpy.firstCall.args[0]).to.be.instanceOf(Event); }); it('calls @onKeydown on input keydown events', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const keydownSpy = sinon.spy(); this.set('onKeydown', keydownSpy); await render(hbs``); await typeIn('[data-test-date-picker-input]', 'lo'); expect(keydownSpy.callCount).to.equal(2); expect(keydownSpy.firstCall.args[0]).to.be.instanceOf(Event); }); it('calls @onBlur on input blur events', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const blurSpy = sinon.spy(); this.set('onBlur', blurSpy); await render(hbs``); await focus('[data-test-date-picker-input]'); await blur('[data-test-date-picker-input]'); expect(blurSpy.callCount).to.equal(1); expect(blurSpy.firstCall.args[0]).to.be.instanceOf(Event); }); it('resets input value on Escape', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-28'); await triggerKeyEvent('[data-test-date-picker-input]', 'keydown', 'Escape'); expect(changeSpy.callCount).to.equal(0); expect(find('[data-test-date-picker-input]')).to.have.value('2022-02-22'); }); it('handles invalid date input', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); const errorSpy = sinon.spy(); this.set('onError', errorSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-31'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.have.text('Invalid date'); expect(changeSpy.callCount, '@onChange call count').to.equal(0); expect(errorSpy.callCount, '@onError call count').to.equal(1); expect(errorSpy.firstCall.args[0]).to.be.instanceof(Error); expect(errorSpy.firstCall.args[0].message).to.equal('Invalid date'); }); it('handles invalid date format input', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); const errorSpy = sinon.spy(); this.set('onError', errorSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', 'narp'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.contain.text('Date must be YYYY-MM-DD'); expect(changeSpy.callCount, '@onChange call count').to.equal(0); expect(errorSpy.callCount, '@onError call count').to.equal(1); expect(errorSpy.firstCall.args[0]).to.be.instanceof(Error); expect(errorSpy.firstCall.args[0].message).to.contain('Date must be YYYY-MM-DD'); }); it('clears error on internal change to valid', async function () { await render(hbs``); await fillIn('[data-test-date-picker-input]', 'narp'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.exist; await fillIn('[data-test-date-picker-input]', '2022-02-22'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.not.exist; }); it('clears error on external @value change to valid', async function () { await render(hbs``); await fillIn('[data-test-date-picker-input]', 'narp'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.exist; this.set('date', moment('2022-02-22')); expect(find('[data-test-date-picker-error]')).to.not.exist; }); it('clears error on reset', async function () { await render(hbs``); await fillIn('[data-test-date-picker-input]', 'narp'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.exist; await triggerKeyEvent('[data-test-date-picker-input]', 'keydown', 'Escape'); expect(find('[data-test-date-picker-error]')).to.not.exist; }); describe('min/max', function () { it('disables datepicker dates outside of range', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); this.set('minDate', moment('2022-02-11 12:00:00.000Z').toDate()); this.set('maxDate', moment('2022-02-24 12:00:00.000Z').toDate()); await render(hbs``); await click('[data-test-date-picker-trigger]'); expect(find('[data-date="2022-02-10"]')).to.have.attribute('disabled'); expect(find('[data-date="2022-02-25"]')).to.have.attribute('disabled'); }); it('errors when date input is earlier than min', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); this.set('minDate', moment('2022-02-11 12:00:00.000Z').toDate()); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); const errorSpy = sinon.spy(); this.set('onError', errorSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-10'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.have.text('Must be on or after 2022-02-11'); expect(changeSpy.callCount, '@onChange call count').to.equal(0); expect(errorSpy.callCount, '@onError call count').to.equal(1); expect(errorSpy.firstCall.args[0]).to.be.instanceof(Error); expect(errorSpy.firstCall.args[0].message).to.equal('Must be on or after 2022-02-11'); expect(errorSpy.firstCall.args[0].date).to.be.equal('2022-02-10'); }); it('allows for min date error override', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); this.set('minDate', moment('2022-02-11 12:00:00.000Z').toDate()); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-10'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.have.text('Must be in the future'); }); it('errors when date input is later than max', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); this.set('maxDate', moment('2022-02-25 12:00:00.000Z').toDate()); const changeSpy = sinon.spy(); this.set('onChange', changeSpy); const errorSpy = sinon.spy(); this.set('onError', errorSpy); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-28'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.have.text('Must be on or before 2022-02-25'); expect(changeSpy.callCount, '@onChange call count').to.equal(0); expect(errorSpy.callCount, '@onError call count').to.equal(1); expect(errorSpy.firstCall.args[0]).to.be.instanceof(Error); expect(errorSpy.firstCall.args[0].message).to.equal('Must be on or before 2022-02-25'); expect(errorSpy.firstCall.args[0].date).to.be.equal('2022-02-28'); }); it('allows for max date error override', async function () { this.set('date', moment('2022-02-22 22:22:22.000Z')).toDate(); this.set('maxDate', moment('2022-02-25 12:00:00.000Z').toDate()); await render(hbs``); await fillIn('[data-test-date-picker-input]', '2022-02-28'); await blur('[data-test-date-picker-input]'); expect(find('[data-test-date-picker-error]')).to.have.text('Must be in the past'); }); }); });