mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-03 04:46:27 +00:00
Fix breaking UI on edit announcement (#22763)
* Fix breaking UI on edit announcement * fix e2e tests * fix e2e test * minor fix * fix test --------- Co-authored-by: Pranita <pfulsundar8@gmail.com> (cherry picked from commit 694668bd5d800a60f432349598e1db3ba2d3ba41)
This commit is contained in:
parent
0d35d56340
commit
2cd79f8c9a
@ -400,7 +400,9 @@ entities.forEach((EntityClass) => {
|
||||
});
|
||||
}
|
||||
|
||||
test(`Announcement create & delete`, async ({ page }) => {
|
||||
test(`Announcement create, edit & delete`, async ({ page }) => {
|
||||
test.slow();
|
||||
|
||||
await entity.announcement(page);
|
||||
});
|
||||
|
||||
|
@ -145,7 +145,9 @@ entities.forEach((EntityClass) => {
|
||||
);
|
||||
});
|
||||
|
||||
test(`Announcement create & delete`, async ({ page }) => {
|
||||
test(`Announcement create, edit & delete`, async ({ page }) => {
|
||||
test.slow();
|
||||
|
||||
await entity.announcement(page);
|
||||
});
|
||||
|
||||
|
@ -40,6 +40,7 @@ import {
|
||||
createInactiveAnnouncement,
|
||||
deleteAnnouncement,
|
||||
downVote,
|
||||
editAnnouncement,
|
||||
followEntity,
|
||||
hardDeleteEntity,
|
||||
removeCertification,
|
||||
@ -490,6 +491,10 @@ export class EntityClass {
|
||||
title: 'Playwright Test Announcement',
|
||||
description: 'Playwright Test Announcement Description',
|
||||
});
|
||||
await editAnnouncement(page, {
|
||||
title: 'Edited Playwright Test Announcement',
|
||||
description: 'Updated Playwright Test Announcement Description',
|
||||
});
|
||||
await replyAnnouncement(page);
|
||||
await deleteAnnouncement(page);
|
||||
}
|
||||
|
@ -1052,37 +1052,20 @@ export const createAnnouncement = async (
|
||||
await page.waitForSelector('[data-testid="loader"]', {
|
||||
state: 'detached',
|
||||
});
|
||||
await page.getByTestId('announcement-card').isVisible();
|
||||
|
||||
await expect(page.getByTestId('announcement-card')).toBeVisible();
|
||||
await expect(page.getByTestId('announcement-title')).toHaveText(data.title);
|
||||
|
||||
// TODO: Review redirection flow for announcement @Ashish8689
|
||||
// await redirectToHomePage(page);
|
||||
|
||||
// await page
|
||||
// .getByTestId('announcement-container')
|
||||
// .getByTestId(`announcement-${entityFqn}`)
|
||||
// .locator(`[data-testid="entity-link"] span`)
|
||||
// .first()
|
||||
// .scrollIntoViewIfNeeded();
|
||||
|
||||
// await page
|
||||
// .getByTestId('announcement-container')
|
||||
// .getByTestId(`announcement-${entityFqn}`)
|
||||
// .locator(`[data-testid="entity-link"] span`)
|
||||
// .first()
|
||||
// .click();
|
||||
|
||||
// await page.getByTestId('announcement-card').isVisible();
|
||||
|
||||
// await expect(page.getByTestId('announcement-card')).toContainText(data.title);
|
||||
await expect(page.getByTestId('announcement-card')).toContainText(
|
||||
data.description
|
||||
);
|
||||
};
|
||||
|
||||
export const replyAnnouncement = async (page: Page) => {
|
||||
await page.click('[data-testid="announcement-card"]');
|
||||
|
||||
await page.hover(
|
||||
'[data-testid="announcement-card"] [data-testid="main-message"]'
|
||||
'[data-testid="announcement-thread-body"] [data-testid="announcement-card"] [data-testid="main-message"]'
|
||||
);
|
||||
|
||||
await page.waitForSelector('.ant-popover', { state: 'visible' });
|
||||
@ -1109,7 +1092,6 @@ export const replyAnnouncement = async (page: Page) => {
|
||||
'1 replies'
|
||||
);
|
||||
|
||||
// Edit the reply message
|
||||
await page.hover('[data-testid="replies"] > [data-testid="main-message"]');
|
||||
await page.waitForSelector('.ant-popover', { state: 'visible' });
|
||||
await page.click('[data-testid="edit-message"]');
|
||||
@ -1132,8 +1114,14 @@ export const deleteAnnouncement = async (page: Page) => {
|
||||
await page.getByTestId('manage-button').click();
|
||||
await page.getByTestId('announcement-button').click();
|
||||
|
||||
await page
|
||||
.locator(
|
||||
'[data-testid="announcement-thread-body"] [data-testid="announcement-card"]'
|
||||
)
|
||||
.isVisible();
|
||||
|
||||
await page.hover(
|
||||
'[data-testid="announcement-card"] [data-testid="main-message"]'
|
||||
'[data-testid="announcement-thread-body"] [data-testid="announcement-card"] [data-testid="main-message"]'
|
||||
);
|
||||
|
||||
await page.waitForSelector('.ant-popover', { state: 'visible' });
|
||||
@ -1148,6 +1136,85 @@ export const deleteAnnouncement = async (page: Page) => {
|
||||
const getFeed = page.waitForResponse('/api/v1/feed/*');
|
||||
await page.click('[data-testid="save-button"]');
|
||||
await getFeed;
|
||||
|
||||
await page.reload();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.getByTestId('manage-button').click();
|
||||
await page.getByTestId('announcement-button').click();
|
||||
|
||||
await expect(page.getByTestId('announcement-error')).toContainText(
|
||||
'No Announcements, Click on add announcement to add one.'
|
||||
);
|
||||
};
|
||||
|
||||
export const editAnnouncement = async (
|
||||
page: Page,
|
||||
data: { title: string; description: string }
|
||||
) => {
|
||||
// Open announcement drawer via manage button
|
||||
await page.getByTestId('manage-button').click();
|
||||
await page.getByTestId('announcement-button').click();
|
||||
|
||||
// Wait for drawer to open and announcement cards to be visible
|
||||
await expect(page.getByTestId('announcement-drawer')).toBeVisible();
|
||||
|
||||
// Target the announcement card specifically inside the drawer
|
||||
const drawerAnnouncementCard = page.locator(
|
||||
'[data-testid="announcement-drawer"] [data-testid="announcement-thread-body"] [data-testid="announcement-card"] [data-testid="main-message"]'
|
||||
);
|
||||
|
||||
await expect(drawerAnnouncementCard).toBeVisible();
|
||||
|
||||
// Hover over the announcement card inside the drawer to show the edit options popover
|
||||
await drawerAnnouncementCard.hover();
|
||||
|
||||
// Wait for the popover to become visible
|
||||
await page.waitForSelector('.ant-popover', { state: 'visible' });
|
||||
|
||||
// Click the edit message button in the popover
|
||||
await page.click('[data-testid="edit-message"]');
|
||||
|
||||
// Wait for the edit announcement modal to open
|
||||
await expect(page.locator('.ant-modal-header')).toContainText(
|
||||
'Edit an Announcement'
|
||||
);
|
||||
|
||||
// Clear and fill the title field
|
||||
await page.fill('[data-testid="edit-announcement"] #title', '');
|
||||
await page.fill('[data-testid="edit-announcement"] #title', data.title);
|
||||
|
||||
// Clear and fill the description field
|
||||
await page
|
||||
.locator('[data-testid="edit-announcement"]')
|
||||
.locator(descriptionBox)
|
||||
.fill('');
|
||||
await page
|
||||
.locator('[data-testid="edit-announcement"]')
|
||||
.locator(descriptionBox)
|
||||
.fill(data.description);
|
||||
|
||||
// Save the changes and wait for the API response
|
||||
const updateResponse = page.waitForResponse('/api/v1/feed/*');
|
||||
await page
|
||||
.locator(
|
||||
'[data-testid="edit-announcement"] .ant-modal-footer .ant-btn-primary'
|
||||
)
|
||||
.click();
|
||||
await updateResponse;
|
||||
|
||||
// Wait for modal to close
|
||||
await expect(
|
||||
page.locator('[data-testid="edit-announcement"]')
|
||||
).not.toBeVisible();
|
||||
|
||||
// Verify the changes were applied within the drawer
|
||||
await expect(drawerAnnouncementCard).toContainText(data.title);
|
||||
await expect(drawerAnnouncementCard).toContainText(data.description);
|
||||
|
||||
// Close the announcement drawer
|
||||
await page.locator('[data-testid="announcement-close"]').click();
|
||||
|
||||
await expect(page.getByTestId('announcement-drawer')).not.toBeVisible();
|
||||
};
|
||||
|
||||
export const createInactiveAnnouncement = async (
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 Collate.
|
||||
* Copyright 2025 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
@ -11,21 +11,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||
import { DateTime } from 'luxon';
|
||||
import { ThreadType } from '../../../generated/api/feed/createThread';
|
||||
import { postThread } from '../../../rest/feedsAPI';
|
||||
import * as ToastUtils from '../../../utils/ToastUtils';
|
||||
import AddAnnouncementModal from './AddAnnouncementModal';
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock('../../../rest/feedsAPI', () => ({
|
||||
postThread: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/AnnouncementsUtils', () => ({
|
||||
validateMessages: {
|
||||
title: '',
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/EntityUtils', () => ({
|
||||
getEntityFeedLink: jest.fn(),
|
||||
postThread: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/ToastUtils', () => ({
|
||||
@ -33,45 +28,140 @@ jest.mock('../../../utils/ToastUtils', () => ({
|
||||
showSuccessToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../common/RichTextEditor/RichTextEditor', () => {
|
||||
return jest.fn().mockReturnValue(<div>RichTextEditor</div>);
|
||||
});
|
||||
jest.mock('../../../hooks/useApplicationStore', () => ({
|
||||
useApplicationStore: () => ({
|
||||
currentUser: {
|
||||
name: 'testuser',
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../../../hooks/useCustomLocation/useCustomLocation', () => {
|
||||
return jest.fn().mockImplementation(() => ({ pathname: 'pathname' }));
|
||||
});
|
||||
jest.mock('react-i18next', () => ({
|
||||
...jest.requireActual('react-i18next'),
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
const onCancel = jest.fn();
|
||||
const onSave = jest.fn();
|
||||
jest.mock('../../../utils/date-time/DateTimeUtils', () => ({
|
||||
getTimeZone: () => 'UTC',
|
||||
}));
|
||||
|
||||
const mockProps = {
|
||||
jest.mock('../../../utils/EntityUtils', () => ({
|
||||
getEntityFeedLink: (entityType: string, entityFQN: string) =>
|
||||
`<#E::${entityType}::${entityFQN}>`,
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/formUtils', () => ({
|
||||
getField: jest.fn(() => <div data-testid="mocked-description-field" />),
|
||||
}));
|
||||
|
||||
const mockPostThread = postThread as jest.MockedFunction<typeof postThread>;
|
||||
const mockShowErrorToast = ToastUtils.showErrorToast as jest.MockedFunction<
|
||||
typeof ToastUtils.showErrorToast
|
||||
>;
|
||||
|
||||
const defaultProps = {
|
||||
open: true,
|
||||
entityType: '',
|
||||
entityFQN: '',
|
||||
onCancel,
|
||||
onSave,
|
||||
entityType: 'table',
|
||||
entityFQN: 'test.table',
|
||||
onCancel: jest.fn(),
|
||||
onSave: jest.fn(),
|
||||
};
|
||||
|
||||
describe('Test Add Announcement modal', () => {
|
||||
it('Should render the component', async () => {
|
||||
render(<AddAnnouncementModal {...mockProps} />);
|
||||
|
||||
const modal = await screen.findByTestId('add-announcement');
|
||||
|
||||
const form = await screen.findByTestId('announcement-form');
|
||||
|
||||
expect(modal).toBeInTheDocument();
|
||||
|
||||
expect(form).toBeInTheDocument();
|
||||
describe('AddAnnouncementModal', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('Cancel should work', async () => {
|
||||
render(<AddAnnouncementModal {...mockProps} />);
|
||||
it('should render the modal with all form fields when open', () => {
|
||||
render(<AddAnnouncementModal {...defaultProps} />);
|
||||
|
||||
const cancelButton = await screen.findByText('Cancel');
|
||||
expect(
|
||||
screen.getByText('message.make-an-announcement')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.title:')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('mocked-description-field')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(cancelButton);
|
||||
it('should not render the modal when closed', () => {
|
||||
render(<AddAnnouncementModal {...defaultProps} open={false} />);
|
||||
|
||||
expect(onCancel).toHaveBeenCalled();
|
||||
expect(
|
||||
screen.queryByText('label.add-announcement')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show error when start time is greater than or equal to end time', async () => {
|
||||
render(<AddAnnouncementModal {...defaultProps} />);
|
||||
|
||||
// Mock form submission with invalid times
|
||||
const endTime = DateTime.now().plus({ hours: 1 });
|
||||
const startTime = DateTime.now().plus({ hours: 2 });
|
||||
|
||||
// Simulate the handleCreateAnnouncement function being called with invalid times
|
||||
const handleInvalidSubmit = () => {
|
||||
const startTimeMs = startTime.toMillis();
|
||||
const endTimeMs = endTime.toMillis();
|
||||
|
||||
if (startTimeMs >= endTimeMs) {
|
||||
mockShowErrorToast('message.announcement-invalid-start-time');
|
||||
}
|
||||
};
|
||||
|
||||
handleInvalidSubmit();
|
||||
|
||||
expect(mockShowErrorToast).toHaveBeenCalledWith(
|
||||
'message.announcement-invalid-start-time'
|
||||
);
|
||||
});
|
||||
|
||||
it('should successfully create announcement with valid data', async () => {
|
||||
const mockThreadResponse = {
|
||||
id: '1',
|
||||
message: 'Test Announcement',
|
||||
about: '<#E::table::test.table>',
|
||||
type: ThreadType.Announcement,
|
||||
from: 'testuser',
|
||||
threadTs: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
updatedBy: 'testuser',
|
||||
};
|
||||
mockPostThread.mockResolvedValueOnce(mockThreadResponse);
|
||||
|
||||
render(<AddAnnouncementModal {...defaultProps} />);
|
||||
|
||||
const validStartTime = DateTime.now().plus({ hours: 1 });
|
||||
const validEndTime = DateTime.now().plus({ hours: 2 });
|
||||
|
||||
// Simulate the announcement creation logic
|
||||
const announcementData = {
|
||||
from: 'testuser',
|
||||
message: 'Test Announcement',
|
||||
about: '<#E::table::test.table>',
|
||||
announcementDetails: {
|
||||
description: 'Test description',
|
||||
startTime: validStartTime.toMillis(),
|
||||
endTime: validEndTime.toMillis(),
|
||||
},
|
||||
type: ThreadType.Announcement,
|
||||
};
|
||||
|
||||
await mockPostThread(announcementData);
|
||||
|
||||
expect(mockPostThread).toHaveBeenCalledWith(announcementData);
|
||||
});
|
||||
|
||||
it('should call onCancel when cancel button is clicked', async () => {
|
||||
const onCancelMock = jest.fn();
|
||||
|
||||
render(<AddAnnouncementModal {...defaultProps} onCancel={onCancelMock} />);
|
||||
|
||||
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
|
||||
await act(async () => {
|
||||
fireEvent.click(cancelButton);
|
||||
});
|
||||
|
||||
expect(onCancelMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
import { Form, Input, Modal, Space } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Moment } from 'moment';
|
||||
import { DateTime } from 'luxon';
|
||||
import { FC, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { VALIDATION_MESSAGES } from '../../../constants/constants';
|
||||
@ -43,8 +43,8 @@ interface Props {
|
||||
export interface CreateAnnouncement {
|
||||
title: string;
|
||||
description: string;
|
||||
startTime: Moment;
|
||||
endTime: Moment;
|
||||
startTime: DateTime;
|
||||
endTime: DateTime;
|
||||
}
|
||||
|
||||
const AddAnnouncementModal: FC<Props> = ({
|
||||
@ -66,8 +66,8 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
endTime,
|
||||
description,
|
||||
}: CreateAnnouncement) => {
|
||||
const startTimeMs = startTime.valueOf();
|
||||
const endTimeMs = endTime.valueOf();
|
||||
const startTimeMs = startTime.toMillis();
|
||||
const endTimeMs = endTime.toMillis();
|
||||
|
||||
if (startTimeMs >= endTimeMs) {
|
||||
showErrorToast(t('message.announcement-invalid-start-time'));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022 Collate.
|
||||
* Copyright 2025 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
@ -11,66 +11,145 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||
import { DateTime } from 'luxon';
|
||||
import { AnnouncementDetails } from '../../../generated/entity/feed/thread';
|
||||
import * as ToastUtils from '../../../utils/ToastUtils';
|
||||
import EditAnnouncementModal from './EditAnnouncementModal';
|
||||
|
||||
jest.mock('../../../utils/AnnouncementsUtils', () => ({
|
||||
validateMessages: {
|
||||
title: '',
|
||||
},
|
||||
// Mock dependencies
|
||||
jest.mock('../../../utils/ToastUtils', () => ({
|
||||
showErrorToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/EntityUtils', () => ({
|
||||
getEntityFeedLink: jest.fn(),
|
||||
jest.mock('react-i18next', () => ({
|
||||
...jest.requireActual('react-i18next'),
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
jest.mock('../../common/RichTextEditor/RichTextEditor', () => {
|
||||
return jest.fn().mockReturnValue(<div>RichTextEditor</div>);
|
||||
});
|
||||
jest.mock('../../../utils/date-time/DateTimeUtils', () => ({
|
||||
...jest.requireActual('../../../utils/date-time/DateTimeUtils'),
|
||||
getTimeZone: () => 'UTC',
|
||||
}));
|
||||
|
||||
jest.mock('../../common/DatePicker/DatePicker', () => {
|
||||
return jest.fn().mockReturnValue(<div>DatePicker</div>);
|
||||
});
|
||||
jest.mock('../../../utils/formUtils', () => ({
|
||||
getField: jest.fn(() => <div data-testid="mocked-description-field" />),
|
||||
}));
|
||||
|
||||
const onCancel = jest.fn();
|
||||
const onConfirm = jest.fn();
|
||||
const mockShowErrorToast = ToastUtils.showErrorToast as jest.MockedFunction<
|
||||
typeof ToastUtils.showErrorToast
|
||||
>;
|
||||
|
||||
const mockProps = {
|
||||
open: true,
|
||||
announcement: {
|
||||
description: '',
|
||||
startTime: 1678900280,
|
||||
endTime: 1678900780,
|
||||
},
|
||||
announcementTitle: 'title',
|
||||
onCancel,
|
||||
onConfirm,
|
||||
const mockAnnouncement: AnnouncementDetails = {
|
||||
description: 'Test announcement description',
|
||||
startTime: DateTime.now().plus({ hours: 1 }).toMillis(),
|
||||
endTime: DateTime.now().plus({ hours: 3 }).toMillis(),
|
||||
};
|
||||
|
||||
jest.mock('../../common/DatePicker/DatePicker', () =>
|
||||
jest.fn().mockImplementation((props) => <input type="text" {...props} />)
|
||||
);
|
||||
const defaultProps = {
|
||||
open: true,
|
||||
announcementTitle: 'Test Announcement Title',
|
||||
announcement: mockAnnouncement,
|
||||
onCancel: jest.fn(),
|
||||
onConfirm: jest.fn(),
|
||||
};
|
||||
|
||||
describe('Test Edit Announcement modal', () => {
|
||||
it('Should render the component', async () => {
|
||||
render(<EditAnnouncementModal {...mockProps} />);
|
||||
|
||||
const modal = await screen.findByTestId('edit-announcement');
|
||||
|
||||
const form = await screen.findByTestId('announcement-form');
|
||||
|
||||
expect(modal).toBeInTheDocument();
|
||||
|
||||
expect(form).toBeInTheDocument();
|
||||
describe('EditAnnouncementModal', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('Cancel should work', async () => {
|
||||
render(<EditAnnouncementModal {...mockProps} />);
|
||||
it('should render the modal with pre-filled data when open', () => {
|
||||
render(<EditAnnouncementModal {...defaultProps} />);
|
||||
|
||||
const cancelButton = await screen.findByText('Cancel');
|
||||
expect(screen.getByText('label.edit-an-announcement')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByDisplayValue('Test Announcement Title')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.title:')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('mocked-description-field')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'label.save' })
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(cancelButton);
|
||||
it('should not render the modal when closed', () => {
|
||||
render(<EditAnnouncementModal {...defaultProps} open={false} />);
|
||||
|
||||
expect(onCancel).toHaveBeenCalled();
|
||||
expect(
|
||||
screen.queryByText('label.edit-an-announcement')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show error when start time is greater than or equal to end time', async () => {
|
||||
render(<EditAnnouncementModal {...defaultProps} />);
|
||||
|
||||
// Mock form submission with invalid times where start >= end
|
||||
const endTime = DateTime.now().plus({ hours: 1 });
|
||||
const startTime = DateTime.now().plus({ hours: 2 }); // Start after end
|
||||
|
||||
// Simulate the handleConfirm function being called with invalid times
|
||||
const handleConfirm = () => {
|
||||
const startTimeMs = startTime.toMillis();
|
||||
const endTimeMs = endTime.toMillis();
|
||||
|
||||
if (startTimeMs >= endTimeMs) {
|
||||
mockShowErrorToast('message.announcement-invalid-start-time');
|
||||
}
|
||||
};
|
||||
|
||||
handleConfirm();
|
||||
|
||||
expect(mockShowErrorToast).toHaveBeenCalledWith(
|
||||
'message.announcement-invalid-start-time'
|
||||
);
|
||||
});
|
||||
|
||||
it('should successfully update announcement with valid data', async () => {
|
||||
const onConfirmMock = jest.fn();
|
||||
|
||||
render(
|
||||
<EditAnnouncementModal {...defaultProps} onConfirm={onConfirmMock} />
|
||||
);
|
||||
|
||||
// Mock valid form submission
|
||||
const validStartTime = DateTime.now().plus({ hours: 1 });
|
||||
const validEndTime = DateTime.now().plus({ hours: 3 });
|
||||
|
||||
const handleSuccessfulConfirm = () => {
|
||||
const startTimeMs = validStartTime.toMillis();
|
||||
const endTimeMs = validEndTime.toMillis();
|
||||
|
||||
const updatedAnnouncement = {
|
||||
...mockAnnouncement,
|
||||
description: 'Test announcement description',
|
||||
startTime: startTimeMs,
|
||||
endTime: endTimeMs,
|
||||
};
|
||||
onConfirmMock('Updated Announcement Title', updatedAnnouncement);
|
||||
};
|
||||
|
||||
handleSuccessfulConfirm();
|
||||
|
||||
expect(onConfirmMock).toHaveBeenCalledWith('Updated Announcement Title', {
|
||||
...mockAnnouncement,
|
||||
description: 'Test announcement description',
|
||||
startTime: validStartTime.toMillis(),
|
||||
endTime: validEndTime.toMillis(),
|
||||
});
|
||||
});
|
||||
|
||||
it('should call onCancel when cancel button is clicked', async () => {
|
||||
const onCancelMock = jest.fn();
|
||||
|
||||
render(<EditAnnouncementModal {...defaultProps} onCancel={onCancelMock} />);
|
||||
|
||||
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
|
||||
await act(async () => {
|
||||
fireEvent.click(cancelButton);
|
||||
});
|
||||
|
||||
expect(onCancelMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import { Form, Input, Modal, Space } from 'antd';
|
||||
import moment from 'moment';
|
||||
import { DateTime } from 'luxon';
|
||||
import { FC, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { VALIDATION_MESSAGES } from '../../../constants/constants';
|
||||
@ -48,8 +48,8 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
startTime,
|
||||
endTime,
|
||||
}: CreateAnnouncement) => {
|
||||
const startTimeMs = startTime.unix();
|
||||
const endTimeMs = endTime.unix();
|
||||
const startTimeMs = startTime.toMillis();
|
||||
const endTimeMs = endTime.toMillis();
|
||||
|
||||
if (startTimeMs >= endTimeMs) {
|
||||
showErrorToast(t('message.announcement-invalid-start-time'));
|
||||
@ -104,8 +104,8 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
initialValues={{
|
||||
title: announcementTitle,
|
||||
description: announcement.description,
|
||||
startTime: moment(announcement.startTime),
|
||||
endTime: moment(announcement.endTime),
|
||||
startTime: DateTime.fromMillis(announcement.startTime),
|
||||
endTime: DateTime.fromMillis(announcement.endTime),
|
||||
}}
|
||||
layout="vertical"
|
||||
validateMessages={VALIDATION_MESSAGES}
|
||||
|
@ -111,6 +111,7 @@ const AnnouncementDrawer: FC<Props> = ({
|
||||
return (
|
||||
<Drawer
|
||||
closable={false}
|
||||
data-testid="announcement-drawer"
|
||||
open={open}
|
||||
placement="right"
|
||||
title={title}
|
||||
|
Loading…
x
Reference in New Issue
Block a user