Skip to content

Commit 42396c2

Browse files
committed
[chore]: add more tests, fix logic for non-mapped attrs in settings
1 parent da0ca32 commit 42396c2

File tree

3 files changed

+77
-22
lines changed

3 files changed

+77
-22
lines changed

__tests__/src/rules/no-static-element-interactions-test.js

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const componentsSettings = {
3535
Button: 'button',
3636
TestComponent: 'div',
3737
Link: {
38-
components: 'a',
38+
component: 'a',
3939
attributes: {
4040
href: ['to', 'href'],
4141
},
@@ -44,16 +44,6 @@ const componentsSettings = {
4444
},
4545
};
4646

47-
const componentsSettingNoAttributes = {
48-
'jsx-a11y': {
49-
components: {
50-
Button: 'button',
51-
TestComponent: 'div',
52-
Link: 'a',
53-
},
54-
},
55-
};
56-
5747
const alwaysValid = [
5848
{ code: '<TestComponent onClick={doFoo} />' },
5949
{ code: '<Button onClick={doFoo} />' },
@@ -373,8 +363,8 @@ const neverValid = [
373363
{ code: '<div onMouseDown={() => {}} />;', errors: [expectedError] },
374364
{ code: '<div onMouseUp={() => {}} />;', errors: [expectedError] },
375365
// Custom components
366+
{ code: '<Link onClick={() => void 0} to="path/to/page" />', settings: { 'jsx-a11y': { components: { Link: 'a' } } }, errors: [expectedError] },
376367
{ code: '<TestComponent onClick={() => void 0} to="path/to/page" />', settings: componentsSettings, errors: [expectedError] },
377-
{ code: '<Link onClick={() => void 0} to="path/to/page" />', settings: componentsSettingNoAttributes, errors: [expectedError] },
378368
// `a` with a `to` is not valid, only custom components listed in `components`
379369
{ code: '<a onClick={() => void 0} to="path/to/page" />', settings: componentsSettings, errors: [expectedError] },
380370
];

__tests__/src/util/getSettingsAttributes-test.js

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ test('getSettingsAttributes', (t) => {
1818
'returns existing attributes when no component settings exist',
1919
);
2020

21+
st.deepEqual(
22+
getSettingsAttributes(JSXElementMock('Link', [JSXAttributeMock('foo', 'path/to/page')]).openingElement, {
23+
'jsx-a11y': {},
24+
}),
25+
[JSXAttributeMock('foo', 'path/to/page')],
26+
'returns existing attributes when `components` is empty',
27+
);
28+
2129
st.end();
2230
});
2331

@@ -40,7 +48,24 @@ test('getSettingsAttributes', (t) => {
4048
);
4149

4250
st.deepEqual(
43-
getSettingsAttributes(JSXElementMock('a', [JSXAttributeMock('foo', 'path/to/page')]).openingElement, {
51+
getSettingsAttributes(JSXElementMock('Link', [JSXAttributeMock('bar', 'path/to/page')]).openingElement, {
52+
'jsx-a11y': {
53+
components: {
54+
Link: {
55+
component: 'a',
56+
attributes: {
57+
href: ['foo', 'bar'],
58+
},
59+
},
60+
},
61+
},
62+
}),
63+
[JSXAttributeMock('href', 'path/to/page')],
64+
'returns the exisiting attributes and the mapped attributes',
65+
);
66+
67+
st.deepEqual(
68+
getSettingsAttributes(JSXElementMock('button', [JSXAttributeMock('foo', 'path/to/page')]).openingElement, {
4469
'jsx-a11y': {
4570
components: {
4671
Link: {
@@ -56,6 +81,37 @@ test('getSettingsAttributes', (t) => {
5681
'should return the existing attributes when no mapping exists',
5782
);
5883

84+
st.deepEqual(
85+
getSettingsAttributes(JSXElementMock('Link', [JSXAttributeMock('bar', 'path/to/page')]).openingElement, {
86+
'jsx-a11y': {
87+
components: {
88+
Link: {
89+
component: 'a',
90+
attributes: {
91+
href: ['foo'],
92+
},
93+
},
94+
},
95+
},
96+
}),
97+
[JSXAttributeMock('bar', 'path/to/page')],
98+
'returns the exisiting attributes when no mapping exists',
99+
);
100+
101+
st.deepEqual(
102+
getSettingsAttributes(JSXElementMock('Link', [JSXAttributeMock('foo', 'path/to/page')]).openingElement, {
103+
settings: {
104+
'jsx-a11y': {
105+
components: {
106+
Link: 'a',
107+
},
108+
},
109+
},
110+
}),
111+
[JSXAttributeMock('foo', 'path/to/page')],
112+
'returns existing attributes when components mapping to the component does not have attributes',
113+
);
114+
59115
st.end();
60116
});
61117

src/util/getSettingsAttributes.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22

33
import type { Node, JSXOpeningElement } from 'ast-types-flow';
4-
import { elementType, getProp } from 'jsx-ast-utils';
4+
import { elementType, getProp, propName } from 'jsx-ast-utils';
55
import type { ESLintSettings } from '../../flow/eslint';
66

77
/**
@@ -37,23 +37,32 @@ const getSettingsAttributes = (node: JSXOpeningElement, settings: ESLintSettings
3737

3838
if (!settingsAttributes || typeof settingsAttributes !== 'object') return rawAttributes;
3939

40+
const mappedRawAttrNames = new Set();
41+
4042
const mappedAttributes = Object.entries(settingsAttributes).flatMap(([originalAttr, mappedAttrs]) => {
4143
if (!Array.isArray(mappedAttrs)) return [];
4244

4345
return mappedAttrs.flatMap((mappedAttr) => {
4446
const originalProp = getProp(rawAttributes, mappedAttr);
4547

46-
return originalProp ? [{
47-
...originalProp,
48-
name: {
49-
...originalProp.name,
50-
name: originalAttr,
51-
},
52-
}] : [];
48+
if (originalProp) {
49+
mappedRawAttrNames.add(mappedAttr);
50+
return [{
51+
...originalProp,
52+
name: {
53+
...originalProp.name,
54+
name: originalAttr,
55+
},
56+
}];
57+
}
58+
return [];
5359
});
5460
});
5561

56-
return mappedAttributes;
62+
// raw attributes that don't have mappings
63+
const unmappedAttributes = rawAttributes.filter((attr) => !mappedRawAttrNames.has(propName(attr)));
64+
65+
return [...unmappedAttributes, ...mappedAttributes];
5766
};
5867

5968
export default getSettingsAttributes;

0 commit comments

Comments
 (0)