fix(localize): don't set modelValue to unparseable if date has a negative timezone

Co-authored-by: Danny Moerkerke<Danny.Moerkerke@ing.com>
This commit is contained in:
gvangeest 2022-12-29 16:29:41 +01:00 committed by Thijs Louisse
parent a47a6e615b
commit 13185da02a
5 changed files with 112 additions and 45 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
don't set unparseable for negative timezones

View file

@ -1,10 +1,12 @@
import { expect } from '@open-wc/testing';
import { localize } from '@lion/ui/localize.js';
import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
import { formatAmount } from '@lion/ui/input-amount.js';
describe('formatAmount()', () => {
const localizeManager = getLocalizeManager();
afterEach(() => {
localizeTearDown();
});
@ -67,9 +69,9 @@ describe('formatAmount()', () => {
});
it('fallbacks to global locale and EUR by default', async () => {
localize.locale = 'en-GB';
localizeManager.locale = 'en-GB';
expect(formatAmount(12345678)).to.equal('12,345,678.00');
localize.locale = 'nl-NL';
localizeManager.locale = 'nl-NL';
expect(formatAmount(12345678)).to.equal('12.345.678,00');
});
});

View file

@ -1,7 +1,7 @@
import { html } from 'lit';
import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
import { MaxDate } from '@lion/ui/form-core.js';
import { MinDate, MaxDate } from '@lion/ui/form-core.js';
import { expect, fixture as _fixture } from '@open-wc/testing';
import { getInputMembers } from '@lion/ui/input-test-helpers.js';
import '@lion/ui/define/lion-input-date.js';
@ -67,49 +67,95 @@ describe('<lion-input-date>', () => {
expect(el.validationStates.error).not.to.have.property('MaxDate');
});
it('uses formatOptions.locale', async () => {
const el = await fixture(html`
<lion-input-date
.formatOptions="${{ locale: 'en-GB' }}"
.modelValue=${new Date('2017/06/15')}
></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017');
describe('locale', () => {
it('uses formatOptions.locale', async () => {
const el = await fixture(html`
<lion-input-date
.formatOptions="${{ locale: 'en-GB' }}"
.modelValue=${new Date('2017/06/15')}
></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017');
const el2 = await fixture(html`
<lion-input-date
.formatOptions="${{ locale: 'en-US' }}"
.modelValue=${new Date('2017/06/15')}
></lion-input-date>
`);
expect(el2.formattedValue).to.equal('06/15/2017');
const el2 = await fixture(html`
<lion-input-date
.formatOptions="${{ locale: 'en-US' }}"
.modelValue=${new Date('2017/06/15')}
></lion-input-date>
`);
expect(el2.formattedValue).to.equal('06/15/2017');
});
it('uses global locale when formatOptions.locale is not defined', async () => {
localizeManager.locale = 'fr-FR';
const el = await fixture(html`
<lion-input-date .modelValue=${new Date('2017/06/15')}></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017');
localizeManager.locale = 'en-US';
const el2 = await fixture(html`
<lion-input-date .modelValue=${new Date('2017/06/15')}></lion-input-date>
`);
expect(el2.formattedValue).to.equal('06/15/2017');
});
it('ignores global locale change if formatOptions.locale is provided', async () => {
const el = await fixture(html`
<lion-input-date
.modelValue=${new Date('2017/06/15')}
.formatOptions="${{ locale: 'en-GB' }}"
></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017'); // british
localizeManager.locale = 'en-US';
await el.updateComplete;
expect(el.formattedValue).to.equal('15/06/2017'); // should stay british
});
});
it('uses global locale when formatOptions.locale is not defined', async () => {
localizeManager.locale = 'fr-FR';
const el = await fixture(html`
<lion-input-date .modelValue=${new Date('2017/06/15')}></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017');
describe('timezones', async () => {
const dateAmsterdam = new Date(
new Date('2017/06/15').toLocaleString('en-US', { timeZone: 'Europe/Amsterdam' }),
);
const dateManila = new Date(
new Date('2017/06/15').toLocaleString('en-US', { timeZone: 'Asia/Manila' }),
);
const dateNewYork = new Date(
new Date('2017/06/15').toLocaleString('en-US', { timeZone: 'America/New_York' }),
);
localizeManager.locale = 'en-US';
const el2 = await fixture(html`
<lion-input-date .modelValue=${new Date('2017/06/15')}></lion-input-date>
`);
expect(el2.formattedValue).to.equal('06/15/2017');
});
it('works with different timezones', async () => {
const el = await fixture(html`
<lion-input-date .modelValue=${dateAmsterdam}></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017', 'Europe/Amsterdam');
it('ignores global locale change if formatOptions.locale is provided', async () => {
const el = await fixture(html`
<lion-input-date
.modelValue=${new Date('2017/06/15')}
.formatOptions="${{ locale: 'en-GB' }}"
></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017'); // british
localizeManager.locale = 'en-US';
await el.updateComplete;
expect(el.formattedValue).to.equal('15/06/2017'); // should stay british
el.modelValue = dateManila;
expect(el.formattedValue).to.equal('15/06/2017', 'Asia/Manila');
el.modelValue = dateNewYork;
expect(el.formattedValue).to.equal('14/06/2017', 'America/New_York');
});
it('validators work with different timezones', async () => {
const el = await fixture(html`
<lion-input-date
.modelValue=${new Date('2017/06/15')}
.validators=${[new MinDate(new Date('2017/06/14'))]}
></lion-input-date>
`);
expect(el.formattedValue).to.equal('15/06/2017', 'Europe/Amsterdam');
expect(el.hasFeedbackFor).not.to.include('error', 'Europe/Amsterdam');
el.modelValue = dateManila;
expect(el.formattedValue).to.equal('15/06/2017', 'Asia/Manila');
expect(el.hasFeedbackFor).not.to.include('error', 'Asia/Manila');
el.modelValue = dateNewYork;
expect(el.formattedValue).to.equal('14/06/2017', 'America/New_York');
expect(el.hasFeedbackFor).not.to.include('error', 'America/New_York');
});
});
it('is accessible', async () => {

View file

@ -58,7 +58,7 @@ export function parseDate(dateString) {
}
const [year, month, day] = parsedString.split('/').map(Number);
const parsedDate = new Date(Date.UTC(year, month - 1, day));
const parsedDate = new Date(new Date(year, month - 1, day));
// Check if parsedDate is not `Invalid Date` or that the date has changed (e.g. the not existing 31.02.2020)
if (

View file

@ -5,13 +5,13 @@ import { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
/**
*
* @param {Date | undefined} value
* @param {Date} date
* @param {Date | undefined} date
*/
function equalsDate(value, date) {
return (
Object.prototype.toString.call(value) === '[object Date]' && // is Date Object
value &&
value.getDate() === date.getDate() && // day
value.getDate() === date?.getDate() && // day
value.getMonth() === date.getMonth() && // month
value.getFullYear() === date.getFullYear() // year
);
@ -52,6 +52,20 @@ describe('parseDate()', () => {
expect(equalsDate(parseDate('12-31-1976'), new Date('1976/12/31'))).to.equal(true);
});
it('handles timezones of the browser and parsed date correctly', () => {
const referenceDate = new Date('2020/01/30');
localizeManager.locale = 'nl-NL';
const parsedDate = parseDate('30-01-2020');
// time zone offset of parsed date: this value is dependent on the browser (basically where the ci or local machine it runs in is located)
const parseDateOffset = parsedDate?.getTimezoneOffset();
// The parseDate time zone should be equal to the default offset of the browser
const browserTimeZoneOffset = referenceDate.getTimezoneOffset();
// This will pass, since parseDate respects browser timezone, and not UTC format
expect(parseDateOffset).to.equal(browserTimeZoneOffset);
// Optional: verify we are dealing with the same date (this is already tested in other tests?)
expect(equalsDate(referenceDate, parsedDate)).to.be.true;
});
it('return undefined when no valid date provided', () => {
expect(parseDate('12.12.1976.,')).to.equal(undefined); // wrong delimiter
expect(parseDate('foo')).to.equal(undefined); // no date