[MM-67905] Allow full Markdown rendering in message attachment footer (#35570)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ben Schumacher 2026-03-19 11:33:16 +01:00 committed by GitHub
parent aea8cbdc7a
commit b9aeb629be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 111 additions and 10 deletions

View file

@ -0,0 +1,94 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @incoming_webhook
describe('Integrations/Incoming Webhook', () => {
let incomingWebhook;
let testTeam;
let testChannel;
before(() => {
// # Create and visit new channel and create incoming webhook
cy.apiInitSetup().then(({team, channel}) => {
testTeam = team;
testChannel = channel;
const newIncomingHook = {
channel_id: channel.id,
channel_locked: true,
description: 'Incoming webhook - attachment footer markdown',
display_name: 'attachment-footer-markdown',
};
cy.apiCreateWebhook(newIncomingHook).then((hook) => {
incomingWebhook = hook;
});
});
});
beforeEach(() => {
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
});
it('MM-67905 Attachment footer renders bold and italic markdown', () => {
const payload = {
channel: testChannel.name,
attachments: [{
text: 'Attachment with markdown footer',
footer: 'Footer with **bold** and _italic_ text',
}],
};
cy.postIncomingWebhook({url: incomingWebhook.url, data: payload});
cy.getLastPost().within(() => {
cy.get('.attachment__footer-container').within(() => {
cy.get('strong').should('have.text', 'bold');
cy.get('em').should('have.text', 'italic');
});
});
});
it('MM-67905 Attachment footer renders links in markdown', () => {
const payload = {
channel: testChannel.name,
attachments: [{
text: 'Attachment with link in footer',
footer: 'Visit [Mattermost](https://mattermost.com) for more info',
}],
};
cy.postIncomingWebhook({url: incomingWebhook.url, data: payload});
cy.getLastPost().within(() => {
cy.get('.attachment__footer-container').within(() => {
cy.get('a.markdown__link[href="https://mattermost.com"]').should('have.text', 'Mattermost');
});
});
});
it('MM-67905 Attachment footer renders emoji in markdown', () => {
const payload = {
channel: testChannel.name,
attachments: [{
text: 'Attachment with emoji in footer',
footer: 'All good :white_check_mark:',
}],
};
cy.postIncomingWebhook({url: incomingWebhook.url, data: payload});
cy.getLastPost().within(() => {
cy.get('.attachment__footer-container').within(() => {
cy.get('span[data-emoticon="white_check_mark"]').should('exist');
});
});
});
});

View file

@ -97,9 +97,10 @@ exports[`components/post_view/MessageAttachment should call actions.doPostAction
>
<Component />
</Connect(Component)>
<span>
footer
</span>
<Connect(Markdown)
message="footer"
postId="post_id"
/>
</div>
<div>
<div
@ -245,9 +246,10 @@ exports[`components/post_view/MessageAttachment should match snapshot 1`] = `
>
<Component />
</Connect(Component)>
<span>
footer
</span>
<Connect(Markdown)
message="footer"
postId="post_id"
/>
</div>
</div>
<div
@ -578,9 +580,10 @@ exports[`components/post_view/MessageAttachment should match snapshot when the f
<div
className="attachment__footer-container"
>
<span>
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…
</span>
<Connect(Markdown)
message="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…"
postId="post_id"
/>
</div>
</div>
<div

View file

@ -545,7 +545,11 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
footer = (
<div className='attachment__footer-container'>
{footerIcon}
<span>{truncate(attachment.footer, {length: Constants.MAX_ATTACHMENT_FOOTER_LENGTH, omission: '…'})}</span>
<Markdown
message={truncate(attachment.footer, {length: Constants.MAX_ATTACHMENT_FOOTER_LENGTH, omission: '…'})}
options={options}
postId={this.props.postId}
/>
</div>
);
}