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

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

@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {screen} from '@testing-library/react'; import {screen, fireEvent} from '@testing-library/react';
import React from 'react'; import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties'; import type {UserPropertyField} from '@mattermost/types/properties';
@@ -12,6 +12,13 @@ import ProfilePopoverPhone from './profile_popover_phone';
import {TestHelper} from '../../utils/test_helper'; import {TestHelper} from '../../utils/test_helper';
// Mock window.open
const mockWindowOpen = jest.fn();
Object.defineProperty(window, 'open', {
writable: true,
value: mockWindowOpen,
});
describe('components/ProfilePopoverPhone', () => { describe('components/ProfilePopoverPhone', () => {
const attribute: UserPropertyField = { const attribute: UserPropertyField = {
id: 'phone_attribute_id', id: 'phone_attribute_id',
@@ -38,6 +45,10 @@ describe('components/ProfilePopoverPhone', () => {
}), }),
}; };
beforeEach(() => {
mockWindowOpen.mockClear();
});
test('should not render when phone is missing', () => { test('should not render when phone is missing', () => {
const props = { const props = {
...baseProps, ...baseProps,
@@ -46,8 +57,8 @@ describe('components/ProfilePopoverPhone', () => {
custom_profile_attributes: {}, custom_profile_attributes: {},
}), }),
}; };
renderWithContext(<ProfilePopoverPhone {...props}/>); const {container} = renderWithContext(<ProfilePopoverPhone {...props}/>);
expect(screen.queryByRole('link')).not.toBeInTheDocument(); expect(container.firstChild).toBeNull();
}); });
test('should not render when phone is empty', () => { test('should not render when phone is empty', () => {
@@ -60,17 +71,17 @@ describe('components/ProfilePopoverPhone', () => {
}, },
}), }),
}; };
renderWithContext(<ProfilePopoverPhone {...props}/>); const {container} = renderWithContext(<ProfilePopoverPhone {...props}/>);
expect(screen.queryByRole('link')).not.toBeInTheDocument(); expect(container.firstChild).toBeNull();
}); });
test('should render phone with icon', () => { test('should render phone with icon', () => {
renderWithContext(<ProfilePopoverPhone {...baseProps}/>); renderWithContext(<ProfilePopoverPhone {...baseProps}/>);
const phone = '+1 (555) 123-4567'; const phone = '+1 (555) 123-4567';
const link = screen.getByRole('link'); const phoneLink = screen.getByText(phone);
expect(link).toHaveAttribute('href', 'tel:+1 (555) 123-4567'); expect(phoneLink).toBeInTheDocument();
expect(link).toHaveTextContent(phone); expect(phoneLink.tagName).toBe('A');
expect(screen.getByTitle(phone)).toBeInTheDocument(); expect(screen.getByTitle(phone)).toBeInTheDocument();
expect(screen.getByLabelText('phone icon')).toBeInTheDocument(); expect(screen.getByLabelText('phone icon')).toBeInTheDocument();
}); });
@@ -88,8 +99,31 @@ describe('components/ProfilePopoverPhone', () => {
renderWithContext(<ProfilePopoverPhone {...props}/>); renderWithContext(<ProfilePopoverPhone {...props}/>);
const phone = '+44 20 7123 4567'; const phone = '+44 20 7123 4567';
const link = screen.getByRole('link'); const phoneLink = screen.getByText(phone);
expect(link).toHaveAttribute('href', 'tel:+44 20 7123 4567'); expect(phoneLink).toBeInTheDocument();
expect(link).toHaveTextContent(phone); 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; return null;
} }
function handlePhoneClick(e: React.MouseEvent<HTMLAnchorElement>) {
e.preventDefault();
window.open(`tel:${phone}`);
}
return ( return (
<div <div
title={phone} title={phone}
@@ -29,7 +34,8 @@ const ProfilePopoverPhone = ({attribute, userProfile}: Props) => {
aria-label='phone icon' aria-label='phone icon'
/> />
<a <a
href={'tel:' + phone} href={`tel:${phone}`}
onClick={handlePhoneClick}
> >
{phone} {phone}
</a> </a>