1
- import { batched , EventBus , markup } from "../src/runtime/utils" ;
1
+ import { batched , EventBus , htmlEscape , markup } from "../src/runtime/utils" ;
2
2
import { nextMicroTick } from "./helpers" ;
3
3
4
4
describe ( "event bus behaviour" , ( ) => {
@@ -78,6 +78,61 @@ describe("markup", () => {
78
78
const html = markup ( "<blink>Hello</blink>" ) ;
79
79
expect ( html ) . toBeInstanceOf ( Markup ) ;
80
80
} ) ;
81
+ describe ( "htmlEscape" , ( ) => {
82
+ test ( "htmlEscape escapes text" , ( ) => {
83
+ const res = htmlEscape ( "<p>test</p>" ) ;
84
+ expect ( res . toString ( ) ) . toBe ( "<p>test</p>" ) ;
85
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
86
+ } ) ;
87
+ test ( "htmlEscape keeps html markup" , ( ) => {
88
+ const res = htmlEscape ( markup ( "<p>test</p>" ) ) ;
89
+ expect ( res . toString ( ) ) . toBe ( "<p>test</p>" ) ;
90
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
91
+ } ) ;
92
+ test ( "htmlEscape produces empty string on undefined" , ( ) => {
93
+ const res = htmlEscape ( undefined ) ;
94
+ expect ( res . toString ( ) ) . toBe ( "" ) ;
95
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
96
+ } ) ;
97
+ test ( "htmlEscape produces string from number" , ( ) => {
98
+ const res = htmlEscape ( 10 ) ;
99
+ expect ( res . toString ( ) ) . toBe ( "10" ) ;
100
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
101
+ } ) ;
102
+ test ( "htmlEscape produces string from boolean" , ( ) => {
103
+ const res = htmlEscape ( false ) ;
104
+ expect ( res . toString ( ) ) . toBe ( "false" ) ;
105
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
106
+ } ) ;
107
+ test ( "htmlEscape correctly escapes various links" , ( ) => {
108
+ expect ( htmlEscape ( "<a>this is a link</a>" ) . toString ( ) ) . toBe (
109
+ "<a>this is a link</a>"
110
+ ) ;
111
+ expect ( htmlEscape ( `<a href="https://www.odoo.com">odoo<a>` ) . toString ( ) ) . toBe (
112
+ `<a href="https://www.odoo.com">odoo<a>`
113
+ ) ;
114
+ expect ( htmlEscape ( `<a href='https://www.odoo.com'>odoo<a>` ) . toString ( ) ) . toBe (
115
+ `<a href='https://www.odoo.com'>odoo<a>`
116
+ ) ;
117
+ expect ( htmlEscape ( "<a href='https://www.odoo.com'>Odoo`s website<a>" ) . toString ( ) ) . toBe (
118
+ `<a href='https://www.odoo.com'>Odoo`s website<a>`
119
+ ) ;
120
+ } ) ;
121
+ test ( "htmlEscape doesn't escape already escaped content" , ( ) => {
122
+ const res = htmlEscape ( "<p>test</p>" ) ;
123
+ expect ( res . toString ( ) ) . toBe ( "<p>test</p>" ) ;
124
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
125
+ const res2 = htmlEscape ( res ) ;
126
+ expect ( res2 . toString ( ) ) . toBe ( "<p>test</p>" ) ;
127
+ expect ( res2 ) . toBeInstanceOf ( Markup ) ;
128
+ expect ( res2 ) . toBe ( res ) ;
129
+ } ) ;
130
+ test ( "htmlEscape returns markup even for only-safe text" , ( ) => {
131
+ const res = htmlEscape ( "safe" ) ;
132
+ expect ( res . toString ( ) ) . toBe ( "safe" ) ;
133
+ expect ( res ) . toBeInstanceOf ( Markup ) ;
134
+ } ) ;
135
+ } ) ;
81
136
describe ( "tag function" , ( ) => {
82
137
test ( "interpolated values are escaped" , ( ) => {
83
138
const maliciousInput = "<script>alert('💥💥')</script>" ;
@@ -99,5 +154,11 @@ describe("markup", () => {
99
154
const html = markup `<img src="${ imgUrl } ">` ;
100
155
expect ( html . toString ( ) ) . toBe ( `<img src="lol" onerror="alert('xss')">` ) ;
101
156
} ) ;
157
+ test ( "already escaped content is not escaped again" , ( ) => {
158
+ const res = htmlEscape ( "<p>test</p>" ) ;
159
+ expect ( res . toString ( ) ) . toBe ( "<p>test</p>" ) ;
160
+ const html = markup `${ res } ` ;
161
+ expect ( html . toString ( ) ) . toBe ( "<p>test</p>" ) ;
162
+ } ) ;
102
163
} ) ;
103
164
} ) ;
0 commit comments