[MM-64371] Prevent WS being closed by browser due to navigation (#31367)

* prevent ws being closed by browser due to navigation

* add href back

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2025-07-10 11:30:54 +02:00
коммит произвёл GitHub
родитель e2b6e807c4
Коммит 254f641182
4 изменённых файлов: 132 добавлений и 13 удалений

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

@@ -0,0 +1,73 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import ProfilePopoverEmail from './profile_popover_email';
// Mock window.open
const mockWindowOpen = jest.fn();
Object.defineProperty(window, 'open', {
writable: true,
value: mockWindowOpen,
});
describe('components/ProfilePopoverEmail', () => {
const baseProps = {
email: 'test@example.com',
haveOverrideProp: false,
isBot: false,
};
beforeEach(() => {
mockWindowOpen.mockClear();
});
test('should not render when email is empty', () => {
const props = {
...baseProps,
email: '',
};
const {container} = renderWithContext(<ProfilePopoverEmail {...props}/>);
expect(container.firstChild).toBeNull();
});
test('should handle different email formats', () => {
const props = {
...baseProps,
email: 'user.name+tag@domain.co.uk',
};
renderWithContext(<ProfilePopoverEmail {...props}/>);
const email = 'user.name+tag@domain.co.uk';
const emailLink = screen.getByText(email);
expect(emailLink).toBeInTheDocument();
expect(emailLink.tagName).toBe('A');
});
test('should open email client when clicked', () => {
renderWithContext(<ProfilePopoverEmail {...baseProps}/>);
const email = 'test@example.com';
const emailLink = screen.getByText(email);
fireEvent.click(emailLink);
expect(mockWindowOpen).toHaveBeenCalledWith('mailto:test@example.com');
});
test('should prevent default click behavior', () => {
renderWithContext(<ProfilePopoverEmail {...baseProps}/>);
const email = 'test@example.com';
const emailLink = screen.getByText(email);
const clickEvent = fireEvent.click(emailLink);
expect(clickEvent).toBe(false); // fireEvent.click returns false when preventDefault was called
expect(mockWindowOpen).toHaveBeenCalledWith('mailto:test@example.com');
});
});

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

@@ -17,6 +17,11 @@ const ProfilePopoverEmail = ({
return null;
}
function handleEmailClick(e: React.MouseEvent<HTMLAnchorElement>) {
e.preventDefault();
window.open(`mailto:${email}`);
}
return (
<div
title={email}
@@ -28,7 +33,8 @@ const ProfilePopoverEmail = ({
aria-hidden='true'
/>
<a
href={'mailto:' + email}
href={`mailto:${email}`}
onClick={handleEmailClick}
>
{email}
</a>

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

@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen} from '@testing-library/react';
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties';
@@ -12,6 +12,13 @@ import ProfilePopoverPhone from './profile_popover_phone';
import {TestHelper} from '../../utils/test_helper';
// Mock window.open
const mockWindowOpen = jest.fn();
Object.defineProperty(window, 'open', {
writable: true,
value: mockWindowOpen,
});
describe('components/ProfilePopoverPhone', () => {
const attribute: UserPropertyField = {
id: 'phone_attribute_id',
@@ -38,6 +45,10 @@ describe('components/ProfilePopoverPhone', () => {
}),
};
beforeEach(() => {
mockWindowOpen.mockClear();
});
test('should not render when phone is missing', () => {
const props = {
...baseProps,
@@ -46,8 +57,8 @@ describe('components/ProfilePopoverPhone', () => {
custom_profile_attributes: {},
}),
};
renderWithContext(<ProfilePopoverPhone {...props}/>);
expect(screen.queryByRole('link')).not.toBeInTheDocument();
const {container} = renderWithContext(<ProfilePopoverPhone {...props}/>);
expect(container.firstChild).toBeNull();
});
test('should not render when phone is empty', () => {
@@ -60,17 +71,17 @@ describe('components/ProfilePopoverPhone', () => {
},
}),
};
renderWithContext(<ProfilePopoverPhone {...props}/>);
expect(screen.queryByRole('link')).not.toBeInTheDocument();
const {container} = renderWithContext(<ProfilePopoverPhone {...props}/>);
expect(container.firstChild).toBeNull();
});
test('should render phone with icon', () => {
renderWithContext(<ProfilePopoverPhone {...baseProps}/>);
const phone = '+1 (555) 123-4567';
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', 'tel:+1 (555) 123-4567');
expect(link).toHaveTextContent(phone);
const phoneLink = screen.getByText(phone);
expect(phoneLink).toBeInTheDocument();
expect(phoneLink.tagName).toBe('A');
expect(screen.getByTitle(phone)).toBeInTheDocument();
expect(screen.getByLabelText('phone icon')).toBeInTheDocument();
});
@@ -88,8 +99,31 @@ describe('components/ProfilePopoverPhone', () => {
renderWithContext(<ProfilePopoverPhone {...props}/>);
const phone = '+44 20 7123 4567';
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', 'tel:+44 20 7123 4567');
expect(link).toHaveTextContent(phone);
const phoneLink = screen.getByText(phone);
expect(phoneLink).toBeInTheDocument();
expect(phoneLink.tagName).toBe('A');
});
test('should open phone dialer when clicked', () => {
renderWithContext(<ProfilePopoverPhone {...baseProps}/>);
const phone = '+1 (555) 123-4567';
const phoneLink = screen.getByText(phone);
fireEvent.click(phoneLink);
expect(mockWindowOpen).toHaveBeenCalledWith('tel:+1 (555) 123-4567');
});
test('should prevent default click behavior', () => {
renderWithContext(<ProfilePopoverPhone {...baseProps}/>);
const phone = '+1 (555) 123-4567';
const phoneLink = screen.getByText(phone);
const clickEvent = fireEvent.click(phoneLink);
expect(clickEvent).toBe(false); // fireEvent.click returns false when preventDefault was called
expect(mockWindowOpen).toHaveBeenCalledWith('tel:+1 (555) 123-4567');
});
});

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

@@ -18,6 +18,11 @@ const ProfilePopoverPhone = ({attribute, userProfile}: Props) => {
return null;
}
function handlePhoneClick(e: React.MouseEvent<HTMLAnchorElement>) {
e.preventDefault();
window.open(`tel:${phone}`);
}
return (
<div
title={phone}
@@ -29,7 +34,8 @@ const ProfilePopoverPhone = ({attribute, userProfile}: Props) => {
aria-label='phone icon'
/>
<a
href={'tel:' + phone}
href={`tel:${phone}`}
onClick={handlePhoneClick}
>
{phone}
</a>