[MM-59296] Can't open web client on iOS Safari (#27607)

Этот коммит содержится в:
M-ZubairAhmed
2024-07-18 10:39:16 +00:00
коммит произвёл GitHub
родитель db138fd23a
Коммит 1ff54a31bc
5 изменённых файлов: 173 добавлений и 22 удалений

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

@@ -0,0 +1,78 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor} from '@testing-library/react';
import React from 'react';
import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import {requestNotificationPermission, isNotificationAPISupported} from 'utils/notifications';
import NotificationPermissionBar from './index';
jest.mock('utils/notifications', () => ({
requestNotificationPermission: jest.fn(),
isNotificationAPISupported: jest.fn(),
}));
describe('NotificationPermissionBar', () => {
const initialState = {
entities: {
users: {
currentUserId: 'user-id',
},
general: {
config: {},
license: {},
},
},
};
beforeEach(() => {
(isNotificationAPISupported as jest.Mock).mockReturnValue(true);
(window as any).Notification = {permission: 'default'};
});
afterEach(() => {
jest.clearAllMocks();
delete (window as any).Notification;
});
test('should render the notification bar when conditions are met', () => {
renderWithContext(<NotificationPermissionBar/>, initialState);
expect(screen.getByText('We need your permission to show desktop notifications.')).toBeInTheDocument();
expect(screen.getByText('Enable notifications')).toBeInTheDocument();
});
test('should not render the notification bar if user is not logged in', () => {
renderWithContext(<NotificationPermissionBar/>);
expect(screen.queryByText('We need your permission to show desktop notifications.')).not.toBeInTheDocument();
expect(screen.queryByText('Enable notifications')).not.toBeInTheDocument();
});
test('should not render the notification bar if Notifications are not supported', () => {
delete (window as any).Notification;
(isNotificationAPISupported as jest.Mock).mockReturnValue(false);
renderWithContext(<NotificationPermissionBar/>, initialState);
expect(screen.queryByText('We need your permission to show desktop notifications.')).not.toBeInTheDocument();
expect(screen.queryByText('Enable notifications')).not.toBeInTheDocument();
});
test('should call requestNotificationPermission and hide the bar when the button is clicked', async () => {
(requestNotificationPermission as jest.Mock).mockResolvedValue('granted');
renderWithContext(<NotificationPermissionBar/>, initialState);
expect(screen.getByText('We need your permission to show desktop notifications.')).toBeInTheDocument();
await waitFor(async () => {
userEvent.click(screen.getByText('Enable notifications'));
});
expect(requestNotificationPermission).toHaveBeenCalled();
expect(screen.queryByText('We need your permission to show desktop notifications.')).not.toBeInTheDocument();
});
});

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

