Compare commits

...

12 Commits

Author SHA1 Message Date
Liam DeBeasi
a08a07cbab fix(datetime): clear button calls reset method 2023-08-14 09:13:30 -04:00
Liam DeBeasi
c2bcdcbec3 run build 2023-08-10 17:20:38 -05:00
Liam DeBeasi
f02aff87af clarity 2023-08-10 17:19:41 -05:00
Liam DeBeasi
2af3702b3e clarify behavior 2023-08-10 17:19:23 -05:00
Liam DeBeasi
783a653071 Update datetime.e2e.ts 2023-08-10 18:17:34 -04:00
Liam DeBeasi
954baf3bef Update datetime.e2e.ts 2023-08-10 18:17:24 -04:00
Liam DeBeasi
48b4cc36b8 add issue annotation 2023-08-10 17:14:50 -05:00
Liam DeBeasi
3cef069078 clean up test 2023-08-10 17:14:05 -05:00
Liam DeBeasi
82f8ca8dd1 fix(datetime): reset falls back to value if set 2023-08-10 17:10:14 -05:00
Liam DeBeasi
6f276099fc fix(datetime): cancel resets internal state of datetime 2023-08-10 17:09:57 -05:00
Liam DeBeasi
f295b35671 lint 2023-08-10 17:09:36 -05:00
Liam DeBeasi
1a9714783f test(datetime): add tests 2023-08-10 17:09:16 -05:00
5 changed files with 198 additions and 53 deletions

View File

