Bin
2025-12-16 9e0b2ba2c317b1a86212f24cbae3195ad1f3dbfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
Feature("Test required param");
 
const createConfig = ({ visibleWhen = "choice-selected" } = {}) => {
  return `
  <View>
    <Text name="text" value="$text"></Text>
    <Choices name="validation-label" required="true" toName="text">
      <Choice value="Missing words" alias="missing-words"></Choice>
      <Choice value="Valid" alias="valid"></Choice>
    </Choices>
    <Choices name="second" required="true" toName="text">
      <Choice value="Don't select me" alias="dont"></Choice>
      <Choice value="Me neither" alias="neither"></Choice>
    </Choices>
    <Choices name="easter-egg" required="true" toName="text"
      visibleWhen="${visibleWhen}"
      whenTagName="second"
      whenChoiceValue="Me neither"
    >
      <Choice value="Secret level"></Choice>
      <Choice value="Click on me now"></Choice>
    </Choices>
  </View>
`;
};
 
const complex = `
  <View>
    <Text name="text" value="$text"></Text>
    <Labels name="toggle">
      <Label value="Hidden" />
      <Label value="Useless" />
    </Labels>
    <View>(select region to see more required controls)</View>
    <View visibleWhen="region-selected">
      <Header>Required per-region choices</Header>
      <Choices name="validation-label" required="true" toName="text" perRegion="true">
        <Choice value="Missing words" alias="missing-words"></Choice>
        <Choice value="Valid" alias="valid"></Choice>
      </Choices>
    </View>
 
    <Header>Required common description</Header>
    <Textarea name="common-description" toName="text" required="true" />
    <View visibleWhen="region-selected">
      <Header>Required region description</Header>
      <Textarea name="region-description" toName="text" required="true" perRegion="true" />
    </View>
 
    <Header>Nested controls are required, but only when you select one of those:</Header>
    <Choices name="switch" toName="text">
      <Choice value="Required textarea" alias="dont"></Choice>
      <Choice value="Required choices" alias="neither"></Choice>
    </Choices>
    <View visibleWhen="choice-selected"
      whenTagName="switch"
      whenChoiceValue="Required textarea">
      <Header>Required only when "Required textarea" selected</Header>
      <Textarea name="choice-description" toName="text" required="true" />
    </View>
 
    <View visibleWhen="choice-selected"
      whenTagName="switch"
      whenChoiceValue="Required choices">
      <Header>Required only when "Required choices" selected</Header>
      <Choices name="choice" toName="text" required="true">
        <Choice value="Don't select me" alias="dont"></Choice>
        <Choice value="Me neither" alias="neither"></Choice>
      </Choices>
    </View>
  </View>
`;
 
const text = "To have faith is to trust yourself to the water";
const result = {
  id: "qwerty",
  from_name: "toggle",
  to_name: "text",
  type: "labels",
  origin: "manual",
  value: { start: 3, end: 7, labels: ["Hidden"] },
};
const annotations = [{ id: "1", result: [result] }];
 
Scenario("Check required param", async ({ I, LabelStudio, Modals }) => {
  const params = { config: createConfig(), data: { text } };
 
  const waitForError = (name) => {
    Modals.seeWarning(`Checkbox "${name}" is required`);
    Modals.closeWarning();
  };
 
  I.amOnPage("/");
  LabelStudio.init(params);
 
  // Add new Annotation to be able to submit it
  I.click('[aria-label="Annotations List Toggle"]');
  I.click('[aria-label="Create Annotation"]');
  I.submitAnnotation();
  waitForError("validation-label");
 
  I.click("Me neither");
  I.submitAnnotation();
  waitForError("validation-label");
 
  I.click("Valid");
  I.submitAnnotation();
  waitForError("easter-egg");
 
  I.click("Don't select me");
  I.submitAnnotation();
  // Annotation is submitted, so now we can only update it
  I.seeAnnotationSubmitted();
 
  // Reload to check another combination
  LabelStudio.init(params);
  // Page is reloaded, there are no new annotation from prev steps
  I.dontSee("New annotation");
  I.click('[aria-label="Annotations List Toggle"]');
  I.click('[aria-label="Create Annotation"]');
  I.click("Valid");
  I.submitAnnotation();
  I.see("Warning");
  I.see('Checkbox "second" is required');
});
 
