[MM-63534] Show errors from Support Packet generation in System Console (#30535)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
4118a0f612
Коммит
8ce78c302d
@@ -60,22 +60,6 @@ exports[`components/CommercialSupportModal should match snapshot 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
<AlertBanner
|
||||
message={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Before downloading the Support Packet, set <strong>Output Logs to File</strong> to <strong>true</strong> and set <strong>File Log Level</strong> to <strong>DEBUG</strong> <debugLink>here</debugLink>."
|
||||
id="commercial_support_modal.warning.banner"
|
||||
values={
|
||||
Object {
|
||||
"debugLink": [Function],
|
||||
"strong": [Function],
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
mode="info"
|
||||
onDismiss={[Function]}
|
||||
/>
|
||||
<div
|
||||
className="CommercialSupportModal__packet_contents_download"
|
||||
>
|
||||
@@ -86,6 +70,26 @@ exports[`components/CommercialSupportModal should match snapshot 1`] = `
|
||||
/>
|
||||
</strong>
|
||||
</div>
|
||||
<div
|
||||
className="CommercialSupportModal__option"
|
||||
key="basic.server.logs"
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
className="CommercialSupportModal__options__checkbox"
|
||||
disabled={true}
|
||||
id="basic.server.logs"
|
||||
name="basic.server.logs"
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
/>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Server Logs"
|
||||
id="mettormost.plugin.metrics.support.packet"
|
||||
>
|
||||
<Component />
|
||||
</MemoizedFormattedMessage>
|
||||
</div>
|
||||
<div
|
||||
className="CommercialSupportModal__download"
|
||||
>
|
||||
|
||||
@@ -24,3 +24,13 @@
|
||||
font-family: Metropolis, sans-serif;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.CommercialSupportModal__error {
|
||||
margin-top: 12px;
|
||||
|
||||
.error-text {
|
||||
display: inline-block;
|
||||
color: var(--error-text);
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,94 @@
|
||||
import {shallow} from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import CommercialSupportModal from 'components/commercial_support_modal/commercial_support_modal';
|
||||
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
describe('components/CommercialSupportModal', () => {
|
||||
beforeAll(() => {
|
||||
// Mock getSystemRoute to return a valid URL
|
||||
jest.spyOn(Client4, 'getSystemRoute').mockImplementation(() => 'http://localhost:8065/api/v4/system');
|
||||
|
||||
// Mock createObjectURL
|
||||
window.URL.createObjectURL = jest.fn().mockReturnValue('mock-url');
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks();
|
||||
|
||||
// @ts-expect-error - TS doesn't like deleting built-in methods
|
||||
delete window.URL.createObjectURL;
|
||||
});
|
||||
|
||||
const baseProps = {
|
||||
onExited: jest.fn(),
|
||||
showBannerWarning: false,
|
||||
isCloud: false,
|
||||
currentUser: TestHelper.getUserMock(),
|
||||
packetContents: [
|
||||
{id: 'basic.server.logs', label: 'Server Logs', selected: true, mandatory: true},
|
||||
],
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const mockUser = TestHelper.getUserMock();
|
||||
const wrapper = shallow(
|
||||
<CommercialSupportModal
|
||||
onExited={jest.fn()}
|
||||
showBannerWarning={true}
|
||||
isCloud={false}
|
||||
currentUser={mockUser}
|
||||
packetContents={[]}
|
||||
/>,
|
||||
);
|
||||
const wrapper = shallow(<CommercialSupportModal {...baseProps}/>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should show error message when download fails', async () => {
|
||||
const errorMessage = 'Failed to download';
|
||||
const detailedError = 'Permission denied';
|
||||
|
||||
// Mock the fetch call to return an error
|
||||
global.fetch = jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
json: () => Promise.resolve({
|
||||
message: errorMessage,
|
||||
detailed_error: detailedError,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
const wrapper = shallow<CommercialSupportModal>(<CommercialSupportModal {...baseProps}/>);
|
||||
|
||||
// Trigger download
|
||||
const instance = wrapper.instance();
|
||||
await instance.downloadSupportPacket();
|
||||
wrapper.update();
|
||||
|
||||
// Verify error message is shown
|
||||
const errorDiv = wrapper.find('.CommercialSupportModal__error');
|
||||
expect(errorDiv.exists()).toBe(true);
|
||||
expect(errorDiv.find('.error-text').text()).toBe(`${errorMessage}: ${detailedError}`);
|
||||
|
||||
// Verify loading state is reset
|
||||
expect(wrapper.state('loading')).toBe(false);
|
||||
});
|
||||
|
||||
test('should clear error when starting new download', async () => {
|
||||
// Mock the fetch call to succeed
|
||||
global.fetch = jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
blob: () => Promise.resolve(new Blob()),
|
||||
headers: {get: () => null},
|
||||
}),
|
||||
);
|
||||
|
||||
const wrapper = shallow<CommercialSupportModal>(<CommercialSupportModal {...baseProps}/>);
|
||||
|
||||
// Set initial error state
|
||||
wrapper.setState({error: 'Previous error'});
|
||||
|
||||
// Start download
|
||||
const instance = wrapper.instance();
|
||||
await instance.downloadSupportPacket();
|
||||
|
||||
// Verify error is cleared
|
||||
expect(wrapper.state('error')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,6 +39,7 @@ type State = {
|
||||
showBannerWarning: boolean;
|
||||
packetContents: SupportPacketContent[];
|
||||
loading: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export default class CommercialSupportModal extends React.PureComponent<Props, State> {
|
||||
@@ -106,11 +107,18 @@ export default class CommercialSupportModal extends React.PureComponent<Props, S
|
||||
};
|
||||
|
||||
downloadSupportPacket = async () => {
|
||||
this.setState({loading: true});
|
||||
this.setState({loading: true, error: undefined});
|
||||
const res = await fetch(this.genereateDownloadURLWithParams(), {
|
||||
method: 'GET',
|
||||
headers: {'Content-Type': 'application/zip'},
|
||||
});
|
||||
if (!res.ok) {
|
||||
const data = await res.json();
|
||||
const error = data.message + ': ' + data.detailed_error;
|
||||
this.setState({loading: false, error});
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = await res.blob();
|
||||
this.setState({loading: false});
|
||||
|
||||
@@ -214,6 +222,11 @@ export default class CommercialSupportModal extends React.PureComponent<Props, S
|
||||
</div>
|
||||
))}
|
||||
<div className='CommercialSupportModal__download'>
|
||||
{this.state.error && (
|
||||
<div className='CommercialSupportModal__error'>
|
||||
<span className='error-text'>{this.state.error}</span>
|
||||
</div>
|
||||
)}
|
||||
<a
|
||||
className='btn btn-primary DownloadSupportPacket'
|
||||
onClick={this.downloadSupportPacket}
|
||||
|
||||
Ссылка в новой задаче
Block a user