2020-08-01 03:43:15 +02:00
"use strict" ;
2020-11-30 23:46:45 +01:00
const { strict : assert } = require ( "assert" ) ;
2021-06-08 04:14:11 +02:00
const markdown _test _cases = require ( "../../zerver/tests/fixtures/markdown_test_cases" ) ;
2023-02-22 23:04:10 +01:00
const markdown _assert = require ( "./lib/markdown_assert" ) ;
2023-12-07 11:41:37 +01:00
const { mock _esm , set _global , zrequire } = require ( "./lib/namespace" ) ;
2023-02-22 23:04:10 +01:00
const { run _test } = require ( "./lib/test" ) ;
const { page _params , user _settings } = require ( "./lib/zpage_params" ) ;
2020-12-01 00:02:16 +01:00
2021-03-30 12:51:54 +02:00
const example _realm _linkifiers = [
{
pattern : "#(?P<id>[0-9]{2,8})" ,
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
url _template : "https://trac.example.com/ticket/{id}" ,
2021-03-30 12:51:54 +02:00
id : 1 ,
} ,
{
pattern : "ZBUG_(?P<id>[0-9]{2,8})" ,
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
url _template : "https://trac2.zulip.net/ticket/{id}" ,
2021-03-30 12:51:54 +02:00
id : 2 ,
} ,
{
pattern : "ZGROUP_(?P<id>[0-9]{2,8}):(?P<zone>[0-9]{1,8})" ,
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
url _template : "https://zone_{zone}.zulip.net/ticket/{id}" ,
2021-03-30 12:51:54 +02:00
id : 3 ,
} ,
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
{
// For example, this linkifier matches:
// FOO_abcde;e;zulip;luxembourg;foo;23;testing
// which expands to:
// https://zone_e.zulip.net/ticket/luxembourg/abcde?name=foo&chapter=23#testi
// This exercises different URL template supported syntax.
pattern :
"FOO_(?P<id>[a-f]{5});(?P<zone>[a-f]);(?P<domain>[a-z]+);(?P<location>[a-z]+);(?P<name>[a-z]{2,8});(?P<chapter>[0-9]{2,3});(?P<fragment>[a-z]{2,8})" ,
url _template :
"https://zone_{zone}{.domain}.net/ticket{/location}{/id}{?name,chapter}{#fragment:5}" ,
id : 4 ,
} ,
2021-03-25 22:35:45 +01:00
] ;
2021-07-28 16:00:58 +02:00
user _settings . translate _emoticons = false ;
2020-07-15 01:29:15 +02:00
2021-05-20 01:15:35 +02:00
set _global ( "document" , { compatMode : "CSS1Compat" } ) ;
2020-12-01 23:21:38 +01:00
2023-12-07 11:41:37 +01:00
mock _esm ( "../src/settings_data" , {
user _can _access _all _other _users : ( ) => false ,
} ) ;
2022-03-25 14:47:51 +01:00
const emoji = zrequire ( "emoji" ) ;
2023-02-22 23:03:47 +01:00
const emoji _codes = zrequire ( "../../static/generated/emoji/emoji_codes.json" ) ;
2021-05-19 06:18:23 +02:00
const linkifiers = zrequire ( "linkifiers" ) ;
2023-02-22 23:03:47 +01:00
const fenced _code = zrequire ( "../shared/src/fenced_code" ) ;
2020-07-15 01:29:15 +02:00
const markdown _config = zrequire ( "markdown_config" ) ;
2021-02-10 04:53:22 +01:00
const markdown = zrequire ( "markdown" ) ;
2020-08-20 21:24:06 +02:00
const people = zrequire ( "people" ) ;
2024-01-13 21:01:07 +01:00
const pygments _data = zrequire ( "pygments_data" ) ;
2021-02-10 04:53:22 +01:00
const stream _data = zrequire ( "stream_data" ) ;
const user _groups = zrequire ( "user_groups" ) ;
2020-07-15 01:29:15 +02:00
2020-07-24 01:21:48 +02:00
const emoji _params = {
2016-10-30 20:54:53 +01:00
realm _emoji : {
2020-07-15 00:34:28 +02:00
1 : {
id : 1 ,
2020-07-15 01:29:15 +02:00
name : "burrito" ,
source _url : "/static/generated/emoji/images/emoji/burrito.png" ,
2018-03-11 18:55:20 +01:00
deactivated : false ,
} ,
2016-10-30 20:54:53 +01:00
} ,
2020-07-25 23:59:49 +02:00
emoji _codes ,
2020-07-24 01:21:48 +02:00
} ;
emoji . initialize ( emoji _params ) ;
2020-09-26 06:02:29 +02:00
fenced _code . initialize ( pygments _data ) ;
2017-08-16 22:00:19 +02:00
2019-11-02 00:06:25 +01:00
const cordelia = {
2021-04-11 16:26:54 +02:00
full _name : "Cordelia, Lear's daughter" ,
2016-10-30 20:58:28 +01:00
user _id : 101 ,
2020-07-15 01:29:15 +02:00
email : "cordelia@zulip.com" ,
2017-01-24 01:51:58 +01:00
} ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( cordelia ) ;
2014-01-04 01:18:30 +01:00
2020-05-26 22:34:15 +02:00
people . add _active _user ( {
2020-07-15 01:29:15 +02:00
full _name : "Leo" ,
2017-01-24 00:44:08 +01:00
user _id : 102 ,
2020-07-15 01:29:15 +02:00
email : "leo@zulip.com" ,
2017-01-24 00:44:08 +01:00
} ) ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( {
2020-07-15 01:29:15 +02:00
full _name : "Bobby <h1>Tables</h1>" ,
2018-03-29 00:25:58 +02:00
user _id : 103 ,
2020-07-15 01:29:15 +02:00
email : "bobby@zulip.com" ,
2018-03-29 00:25:58 +02:00
} ) ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( {
2020-07-15 01:29:15 +02:00
full _name : "Mark Twin" ,
2018-08-19 03:39:57 +02:00
user _id : 104 ,
2020-07-15 01:29:15 +02:00
email : "twin1@zulip.com" ,
2018-08-19 03:39:57 +02:00
} ) ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( {
2020-07-15 01:29:15 +02:00
full _name : "Mark Twin" ,
2018-08-19 03:39:57 +02:00
user _id : 105 ,
2020-07-15 01:29:15 +02:00
email : "twin2@zulip.com" ,
2018-08-19 03:39:57 +02:00
} ) ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( {
2020-07-15 01:29:15 +02:00
full _name : "Brother of Bobby|123" ,
2018-08-19 03:39:57 +02:00
user _id : 106 ,
2020-07-15 01:29:15 +02:00
email : "bobby2@zulip.com" ,
2018-08-19 03:39:57 +02:00
} ) ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( {
2019-12-13 01:38:49 +01:00
full _name : "& & &" ,
user _id : 107 ,
email : "ampampamp@zulip.com" ,
} ) ;
2024-06-12 17:13:34 +02:00
people . add _active _user ( {
full _name : "Zoe" ,
user _id : 7 ,
email : "zoe@zulip.com" ,
} ) ;
2023-12-07 11:41:37 +01:00
people . add _inaccessible _user ( 108 ) ;
2017-01-24 01:51:58 +01:00
people . initialize _current _user ( cordelia . user _id ) ;
2017-01-24 00:44:08 +01:00
2019-11-02 00:06:25 +01:00
const hamletcharacters = {
2017-11-22 09:11:07 +01:00
name : "hamletcharacters" ,
id : 1 ,
description : "Characters of Hamlet" ,
members : [ cordelia . user _id ] ,
} ;
2019-11-02 00:06:25 +01:00
const backend = {
2017-11-22 09:11:07 +01:00
name : "Backend" ,
id : 2 ,
description : "Backend team" ,
members : [ ] ,
} ;
2019-11-02 00:06:25 +01:00
const edgecase _group = {
2018-03-29 00:25:58 +02:00
name : "Bobby <h1>Tables</h1>" ,
id : 3 ,
2021-05-10 07:02:14 +02:00
description : "HTML syntax to check for Markdown edge cases." ,
2018-03-29 00:25:58 +02:00
members : [ ] ,
} ;
2019-12-13 01:38:49 +01:00
const amp _group = {
name : "& & &" ,
id : 4 ,
description : "Check ampersand escaping" ,
members : [ ] ,
} ;
2020-12-01 00:57:57 +01:00
user _groups . add ( hamletcharacters ) ;
user _groups . add ( backend ) ;
user _groups . add ( edgecase _group ) ;
user _groups . add ( amp _group ) ;
2017-11-22 09:11:07 +01:00
2019-11-02 00:06:25 +01:00
const denmark = {
2016-11-10 20:20:40 +01:00
subscribed : false ,
2020-07-15 01:29:15 +02:00
color : "blue" ,
name : "Denmark" ,
2016-11-10 20:20:40 +01:00
stream _id : 1 ,
2019-05-15 08:54:25 +02:00
is _muted : true ,
2016-11-10 20:20:40 +01:00
} ;
2019-11-02 00:06:25 +01:00
const social = {
2016-11-10 20:20:40 +01:00
subscribed : true ,
2020-07-15 01:29:15 +02:00
color : "red" ,
name : "social" ,
2016-11-10 20:20:40 +01:00
stream _id : 2 ,
2019-05-15 08:54:25 +02:00
is _muted : false ,
2016-12-03 23:17:57 +01:00
invite _only : true ,
2016-11-10 20:20:40 +01:00
} ;
2019-11-02 00:06:25 +01:00
const edgecase _stream = {
2018-03-29 00:25:58 +02:00
subscribed : true ,
2020-07-15 01:29:15 +02:00
color : "green" ,
name : "Bobby <h1>Tables</h1>" ,
2018-03-29 00:25:58 +02:00
stream _id : 3 ,
2019-05-15 08:54:25 +02:00
is _muted : false ,
2018-03-29 00:25:58 +02:00
} ;
2019-11-02 00:06:25 +01:00
const edgecase _stream _2 = {
2019-06-21 20:47:09 +02:00
subscribed : true ,
2020-07-15 01:29:15 +02:00
color : "yellow" ,
name : "Bobby <h1" ,
2019-06-21 20:47:09 +02:00
stream _id : 4 ,
is _muted : false ,
} ;
2019-12-13 01:38:49 +01:00
const amp _stream = {
subscribed : true ,
2020-07-15 01:29:15 +02:00
color : "orange" ,
name : "& & &" ,
2019-12-13 01:38:49 +01:00
stream _id : 5 ,
is _muted : false ,
} ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( denmark ) ;
stream _data . add _sub ( social ) ;
stream _data . add _sub ( edgecase _stream ) ;
stream _data . add _sub ( edgecase _stream _2 ) ;
2019-06-21 20:47:09 +02:00
// Note: edgecase_stream cannot be mentioned because it is caught by
// streamTopicHandler and it would be parsed as edgecase_stream_2.
2019-12-13 01:38:49 +01:00
stream _data . add _sub ( amp _stream ) ;
2016-11-10 20:20:40 +01:00
2021-05-19 06:18:23 +02:00
markdown . initialize ( markdown _config . get _helpers ( ) ) ;
linkifiers . initialize ( example _realm _linkifiers ) ;
2013-12-04 17:16:08 +01:00
2021-03-16 12:31:25 +01:00
function test ( label , f ) {
2022-07-10 01:06:33 +02:00
run _test ( label , ( helpers ) => {
2021-04-03 19:07:13 +02:00
page _params . realm _users = [ ] ;
2021-05-19 06:18:23 +02:00
linkifiers . update _linkifier _rules ( example _realm _linkifiers ) ;
2022-07-10 01:06:33 +02:00
f ( helpers ) ;
2021-03-16 12:31:25 +01:00
} ) ;
}
test ( "markdown_detection" , ( ) => {
2019-11-02 00:06:25 +01:00
const no _markup = [
2018-05-07 03:30:13 +02:00
"This is a plaintext message" ,
"This is a plaintext: message" ,
"This is a :plaintext message" ,
"This is a :plaintext message: message" ,
"Contains a not an image.jpeg/ok file" ,
"Contains a not an http://www.google.com/ok/image.png/stop file" ,
"No png to be found here, a png" ,
"No user mention **leo**" ,
"No user mention @what there" ,
"No group mention *hamletcharacters*" ,
2020-07-15 00:34:28 +02:00
'We like to code\n~~~\ndef code():\n we = "like to do"\n~~~' ,
2018-05-07 03:30:13 +02:00
"This is a\nmultiline :emoji: here\n message" ,
"This is an :emoji: message" ,
"User Mention @**leo**" ,
"User Mention @**leo f**" ,
"User Mention @**leo with some name**" ,
"Group Mention @*hamletcharacters*" ,
"Stream #**Verona**" ,
] ;
2013-12-04 17:16:08 +01:00
2019-11-02 00:06:25 +01:00
const markup = [
2018-05-07 03:30:13 +02:00
"Contains a https://zulip.com/image.png file" ,
"Contains a https://zulip.com/image.jpg file" ,
"https://zulip.com/image.jpg" ,
"also https://zulip.com/image.jpg" ,
"https://zulip.com/image.jpg too" ,
"Contains a zulip.com/foo.jpeg file" ,
"Contains a https://zulip.com/image.png file" ,
2020-10-23 02:43:28 +02:00
"Twitter URL https://twitter.com/jacobian/status/407886996565016579" ,
2018-05-07 03:30:13 +02:00
"https://twitter.com/jacobian/status/407886996565016579" ,
"then https://twitter.com/jacobian/status/407886996565016579" ,
2020-10-23 02:43:28 +02:00
"Twitter URL http://twitter.com/jacobian/status/407886996565016579" ,
"YouTube URL https://www.youtube.com/watch?v=HHZ8iqswiCw&feature=youtu.be&a" ,
2018-05-07 03:30:13 +02:00
] ;
2013-12-04 17:16:08 +01:00
2021-01-22 22:29:08 +01:00
for ( const content of no _markup ) {
2017-07-29 02:51:33 +02:00
assert . equal ( markdown . contains _backend _only _syntax ( content ) , false ) ;
2021-01-22 22:29:08 +01:00
}
2013-12-04 17:16:08 +01:00
2021-01-22 22:29:08 +01:00
for ( const content of markup ) {
2017-07-29 02:51:33 +02:00
assert . equal ( markdown . contains _backend _only _syntax ( content ) , true ) ;
2021-01-22 22:29:08 +01:00
}
2018-05-15 12:40:07 +02:00
} ) ;
2013-12-04 17:16:08 +01:00
2021-03-16 12:31:25 +01:00
test ( "marked_shared" , ( ) => {
2020-12-01 00:26:16 +01:00
const tests = markdown _test _cases . regular _tests ;
2017-12-10 09:01:37 +01:00
2021-01-22 22:29:08 +01:00
for ( const test of tests ) {
2018-03-28 10:40:44 +02:00
// Ignore tests if specified
2022-04-09 23:44:38 +02:00
/* istanbul ignore if */
2018-03-28 10:40:44 +02:00
if ( test . ignore === true ) {
2021-01-22 22:29:08 +01:00
continue ;
2018-03-28 10:40:44 +02:00
}
2024-01-22 07:55:55 +01:00
let message = { raw _content : test . input } ;
2021-07-28 16:00:58 +02:00
user _settings . translate _emoticons = test . translate _emoticons || false ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2019-11-02 00:06:25 +01:00
const output = message . content ;
const error _message = ` Failure in test: ${ test . name } ` ;
2017-07-29 03:04:17 +02:00
if ( test . marked _expected _output ) {
2020-12-01 00:21:17 +01:00
markdown _assert . notEqual ( test . expected _output , output , error _message ) ;
markdown _assert . equal ( test . marked _expected _output , output , error _message ) ;
2017-07-29 03:17:25 +02:00
} else if ( test . backend _only _rendering ) {
assert . equal ( markdown . contains _backend _only _syntax ( test . input ) , true ) ;
2017-06-13 23:49:50 +02:00
} else {
2020-12-01 00:21:17 +01:00
markdown _assert . equal ( test . expected _output , output , error _message ) ;
2017-06-13 23:49:50 +02:00
}
2021-01-22 22:29:08 +01:00
}
2018-05-15 12:40:07 +02:00
} ) ;
2014-01-17 21:08:45 +01:00
2021-03-16 12:31:25 +01:00
test ( "message_flags" , ( ) => {
2020-07-15 01:29:15 +02:00
let message = { raw _content : "@**Leo**" } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2022-03-24 07:01:47 +01:00
assert . ok ( ! message . flags . includes ( "mentioned" ) ) ;
2017-01-24 01:51:58 +01:00
2021-04-11 16:26:54 +02:00
message = { raw _content : "@**Cordelia, Lear's daughter**" } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2022-03-24 07:01:47 +01:00
assert . ok ( message . flags . includes ( "mentioned" ) ) ;
2017-01-24 01:51:58 +01:00
2020-07-15 01:29:15 +02:00
message = { raw _content : "@**all**" } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . ok ( message . flags . includes ( "stream_wildcard_mentioned" ) ) ;
assert . ok ( ! message . flags . includes ( "topic_wildcard_mentioned" ) ) ;
message = { raw _content : "@**topic**" } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . ok ( ! message . flags . includes ( "stream_wildcard_mentioned" ) ) ;
assert . ok ( message . flags . includes ( "topic_wildcard_mentioned" ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-01-24 01:51:58 +01:00
2021-03-16 12:31:25 +01:00
test ( "marked" , ( ) => {
2019-11-02 00:06:25 +01:00
const test _cases = [
2020-07-15 01:29:15 +02:00
{ input : "hello" , expected : "<p>hello</p>" } ,
{ input : "hello there" , expected : "<p>hello there</p>" } ,
{ input : "hello **bold** for you" , expected : "<p>hello <strong>bold</strong> for you</p>" } ,
2020-07-15 00:34:28 +02:00
{
input : "hello ***foo*** for you" ,
expected : "<p>hello <strong><em>foo</em></strong> for you</p>" ,
} ,
2020-07-15 01:29:15 +02:00
{ input : "__hello__" , expected : "<p>__hello__</p>" } ,
2020-07-15 00:34:28 +02:00
{
input : "\n```\nfenced code\n```\n\nand then after\n" ,
expected :
2020-10-19 04:49:17 +02:00
'<div class="codehilite"><pre><span></span><code>fenced code\n</code></pre></div>\n<p>and then after</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
2021-05-09 22:29:53 +02:00
input : "\n```\n fenced code trailing whitespace \n```\n\nand then after\n" ,
2020-07-15 00:34:28 +02:00
expected :
2020-10-19 04:49:17 +02:00
'<div class="codehilite"><pre><span></span><code> fenced code trailing whitespace\n</code></pre></div>\n<p>and then after</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "* a\n* list \n* here" ,
expected : "<ul>\n<li>a</li>\n<li>list </li>\n<li>here</li>\n</ul>" ,
} ,
{
input : "\n```c#\nfenced code special\n```\n\nand then after\n" ,
expected :
2020-10-19 04:49:17 +02:00
'<div class="codehilite" data-code-language="C#"><pre><span></span><code>fenced code special\n</code></pre></div>\n<p>and then after</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "\n```vb.net\nfenced code dot\n```\n\nand then after\n" ,
expected :
2020-10-19 04:49:17 +02:00
'<div class="codehilite" data-code-language="VB.net"><pre><span></span><code>fenced code dot\n</code></pre></div>\n<p>and then after</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "Some text first\n* a\n* list \n* here\n\nand then after" ,
expected :
"<p>Some text first</p>\n<ul>\n<li>a</li>\n<li>list </li>\n<li>here</li>\n</ul>\n<p>and then after</p>" ,
} ,
{
input : "1. an\n2. ordered \n3. list" ,
expected : "<ol>\n<li>an</li>\n<li>ordered </li>\n<li>list</li>\n</ol>" ,
} ,
{
input : "\n~~~quote\nquote this for me\n~~~\nthanks\n" ,
expected : "<blockquote>\n<p>quote this for me</p>\n</blockquote>\n<p>thanks</p>" ,
} ,
{
2021-04-11 16:26:54 +02:00
input : "This is a @**CordeLIA, Lear's daughter** mention" ,
2020-07-15 00:34:28 +02:00
expected :
2021-04-11 16:26:54 +02:00
'<p>This is a <span class="user-mention" data-user-id="101">@Cordelia, Lear's daughter</span> mention</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "These @ @**** are not mentions" ,
expected : "<p>These @ @<em>**</em> are not mentions</p>" ,
} ,
{
input : "These # #**** are not mentions" ,
expected : "<p>These # #<em>**</em> are not mentions</p>" ,
} ,
{ input : "These @* are not mentions" , expected : "<p>These @* are not mentions</p>" } ,
{
input : "These #* #*** are also not mentions" ,
expected : "<p>These #* #*** are also not mentions</p>" ,
} ,
{
input : "This is a #**Denmark** stream link" ,
expected :
'<p>This is a <a class="stream" data-stream-id="1" href="/#narrow/stream/1-Denmark">#Denmark</a> stream link</p>' ,
} ,
{
input : "This is #**Denmark** and #**social** stream links" ,
expected :
'<p>This is <a class="stream" data-stream-id="1" href="/#narrow/stream/1-Denmark">#Denmark</a> and <a class="stream" data-stream-id="2" href="/#narrow/stream/2-social">#social</a> stream links</p>' ,
} ,
{
input : "And this is a #**wrong** stream link" ,
expected : "<p>And this is a #**wrong** stream link</p>" ,
} ,
{
input : "This is a #**Denmark>some topic** stream_topic link" ,
expected :
2020-10-07 13:17:55 +02:00
'<p>This is a <a class="stream-topic" data-stream-id="1" href="/#narrow/stream/1-Denmark/topic/some.20topic">#Denmark > some topic</a> stream_topic link</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "This has two links: #**Denmark>some topic** and #**social>other topic**." ,
expected :
2020-10-07 13:17:55 +02:00
'<p>This has two links: <a class="stream-topic" data-stream-id="1" href="/#narrow/stream/1-Denmark/topic/some.20topic">#Denmark > some topic</a> and <a class="stream-topic" data-stream-id="2" href="/#narrow/stream/2-social/topic/other.20topic">#social > other topic</a>.</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "This is not a #**Denmark>** stream_topic link" ,
expected : "<p>This is not a #**Denmark>** stream_topic link</p>" ,
} ,
{
input : "mmm...:burrito:s" ,
expected :
'<p>mmm...<img alt=":burrito:" class="emoji" src="/static/generated/emoji/images/emoji/burrito.png" title="burrito">s</p>' ,
} ,
{
input : "This is an :poop: message" ,
expected :
'<p>This is an <span aria-label="poop" class="emoji emoji-1f4a9" role="img" title="poop">:poop:</span> message</p>' ,
} ,
{
2020-10-07 10:24:09 +02:00
input : "\uD83D\uDCA9" ,
2020-07-15 00:34:28 +02:00
expected :
'<p><span aria-label="poop" class="emoji emoji-1f4a9" role="img" title="poop">:poop:</span></p>' ,
} ,
{
2021-04-11 16:26:54 +02:00
input : "Silent mention: @_**Cordelia, Lear's daughter**" ,
2020-07-15 00:34:28 +02:00
expected :
2021-04-11 16:26:54 +02:00
'<p>Silent mention: <span class="user-mention silent" data-user-id="101">Cordelia, Lear's daughter</span></p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
2021-05-09 22:29:53 +02:00
input : "> Mention in quote: @**Cordelia, Lear's daughter**\n\nMention outside quote: @**Cordelia, Lear's daughter**" ,
2020-07-15 00:34:28 +02:00
expected :
2021-04-11 16:26:54 +02:00
'<blockquote>\n<p>Mention in quote: <span class="user-mention silent" data-user-id="101">Cordelia, Lear's daughter</span></p>\n</blockquote>\n<p>Mention outside quote: <span class="user-mention" data-user-id="101">@Cordelia, Lear's daughter</span></p>' ,
2020-07-15 00:34:28 +02:00
} ,
2021-05-19 21:22:58 +02:00
{
2023-07-11 14:42:31 +02:00
input : "Stream Wildcard mention: @**all**\nStream Wildcard silent mention: @_**all**" ,
2021-05-19 21:22:58 +02:00
expected :
2024-07-26 04:45:20 +02:00
'<p>Stream Wildcard mention: <span class="user-mention channel-wildcard-mention" data-user-id="*">@all</span><br>\nStream Wildcard silent mention: <span class="user-mention channel-wildcard-mention silent" data-user-id="*">all</span></p>' ,
2021-05-19 21:22:58 +02:00
} ,
{
2023-07-11 14:42:31 +02:00
input : "> Stream Wildcard mention in quote: @**all**\n\n> Another stream wildcard mention in quote: @_**all**" ,
2021-05-19 21:22:58 +02:00
expected :
2024-07-26 04:45:20 +02:00
'<blockquote>\n<p>Stream Wildcard mention in quote: <span class="user-mention channel-wildcard-mention silent" data-user-id="*">all</span></p>\n</blockquote>\n<blockquote>\n<p>Another stream wildcard mention in quote: <span class="user-mention channel-wildcard-mention silent" data-user-id="*">all</span></p>\n</blockquote>' ,
2021-05-19 21:22:58 +02:00
} ,
{
2023-07-11 14:42:31 +02:00
input : "```quote\nStream Wildcard mention in quote: @**all**\n```\n\n```quote\nAnother stream wildcard mention in quote: @_**all**\n```" ,
2021-05-19 21:22:58 +02:00
expected :
2024-07-26 04:45:20 +02:00
'<blockquote>\n<p>Stream Wildcard mention in quote: <span class="user-mention channel-wildcard-mention silent" data-user-id="*">all</span></p>\n</blockquote>\n<blockquote>\n<p>Another stream wildcard mention in quote: <span class="user-mention channel-wildcard-mention silent" data-user-id="*">all</span></p>\n</blockquote>' ,
2021-05-19 21:22:58 +02:00
} ,
2023-06-06 09:23:01 +02:00
{
input : "Topic Wildcard mention: @**topic**\nTopic Wildcard silent mention: @_**topic**" ,
expected :
'<p>Topic Wildcard mention: <span class="topic-mention">@topic</span><br>\nTopic Wildcard silent mention: <span class="topic-mention silent">topic</span></p>' ,
} ,
{
input : "> Topic Wildcard mention in quote: @**topic**\n\n> Another topic wildcard mention in quote: @_**topic**" ,
expected :
'<blockquote>\n<p>Topic Wildcard mention in quote: <span class="topic-mention silent">topic</span></p>\n</blockquote>\n<blockquote>\n<p>Another topic wildcard mention in quote: <span class="topic-mention silent">topic</span></p>\n</blockquote>' ,
} ,
{
input : "```quote\nTopic Wildcard mention in quote: @**topic**\n```\n\n```quote\nAnother topic wildcard mention in quote: @_**topic**\n```" ,
expected :
'<blockquote>\n<p>Topic Wildcard mention in quote: <span class="topic-mention silent">topic</span></p>\n</blockquote>\n<blockquote>\n<p>Another topic wildcard mention in quote: <span class="topic-mention silent">topic</span></p>\n</blockquote>' ,
} ,
2021-05-19 21:34:58 +02:00
{
input : "User group mention: @*backend*\nUser group silent mention: @_*hamletcharacters*" ,
expected :
'<p>User group mention: <span class="user-group-mention" data-user-group-id="2">@Backend</span><br>\nUser group silent mention: <span class="user-group-mention silent" data-user-group-id="1">hamletcharacters</span></p>' ,
} ,
2021-05-19 21:38:28 +02:00
{
input : "> User group mention in quote: @*backend*\n\n> Another user group mention in quote: @*hamletcharacters*" ,
expected :
'<blockquote>\n<p>User group mention in quote: <span class="user-group-mention silent" data-user-group-id="2">Backend</span></p>\n</blockquote>\n<blockquote>\n<p>Another user group mention in quote: <span class="user-group-mention silent" data-user-group-id="1">hamletcharacters</span></p>\n</blockquote>' ,
} ,
{
input : "```quote\nUser group mention in quote: @*backend*\n```\n\n```quote\nAnother user group mention in quote: @*hamletcharacters*\n```" ,
expected :
'<blockquote>\n<p>User group mention in quote: <span class="user-group-mention silent" data-user-group-id="2">Backend</span></p>\n</blockquote>\n<blockquote>\n<p>Another user group mention in quote: <span class="user-group-mention silent" data-user-group-id="1">hamletcharacters</span></p>\n</blockquote>' ,
} ,
2023-11-16 23:59:18 +01:00
// Test only those linkifiers which don't return True for
// `contains_backend_only_syntax()`. Those which return True
// are tested separately.
2020-07-15 00:34:28 +02:00
{
2021-03-13 18:15:14 +01:00
input : "This is a linkifier #1234 with text after it" ,
2020-07-15 00:34:28 +02:00
expected :
2021-03-13 18:15:14 +01:00
'<p>This is a linkifier <a href="https://trac.example.com/ticket/1234" title="https://trac.example.com/ticket/1234">#1234</a> with text after it</p>' ,
2020-07-15 00:34:28 +02:00
} ,
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
{
input : "This is a complicated linkifier FOO_abcde;e;zulip;luxembourg;foo;23;testing with text after it" ,
expected :
'<p>This is a complicated linkifier <a href="https://zone_e.zulip.net/ticket/luxembourg/abcde?name=foo&chapter=23#testi" title="https://zone_e.zulip.net/ticket/luxembourg/abcde?name=foo&chapter=23#testi">FOO_abcde;e;zulip;luxembourg;foo;23;testing</a> with text after it</p>' ,
} ,
2021-03-13 18:15:14 +01:00
{ input : "#1234is not a linkifier." , expected : "<p>#1234is not a linkifier.</p>" } ,
2020-07-15 00:34:28 +02:00
{
2021-03-13 18:15:14 +01:00
input : "A pattern written as #1234is not a linkifier." ,
expected : "<p>A pattern written as #1234is not a linkifier.</p>" ,
2020-07-15 00:34:28 +02:00
} ,
{
2021-03-13 18:15:14 +01:00
input : "This is a linkifier with ZGROUP_123:45 groups" ,
2020-07-15 00:34:28 +02:00
expected :
2021-03-13 18:15:14 +01:00
'<p>This is a linkifier with <a href="https://zone_45.zulip.net/ticket/123" title="https://zone_45.zulip.net/ticket/123">ZGROUP_123:45</a> groups</p>' ,
2020-07-15 00:34:28 +02:00
} ,
{ input : "Test *italic*" , expected : "<p>Test <em>italic</em></p>" } ,
{
input : "T\n#**Denmark**" ,
expected :
'<p>T<br>\n<a class="stream" data-stream-id="1" href="/#narrow/stream/1-Denmark">#Denmark</a></p>' ,
} ,
{
2021-04-11 16:26:54 +02:00
input : "T\n@**Cordelia, Lear's daughter**" ,
2020-07-15 00:34:28 +02:00
expected :
2021-04-11 16:26:54 +02:00
'<p>T<br>\n<span class="user-mention" data-user-id="101">@Cordelia, Lear's daughter</span></p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "@**Mark Twin|104** and @**Mark Twin|105** are out to confuse you." ,
expected :
'<p><span class="user-mention" data-user-id="104">@Mark Twin</span> and <span class="user-mention" data-user-id="105">@Mark Twin</span> are out to confuse you.</p>' ,
} ,
{ input : "@**Invalid User|1234**" , expected : "<p>@**Invalid User|1234**</p>" } ,
{
2021-04-11 16:26:54 +02:00
input : "@**Cordelia, Lear's daughter|103** has a wrong user_id." ,
expected : "<p>@**Cordelia, Lear's daughter|103** has a wrong user_id.</p>" ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "@**Brother of Bobby|123** is really the full name." ,
expected :
'<p><span class="user-mention" data-user-id="106">@Brother of Bobby|123</span> is really the full name.</p>' ,
} ,
{
input : "@**Brother of Bobby|123|106**" ,
expected :
'<p><span class="user-mention" data-user-id="106">@Brother of Bobby|123</span></p>' ,
} ,
2021-03-23 20:22:04 +01:00
{
input : "@**|106** valid user id." ,
expected :
'<p><span class="user-mention" data-user-id="106">@Brother of Bobby|123</span> valid user id.</p>' ,
} ,
{
input : "@**|123|106** comes under user|id case." ,
expected : "<p>@**|123|106** comes under user|id case.</p>" ,
} ,
2023-12-07 11:41:37 +01:00
{
input : "@**|108** mention inaccessible user using ID." ,
expected : "<p>@**|108** mention inaccessible user using ID.</p>" ,
} ,
{
input : "@**Unknown user|108** mention inaccessible user using name and ID." ,
expected : "<p>@**Unknown user|108** mention inaccessible user using name and ID.</p>" ,
} ,
2021-03-23 20:22:04 +01:00
{ input : "@**|1234** invalid id." , expected : "<p>@**|1234** invalid id.</p>" } ,
2020-07-15 00:34:28 +02:00
{ input : "T\n@hamletcharacters" , expected : "<p>T<br>\n@hamletcharacters</p>" } ,
{
input : "T\n@*hamletcharacters*" ,
expected :
'<p>T<br>\n<span class="user-group-mention" data-user-group-id="1">@hamletcharacters</span></p>' ,
} ,
{ input : "T\n@*notagroup*" , expected : "<p>T<br>\n@*notagroup*</p>" } ,
{
input : "T\n@*backend*" ,
expected :
'<p>T<br>\n<span class="user-group-mention" data-user-group-id="2">@Backend</span></p>' ,
} ,
{ input : "@*notagroup*" , expected : "<p>@*notagroup*</p>" } ,
{
2021-03-13 18:15:14 +01:00
input : "This is a linkifier `hello` with text after it" ,
expected : "<p>This is a linkifier <code>hello</code> with text after it</p>" ,
2020-07-15 00:34:28 +02:00
} ,
2018-03-25 18:10:59 +02:00
// Test the emoticon conversion
2020-07-15 00:34:28 +02:00
{ input : ":)" , expected : "<p>:)</p>" } ,
{
input : ":)" ,
expected :
2020-06-30 21:16:29 +02:00
'<p><span aria-label="smile" class="emoji emoji-1f642" role="img" title="smile">:smile:</span></p>' ,
2020-07-15 00:34:28 +02:00
translate _emoticons : true ,
} ,
2020-10-23 02:43:28 +02:00
// Test HTML escaping in custom Zulip rules
2020-07-15 00:34:28 +02:00
{
input : "@**<h1>The Rogue One</h1>**" ,
expected : "<p>@**<h1>The Rogue One</h1>**</p>" ,
} ,
{
input : "#**<h1>The Rogue One</h1>**" ,
expected : "<p>#**<h1>The Rogue One</h1>**</p>" ,
} ,
{
input : ":<h1>The Rogue One</h1>:" ,
expected : "<p>:<h1>The Rogue One</h1>:</p>" ,
} ,
{ input : "@**O'Connell**" , expected : "<p>@**O'Connell**</p>" } ,
{
input : "@*Bobby <h1>Tables</h1>*" ,
expected :
'<p><span class="user-group-mention" data-user-group-id="3">@Bobby <h1>Tables</h1></span></p>' ,
} ,
{
input : "@*& & &amp;*" ,
expected :
'<p><span class="user-group-mention" data-user-group-id="4">@& & &amp;</span></p>' ,
} ,
{
input : "@**Bobby <h1>Tables</h1>**" ,
expected :
'<p><span class="user-mention" data-user-id="103">@Bobby <h1>Tables</h1></span></p>' ,
} ,
{
input : "@**& & &amp;**" ,
expected :
'<p><span class="user-mention" data-user-id="107">@& & &amp;</span></p>' ,
} ,
{
input : "#**Bobby <h1>Tables</h1>**" ,
expected :
2020-10-07 13:17:55 +02:00
'<p><a class="stream-topic" data-stream-id="4" href="/#narrow/stream/4-Bobby-.3Ch1/topic/Tables.3C.2Fh1.3E">#Bobby <h1 > Tables</h1></a></p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "#**& & &amp;**" ,
expected :
2022-02-28 20:54:06 +01:00
'<p><a class="stream" data-stream-id="5" href="/#narrow/stream/5-.26-.26-.26amp.3B">#& & &amp;</a></p>' ,
2020-07-15 00:34:28 +02:00
} ,
{
input : "#**& & &amp;>& & &amp;**" ,
expected :
2022-02-28 20:54:06 +01:00
'<p><a class="stream-topic" data-stream-id="5" href="/#narrow/stream/5-.26-.26-.26amp.3B/topic/.26.20.26.20.26amp.3B">#& & &amp; > & & &amp;</a></p>' ,
2020-07-15 00:34:28 +02:00
} ,
2017-06-13 23:49:50 +02:00
] ;
2021-01-22 22:29:08 +01:00
for ( const test _case of test _cases ) {
2018-03-25 18:10:59 +02:00
// Disable emoji conversion by default.
2021-07-28 16:00:58 +02:00
user _settings . translate _emoticons = test _case . translate _emoticons || false ;
2018-03-25 18:10:59 +02:00
2019-11-02 00:06:25 +01:00
const input = test _case . input ;
const expected = test _case . expected ;
2017-06-13 23:49:50 +02:00
2024-01-22 07:55:55 +01:00
const message = markdown . render ( input ) ;
2019-11-02 00:06:25 +01:00
const output = message . content ;
2020-07-28 17:00:59 +02:00
assert . equal ( output , expected ) ;
2021-01-22 22:29:08 +01:00
}
2018-05-15 12:40:07 +02:00
} ) ;
2014-01-24 21:48:56 +01:00
2021-03-16 12:31:25 +01:00
test ( "topic_links" , ( ) => {
2020-07-15 01:29:15 +02:00
let message = { type : "stream" , topic : "No links here" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 0 ) ;
2017-06-13 23:49:50 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "One #123 link here" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 1 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://trac.example.com/ticket/123" ,
text : "#123" ,
} ) ;
2017-06-13 23:49:50 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "Two #123 #456 link here" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 2 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://trac.example.com/ticket/123" ,
text : "#123" ,
} ) ;
assert . deepEqual ( message . topic _links [ 1 ] , {
url : "https://trac.example.com/ticket/456" ,
text : "#456" ,
} ) ;
2017-06-13 23:49:50 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "New ZBUG_123 link here" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 1 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://trac2.zulip.net/ticket/123" ,
text : "ZBUG_123" ,
} ) ;
2017-06-13 23:49:50 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "New ZBUG_123 with #456 link here" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 2 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://trac2.zulip.net/ticket/123" ,
text : "ZBUG_123" ,
} ) ;
assert . deepEqual ( message . topic _links [ 1 ] , {
url : "https://trac.example.com/ticket/456" ,
text : "#456" ,
} ) ;
2017-06-13 23:49:50 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "One ZGROUP_123:45 link here" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 1 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://zone_45.zulip.net/ticket/123" ,
text : "ZGROUP_123:45" ,
} ) ;
2017-06-13 23:49:50 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "Hello https://google.com" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 1 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://google.com" ,
text : "https://google.com" ,
} ) ;
2019-05-25 16:10:30 +02:00
2020-07-15 01:29:15 +02:00
message = { type : "stream" , topic : "#456 https://google.com https://github.com" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 3 ) ;
2021-01-26 07:32:29 +01:00
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://trac.example.com/ticket/456" ,
text : "#456" ,
} ) ;
assert . deepEqual ( message . topic _links [ 1 ] , {
url : "https://google.com" ,
text : "https://google.com" ,
} ) ;
assert . deepEqual ( message . topic _links [ 2 ] , {
url : "https://github.com" ,
text : "https://github.com" ,
} ) ;
2019-05-25 16:10:30 +02:00
2017-06-13 23:49:50 +02:00
message = { type : "not-stream" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
2020-02-14 13:39:04 +01:00
assert . equal ( message . topic _links . length , 0 ) ;
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
message = { type : "stream" , topic : "FOO_abcde;e;zulip;luxembourg;foo;23;testing" } ;
2024-01-22 08:10:12 +01:00
message . topic _links = markdown . get _topic _links ( message . topic ) ;
linkifier: Support URL templates for linkifiers.
This swaps out url_format_string from all of our APIs and replaces it
with url_template. Note that the documentation changes in the following
commits will be squashed with this commit.
We change the "url_format" key to "url_template" for the
realm_linkifiers events in event_schema, along with updating
LinkifierDict. "url_template" is the name chosen to normalize
mixed usages of "url_format_string" and "url_format" throughout
the backend.
The markdown processor is updated to stop handling the format string
interpolation and delegate the task template expansion to the uri_template
library instead.
This change affects many test cases. We mostly just replace "%(name)s"
with "{name}", "url_format_string" with "url_template" to make sure that
they still pass. There are some test cases dedicated for testing "%"
escaping, which aren't relevant anymore and are subject to removal.
But for now we keep most of them as-is, and make sure that "%" is always
escaped since we do not use it for variable substitution any more.
Since url_format_string is not populated anymore, a migration is created
to remove this field entirely, and make url_template non-nullable since
we will always populate it. Note that it is possible to have
url_template being null after migration 0422 and before 0424, but
in practice, url_template will not be None after backfilling and the
backend now is always setting url_template.
With the removal of url_format_string, RealmFilter model will now be cleaned
with URL template checks, and the old checks for escapes are removed.
We also modified RealmFilter.clean to skip the validation when the
url_template is invalid. This avoids raising mulitple ValidationError's
when calling full_clean on a linkifier. But we might eventually want to
have a more centric approach to data validation instead of having
the same validation in both the clean method and the validator.
Fixes #23124.
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
2022-10-05 20:55:31 +02:00
assert . equal ( message . topic _links . length , 1 ) ;
assert . deepEqual ( message . topic _links [ 0 ] , {
url : "https://zone_e.zulip.net/ticket/luxembourg/abcde?name=foo&chapter=23#testi" ,
text : "FOO_abcde;e;zulip;luxembourg;foo;23;testing" ,
} ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2014-01-27 17:06:59 +01:00
2021-03-16 12:31:25 +01:00
test ( "message_flags" , ( ) => {
2019-11-02 00:06:25 +01:00
let input = "/me is testing this" ;
let message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2017-06-13 23:49:50 +02:00
2017-08-27 18:10:36 +02:00
assert . equal ( message . is _me _message , true ) ;
2021-06-10 08:32:54 +02:00
assert . ok ( ! message . unread ) ;
2017-06-13 23:49:50 +02:00
2018-01-21 19:27:36 +01:00
input = "/me is testing\nthis" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2018-01-21 19:27:36 +01:00
2018-12-29 11:07:27 +01:00
assert . equal ( message . is _me _message , true ) ;
2018-01-21 19:27:36 +01:00
2021-04-11 16:26:54 +02:00
input = "testing this @**all** @**Cordelia, Lear's daughter**" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2017-08-27 18:10:36 +02:00
assert . equal ( message . is _me _message , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , true ) ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , true ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2023-06-07 19:19:33 +02:00
2018-04-03 17:55:57 +02:00
input = "test @**everyone**" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2018-04-03 17:55:57 +02:00
assert . equal ( message . is _me _message , false ) ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , true ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2018-04-03 17:55:57 +02:00
input = "test @**stream**" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-03-13 19:19:24 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
assert . equal ( message . is _me _message , false ) ;
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , true ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
input = "test @**channel**" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2018-04-03 17:55:57 +02:00
assert . equal ( message . is _me _message , false ) ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , true ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2018-04-03 17:55:57 +02:00
2023-06-07 19:19:33 +02:00
input = "test @**topic**" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-06-07 19:19:33 +02:00
assert . equal ( message . is _me _message , false ) ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , true ) ;
2023-06-07 19:19:33 +02:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2017-06-13 23:49:50 +02:00
input = "test @all" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2018-01-24 17:18:07 +01:00
input = "test @everyone" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2017-06-13 23:49:50 +02:00
2023-06-07 19:19:33 +02:00
input = "test @topic" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2023-06-07 19:19:33 +02:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2017-06-13 23:49:50 +02:00
input = "test @any" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2017-11-22 09:11:07 +01:00
2018-01-24 17:18:07 +01:00
input = "test @alleycat.com" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2018-01-24 17:18:07 +01:00
2017-11-22 09:11:07 +01:00
input = "test @*hamletcharacters*" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , true ) ;
2017-11-22 09:11:07 +01:00
input = "test @*backend*" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2018-01-24 17:18:07 +01:00
input = "test @**invalid_user**" ;
2018-12-23 16:49:14 +01:00
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2021-05-19 21:22:58 +02:00
input = "test @_**all**" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2021-05-19 21:22:58 +02:00
input = "> test @**all**" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2021-05-19 21:34:58 +02:00
2023-06-07 19:19:33 +02:00
input = "test @_**topic**" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2023-06-07 19:19:33 +02:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
input = "> test @**topic**" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2023-06-07 19:19:33 +02:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2021-05-19 21:34:58 +02:00
input = "test @_*hamletcharacters*" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2021-05-19 21:38:28 +02:00
input = "> test @*hamletcharacters*" ;
message = { topic : "No links here" , raw _content : input } ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2023-11-03 15:20:44 +01:00
assert . equal ( message . flags . includes ( "stream_wildcard_mentioned" ) , false ) ;
assert . equal ( message . flags . includes ( "topic_wildcard_mentioned" ) , false ) ;
2022-03-24 07:01:47 +01:00
assert . equal ( message . flags . includes ( "mentioned" ) , false ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-06-13 23:26:27 +02:00
2023-11-16 23:59:18 +01:00
test ( "backend_only_linkifiers" , ( ) => {
const backend _only _linkifiers = [
"Here is the PR-#123." ,
"Function abc() was introduced in (PR)#123." ,
] ;
for ( const content of backend _only _linkifiers ) {
assert . equal ( markdown . contains _backend _only _syntax ( content ) , true ) ;
}
} ) ;
2021-03-16 12:31:25 +01:00
test ( "translate_emoticons_to_names" , ( ) => {
2022-04-04 18:05:02 +02:00
const get _emoticon _translations = emoji . get _emoticon _translations ;
function translate _emoticons _to _names ( src ) {
return markdown . translate _emoticons _to _names ( { src , get _emoticon _translations } ) ;
}
2020-02-15 15:21:32 +01:00
// Simple test
2020-07-15 01:29:15 +02:00
const test _text = "Testing :)" ;
2020-06-30 21:16:29 +02:00
const expected = "Testing :smile:" ;
2022-04-04 18:05:02 +02:00
const result = translate _emoticons _to _names ( test _text ) ;
2020-07-28 17:00:59 +02:00
assert . equal ( result , expected ) ;
2020-02-15 15:21:32 +01:00
// Extensive tests.
// The following code loops over the test cases and each emoticon conversion
// to generate multiple test cases.
for ( const [ shortcut , full _name ] of Object . entries ( emoji _codes . emoticon _conversions ) ) {
2022-03-02 03:45:35 +01:00
for ( const { original , expected } of [
{ name : ` only emoticon ` , original : shortcut , expected : full _name } ,
{ name : ` space at start ` , original : ` ${ shortcut } ` , expected : ` ${ full _name } ` } ,
{ name : ` space at end ` , original : ` ${ shortcut } ` , expected : ` ${ full _name } ` } ,
{ name : ` symbol at end ` , original : ` ${ shortcut } ! ` , expected : ` ${ full _name } ! ` } ,
{
name : ` symbol at start ` ,
original : ` Hello, ${ shortcut } ` ,
expected : ` Hello, ${ full _name } ` ,
} ,
{ name : ` after a word ` , original : ` Hello ${ shortcut } ` , expected : ` Hello ${ shortcut } ` } ,
{
name : ` between words ` ,
original : ` Hello ${ shortcut } World ` ,
expected : ` Hello ${ shortcut } World ` ,
} ,
{
name : ` end of sentence ` ,
original : ` End of sentence. ${ shortcut } ` ,
expected : ` End of sentence. ${ full _name } ` ,
} ,
{
name : ` between symbols ` ,
original : ` Hello. ${ shortcut } ! World. ` ,
expected : ` Hello. ${ shortcut } ! World. ` ,
} ,
{
name : ` before end of sentence ` ,
original : ` Hello ${ shortcut } ! ` ,
expected : ` Hello ${ full _name } ! ` ,
} ,
] ) {
2022-04-04 18:05:02 +02:00
const result = translate _emoticons _to _names ( original ) ;
2020-02-15 15:21:32 +01:00
assert . equal ( result , expected ) ;
}
}
} ) ;
2020-07-25 17:50:34 +02:00
2022-03-31 14:16:20 +02:00
test ( "parse_non_message" , ( ) => {
assert . equal ( markdown . parse _non _message ( "type `/day`" ) , "<p>type <code>/day</code></p>" ) ;
} ) ;
2022-07-10 01:06:33 +02:00
test ( "missing unicode emojis" , ( { override } ) => {
2024-01-22 07:55:55 +01:00
let message = { raw _content : "\u{1F6B2}" } ;
2020-07-25 17:50:34 +02:00
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2020-07-25 17:50:34 +02:00
assert . equal (
message . content ,
'<p><span aria-label="bike" class="emoji emoji-1f6b2" role="img" title="bike">:bike:</span></p>' ,
) ;
2022-07-10 01:06:33 +02:00
// Now simulate that we don't know this emoji name.
override ( emoji _codes . codepoint _to _name , "1f6b2" , undefined ) ;
2022-03-29 16:28:28 +02:00
markdown . initialize ( markdown _config . get _helpers ( ) ) ;
2024-01-22 07:55:55 +01:00
message = {
... message ,
... markdown . render ( message . raw _content ) ,
} ;
2020-10-07 10:24:09 +02:00
assert . equal ( message . content , "<p>\u{1F6B2}</p>" ) ;
2020-07-25 17:50:34 +02:00
} ) ;
2021-05-18 17:32:04 +02:00
2022-07-09 23:25:05 +02:00
test ( "katex_throws_unexpected_exceptions" , ( { override _rewire } ) => {
2021-05-18 17:32:04 +02:00
const message = { raw _content : "$$a$$" } ;
2022-07-09 23:25:05 +02:00
override _rewire ( markdown , "katex" , {
2022-11-17 23:33:43 +01:00
renderToString ( ) {
2022-07-09 23:25:05 +02:00
throw new Error ( "some-exception" ) ;
2021-05-18 17:32:04 +02:00
} ,
2022-07-09 23:25:05 +02:00
} ) ;
2024-01-22 07:55:55 +01:00
assert . throws ( ( ) => markdown . render ( message . raw _content ) , {
2022-07-09 23:25:05 +02:00
name : "Error" ,
message : "some-exception\nPlease report this to https://zulip.com/development-community/" ,
} ) ;
2021-05-18 17:32:04 +02:00
} ) ;