Skip to content
This repository was archived by the owner on May 17, 2023. It is now read-only.

Commit 7bda0c2

Browse files
siddharthkpFranco Correa
authored andcommitted
Alternate implementation for uniqueId (#1374)
Will wait for @francocorreasosa's review ---- Story time! In certain components, we want to create a relation between 2 html elements examples: 1. form field labels ```jsx <Form.Field> <Label for="my-input">field</Label> <TextInput id="my-input"/> </Form.Field> ``` 2. tabs ```jsx <Tab.Link id="first-tab">Tab 1</Tab.Link> <Tab.Item id="first-tab-item" aria-labelledby="first-tab">...<Tab.Item> ``` We try to implement this without asking to specify an id/label for each of these items A naive implement (the previous one) would be to generate random unique ids and use them. However this approach breaks snapshot tests because the id is not consistent across multiple test runs. This can be solved in user land by mocking this function jest.mock('path_to_this_file', () => () => '-m0ck3d') Another solution could be to generate IDs based on an "pure"-ish algorithm, which gives the same id as long as other environment factors are not changed 1. In an isolated environment, the IDs are consistent across each run 2. In a composed applications, the IDs change but are still unique The implementation, it could just be an increasing integer. Related to #1267
1 parent 2fd7363 commit 7bda0c2

File tree

5 files changed

+374
-49
lines changed

5 files changed

+374
-49
lines changed
Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,46 @@
1-
const id = (prefix = '') => {
2-
prefix = prefix.toLowerCase().replace(/ /g, '_')
1+
/*
2+
Story time!
3+
4+
In certain components, we want to create a relation between
5+
2 html elements
6+
7+
examples:
8+
9+
1. form field labels
10+
11+
<Form>
12+
<Label for="my-input">field</Label>
13+
<TextInput id="my-input"/>
14+
</Form>
15+
16+
2. tabs
17+
18+
<Tab.Link id="first-tab">Tab 1</Tab.Link>
19+
<Tab.Item id="first-tab-item" aria-labelledby="first-tab">...<Tab.Item>
320
4-
const hash = Math.random()
5-
.toString(36)
6-
.substring(5)
21+
We try to implement this without asking to specify an id/label for each of these items
22+
23+
A naive implement (the previous one) would be to generate random unique ids
24+
and use them. However this approach breaks snapshot tests because the id is
25+
not consistent across multiple test runs.
26+
27+
This can be solved in user land by mocking this function
28+
jest.mock('path_to_this_file', () => () => '-m0ck3d')
29+
30+
Another solution could be to generate IDs based on an "pure"-ish algorithm,
31+
which gives the same id as long as other environment factors are not changed
32+
1. In an isolated environment, the IDs are consistent across each run
33+
2. In a composed applications, the IDs change but are still unique
34+
35+
The implemenation, it could just be an increasing integer.
36+
*/
37+
38+
let globalCounter = 0
39+
40+
const generateId = (prefix = 'cosmos') => {
41+
prefix = prefix.toLowerCase().replace(/ /g, '_')
742

8-
return prefix + '-' + hash
43+
return prefix + '-' + globalCounter++
944
}
1045

11-
export default id
46+
export default generateId
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Form Field - old API renders the correct id 1`] = `
4+
<Form
5+
layout="label-on-left"
6+
>
7+
<form
8+
data-cosmos-key="form"
9+
layout="label-on-left"
10+
>
11+
<Component
12+
label="Old API"
13+
>
14+
<Form Field
15+
error={null}
16+
helpText={null}
17+
label="Old API"
18+
>
19+
<styled.div
20+
data-cosmos-key="form.field"
21+
layout="label-on-left"
22+
>
23+
<div
24+
className="sc-esjQYD jDoXVb"
25+
data-cosmos-key="form.field"
26+
>
27+
<styled.div
28+
layout="label-on-left"
29+
>
30+
<div
31+
className="sc-kIPQKe icUXMf"
32+
>
33+
<styled.label
34+
htmlFor="old_api-2"
35+
>
36+
<label
37+
className="sc-hwwEjo fSYpod"
38+
htmlFor="old_api-2"
39+
>
40+
Old API
41+
</label>
42+
</styled.label>
43+
</div>
44+
</styled.div>
45+
<styled.div
46+
layout="label-on-left"
47+
>
48+
<div
49+
className="sc-eXEjpC iUchoc"
50+
>
51+
<Component
52+
type="text"
53+
>
54+
<Form Field
55+
error={null}
56+
fieldComponent={[Function]}
57+
helpText={null}
58+
label="Form label"
59+
type="text"
60+
>
61+
<styled.div
62+
data-cosmos-key="form.field"
63+
layout="label-on-left"
64+
>
65+
<div
66+
className="sc-esjQYD jDoXVb"
67+
data-cosmos-key="form.field"
68+
>
69+
<styled.div
70+
layout="label-on-left"
71+
>
72+
<div
73+
className="sc-kIPQKe icUXMf"
74+
>
75+
<styled.label
76+
htmlFor="form_label-3"
77+
>
78+
<label
79+
className="sc-hwwEjo fSYpod"
80+
htmlFor="form_label-3"
81+
>
82+
Form label
83+
</label>
84+
</styled.label>
85+
</div>
86+
</styled.div>
87+
<styled.div
88+
layout="label-on-left"
89+
>
90+
<div
91+
className="sc-eXEjpC iUchoc"
92+
>
93+
<TextInput
94+
actions={Array []}
95+
code={false}
96+
error={null}
97+
fieldComponent={[Function]}
98+
hasError={false}
99+
helpText={null}
100+
id="form_label-3"
101+
label="Form label"
102+
onChange={null}
103+
readOnly={false}
104+
size="default"
105+
type="text"
106+
>
107+
<Styled(styled.input)
108+
actions={Array []}
109+
code={false}
110+
data-cosmos-key="text-input"
111+
error={null}
112+
fieldComponent={[Function]}
113+
hasError={false}
114+
helpText={null}
115+
id="form_label-3"
116+
label="Form label"
117+
onChange={null}
118+
readOnly={false}
119+
size="default"
120+
type="text"
121+
>
122+
<styled.input
123+
actions={Array []}
124+
className="sc-kgAjT iqekDB"
125+
code={false}
126+
data-cosmos-key="text-input"
127+
error={null}
128+
fieldComponent={[Function]}
129+
hasError={false}
130+
helpText={null}
131+
id="form_label-3"
132+
label="Form label"
133+
onChange={null}
134+
readOnly={false}
135+
size="default"
136+
type="text"
137+
>
138+
<input
139+
className="sc-kgAjT iqekDB sc-csuQGl hIrBSd"
140+
data-cosmos-key="text-input"
141+
id="form_label-3"
142+
label="Form label"
143+
onChange={null}
144+
readOnly={false}
145+
size="default"
146+
type="text"
147+
/>
148+
</styled.input>
149+
</Styled(styled.input)>
150+
</TextInput>
151+
</div>
152+
</styled.div>
153+
</div>
154+
</styled.div>
155+
</Form Field>
156+
</Component>
157+
</div>
158+
</styled.div>
159+
</div>
160+
</styled.div>
161+
</Form Field>
162+
</Component>
163+
</form>
164+
</Form>
165+
`;
166+
167+
exports[`Form Field renders the correct id 1`] = `
168+
<Form
169+
layout="label-on-left"
170+
>
171+
<form
172+
data-cosmos-key="form"
173+
layout="label-on-left"
174+
>
175+
<Component
176+
label="Field label"
177+
>
178+
<Form Field
179+
error={null}
180+
helpText={null}
181+
label="Field label"
182+
>
183+
<styled.div
184+
data-cosmos-key="form.field"
185+
layout="label-on-left"
186+
>
187+
<div
188+
className="sc-esjQYD jDoXVb"
189+
data-cosmos-key="form.field"
190+
>
191+
<styled.div
192+
layout="label-on-left"
193+
>
194+
<div
195+
className="sc-kIPQKe icUXMf"
196+
>
197+
<styled.label
198+
htmlFor="field_label-1"
199+
>
200+
<label
201+
className="sc-hwwEjo fSYpod"
202+
htmlFor="field_label-1"
203+
>
204+
Field label
205+
</label>
206+
</styled.label>
207+
</div>
208+
</styled.div>
209+
<styled.div
210+
layout="label-on-left"
211+
>
212+
<div
213+
className="sc-eXEjpC iUchoc"
214+
>
215+
<TextInput
216+
actions={Array []}
217+
code={false}
218+
error={null}
219+
onChange={null}
220+
readOnly={false}
221+
size="default"
222+
type="text"
223+
>
224+
<Styled(styled.input)
225+
actions={Array []}
226+
code={false}
227+
data-cosmos-key="text-input"
228+
error={null}
229+
onChange={null}
230+
readOnly={false}
231+
size="default"
232+
type="text"
233+
>
234+
<styled.input
235+
actions={Array []}
236+
className="sc-kgAjT iqekDB"
237+
code={false}
238+
data-cosmos-key="text-input"
239+
error={null}
240+
onChange={null}
241+
readOnly={false}
242+
size="default"
243+
type="text"
244+
>
245+
<input
246+
className="sc-kgAjT iqekDB sc-csuQGl hIrBSd"
247+
data-cosmos-key="text-input"
248+
onChange={null}
249+
readOnly={false}
250+
size="default"
251+
type="text"
252+
/>
253+
</styled.input>
254+
</Styled(styled.input)>
255+
</TextInput>
256+
</div>
257+
</styled.div>
258+
</div>
259+
</styled.div>
260+
</Form Field>
261+
</Component>
262+
</form>
263+
</Form>
264+
`;

0 commit comments

Comments
 (0)