MM-61382 Date/Time Picker Input Fix and Refactor (#31330)

Этот коммит содержится в:
Matthew Birtch
2025-06-16 08:01:16 -04:00
коммит произвёл GitHub
родитель 6f5c92fc79
Коммит 77e50cf110
21 изменённых файлов: 674 добавлений и 701 удалений

Просмотреть файл

@@ -118,17 +118,19 @@ describe('MM-T4065 Setting manual status clear time less than 7 days away', () =
it('MM-T4065_7 should show selected time in the time input field', () => {
// * Check that the timepicker menu is not present and click to open it
cy.get('#custom_status_modal .dateTime__time-menu #expiryTimeMenu').should('not.exist');
cy.get('#custom_status_modal .dateTime__time-menu').click();
cy.get('#expiryTimeMenu').should('not.exist');
// # Click the time button
cy.get('#custom_status_modal #time_button').click();
// * Check that the time picker menu is present
cy.get('#custom_status_modal .dateTime__time-menu #expiryTimeMenu').should('exist');
cy.get('#expiryTimeMenu').should('exist');
// # Choose the last item in the time picker menu
cy.get('#custom_status_modal .dateTime__time-menu #expiryTimeMenu li').last().click();
cy.get('#expiryTimeMenu li').last().click();
// * Check that the time input contains the correct time
cy.get('.dateTime__time-menu .dateTime__input time').should('have.text', '11:30 PM');
cy.get('#custom_status_modal #time_button time').should('have.text', '11:30 PM');
});
it('MM-T4065_8 should set custom status when click on Set Status', () => {

Просмотреть файл

@@ -112,7 +112,7 @@ describe('MM-T4066 Setting manual status clear time more than 7 days away', () =
cy.get('.date-picker__popper').find(`.rdp-month button[aria-label="${dateToBeSelected.format('Do MMMM (dddd)')}"]`).click();
// * Check that the date input should have the correct value
cy.get('input#customStatus__calendar-input').should('have.value', dateToBeSelected.format('YYYY-MM-DD'));
cy.get('#custom_status_modal [role="button"][aria-label*="Date"]').should('contain.text', dateToBeSelected.format('MMM DD'));
});
it('MM-T4066_7 should set custom status when click on Set Status', () => {

Просмотреть файл

@@ -20,8 +20,6 @@ describe('DND Status - Setting Your Own DND Status', () => {
];
before(() => {
cy.shouldHaveFeatureFlag('TimedDND', true);
// # Login as test user and visit channel
cy.apiInitSetup({loginAfter: true}).then(({team, channel}) => {
cy.visit(`/${team.name}/channels/${channel.name}`);
@@ -77,13 +75,13 @@ describe('DND Status - Setting Your Own DND Status', () => {
cy.get(`.SubMenuItemContainer li#${dndTimes[4]}`).click();
// # Click on DayPicker input field
cy.get('.DayPickerInput input').click();
cy.get('.dateTime__date .date-time-input').click();
// * Verify that DayPicker overlay is visible
cy.get('.DayPickerInput-Overlay').should('be.visible');
cy.get('.date-picker__popper').should('be.visible');
// # Click on tomorrow's day
cy.get('.DayPickerInput-Overlay').find('.DayPicker-Day--today').next('.DayPicker-Day').click();
cy.get('.date-picker__popper').find('.rdp-day_today').next('.rdp-day').click();
// # Click 'Disable Notification' button
cy.get('.DndModal__footer span').should('have.text', 'Disable Notifications').click();
@@ -105,13 +103,13 @@ describe('DND Status - Setting Your Own DND Status', () => {
cy.get(`.SubMenuItemContainer li#${dndTimes[4]}`).click();
// # Click on time picker input field
cy.get('.MenuWrapper .DndModal__input').click();
cy.get('.dateTime__time .date-time-input').click();
// * Verify that time picker menu is visible
cy.get('ul.Menu__content.dropdown-menu').should('be.visible');
cy.get('#expiryTimeMenu').should('be.visible');
// # Click on last time available in list
cy.get('ul.Menu__content.dropdown-menu').last('.MenuItem').click();
cy.get('#expiryTimeMenu li').last().click();
// # Click 'Disable Notification' button
cy.get('.DndModal__footer span').should('have.text', 'Disable Notifications').click();
@@ -133,22 +131,22 @@ describe('DND Status - Setting Your Own DND Status', () => {
cy.get(`.SubMenuItemContainer li#${dndTimes[4]}`).click();
// # Click on DayPicker input field
cy.get('.DayPickerInput input').click();
cy.get('.dateTime__date .date-time-input').click();
// * Verify that DayPicker overlay is visible
cy.get('.DayPickerInput-Overlay').should('be.visible');
cy.get('.date-picker__popper').should('be.visible');
// # Click on tomorrow's day
cy.get('.DayPickerInput-Overlay').find('.DayPicker-Day--today').next('.DayPicker-Day').click();
cy.get('.date-picker__popper').find('.rdp-day_today').next('.rdp-day').click();
// # Click on time picker input field
cy.get('.MenuWrapper .DndModal__input').click();
cy.get('.dateTime__time .date-time-input').click();
// * Verify that time picker menu is visible
cy.get('ul.Menu__content.dropdown-menu').should('be.visible');
cy.get('#expiryTimeMenu').should('be.visible');
// # Click on last time available in list
cy.get('ul.Menu__content.dropdown-menu').last('.MenuItem').click();
cy.get('#expiryTimeMenu li').last().click();
// # Click 'Disable Notification' button
cy.get('.DndModal__footer span').should('have.text', 'Disable Notifications').click();

Просмотреть файл

@@ -14,7 +14,7 @@ export default class ScheduleMessageModal {
constructor(container: Locator) {
this.container = container;
this.dateButton = container.locator('#customStatus__calendar-input');
this.dateButton = container.getByRole('button', {name: /Date/});
this.timeButton = container.getByTestId('time_button');
this.timeOptionDropdown = container.getByLabel('Choose a time');
this.closeButton = container.getByRole('button', {name: 'Close'});
@@ -80,7 +80,7 @@ export default class ScheduleMessageModal {
async selectTime(optionIndex: number = 0) {
await this.timeButton.click();
const timeButton = this.timeOptionDropdown.getByTestId(`time_option_${optionIndex}-button`);
const timeButton = this.container.page().getByTestId(`time_option_${optionIndex}`);
await expect(timeButton).toBeVisible();
await timeButton.click();
@@ -91,7 +91,7 @@ export default class ScheduleMessageModal {
await this.toBeVisible();
const selectedDate = await this.selectDate(dayFromToday);
const fromDateButton = await this.dateButton.inputValue();
const fromDateButton = await this.dateButton.textContent();
const selectedTime = await this.selectTime(timeOptionIndex);
await this.scheduleButton.click();

Просмотреть файл

@@ -36,8 +36,7 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessage(draftMessage, 0, 1);
// * Verify scheduled post indicator shows correct date and time
const indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, indicatorMessage);
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, selectedDate, selectedTime);
// * Verify scheduled post badge in left sidebar shows count of 1
await verifyScheduledPostBadgeOnLeftSidebar(channelsPage, 1);
@@ -46,8 +45,7 @@ test(
await channelsPage.centerView.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send ${selectedDate} at ${selectedTime}`;
await verifyScheduledPost(scheduledPostsPage, {draftMessage, sendOnMessage, badgeCountOnTab: 1});
await verifyScheduledPost(scheduledPostsPage, {draftMessage, selectedDate, selectedTime, badgeCountOnTab: 1});
// # Return to the channels page
await page.goBack();
@@ -98,17 +96,16 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessageFromThread(draftMessage, 1);
// * Verify scheduled post indicator shows correct date and time
const indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
await verifyScheduledPostIndicator(sidebarRight.scheduledPostIndicator, indicatorMessage);
await verifyScheduledPostIndicator(sidebarRight.scheduledPostIndicator, selectedDate, selectedTime);
// # Navigate to scheduled posts page using indicator link
await sidebarRight.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -153,8 +150,7 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessage(draftMessage, 1);
// * Verify scheduled message indicator shows correct date and time
const indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, indicatorMessage);
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, selectedDate, selectedTime);
// * Verify scheduled post badge appears with count of 1
await verifyScheduledPostBadgeOnLeftSidebar(channelsPage, 1);
@@ -163,10 +159,10 @@ test(
await channelsPage.centerView.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -178,8 +174,11 @@ test(
await channelsPage.goto();
// * Verify indicator shows the updated scheduled time
const newIndicatorMessage = `Message scheduled for ${newSelectedDate} at ${newSelectedTime}.`;
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, newIndicatorMessage);
await verifyScheduledPostIndicator(
channelsPage.centerView.scheduledPostIndicator,
newSelectedDate,
newSelectedTime,
);
},
);
@@ -205,17 +204,16 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessage(draftMessage, 1);
// * Verify scheduled message indicator shows correct date and time
const indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, indicatorMessage);
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, selectedDate, selectedTime);
// # Navigate to scheduled posts page via indicator link
await channelsPage.centerView.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -256,17 +254,16 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessage(draftMessage, 1);
// * Verify scheduled message indicator shows correct date and time
const indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, indicatorMessage);
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, selectedDate, selectedTime);
// # Navigate to scheduled posts page via indicator link
await channelsPage.centerView.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -314,14 +311,20 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessage(draftMessage, 1);
// * Verify appropriate scheduled message indicator appears
let indicatorMessage;
if (pw.isOutsideRemoteUserHour(otherUser.timezone)) {
indicatorMessage = 'You have one scheduled message.';
} else {
indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
}
await channelsPage.centerView.scheduledPostIndicator.toBeVisible();
await expect(channelsPage.centerView.scheduledPostIndicator.messageText).toContainText(indicatorMessage);
if (pw.isOutsideRemoteUserHour(otherUser.timezone)) {
// Special case for timezone - expect generic message
await expect(channelsPage.centerView.scheduledPostIndicator.messageText).toContainText(
'You have one scheduled message.',
);
} else {
// Normal case - verify the scheduled indicator
await verifyScheduledPostIndicator(
channelsPage.centerView.scheduledPostIndicator,
selectedDate,
selectedTime,
);
}
// # Navigate to scheduled posts page using appropriate link
if (pw.isOutsideRemoteUserHour(otherUser.timezone)) {
@@ -331,10 +334,10 @@ test(
}
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -399,8 +402,7 @@ test(
await scheduledPostsPage.goto(team.name);
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
await verifyScheduledPost(scheduledPostsPage, {draftMessage, sendOnMessage, badgeCountOnTab: 1});
await verifyScheduledPost(scheduledPostsPage, {draftMessage, selectedDate, selectedTime, badgeCountOnTab: 1});
},
);
@@ -426,8 +428,7 @@ test(
const {selectedDate, selectedTime} = await channelsPage.scheduleMessage(draftMessage, 2);
// * Verify scheduled message indicator shows correct date and time
const indicatorMessage = `Message scheduled for ${selectedDate} at ${selectedTime}.`;
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, indicatorMessage);
await verifyScheduledPostIndicator(channelsPage.centerView.scheduledPostIndicator, selectedDate, selectedTime);
// * Verify scheduled post badge shows count of 1
await verifyScheduledPostBadgeOnLeftSidebar(channelsPage, 1);
@@ -436,10 +437,10 @@ test(
await channelsPage.centerView.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -454,7 +455,7 @@ test(
await expect(scheduledPost.panelBody).toContainText(updatedText);
// * Verify scheduled date/time remains unchanged
await expect(scheduledPost.panelHeader).toContainText(`Send on ${selectedDate} at ${selectedTime}`);
await expect(scheduledPost.panelHeader).toContainText(selectedTime);
// # Send the edited message immediately
await scheduledPost.hover();
@@ -506,10 +507,10 @@ test(
await channelsPage.centerView.scheduledPostIndicator.seeAllLink.click();
// * Verify scheduled post appears with correct information
const sendOnMessage = `Send on ${selectedDate} at ${selectedTime}`;
const scheduledPost = await verifyScheduledPost(scheduledPostsPage, {
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab: 1,
});
@@ -532,15 +533,36 @@ test(
);
/**
* Verifies that the scheduled post indicator is visible and displays the correct date and time.
*
* @param scheduledPostIndicator - The ScheduledPostIndicator instance
* @param messageText - A post message
* Verifies that the scheduled post indicator shows the correct date and time.
*/
async function verifyScheduledPostIndicator(scheduledPostIndicator: ScheduledPostIndicator, messageText: string) {
async function verifyScheduledPostIndicator(
scheduledPostIndicator: ScheduledPostIndicator,
selectedDate: string,
selectedTime: string | null,
) {
await scheduledPostIndicator.toBeVisible();
await expect(scheduledPostIndicator.icon).toBeVisible();
await expect(scheduledPostIndicator.messageText).toContainText(messageText);
if (!selectedTime) {
throw new Error('selectedTime is required');
}
// Verify the indicator contains both the time and a valid date
const messageText = await scheduledPostIndicator.messageText.textContent();
await expect(scheduledPostIndicator.messageText).toContainText(selectedTime);
const datePatterns = [
selectedDate, // Original date
'Today',
'Tomorrow',
];
const hasValidDate = datePatterns.some((pattern) => messageText?.toLowerCase().includes(pattern.toLowerCase()));
if (!hasValidDate) {
throw new Error(
`Indicator text "${messageText}" does not contain any expected date pattern: ${datePatterns.join(', ')}`,
);
}
}
async function verifyScheduledPostBadgeOnLeftSidebar(channelsPage: ChannelsPage, count: number) {
@@ -552,9 +574,10 @@ async function verifyScheduledPost(
scheduledPostsPage: ScheduledPostsPage,
{
draftMessage,
sendOnMessage,
selectedDate,
selectedTime,
badgeCountOnTab,
}: {draftMessage: string; sendOnMessage: string; badgeCountOnTab: number},
}: {draftMessage: string; selectedDate: string; selectedTime: string | null; badgeCountOnTab: number},
) {
// * Verify scheduled posts page is visible
await scheduledPostsPage.toBeVisible();
@@ -566,7 +589,26 @@ async function verifyScheduledPost(
const scheduledPost = await scheduledPostsPage.getLastPost();
await expect(scheduledPost.panelBody).toContainText(draftMessage);
await expect(scheduledPost.panelHeader).toContainText(sendOnMessage);
if (!selectedTime) {
throw new Error('selectedTime is required');
}
// Verify the header contains both the time and a valid date
const headerText = await scheduledPost.panelHeader.textContent();
await expect(scheduledPost.panelHeader).toContainText(selectedTime);
const datePatterns = [
selectedDate, // Original date
'Today',
'Tomorrow',
];
const hasValidDate = datePatterns.some((pattern) => headerText?.toLowerCase().includes(pattern.toLowerCase()));
if (!hasValidDate) {
throw new Error(
`Header "${headerText}" does not contain any expected date pattern: ${datePatterns.join(', ')}`,
);
}
return scheduledPost;
}