Skip to content

Commit

Permalink
Fix consistent event types for kol-input-date (#6896)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdvg authored Oct 15, 2024
2 parents 190bfe6 + 8c4698b commit a98312f
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 8 deletions.
158 changes: 158 additions & 0 deletions packages/components/src/components/input-date/input-date.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from '@playwright/test';
import { test } from '@stencil/playwright';
import type { Iso8601 } from '../../schema';

test.describe('kol-input-date', () => {
test.describe('when value is Date object', () => {
Expand Down Expand Up @@ -60,6 +61,153 @@ test.describe('kol-input-date', () => {
});
});

test.describe('Events', () => {
const testValues = [
{ label: 'ISO String', value: '2020-03-03' as Iso8601 },
{ label: 'Date Object', value: new Date('2020-03-03T03:02:01.099Z') },
];

testValues.forEach(({ label, value }) => {
test.describe(`when initial value is a ${label}`, () => {
test(`should call onChange with value parameter as ${label}`, async ({ page }) => {
await page.setContent('<kol-input-date _label="Date input"></kol-input-date>');
const inputDate = page.locator('kol-input-date');
void inputDate.evaluate((element: HTMLKolInputDateElement, date) => {
element._value = date;
}, value);

const inputDateEventPromise = inputDate.evaluate((element) => {
return new Promise<Date | Iso8601>((resolve) => {
(element as HTMLKolSelectElement)._on = {
onChange: (_event, eventValue: unknown) => {
resolve(eventValue as Date | Iso8601);
},
};
});
});

await page.waitForChanges();
await page.locator('input').dispatchEvent('change');

const eventDetail = await inputDateEventPromise;
if (value instanceof Date) {
expect(eventDetail).toBeInstanceOf(Date);
expect((eventDetail as Date).toISOString().split('T')[0]).toBe(value.toISOString().split('T')[0]);
} else {
expect(eventDetail).toBe(value);
}
});

test(`should call onInput with value parameter as ${label}`, async ({ page }) => {
await page.setContent('<kol-input-date _label="Date input"></kol-input-date>');
const inputDate = page.locator('kol-input-date');
void inputDate.evaluate((element: HTMLKolInputDateElement, date) => {
element._value = date;
}, value);

const inputDateEventPromise = inputDate.evaluate((element) => {
return new Promise<Date | Iso8601>((resolve) => {
(element as HTMLKolSelectElement)._on = {
onInput: (_event, eventValue: unknown) => {
resolve(eventValue as Date | Iso8601);
},
};
});
});

await page.waitForChanges();
await page.locator('input').dispatchEvent('input');

const eventDetail = await inputDateEventPromise;
if (value instanceof Date) {
expect(eventDetail).toBeInstanceOf(Date);
expect((eventDetail as Date).toISOString().split('T')[0]).toBe(value.toISOString().split('T')[0]);
} else {
expect(eventDetail).toBe(value);
}
});

test(`should trigger custom "kol-change" DOM event with ${label} as event detail`, async ({ page }) => {
await page.setContent('<kol-input-date _label="Date input"></kol-input-date>');
const inputDate = page.locator('kol-input-date');

await inputDate.evaluate((element: HTMLKolInputDateElement, date) => {
element._value = date;
}, value);

const inputDateEventPromise = inputDate.evaluate((element: HTMLKolInputDateElement) => {
return new Promise<Date | Iso8601>((resolve) => {
element.addEventListener('kol-change', (e: Event) => {
const eventValue: Date | Iso8601 = (e as CustomEvent).detail;

Check warning on line 141 in packages/components/src/components/input-date/input-date.e2e.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe assignment of an `any` value
resolve(eventValue);
});
});
});

await page.waitForChanges();
await page.locator('input').dispatchEvent('change');

const eventDetail = await inputDateEventPromise;

if (value instanceof Date) {
expect(eventDetail).toBeInstanceOf(Date);
expect((eventDetail as Date).toISOString().split('T')[0]).toBe(value.toISOString().split('T')[0]);
} else {
expect(eventDetail).toBe(value);
}
});

test(`should trigger custom "kol-input" DOM event with ${label} as event detail`, async ({ page }) => {
await page.setContent('<kol-input-date _label="Date input"></kol-input-date>');
const inputDate = page.locator('kol-input-date');

await inputDate.evaluate((element: HTMLKolInputDateElement, date) => {
element._value = date;
}, value);

const inputDateEventPromise = inputDate.evaluate((element: HTMLKolInputDateElement) => {
return new Promise<Date | Iso8601>((resolve) => {
element.addEventListener('kol-input', (e: Event) => {
const eventValue: Date | Iso8601 = (e as CustomEvent).detail;

Check warning on line 171 in packages/components/src/components/input-date/input-date.e2e.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe assignment of an `any` value
resolve(eventValue);
});
});
});

await page.waitForChanges();
await page.locator('input').dispatchEvent('input');

const eventDetail = await inputDateEventPromise;

if (value instanceof Date) {
expect(eventDetail).toBeInstanceOf(Date);
expect((eventDetail as Date).toISOString().split('T')[0]).toBe(value.toISOString().split('T')[0]);
} else {
expect(eventDetail).toBe(value);
}
});

test(`should return the correct value for getValue() as ${label}`, async ({ page }) => {
await page.setContent('<kol-input-date _label="Date input"></kol-input-date>');
await page.locator('kol-input-date').evaluate((element: HTMLKolInputDateElement, date) => {
element._value = date;
}, value);

const getValue = await page.locator('kol-input-date').evaluate((element: HTMLKolInputDateElement) => {
return element.getValue();
});

if (value instanceof Date) {
expect(getValue).toBeInstanceOf(Date);
expect((getValue as Date).toISOString().split('T')[0]).toBe(value.toISOString().split('T')[0]);
} else {
expect(getValue).toBe(value);
}
});
});
});
});

test.describe('when min and max is set', () => {
test.describe('for Iso8601-Format', () => {
test('should set correct min and max for type date', async ({ page }) => {
Expand Down Expand Up @@ -202,4 +350,14 @@ test.describe('kol-input-date', () => {
});
});
});

test.describe('when initial value is null', () => {
test('should set value as empty string', async ({ page }) => {
await page.setContent('<kol-input-date _label="Date input"></kol-input-date>');
await page.locator('kol-input-date').evaluate((element: HTMLKolInputDateElement) => {
element._value = null;
});
await expect(page.locator('input')).toHaveValue('');
});
});
});
35 changes: 33 additions & 2 deletions packages/components/src/components/input-date/shadow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ export class KolInputDate implements InputDateAPI, FocusableElement {
@Element() private readonly host?: HTMLKolInputDateElement;
private inputRef?: HTMLInputElement;

@State() private _initialValueType: 'Date' | 'String' | null = null;

private readonly catchRef = (ref?: HTMLInputElement) => {
this.inputRef = ref;
};

@Method()
// eslint-disable-next-line @typescript-eslint/require-await
public async getValue(): Promise<string | undefined> {
return this.inputRef?.value;
public async getValue(): Promise<string | Date | undefined> {
return this.inputRef && this.remapValue(this.inputRef?.value);
}

/**
Expand Down Expand Up @@ -82,6 +84,31 @@ export class KolInputDate implements InputDateAPI, FocusableElement {
}
}

private setInitialValueType(value: Iso8601 | Date | null) {
if (value instanceof Date) {
this._initialValueType = 'Date';
} else if (typeof value === 'string') {
this._initialValueType = 'String';
} else {
this._initialValueType = null;
}
}
private remapValue(newValue: string): Date | string {
return this._initialValueType === 'Date' ? new Date(newValue) : newValue;
}

private readonly onChange = (event: Event) => {
const newValue = (event.target as HTMLInputElement).value;
const remappedValue = this.remapValue(newValue);
this.controller.onFacade.onChange(event, remappedValue);
};

private readonly onInput = (event: Event) => {
const newValue = (event.target as HTMLInputElement).value;
const remappedValue = this.remapValue(newValue);
this.controller.onFacade.onInput(event, true, remappedValue);
};

private readonly onKeyDown = (event: KeyboardEvent) => {
if (event.code === 'Enter' || event.code === 'NumpadEnter') {
propagateSubmitEventToForm({
Expand Down Expand Up @@ -157,6 +184,8 @@ export class KolInputDate implements InputDateAPI, FocusableElement {
value={this.state._value || undefined}
{...this.controller.onFacade}
onKeyDown={this.onKeyDown}
onChange={this.onChange}
onInput={this.onInput}
/>
</div>
</KolInputWcTag>
Expand Down Expand Up @@ -455,9 +484,11 @@ export class KolInputDate implements InputDateAPI, FocusableElement {
deprecatedHint('Date type will be removed in v3. Use `Iso8601` instead.');
}
this.controller.validateValueEx(value);
if (value !== undefined) this.setInitialValueType(value);
}

public componentWillLoad(): void {
if (this._value !== undefined) this.setInitialValueType(this._value);
this._alert = this._alert === true;
this._touched = this._touched === true;
this.controller.componentWillLoad();
Expand Down
41 changes: 35 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a98312f

Please sign in to comment.