@@ -819,7 +819,7 @@ export namespace Components {
}
interface IonDatetime {
/**
* Emits the ionCancel event and optionally closes the popover or modal that the datetime was presented in.
* The cancel method performs the following actions: 1. Emits the ionCancel event 2. Resets the internal state of the datetime 3. Closes the parent popover or modal if "closeOverlay" is true.
*/
"cancel": (closeOverlay?: boolean) => Promise<void>;
/**
@@ -915,15 +915,15 @@ export namespace Components {
*/
"readonly": boolean;
/**
* Resets the internal state of the datetime but does not update the value. Passing a valid ISO-8601 string will reset the state of the component to the provided date. If no value is provided, the internal state will be reset to the clamped value of the min, max and today.
* Resets the internal state of the datetime but does not update the value property. Passing a valid ISO-8601 string will reset the state of the component to the provided date. If no date string was passed but the value property is set, then the internal state of datetime will be reset to that value. Otherwise, the internal state will be reset to the clamped value of the min, max and today.
*/
"reset": (startDate?: string) => Promise<void>;
/**
* If `true`, a "Clear" button will be rendered alongside the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
* If `true`, a "Clear" button will be rendered alongside the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered. Pressing the "Clear" button will call the "reset" method.
*/
"showClearButton": boolean;
/**
* If `true`, the default "Cancel" and "OK" buttons will be rendered at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
* If `true`, the default "Cancel" and "OK" buttons will be rendered at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered. Pressing the "Cancel" button will call the "cancel" method. Pressing the "OK" button will the "confirm" method.
*/
"showDefaultButtons": boolean;
/**
@@ -4954,11 +4954,11 @@ declare namespace LocalJSX {
*/
"readonly"?: boolean;
/**
* If `true`, a "Clear" button will be rendered alongside the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
* If `true`, a "Clear" button will be rendered alongside the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered. Pressing the "Clear" button will call the "reset" method.
*/
"showClearButton"?: boolean;
/**
* If `true`, the default "Cancel" and "OK" buttons will be rendered at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered.
* If `true`, the default "Cancel" and "OK" buttons will be rendered at the bottom of the `ion-datetime` component. Developers can also use the `button` slot if they want to customize these buttons. If custom buttons are set in the `button` slot then the default buttons will not be rendered. Pressing the "Cancel" button will call the "cancel" method. Pressing the "OK" button will the "confirm" method.
*/
"showDefaultButtons"?: boolean;
/**

View File

@@ -424,6 +424,9 @@ export class Datetime implements ComponentInterface {
* if they want to customize these buttons. If custom
* buttons are set in the `button` slot then the
* default buttons will not be rendered.
*
* Pressing the "Cancel" button will call the "cancel" method.
* Pressing the "OK" button will the "confirm" method.
*/
@Prop() showDefaultButtons = false;
@@ -434,6 +437,8 @@ export class Datetime implements ComponentInterface {
* if they want to customize these buttons. If custom
* buttons are set in the `button` slot then the
* default buttons will not be rendered.
*
* Pressing the "Clear" button will call the "reset" method.
*/
@Prop() showClearButton = false;
@@ -540,25 +545,29 @@ export class Datetime implements ComponentInterface {
}
/**
* Resets the internal state of the datetime but does not update the value.
* Resets the internal state of the datetime but does not update the value property.
* Passing a valid ISO-8601 string will reset the state of the component to the provided date.
* If no value is provided, the internal state will be reset to the clamped value of the min, max and today.
* If no date string was passed but the value property is set, then the internal state of
* datetime will be reset to that value. Otherwise, the internal state will be reset to the
* clamped value of the min, max and today.
*/
@Method()
async reset(startDate?: string) {
this.processValue(startDate);
this.processValue(startDate ?? this.value);
}
/**
* Emits the ionCancel event and
* optionally closes the popover
* or modal that the datetime was
* presented in.
* The cancel method performs the following actions:
* 1. Emits the ionCancel event
* 2. Resets the internal state of the datetime
* 3. Closes the parent popover or modal if "closeOverlay" is true.
*/
@Method()
async cancel(closeOverlay = false) {
this.ionCancel.emit();
this.reset();
if (closeOverlay) {
this.closeParentOverlay();
}
@@ -1376,11 +1385,6 @@ export class Datetime implements ComponentInterface {
return;
}
const clearButtonClick = () => {
this.reset();
this.setValue(undefined);
};
/**
* By default we render two buttons:
* Cancel - Dismisses the datetime and
@@ -1406,7 +1410,7 @@ export class Datetime implements ComponentInterface {
)}
<div>
{showClearButton && (
<ion-button id="clear-button" color={this.color} onClick={() => clearButtonClick()}>
<ion-button id="clear-button" color={this.color} onClick={() => this.reset()}>
{this.clearText}
</ion-button>
)}

View File

@@ -380,40 +380,6 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
});
});
/**
* This behavior does not differ across
* modes/directions.
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('datetime: clear button'), () => {
test('should clear the active calendar day', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/26258',
});
await page.setContent(
`
<ion-datetime value="2022-11-10" show-clear-button="true"></ion-datetime>
`,
config
);
await page.waitForSelector('.datetime-ready');
const selectedDay = page.locator('ion-datetime .calendar-day-active');
await expect(selectedDay).toHaveText('10');
await page.click('ion-datetime #clear-button');
await page.waitForChanges();
await expect(selectedDay).toHaveCount(0);
});
});
});
/**
* This behavior does not differ across
* modes/directions.

View File

@@ -0,0 +1,75 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('datetime: cancel method'), () => {
test('should emit ionCancel', async ({ page }) => {
await page.setContent(
`
<ion-datetime></ion-datetime>
`,
config
);
const ionCancel = await page.spyOnEvent('ionCancel');
const datetime = page.locator('ion-datetime');
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.cancel());
await ionCancel.next();
});
test('parent overlay should be dismissed when true is passed', async ({ page }) => {
await page.setContent(
`
<ion-modal>
<ion-datetime></ion-datetime>
</ion-modal>
`,
config
);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
const datetime = page.locator('ion-datetime');
const modal = page.locator('ion-modal');
await modal.evaluate((el: HTMLIonModalElement) => el.present());
await ionModalDidPresent.next();
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.cancel(true));
await ionModalDidDismiss.next();
});
test('should reset the internal state of datetime', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/27975',
});
await page.setContent(
`
<ion-datetime value="2023-06-06T16:30" show-default-buttons="true"></ion-datetime>
`,
config
);
const datetime = page.locator('ion-datetime');
const dayOne = datetime.locator('.calendar-day[data-month="6"][data-day="1"][data-year="2023"]');
const daySix = datetime.locator('.calendar-day[data-month="6"][data-day="6"][data-year="2023"]');
await dayOne.click();
await page.waitForChanges();
await expect(dayOne).toHaveClass(/calendar-day-active/);
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.cancel());
await page.waitForChanges();
await expect(daySix).toHaveClass(/calendar-day-active/);
});
});
});

View File

@@ -0,0 +1,100 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('datetime: reset method'), () => {
test('should reset the internal state of datetime to the set value', async ({ page }) => {
await page.setContent(
`
<ion-datetime value="2023-06-06T16:30" show-default-buttons="true"></ion-datetime>
`,
config
);
const datetime = page.locator('ion-datetime');
const dayOne = datetime.locator('.calendar-day[data-month="6"][data-day="1"][data-year="2023"]');
const daySix = datetime.locator('.calendar-day[data-month="6"][data-day="6"][data-year="2023"]');
await dayOne.click();
await page.waitForChanges();
await expect(dayOne).toHaveClass(/calendar-day-active/);
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.reset());
await page.waitForChanges();
await expect(daySix).toHaveClass(/calendar-day-active/);
});
test('should reset the internal state of datetime to the provided value', async ({ page }) => {
await page.setContent(
`
<ion-datetime show-default-buttons="true"></ion-datetime>
<script>
const mockToday = '2023-06-12T16:22';
Date = class extends Date {
constructor(...args) {
if (args.length === 0) {
super(mockToday)
} else {
super(...args);
}
}
}
</script>
`,
config
);
const datetime = page.locator('ion-datetime');
const dayOne = datetime.locator('.calendar-day[data-month="6"][data-day="1"][data-year="2023"]');
const daySix = datetime.locator('.calendar-day[data-month="6"][data-day="6"][data-year="2023"]');
await dayOne.click();
await page.waitForChanges();
await expect(dayOne).toHaveClass(/calendar-day-active/);
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.reset('2023-06-06T16:30'));
await page.waitForChanges();
await expect(daySix).toHaveClass(/calendar-day-active/);
});
test('should reset the internal state of datetime to today when value is set or passed', async ({ page }) => {
await page.setContent(
`
<ion-datetime show-default-buttons="true"></ion-datetime>
<script>
const mockToday = '2023-06-06T16:22';
Date = class extends Date {
constructor(...args) {
if (args.length === 0) {
super(mockToday)
} else {
super(...args);
}
}
}
</script>
`,
config
);
const datetime = page.locator('ion-datetime');
const dayOne = datetime.locator('.calendar-day[data-month="6"][data-day="1"][data-year="2023"]');
await dayOne.click();
await page.waitForChanges();
await expect(dayOne).toHaveClass(/calendar-day-active/);
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.reset());
await page.waitForChanges();
await expect(await datetime.locator('.calendar-day-active').count()).toBe(0);
});
});
});