Skip to content

Commit 7dc687d

Browse files
Clear Inline Functions
* Improve tests and pattern match * Create cheerio manip * Update deps
1 parent 03a0208 commit 7dc687d

15 files changed

+429
-140
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ The following can all be adjusted in your `vue.config.js` settings.
4747
* `data-qa="whatever"`
4848
* `id="testWhatever"`
4949
* `class="test-whatever"`
50+
1. Can clear out inline functions from snapshots, or keep them but remove Istanbul's auto-inserted comments.
5051
1. Has an experimental feature to display JSON data stored in HTML attributes instead of `href="[object Object]"`
5152
1. Has much better snapshot defaults.
5253
1. Lets you control your snapshot formatting with an API.
@@ -159,6 +160,7 @@ Though all default settings are designed to be the best choice for most people,
159160
module.exports = {
160161
pluginOptions: {
161162
jestSerializer: {
163+
clearInlineFunctions: false,
162164
// All available options: https://github.com/beautify-web/js-beautify/blob/master/js/src/html/options.js
163165
formatting: {
164166
unformatted: ['code', 'pre', 'em', 'strong', 'span'],
@@ -196,6 +198,7 @@ module.exports = {
196198
pluginOptions: {
197199
jestSerializer: {
198200
attributesToClear: [],
201+
clearInlineFunctions: false,
199202
// All available formatting options: https://github.com/beautify-web/js-beautify/blob/master/js/src/html/options.js
200203
formatting: {
201204
indent_char: ' ',
@@ -227,6 +230,7 @@ module.exports = {
227230
Setting | Default | Description
228231
:-- | :-- | :--
229232
attributesToClear | [] | Takes an array of attribute strings, like `['title', 'id']`, to remove the values from these attributes. `<input title id class="stuff">`.
233+
clearInlineFunctions | `false` | Replaces `<div title="function () { return true; }">` or this `<div title="(x) => !x">` with this placeholder `<div title="[function]">`.
230234
formatting | See above example | These options format the snapshot. [See all available options here](https://github.com/beautify-web/js-beautify/blob/master/js/src/html/options.js).
231235
removeClassTest | `false` | Removes all CSS classes that start with "test", `class="test-whatever"`. **Warning:** Don't use this approach. Use `data-test` instead. It is better suited for this because it doesn't conflate CSS and test tokens.
232236
removeComments | `false` | Removes all HTML comments from your snapshots. This is false by default, as sometimes these comments can infer important information about how your DOM was rendered. However, this is mostly just personal preference.

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "jest-serializer-vue-tjw",
33
"description": "A superb jest serializer for Vue snapshots",
4-
"version": "3.16.0",
4+
"version": "3.17.0",
55
"main": "index.js",
66
"scripts": {
77
"lint": "eslint --ext .js,.vue .",
@@ -19,7 +19,7 @@
1919
],
2020
"dependencies": {
2121
"cheerio": "^1.0.0-rc.3",
22-
"htmlparser2": "^6.0.0",
22+
"htmlparser2": "^6.0.1",
2323
"js-beautify": "^1.13.5",
2424
"lodash.clonedeep": "^4.5.0"
2525
},

src/cheerioManipulation.js

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
const helpers = require('./helpers.js');
2+
const removeTestTokens = require('./removeTestTokens.js');
3+
4+
/**
5+
* This removes the data-server-rendered="true" from your snapshots.
6+
*
7+
* @param {object} $ The markup as a cheerio object
8+
* @param {object} options Options object for this serializer
9+
*/
10+
function removeServerRenderedText ($, options) {
11+
if (!options || options.removeServerRendered) {
12+
$('[data-server-rendered]').removeAttr('data-server-rendered');
13+
}
14+
}
15+
16+
/**
17+
* This removes data-v-1234abcd="" from your snapshots.
18+
*
19+
* @param {object} $ The markup as a cheerio object
20+
* @param {object} options Options object for this serializer
21+
*/
22+
function removeScopedStylesDataVIDAttributes ($, options) {
23+
if (!options || options.removeDataVId) {
24+
// [-\w]+ will catch 1 or more instaces of a-z, A-Z, 0-9, hyphen (-), or underscore (_)
25+
const regex = / data-v-[-\w]+/g;
26+
27+
// [' data-v-asdf=""', ' data-v-qwer', ' data-v-asdf']
28+
let dataVIds = $.html().match(regex) || [];
29+
// ['data-v-asdf', 'data-v-qwer', 'data-v-asdf']
30+
dataVIds = dataVIds.map(function (match) {
31+
return match.trim().replace('=""', '');
32+
});
33+
// ['data-v-asdf', 'data-v-qwer']
34+
dataVIds = Array.from(new Set(dataVIds));
35+
36+
dataVIds.forEach(function (attribute) {
37+
$('[' + attribute + ']').removeAttr(attribute);
38+
});
39+
}
40+
}
41+
42+
/**
43+
* Loops over the attributesToClear array to set the attribute
44+
* value to empty string on all matching elements.
45+
*
46+
* @param {object} $ The markup as a cheerio object
47+
* @param {object} options Options object for this serializer
48+
*/
49+
function clearAttributes ($, options) {
50+
if (
51+
options &&
52+
options.attributesToClear &&
53+
options.attributesToClear.length
54+
) {
55+
options.attributesToClear.forEach(function (attribute) {
56+
$('[' + attribute + ']').attr(attribute, '');
57+
});
58+
}
59+
}
60+
61+
/**
62+
* Replaces inline functions with the '[function]' placeholder.
63+
*
64+
* @param {object} $ The markup as a cheerio object
65+
* @param {object} options Options object for this serializer
66+
*/
67+
function clearInlineFunctions ($, options) {
68+
if (options && options.clearInlineFunctions) {
69+
$('*').each(function (index, element) {
70+
Object.keys(element.attribs).forEach(function (attributeName) {
71+
let value = element.attribs[attributeName];
72+
if (
73+
(
74+
value.startsWith('function ') ||
75+
value.startsWith('function(')
76+
) &&
77+
value.endsWith('}') &&
78+
helpers.functionRegex.test(value)
79+
) {
80+
element.attribs[attributeName] = '[function]';
81+
}
82+
});
83+
});
84+
}
85+
}
86+
87+
/**
88+
* Inline functions get weird istanbul coverage comments.
89+
* This removes them.
90+
* <div title="function () {
91+
* /* istanbul ignore next *\/
92+
* cov_1lmjj6lxv1.f[3]++;
93+
* cov_1lmjj6lxv1.s[15]++;
94+
* return true;
95+
* }">
96+
*
97+
* @param {object} $ The markup as a cheerio object
98+
* @param {object} options Options object for this serializer
99+
*/
100+
function removeIstanbulComments ($, options) {
101+
if (
102+
options &&
103+
options.removeIstanbulComments &&
104+
$.html().includes('/* istanbul')
105+
) {
106+
$('*').each(function (index, element) {
107+
Object.keys(element.attribs).forEach(function (attributeName) {
108+
let value = element.attribs[attributeName];
109+
if (value.includes('/* istanbul')) {
110+
value = value.split('\n').filter(function (line) {
111+
return (
112+
!line.trim().startsWith('/* istanbul') &&
113+
!line.trim().startsWith('cov_')
114+
);
115+
});
116+
element.attribs[attributeName] = value.join('\n');
117+
}
118+
});
119+
});
120+
}
121+
}
122+
123+
/**
124+
* Performs all string manipulations on the rendered DOM
125+
* prior to formatting. Using Cheerio for DOM manipulation.
126+
*
127+
* @param {string} html The markup being serialized
128+
* @param {object} options Options object for this serializer
129+
* @return {string} The markup being serialized
130+
*/
131+
function cheerioManipulation (html, options) {
132+
let $ = helpers.$(html);
133+
134+
removeServerRenderedText($, options);
135+
removeTestTokens($, options);
136+
removeScopedStylesDataVIDAttributes($, options);
137+
clearAttributes($, options);
138+
139+
// clearInlineFunctions should always be ran before removeIstanbulComments for speed
140+
clearInlineFunctions($, options);
141+
removeIstanbulComments($, options);
142+
143+
return $.html();
144+
}
145+
146+
module.exports = cheerioManipulation;

src/helpers.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@ const htmlparser2 = require('htmlparser2');
33
const Vue = require ('vue');
44

55
const helpers = {
6+
// Matches strings that look like functions
7+
// START:
8+
// function
9+
// 0 or more spaces
10+
// FUNCTION NAME:
11+
// anything 0 or more times
12+
// 0 or more spaces
13+
// ARGUMENTS:
14+
// (
15+
// ARGUMENT:
16+
// anything followed by a comma, 0 or more times
17+
// 0 or more spaces
18+
// 0 or more times
19+
// )
20+
// 0 or more spaces
21+
// DECLARATION:
22+
// {
23+
// maybe anything
24+
// maybe return(s)
25+
// 0 or more times
26+
// }
27+
functionRegex: /function( )*(.)*( )*\((.,* *){0,}\) *{(.*\n*)*}/,
28+
629
/**
730
* Console logs helper error messages if verbose mode is enabled.
831
*

src/loadOptions.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const path = require('path');
1010
function booleanSettings (options, vueConfigOptions) {
1111
const booleanSettings = [
1212
'addInputValues',
13+
'clearInlineFunctions',
1314
'removeClassTest',
1415
'removeComments',
1516
'removeDataTest',
@@ -88,6 +89,7 @@ function applySettings (vueConfigOptions) {
8889
let defaultSettings = {
8990
addInputValues: false,
9091
attributesToClear: [],
92+
clearInlineFunctions: false,
9193
// To see available options: https://github.com/beautify-web/js-beautify/blob/master/js/src/html/options.js
9294
formatting: {
9395
indent_char: ' ',

src/removeTestTokens.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const helpers = require('./helpers.js');
2-
31
/**
42
* Removes any data-* attribute passed in.
53
*
@@ -26,7 +24,6 @@ function removeIdTest ($, options) {
2624
}
2725
}
2826

29-
3027
/**
3128
* Removes classes from elements where the class starts with `test`.
3229
*
@@ -71,13 +68,10 @@ function removeClassTest ($, options) {
7168
* If you also want to remove them from your production builds, see:
7269
* https://forum.vuejs.org/t/how-to-remove-attributes-from-tags-inside-vue-components/24138
7370
*
74-
* @param {string} html The markup being serialized
71+
* @param {object} $ The markup as a cheerio object
7572
* @param {object} options Options object for this serializer
76-
* @return {string} Modified HTML string
7773
*/
78-
function removeTestTokens (html, options) {
79-
const $ = helpers.$(html);
80-
74+
function removeTestTokens ($, options) {
8175
if (!options || options.removeDataTest) {
8276
removeDataAttribute($, 'test');
8377
}
@@ -96,9 +90,6 @@ function removeTestTokens (html, options) {
9690

9791
removeIdTest($, options);
9892
removeClassTest($, options);
99-
100-
html = $.html();
101-
return html;
10293
}
10394

10495
module.exports = removeTestTokens;

0 commit comments

Comments
 (0)