@@ -10,25 +10,25 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar';
import {AnnouncementBarTypes} from 'utils/constants';
import {requestNotificationPermission, isNotificationAPISupported} from 'utils/notifications';
export default function NotificationPermissionBar() {
const isLoggedIn = Boolean(useSelector(getCurrentUserId));
const [show, setShow] = useState(Notification.permission === 'default');
const [show, setShow] = useState(isNotificationAPISupported() ? Notification.permission === 'default' : false);
const handleClose = useCallback(() => {
// If the user closes the bar, don't show the notification bar any more for the rest of the session, but
// show it again after refresh.
const handleClick = useCallback(async () => {
await requestNotificationPermission();
setShow(false);
}, []);
const handleClick = useCallback(() => {
Notification.requestPermission().then(() => {
setShow(false);
});
const handleClose = useCallback(() => {
// If the user closes the bar, don't show the notification bar any more for the rest of the session, but
// show it again on app refresh.
setShow(false);
}, []);
if (!show || !isLoggedIn) {
if (!show || !isLoggedIn || !isNotificationAPISupported()) {
return null;
}
@@ -39,7 +39,7 @@ export default function NotificationPermissionBar() {
type={AnnouncementBarTypes.ANNOUNCEMENT}
message={
<FormattedMessage
id='announcement_bar.notification.needs_permisson'
id='announcement_bar.notification.needs_permission'
defaultMessage='We need your permission to show desktop notifications.'
/>
}

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

@@ -2814,7 +2814,7 @@
"announcement_bar.error.trial_license_expiring_last_day.short": "This is the last day of your free trial.",
"announcement_bar.notification.email_verified": "Email verified",
"announcement_bar.notification.enable_notifications": "Enable notifications",
"announcement_bar.notification.needs_permisson": "We need your permission to show desktop notifications.",
"announcement_bar.notification.needs_permission": "We need your permission to show desktop notifications.",
"announcement_bar.warn.contact_support_text": "To renew your license, contact support at support@mattermost.com.",
"announcement_bar.warn.email_support": "[Contact support](!{email}).",
"announcement_bar.warn.no_internet_connection": "Looks like you do not have access to the internet.",

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

@@ -3,11 +3,10 @@
/* eslint-disable global-require */
// to enable being a typescript file
export const a = '';
import configureStore from 'tests/test_store';
import type {showNotification} from './notifications';
import {isNotificationAPISupported, requestNotificationPermission} from './notifications';
declare global {
interface Window {
@@ -39,20 +38,20 @@ describe('Notifications.showNotification', () => {
it('should throw an exception if Notification is not defined on window', async () => {
delete window.Notification;
await expect(store.dispatch(Notifications.showNotification())).rejects.toThrow('Notification not supported');
await expect(store.dispatch(Notifications.showNotification())).rejects.toThrow('Notification API is not supported');
});
it('should throw an exception if Notification.requestPermission is not defined', async () => {
window.Notification = jest.fn();
await expect(store.dispatch(Notifications.showNotification())).rejects.toThrow('Notification.requestPermission not supported');
await expect(store.dispatch(Notifications.showNotification())).rejects.toThrow('Notification API is not supported');
});
it('should throw an exception if Notification.requestPermission is not a function', async () => {
window.Notification = jest.fn();
window.Notification.requestPermission = true;
await expect(store.dispatch(Notifications.showNotification())).rejects.toThrow('Notification.requestPermission not supported');
await expect(store.dispatch(Notifications.showNotification())).rejects.toThrow('Notification API is not supported');
expect(window.Notification).not.toHaveBeenCalled();
});
@@ -241,3 +240,64 @@ describe('Notifications.showNotification', () => {
expect(window.Notification.requestPermission).toHaveBeenCalledTimes(0);
});
});
describe('Notifications.isNotificationAPISupported', () => {
beforeEach(() => {
window.Notification = {
requestPermission: jest.fn(),
};
});
afterEach(() => {
delete (window as any).Notification;
});
it('should return true if Notification is supported', () => {
expect(isNotificationAPISupported()).toBe(true);
});
it('should return false if Notification is not supported', () => {
delete (window as any).Notification;
expect(isNotificationAPISupported()).toBe(false);
});
it('should return false if requestPermission is not a function', () => {
(window as any).Notification = {};
expect(isNotificationAPISupported()).toBe(false);
});
});
describe('Notifications.requestNotificationPermission', () => {
beforeEach(() => {
(window as any).Notification = {
requestPermission: jest.fn(),
};
});
afterEach(() => {
delete (window as any).Notification;
});
it('should return the permission if Notification.requestPermission resolves', async () => {
(window as any).Notification.requestPermission = jest.fn().mockResolvedValue('granted');
const permission = await requestNotificationPermission();
expect(permission).toBe('granted');
});
it('should return null if Notification is not supported', async () => {
delete (window as any).Notification;
const permission = await requestNotificationPermission();
expect(permission).toBeNull();
});
it('should return null if requestPermission throws an error', async () => {
(window as any).Notification.requestPermission = jest.fn().mockRejectedValue('some error');
const permission = await requestNotificationPermission();
expect(permission).toBeNull();
});
});

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

@@ -50,12 +50,8 @@ export function showNotification(
icon = iconWS;
}
if (!('Notification' in window)) {
throw new Error('Notification not supported');
}
if (typeof Notification.requestPermission !== 'function') {
throw new Error('Notification.requestPermission not supported');
if (!isNotificationAPISupported()) {
throw new Error('Notification API is not supported');
}
if (Notification.permission !== 'granted') {
@@ -104,3 +100,20 @@ export function showNotification(
};
};
}
export function isNotificationAPISupported() {
return ('Notification' in window) && (typeof Notification.requestPermission === 'function');
}
export async function requestNotificationPermission() {
if (!isNotificationAPISupported()) {
return null;
}
try {
const notificationPermission = await Notification.requestPermission();
return notificationPermission;
} catch (error) {
return null;
}
}