Scenario("Check required param in complex config", async ({ I, LabelStudio, AtOutliner, Modals }) => {
  const params = { annotations, config: complex, data: { text } };
 
  const waitForError = (name) => {
    // Two possible errors:
    // - Checkbox "name" is required.
    // - Input for the textarea "name" is required.
    Modals.seeWarning(`"${name}" is required`);
    Modals.closeWarning();
  };
 
  I.amOnPage("/");
  LabelStudio.init(params);
 
  // we already have an annotation
  I.updateAnnotation();
  waitForError("validation-label");
 
  // region stays selected after error, so per-region controls are visible
  I.click("Valid");
  I.updateAnnotation();
  waitForError("common-description");
 
  I.fillField("common-description", "some text");
  I.updateAnnotation();
  waitForError("region-description");
 
  // again stays visible
  I.fillField("region-description", "some description");
 
  I.updateAnnotation();
  // after successful update region is unselected and no modals shown
  I.dontSee("Valid");
  I.dontSeeElement(".ant-modal");
 
  I.click("Required textarea");
  I.updateAnnotation();
  waitForError("choice-description");
 
  I.click("Required choices");
  I.updateAnnotation();
  waitForError("choice");
 
  I.click("Me neither");
  // select labeled region
  AtOutliner.clickRegion("have");
  I.see("Valid");
  I.updateAnnotation();
  I.dontSee("Valid");
 
  I.click("Required textarea");
  I.updateAnnotation();
  waitForError("choice-description");
  I.fillField("choice-description", "test text");
  // select labeled region
  AtOutliner.clickRegion("have");
  I.see("Valid");
  I.updateAnnotation();
  I.dontSee("Valid");
 
  I.click('[aria-label="Annotations List Toggle"]');
  I.click('[aria-label="Create Annotation"]');
  I.submitAnnotation();
  waitForError("common-description");
  I.fillField("common-description", "some text");
  I.submitAnnotation();
  I.seeAnnotationSubmitted();
});
 
Scenario("Check required param with visibleWhen='choice-unselected'", async ({ I, LabelStudio, Modals }) => {
  const params = { config: createConfig({ visibleWhen: "choice-unselected" }), data: { text } };
  const waitForError = (name) => {
    Modals.seeWarning(`Checkbox "${name}" is required`);
    Modals.closeWarning();
  };
 
  I.amOnPage("/");
  LabelStudio.init(params);
 
  // Add new Annotation to be able to submit it
  I.click('[aria-label="Annotations List Toggle"]');
  I.click('[aria-label="Create Annotation"]');
 
  // Select one from each choices groups, except the one with visibleWhen condition
  I.click("Valid");
  I.click("Don't select me");
 
  // We should get error, cause "easter-egg" is visible and required
  I.submitAnnotation();
  waitForError("easter-egg");
 
  // Select the "Me neither" option to make the "easter-egg" block not required
  I.click("Me neither");
  I.submitAnnotation();
  // Annotation is submitted, so now we can only update it
  I.seeAnnotationSubmitted();
 
  // Reset to check another scenario
  LabelStudio.init(params);
  // LabelStudio is reloaded, there are no new annotation from prev steps
  I.dontSee("New annotation");
  I.click('[aria-label="Annotations List Toggle"]');
  I.click('[aria-label="Create Annotation"]');
 
  // Select all required options we have
  I.click("Valid");
  I.click("Don't select me");
  I.click("Secret level");
 
  I.submitAnnotation();
  // Annotation is submitted, so now we can only update it
  I.seeAnnotationSubmitted();
});