-
-
Notifications
You must be signed in to change notification settings - Fork 640
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(label-has-associated-control): add option for enforcing label's …
…htmlFor matches control's id This change adds an option to the `label-has-associated-control` rule, enforcing that the label's htmlFor attribute matches the associated control's id attribute. Previously, the only validation done on htmlFor was that it was on the label component and had text. There was no attempt to cross-check that value against any attribute on the associated control. Not, when the option is enabled, cases where they don't match will report. I also took the opportunity to update the error messages so that each assert type gets an error message with verbiage specific to the assertion. (not sure if this should be called out as a separate feature in the changelog?). Note: the current implementation only checks the first instance it finds of child component that matches each control component type. It assumes that there won't be any acceptable cases where a label would have multiple inputs nested beneath it. Let me know if that assumption doesn't hold. Closes:
- Loading branch information
1 parent
bfb0e9e
commit d38df62
Showing
6 changed files
with
424 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
import test from 'tape'; | ||
|
||
import getChildComponent from '../../../src/util/getChildComponent'; | ||
import JSXAttributeMock from '../../../__mocks__/JSXAttributeMock'; | ||
import JSXElementMock from '../../../__mocks__/JSXElementMock'; | ||
import JSXExpressionContainerMock from '../../../__mocks__/JSXExpressionContainerMock'; | ||
|
||
test('mayContainChildComponent', (t) => { | ||
t.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('span', [], []), | ||
JSXElementMock('span', [], [ | ||
JSXElementMock('span', [], []), | ||
JSXElementMock('span', [], [ | ||
JSXElementMock('span', [], []), | ||
]), | ||
]), | ||
]), | ||
JSXElementMock('span', [], []), | ||
JSXElementMock('img', [ | ||
JSXAttributeMock('src', 'some/path'), | ||
]), | ||
]), | ||
'FancyComponent', | ||
5, | ||
), | ||
undefined, | ||
'no FancyComponent returns undefined', | ||
); | ||
|
||
t.test('contains an indicated component', (st) => { | ||
const inputMock = JSXElementMock('input'); | ||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
inputMock, | ||
]), | ||
'input', | ||
), | ||
inputMock, | ||
'returns input', | ||
); | ||
|
||
const FancyComponentMock = JSXElementMock('FancyComponent'); | ||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
FancyComponentMock, | ||
]), | ||
'FancyComponent', | ||
), | ||
FancyComponentMock, | ||
'returns FancyComponent', | ||
); | ||
|
||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('FancyComponent'), | ||
]), | ||
]), | ||
'FancyComponent', | ||
), | ||
undefined, | ||
'FancyComponent is outside of default depth, should return undefined', | ||
); | ||
|
||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('div', [], [ | ||
FancyComponentMock, | ||
]), | ||
]), | ||
'FancyComponent', | ||
2, | ||
), | ||
FancyComponentMock, | ||
'FancyComponent is inside of custom depth, should return FancyComponent', | ||
); | ||
|
||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('span', [], []), | ||
JSXElementMock('span', [], [ | ||
JSXElementMock('span', [], []), | ||
JSXElementMock('span', [], [ | ||
JSXElementMock('span', [], [ | ||
JSXElementMock('span', [], [ | ||
FancyComponentMock, | ||
]), | ||
]), | ||
]), | ||
]), | ||
]), | ||
JSXElementMock('span', [], []), | ||
JSXElementMock('img', [ | ||
JSXAttributeMock('src', 'some/path'), | ||
]), | ||
]), | ||
'FancyComponent', | ||
6, | ||
), | ||
FancyComponentMock, | ||
'deep nesting, returns FancyComponent', | ||
); | ||
|
||
st.end(); | ||
}); | ||
|
||
const MysteryBox = JSXExpressionContainerMock('mysteryBox'); | ||
t.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
MysteryBox, | ||
]), | ||
'FancyComponent', | ||
), | ||
MysteryBox, | ||
'Indeterminate situations + expression container children - returns component', | ||
); | ||
|
||
t.test('Glob name matching - component name contains question mark ? - match any single character', (st) => { | ||
const FancyComponentMock = JSXElementMock('FancyComponent'); | ||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
FancyComponentMock, | ||
]), | ||
'Fanc?Co??onent', | ||
), | ||
FancyComponentMock, | ||
'returns component', | ||
); | ||
|
||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('FancyComponent'), | ||
]), | ||
'FancyComponent?', | ||
), | ||
undefined, | ||
'returns undefined', | ||
); | ||
|
||
st.test('component name contains asterisk * - match zero or more characters', (s2t) => { | ||
s2t.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
FancyComponentMock, | ||
]), | ||
'Fancy*', | ||
), | ||
FancyComponentMock, | ||
'returns component', | ||
); | ||
|
||
s2t.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
FancyComponentMock, | ||
]), | ||
'*Component', | ||
), | ||
FancyComponentMock, | ||
'returns component', | ||
); | ||
|
||
s2t.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
FancyComponentMock, | ||
]), | ||
'Fancy*C*t', | ||
), | ||
FancyComponentMock, | ||
'returns component', | ||
); | ||
|
||
s2t.end(); | ||
}); | ||
|
||
st.end(); | ||
}); | ||
|
||
t.test('using a custom elementType function', (st) => { | ||
const CustomInputMock = JSXElementMock('CustomInput'); | ||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
CustomInputMock, | ||
]), | ||
'input', | ||
2, | ||
() => 'input', | ||
), | ||
CustomInputMock, | ||
'returns the component when the custom elementType returns the proper name', | ||
); | ||
|
||
st.equal( | ||
getChildComponent( | ||
JSXElementMock('div', [], [ | ||
JSXElementMock('CustomInput'), | ||
]), | ||
'input', | ||
2, | ||
() => 'button', | ||
), | ||
undefined, | ||
'returns undefined when the custom elementType returns a wrong name', | ||
); | ||
|
||
st.end(); | ||
}); | ||
|
||
t.end(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.