Skip to content

Commit 9e14968

Browse files
committed
add more tests, and code to fix those newly broken tests
1 parent 50a80cd commit 9e14968

File tree

2 files changed

+47
-29
lines changed

2 files changed

+47
-29
lines changed

x-pack/plugins/actions/server/lib/mustache_renderer.test.ts

+23-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { renderMustacheString, renderMustacheObject } from './mustache_renderer';
7+
import { renderMustacheString, renderMustacheObject, Escape } from './mustache_renderer';
88

99
const variables = {
1010
a: 1,
@@ -14,7 +14,9 @@ const variables = {
1414
e: undefined,
1515
f: {
1616
g: 3,
17+
h: null,
1718
},
19+
i: [42, 43, 44],
1820
lt: '<',
1921
gt: '>',
2022
amp: '&',
@@ -29,15 +31,26 @@ const variables = {
2931

3032
describe('mustache_renderer', () => {
3133
describe('renderMustacheString()', () => {
32-
it('handles basic templating that does not need escaping', () => {
33-
expect(renderMustacheString('', variables, 'none')).toBe('');
34-
expect(renderMustacheString('{{a}}', variables, 'none')).toBe('1');
35-
expect(renderMustacheString('{{b}}', variables, 'none')).toBe('2');
36-
expect(renderMustacheString('{{c}}', variables, 'none')).toBe('false');
37-
expect(renderMustacheString('{{d}}', variables, 'none')).toBe('');
38-
expect(renderMustacheString('{{e}}', variables, 'none')).toBe('');
39-
expect(renderMustacheString('{{f.g}}', variables, 'none')).toBe('3');
40-
});
34+
for (const escapeVal of ['none', 'slack', 'markdown', 'json']) {
35+
const escape = escapeVal as Escape;
36+
37+
it(`handles basic templating that does not need escaping for ${escape}`, () => {
38+
expect(renderMustacheString('', variables, escape)).toBe('');
39+
expect(renderMustacheString('{{a}}', variables, escape)).toBe('1');
40+
expect(renderMustacheString('{{b}}', variables, escape)).toBe('2');
41+
expect(renderMustacheString('{{c}}', variables, escape)).toBe('false');
42+
expect(renderMustacheString('{{d}}', variables, escape)).toBe('');
43+
expect(renderMustacheString('{{e}}', variables, escape)).toBe('');
44+
if (escape === 'markdown') {
45+
expect(renderMustacheString('{{f}}', variables, escape)).toBe('\\[object Object\\]');
46+
} else {
47+
expect(renderMustacheString('{{f}}', variables, escape)).toBe('[object Object]');
48+
}
49+
expect(renderMustacheString('{{f.g}}', variables, escape)).toBe('3');
50+
expect(renderMustacheString('{{f.h}}', variables, escape)).toBe('');
51+
expect(renderMustacheString('{{i}}', variables, escape)).toBe('42,43,44');
52+
});
53+
}
4154

4255
it('handles escape:none with commonly escaped strings', () => {
4356
expect(renderMustacheString('{{lt}}', variables, 'none')).toBe(variables.lt);

x-pack/plugins/actions/server/lib/mustache_renderer.ts

+24-19
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import Mustache from 'mustache';
88
import { isString, cloneDeepWith } from 'lodash';
99

10-
type Escape = 'markdown' | 'slack' | 'json' | 'none';
10+
export type Escape = 'markdown' | 'slack' | 'json' | 'none';
1111
type Variables = Record<string, unknown>;
1212

1313
// return a rendered mustache template given the specified variables and escape
@@ -40,19 +40,20 @@ export function renderMustacheObject<Params>(params: Params, variables: Variable
4040
return (result as unknown) as Params;
4141
}
4242

43-
function getEscape(escape: Escape): (string: string) => string {
43+
function getEscape(escape: Escape): (value: unknown) => string {
4444
if (escape === 'markdown') return escapeMarkdown;
4545
if (escape === 'slack') return escapeSlack;
4646
if (escape === 'json') return escapeJSON;
4747
return escapeNone;
4848
}
4949

50-
function escapeNone(value: string): string {
51-
return value;
50+
function escapeNone(value: unknown): string {
51+
if (value == null) return '';
52+
return `${value}`;
5253
}
5354

5455
// replace with JSON stringified version, removing leading and trailing double quote
55-
function escapeJSON(value: string): string {
56+
function escapeJSON(value: unknown): string {
5657
if (value == null) return '';
5758

5859
const quoted = JSON.stringify(`${value}`);
@@ -62,28 +63,32 @@ function escapeJSON(value: string): string {
6263

6364
// see: https://api.slack.com/reference/surfaces/formatting
6465
// but in practice, a bit more needs to be escaped, in drastic ways
65-
function escapeSlack(value: string): string {
66+
function escapeSlack(value: unknown): string {
67+
if (value == null) return '';
68+
69+
const valueString = `${value}`;
6670
// if the value contains * or _, escape the whole thing with back tics
67-
if (value.includes('_') || value.includes('*')) {
71+
if (valueString.includes('_') || valueString.includes('*')) {
6872
// replace unescapable back tics with single quote
69-
value = value.replace(/`/g, `'`);
70-
return '`' + value + '`';
73+
return '`' + valueString.replace(/`/g, `'`) + '`';
7174
}
7275

7376
// otherwise, do "standard" escaping
74-
value = value
75-
.replace(/&/g, '&amp;')
76-
.replace(/</g, '&lt;')
77-
.replace(/>/g, '&gt;')
78-
// this isn't really standard escaping, but escaping back tics is problematic
79-
.replace(/`/g, `'`);
80-
81-
return value;
77+
return (
78+
valueString
79+
.replace(/&/g, '&amp;')
80+
.replace(/</g, '&lt;')
81+
.replace(/>/g, '&gt;')
82+
// this isn't really standard escaping, but escaping back tics is problematic
83+
.replace(/`/g, `'`)
84+
);
8285
}
8386

8487
// see: https://www.markdownguide.org/basic-syntax/#characters-you-can-escape
85-
function escapeMarkdown(value: string): string {
86-
return value
88+
function escapeMarkdown(value: unknown): string {
89+
if (value == null) return '';
90+
91+
return `${value}`
8792
.replace(/\\/g, '\\\\')
8893
.replace(/`/g, '\\`')
8994
.replace(/\*/g, '\\*')

0 commit comments

Comments
 (0)