Skip to content

Commit d2c97a7

Browse files
attributesNotToStringify
1 parent db19877 commit d2c97a7

File tree

9 files changed

+183
-41
lines changed

9 files changed

+183
-41
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Related to issue #0
1111
**Checklist:**
1212

1313
* [ ] Update documentation site
14-
* [ ] Update dependencies
15-
* [ ] Run `volta pin node@latest && volta pin npm@latest`
16-
* [ ] Bump
14+
* [ ] Update dependencies - `npm outdated`
15+
* [ ] `npm run volta`
16+
* [ ] `npm run bump`
1717
* [ ] If API changed, update `types.js`

package-lock.json

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

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
{
22
"name": "vue3-snapshot-serializer",
33
"type": "module",
4-
"version": "2.8.0",
4+
"version": "2.9.0",
55
"description": "Vitest snapshot serializer for Vue 3 components",
66
"main": "index.js",
77
"scripts": {
88
"lint": "eslint *.js src tests",
99
"fix": "npm run lint -- --fix",
1010
"test": "vitest --coverage",
1111
"unit": "vitest --run",
12+
"volta": "volta pin node@latest && volta pin npm@latest",
13+
"bump": "npx --yes -- @jsdevtools/version-bump-prompt && npm i",
1214
"debug": "vitest --inspect-brk --no-file-parallelism -t \"Renders\" \"testingLibrary\""
1315
},
1416
"dependencies": {

src/cheerioManipulation.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ const stringifyAttributes = function ($, vueWrapper) {
226226
const attributeNames = Object.keys(attributes);
227227
for (let attributeName of attributeNames) {
228228
let value = vnode?.wrapperElement?.__vnode?.props?.[attributeName];
229-
if (value !== undefined && typeof(value) !== 'string') {
229+
if (
230+
value !== undefined &&
231+
typeof(value) !== 'string' &&
232+
!globalThis.vueSnapshots.attributesNotToStringify.includes(attributeName)
233+
) {
230234
value = swapQuotes(stringify(value));
231235
$(element).attr(attributeName, value);
232236
}
@@ -236,14 +240,14 @@ const stringifyAttributes = function ($, vueWrapper) {
236240
const attributes = Array.from(vnode.attributes);
237241
for (let attribute of attributes) {
238242
const attributeName = attribute.name;
239-
let value;
240-
if (vnode.__vnode?.props?.[attributeName] !== undefined) {
241-
value = vnode.__vnode.props[attributeName];
242-
} else {
243-
value = attribute.value;
244-
}
245-
if (value !== undefined && typeof(value) !== 'string') {
246-
value = swapQuotes(stringify(value));
243+
let value = attribute.value;
244+
if (!globalThis.vueSnapshots.attributesNotToStringify.includes(attributeName)) {
245+
if (vnode.__vnode?.props?.[attributeName] !== undefined) {
246+
value = vnode.__vnode.props[attributeName];
247+
}
248+
if (value !== undefined && typeof(value) !== 'string') {
249+
value = swapQuotes(stringify(value));
250+
}
247251
}
248252
$(element).attr(attributeName, value);
249253
}

src/loadOptions.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const ALLOWED_FORMATTERS = [
4040
'diffable',
4141
'none'
4242
];
43+
const ATTRIBUTES_NOT_TO_STRINGIFY_DEFAULTS = ['style'];
4344
const TAGS_WITH_WHITESPACE_PRESERVED_DEFAULTS = ['a', 'pre'];
4445
const VOID_ELEMENTS_DEFAULT = 'xhtml';
4546
const ALLOWED_VOID_ELEMENTS = Object.freeze([
@@ -110,6 +111,25 @@ export const loadOptions = function () {
110111
}
111112
globalThis.vueSnapshots.attributesToClear = attributesToClear;
112113

114+
let attributesNotToStringify = [];
115+
if (Array.isArray(globalThis.vueSnapshots.attributesNotToStringify)) {
116+
for (const attribute of globalThis.vueSnapshots.attributesNotToStringify) {
117+
if (
118+
typeof(attribute) === 'string' &&
119+
!attribute.trim().includes(' ')
120+
) {
121+
attributesNotToStringify.push(attribute.trim());
122+
} else if (typeof(attribute) === 'string' && attribute.includes(' ')) {
123+
logger('Attributes should not inlcude a space in global.vueSnapshots.attributesNotToStringify. Received: ' + attribute);
124+
} else {
125+
logger('Attributes must be a type of string in global.vueSnapshots.attributesNotToStringify. Received: ' + attribute);
126+
}
127+
}
128+
} else {
129+
attributesNotToStringify = ATTRIBUTES_NOT_TO_STRINGIFY_DEFAULTS;
130+
}
131+
globalThis.vueSnapshots.attributesNotToStringify = attributesNotToStringify;
132+
113133
// Normalize Stubs
114134
const stubs = globalThis.vueSnapshots.stubs;
115135
const stubsToProcess = {};
@@ -366,6 +386,7 @@ export const loadOptions = function () {
366386

367387
const permittedRootKeys = [
368388
...Object.keys(booleanDefaults),
389+
'attributesNotToStringify',
369390
'attributesToClear',
370391
'classicFormatting',
371392
'formatter',
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<h1
3+
:class="{ active: true, disabled: false }"
4+
:style="{ background: '#F00', width: 0 }"
5+
:title="{ a: 2 }"
6+
>
7+
Text
8+
</h1>
9+
</template>
10+
11+
<script>
12+
export default {
13+
name: 'AttributesNotToStringify'
14+
};
15+
</script>

tests/unit/src/cheerioManipulation.test.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { mount } from '@vue/test-utils';
44

55
import { cheerioManipulation } from '@/cheerioManipulation.js';
66

7+
import AttributesNotToStringify from '@@/mockComponents/AttributesNotToStringify.vue';
78
import DataVId from '@@/mockComponents/DataVId.vue';
89
import CheckboxesAndRadios from '@@/mockComponents/CheckboxesAndRadios.vue';
910
import EmbeddedStyles from '@@/mockComponents/EmbeddedStyles.vue';
@@ -406,6 +407,80 @@ describe('Cheerio Manipulation', () => {
406407
});
407408
});
408409

410+
describe('Attributes not to stringify', () => {
411+
test('Skips style by default', async () => {
412+
globalThis.vueSnapshots.stringifyAttributes = true;
413+
globalThis.vueSnapshots.attributesNotToStringify = undefined;
414+
415+
const wrapper = await mount(AttributesNotToStringify);
416+
417+
expect(wrapper)
418+
.toMatchInlineSnapshot(`
419+
<h1
420+
class="active"
421+
style="background: #F00; width: 0px;"
422+
title="{ a: 2 }"
423+
>
424+
Text
425+
</h1>
426+
`);
427+
});
428+
429+
test('Has no effect if stringifyAttributes is disabled', async () => {
430+
globalThis.vueSnapshots.stringifyAttributes = false;
431+
globalThis.vueSnapshots.attributesNotToStringify = ['style'];
432+
433+
const wrapper = await mount(AttributesNotToStringify);
434+
435+
expect(wrapper)
436+
.toMatchInlineSnapshot(`
437+
<h1
438+
class="active"
439+
style="background: #F00; width: 0px;"
440+
title="[object Object]"
441+
>
442+
Text
443+
</h1>
444+
`);
445+
});
446+
447+
test('Stringifies everything', async () => {
448+
globalThis.vueSnapshots.stringifyAttributes = true;
449+
globalThis.vueSnapshots.attributesNotToStringify = [];
450+
451+
const wrapper = await mount(AttributesNotToStringify);
452+
453+
expect(wrapper)
454+
.toMatchInlineSnapshot(`
455+
<h1
456+
class="active"
457+
style="{ background: '#F00', width: 0 }"
458+
title="{ a: 2 }"
459+
>
460+
Text
461+
</h1>
462+
`);
463+
});
464+
465+
test('Inverted settings', async () => {
466+
globalThis.vueSnapshots.stringifyAttributes = true;
467+
globalThis.vueSnapshots.attributesNotToStringify = ['title'];
468+
469+
const wrapper = await mount(AttributesNotToStringify);
470+
471+
expect(wrapper)
472+
.toMatchInlineSnapshot(`
473+
<h1
474+
class="active"
475+
style="{ background: '#F00', width: 0 }"
476+
title="[object Object]"
477+
>
478+
Text
479+
</h1>
480+
`);
481+
});
482+
});
483+
409484
describe('Stubs', () => {
410485
let input;
411486

tests/unit/src/loadOptions.test.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe('Load options', () => {
1515
const defaultSettings = Object.freeze({
1616
...booleanDefaults,
1717
attributesToClear: [],
18+
attributesNotToStringify: ['style'],
1819
stubs: {},
1920
formatter: 'diffable',
2021
formatting: {
@@ -40,7 +41,8 @@ describe('Load options', () => {
4041

4142
test('Override defaults', () => {
4243
const invertedDefaults = {
43-
attributesToClear: [false]
44+
attributesToClear: [false],
45+
attributesNotToStringify: []
4446
};
4547
for (const setting in booleanDefaults) {
4648
invertedDefaults[setting] = !booleanDefaults[setting];
@@ -52,7 +54,8 @@ describe('Load options', () => {
5254
expect(globalThis.vueSnapshots)
5355
.toEqual({
5456
...invertedDefaults,
55-
attributesToClear: []
57+
attributesToClear: [],
58+
attributesNotToStringify: []
5659
});
5760

5861
expect(console.info)
@@ -66,6 +69,7 @@ describe('Load options', () => {
6669
settings: {
6770
addInputValues: false,
6871
attributesToClear: [],
72+
attributesNotToStringify: [],
6973
clearInlineFunctions: true,
7074
debug: true,
7175
formatter: 'diffable',
@@ -107,6 +111,7 @@ describe('Load options', () => {
107111
settings: {
108112
addInputValues: false,
109113
attributesToClear: [],
114+
attributesNotToStringify: [],
110115
clearInlineFunctions: true,
111116
debug: true,
112117
formatter: 'diffable',
@@ -206,6 +211,25 @@ describe('Load options', () => {
206211
});
207212
});
208213

214+
describe('Attributes not to stringify', () => {
215+
test('Sets attributesNotToStringify', () => {
216+
globalThis.vueSnapshots = {
217+
attributesNotToStringify: ['title', 'id', 'two words', 22]
218+
};
219+
220+
loadOptions();
221+
222+
expect(globalThis.vueSnapshots.attributesNotToStringify)
223+
.toEqual(['title', 'id']);
224+
225+
expect(console.info)
226+
.toHaveBeenCalledWith('Vue 3 Snapshot Serializer: Attributes should not inlcude a space in global.vueSnapshots.attributesNotToStringify. Received: two words');
227+
228+
expect(console.info)
229+
.toHaveBeenCalledWith('Vue 3 Snapshot Serializer: Attributes must be a type of string in global.vueSnapshots.attributesNotToStringify. Received: 22');
230+
});
231+
});
232+
209233
describe('Stubs', () => {
210234
test('Array must be strings', () => {
211235
globalThis.vueSnapshots.stubs = ['a', 2, 'b'];

0 commit comments

Comments
 (0)