- Add a document details view that surfaces crawled content, source metadata, and generated FAQ counts. - Rename the document card action to open details and show the FAQ count inline in the list. - Return `responses_count` from the documents API efficiently and expose document content in the show payload. - Update related Captain copy to reflect the new details-oriented flow. **Preview** <img width="1640" height="1596" alt="CleanShot 2026-06-26 at 09 25 15@2x" src="https://github.com/user-attachments/assets/0c408fae-7d37-422a-8869-ece466292cb1" /> --------- Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com> Co-authored-by: Sony Mathew <sony@chatwoot.com> Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
169 lines
6.7 KiB
JavaScript
169 lines
6.7 KiB
JavaScript
import MessageFormatter from '../MessageFormatter';
|
|
|
|
describe('#MessageFormatter', () => {
|
|
describe('content with links', () => {
|
|
it('should format correctly', () => {
|
|
const message =
|
|
'Chatwoot is an opensource tool. [Chatwoot](https://www.chatwoot.com)';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
'<p>Chatwoot is an opensource tool. <a href="https://www.chatwoot.com" class="link" rel="noreferrer noopener nofollow" target="_blank">Chatwoot</a></p>'
|
|
);
|
|
});
|
|
it('should format correctly', () => {
|
|
const message =
|
|
'Chatwoot is an opensource tool. https://www.chatwoot.com';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
'<p>Chatwoot is an opensource tool. <a href="https://www.chatwoot.com" class="link" rel="noreferrer noopener nofollow" target="_blank">https://www.chatwoot.com</a></p>'
|
|
);
|
|
});
|
|
it('should not convert template variables to links when linkify is disabled', () => {
|
|
const message = 'Hey {{customer.name}}, check https://chatwoot.com';
|
|
const formatter = new MessageFormatter(message, false, false, false);
|
|
expect(formatter.formattedMessage).toMatch(
|
|
'<p>Hey {{customer.name}}, check https://chatwoot.com</p>'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('parses heading to strong', () => {
|
|
it('should format correctly', () => {
|
|
const message = '### opensource \n ## tool';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
`<h3>opensource</h3>
|
|
<h2>tool</h2>`
|
|
);
|
|
});
|
|
|
|
it('should not render a setext heading when text is followed by "--"', () => {
|
|
const message = 'hy\n\n\\\n\\-\\-\n\nHello there';
|
|
const result = new MessageFormatter(message).formattedMessage;
|
|
expect(result).not.toMatch('<h2>');
|
|
expect(result).not.toMatch('<h1>');
|
|
});
|
|
});
|
|
|
|
describe('content with image and has "cw_image_height" query at the end of URL', () => {
|
|
it('should set image height correctly', () => {
|
|
const message =
|
|
'Chatwoot is an opensource tool. ';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
'<p>Chatwoot is an opensource tool. <img src="http://chatwoot.com/chatwoot.png?cw_image_height=24px" alt="" style="height: 24px;" /></p>'
|
|
);
|
|
});
|
|
|
|
it('should set image height correctly if its original size', () => {
|
|
const message =
|
|
'Chatwoot is an opensource tool. ';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
'<p>Chatwoot is an opensource tool. <img src="http://chatwoot.com/chatwoot.png?cw_image_height=auto" alt="" style="height: auto;" /></p>'
|
|
);
|
|
});
|
|
|
|
it('should not set height', () => {
|
|
const message =
|
|
'Chatwoot is an opensource tool. ';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
'<p>Chatwoot is an opensource tool. <img src="http://chatwoot.com/chatwoot.png" alt="" /></p>'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('#disableImageRendering', () => {
|
|
it('omits nested and reference images with relative URLs', () => {
|
|
const message = `Before ![nested [alt]](/relative.png)
|
|
|
|
![reference][logo]
|
|
|
|
[logo]: /logo.png
|
|
|
|
After`;
|
|
const formatter = new MessageFormatter(message);
|
|
|
|
formatter.disableImageRendering();
|
|
|
|
expect(formatter.formattedMessage).not.toContain('<img');
|
|
expect(formatter.formattedMessage).toContain('Before');
|
|
expect(formatter.formattedMessage).toContain('After');
|
|
});
|
|
});
|
|
|
|
describe('tweets', () => {
|
|
it('should return the same string if not tags or @mentions', () => {
|
|
const message = 'Chatwoot is an opensource tool';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(message);
|
|
});
|
|
|
|
it('should add links to @mentions', () => {
|
|
const message =
|
|
'@chatwootapp is an opensource tool thanks @longnonexistenttwitterusername';
|
|
expect(
|
|
new MessageFormatter(message, true, false).formattedMessage
|
|
).toMatch(
|
|
'<p><a href="http://twitter.com/chatwootapp" class="link" rel="noreferrer noopener nofollow" target="_blank">@chatwootapp</a> is an opensource tool thanks @longnonexistenttwitterusername</p>'
|
|
);
|
|
});
|
|
|
|
it('should add links to #tags', () => {
|
|
const message = '#chatwootapp is an opensource tool';
|
|
expect(
|
|
new MessageFormatter(message, true, false).formattedMessage
|
|
).toMatch(
|
|
'<p><a href="https://twitter.com/hashtag/chatwootapp" class="link" rel="noreferrer noopener nofollow" target="_blank">#chatwootapp</a> is an opensource tool</p>'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('private notes', () => {
|
|
it('should return the same string if not tags or @mentions', () => {
|
|
const message = 'Chatwoot is an opensource tool';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(message);
|
|
});
|
|
|
|
it('should add links to @mentions', () => {
|
|
const message =
|
|
'@chatwootapp is an opensource tool thanks @longnonexistenttwitterusername';
|
|
expect(
|
|
new MessageFormatter(message, false, true).formattedMessage
|
|
).toMatch(message);
|
|
});
|
|
|
|
it('should add links to #tags', () => {
|
|
const message = '#chatwootapp is an opensource tool';
|
|
expect(
|
|
new MessageFormatter(message, false, true).formattedMessage
|
|
).toMatch(message);
|
|
});
|
|
});
|
|
|
|
describe('plain text content', () => {
|
|
it('returns the plain text without HTML', () => {
|
|
const message =
|
|
'<b>Chatwoot is an opensource tool. https://www.chatwoot.com</b>';
|
|
expect(new MessageFormatter(message).plainText).toMatch(
|
|
'Chatwoot is an opensource tool. https://www.chatwoot.com'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('help center table colwidth marker', () => {
|
|
it('strips the internal colwidths marker from rendered output', () => {
|
|
const message =
|
|
'<!--cw-colwidths:120,200-->\n| A | B |\n| --- | --- |\n| 1 | 2 |';
|
|
const formatter = new MessageFormatter(message);
|
|
expect(formatter.formattedMessage).not.toContain('cw-colwidths');
|
|
expect(formatter.plainText).not.toContain('cw-colwidths');
|
|
});
|
|
});
|
|
|
|
describe('#sanitize', () => {
|
|
it('sanitizes markup and removes all unnecessary elements', () => {
|
|
const message =
|
|
'[xssLink](javascript:alert(document.cookie))\n[normalLink](https://google.com)**I am a bold text paragraph**';
|
|
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
|
`<p>[xssLink](javascript:alert(document.cookie))<br />
|
|
<a href="https://google.com" class="link" rel="noreferrer noopener nofollow" target="_blank">normalLink</a><strong>I am a bold text paragraph</strong></p>`
|
|
);
|
|
});
|
|
});
|
|
});
|