Skip to content

Commit fa47156

Browse files
talissoncostaclaude
andcommitted
test(e2e): select the value editors by role and name
ValueEditor no longer takes a data-test. Three accessors replace it, and setText/waitForElementVisible accept a Locator so callers can pass one. featureValueField() role=textbox, /^(Value|Control Value)/ variationValueField(i) role=textbox, "Variation Value", nth(i) segmentOverrideValueField(i) scoped to the override, then role+name The feature value alternation is not cosmetic: the label becomes "Control Value <weight>%" once a feature has variations. This also retires a selector that encoded its own value: data-test={`featureVariationValue${featureStateToValue(value) || index}`} The id was featureVariationValue1 only while the field was empty, and became featureVariationValueadded once you typed. The tests passed because they addressed it before typing. toHaveValue becomes toHaveText in change-request-test: the editor is a contenteditable, not a textarea, so there is no value to assert on. No new type errors in e2e (3 before, 3 after, all pre-existing). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 280e3fc commit fa47156

10 files changed

Lines changed: 43 additions & 31 deletions

File tree

frontend/documentation/components/ValueEditor.stories.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ const Interactive = ({
2020
const [value, setValue] = useState(initialValue)
2121
return (
2222
<div style={{ maxWidth: width, padding: 16 }}>
23-
<ValueEditor
24-
data-test='valueEditor'
25-
{...props}
26-
value={value}
27-
onChange={setValue}
28-
/>
23+
<ValueEditor {...props} value={value} onChange={setValue} />
2924
</div>
3025
)
3126
}

frontend/e2e/helpers/e2e-helpers.playwright.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Page, expect } from '@playwright/test';
1+
import { Locator, Page, expect } from '@playwright/test';
22
import { LONG_TIMEOUT, SHORT_TIMEOUT, byId, log, logUsingLastSection, getFlagsmith } from './utils.playwright';
33

44
// Re-export for backwards compatibility
@@ -18,23 +18,41 @@ export type Rule = {
1818
export class E2EHelpers {
1919
constructor(private page: Page) {}
2020

21+
// The value editors are selected by role and accessible name rather than a
22+
// data-test. The feature value label switches to "Control Value <weight>%"
23+
// once the feature has variations, hence the alternation.
24+
featureValueField(): Locator {
25+
return this.page.getByRole('textbox', { name: /^(Value|Control Value)/ });
26+
}
27+
28+
variationValueField(index: number): Locator {
29+
return this.page.getByRole('textbox', { name: 'Variation Value' }).nth(index);
30+
}
31+
32+
segmentOverrideValueField(index: number): Locator {
33+
return this.page
34+
.locator(byId(`segment-override-${index}`))
35+
.getByRole('textbox', { name: 'Value' });
36+
}
37+
2138
async isElementExists(selector: string): Promise<boolean> {
2239
return await this.page.locator(byId(selector)).count() > 0;
2340
}
2441

25-
async setText(selector: string, text: string) {
42+
async setText(selector: string | Locator, text: string) {
2643
logUsingLastSection(`Set text ${selector} : ${text}`);
27-
const element = this.page.locator(selector).first();
44+
const element = typeof selector === 'string' ? this.page.locator(selector).first() : selector;
2845
await element.waitFor({ state: 'visible', timeout: LONG_TIMEOUT });
2946
await element.clear();
3047
if (text) {
3148
await element.fill(text);
3249
}
3350
}
3451

35-
async waitForElementVisible(selector: string, timeout: number = LONG_TIMEOUT) {
52+
async waitForElementVisible(selector: string | Locator, timeout: number = LONG_TIMEOUT) {
3653
logUsingLastSection(`Waiting element visible ${selector}`);
37-
await this.page.locator(selector).first().waitFor({
54+
const element = typeof selector === 'string' ? this.page.locator(selector).first() : selector;
55+
await element.waitFor({
3856
state: 'visible',
3957
timeout
4058
});
@@ -269,7 +287,7 @@ export class E2EHelpers {
269287
await featureRow.waitFor({ state: 'visible', timeout: LONG_TIMEOUT });
270288
await featureRow.dispatchEvent('click');
271289
await this.waitForElementVisible('#create-feature-modal');
272-
await this.waitForElementVisible(byId('featureValue'));
290+
await this.waitForElementVisible(this.featureValueField());
273291
}
274292

275293
// Create a feature
@@ -296,7 +314,7 @@ export class E2EHelpers {
296314
await this.gotoFeatures();
297315
await this.click('#show-create-feature-btn');
298316
await this.setText(byId('featureID'), name);
299-
await this.setText(byId('featureValue'), `${value}`);
317+
await this.setText(this.featureValueField(), `${value}`);
300318
await this.setText(byId('featureDesc'), description);
301319
if (!defaultOff) {
302320
await this.click(byId('toggle-feature-button'));
@@ -305,7 +323,7 @@ export class E2EHelpers {
305323
const v = mvs[i];
306324
await this.click(byId('add-variation'));
307325
await this.page.waitForTimeout(200);
308-
await this.setText(byId(`featureVariationValue${i}`), v.value);
326+
await this.setText(this.variationValueField(i), v.value);
309327
await this.setText(byId(`featureVariationWeight${v.value}`), `${v.weight}`);
310328
await this.page.waitForTimeout(100);
311329
}
@@ -588,7 +606,7 @@ export class E2EHelpers {
588606
await this.click(byId('segment_overrides'));
589607
}
590608
await this.click(dropdownSelector);
591-
await this.waitForElementVisible(byId(`segment-override-value-${index}`));
609+
await this.waitForElementVisible(this.segmentOverrideValueField(index));
592610
}
593611

594612
// Add segment override for boolean flags
@@ -611,7 +629,7 @@ export class E2EHelpers {
611629
// Add segment override for remote configs
612630
async addSegmentOverrideConfig(index: number, value: string | number | boolean, selectionIndex: number = 0) {
613631
await this.openSegmentOverride(index, selectionIndex);
614-
await this.setText(byId(`segment-override-value-${index}`), `${value}`);
632+
await this.setText(this.segmentOverrideValueField(index), `${value}`);
615633
await this.click(byId(`segment-override-toggle-${index}`));
616634
}
617635

@@ -631,7 +649,7 @@ export class E2EHelpers {
631649
await featureRow.dispatchEvent('click');
632650
await this.waitForElementVisible(byId('update-feature-btn'));
633651
if (value !== '') {
634-
await this.setText(byId('featureValue'), `${value}`);
652+
await this.setText(this.featureValueField(), `${value}`);
635653
}
636654
if (mvs.length > 0) {
637655
await this.page.waitForTimeout(500);

frontend/e2e/tests/change-request-test.pw.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ test.describe('Change Request Tests', () => {
1212
page,
1313
}, testInfo) => {
1414
const {
15+
featureValueField,
1516
assertChangeRequestCount,
1617
approveChangeRequest,
1718
assertInputValue,
@@ -73,7 +74,7 @@ test.describe('Change Request Tests', () => {
7374
log('Create change request by editing feature value')
7475
await gotoFeatures()
7576
await gotoFeature(featureName)
76-
await setText(byId('featureValue'), 'updated_value')
77+
await setText(featureValueField(), 'updated_value')
7778

7879
await createChangeRequest(
7980
'Update feature value',
@@ -126,7 +127,7 @@ test.describe('Change Request Tests', () => {
126127
await page.reload({ waitUntil: 'domcontentloaded' })
127128
await waitForElementVisible('#show-create-feature-btn')
128129
await gotoFeature(featureName)
129-
await expect(page.locator(byId('featureValue'))).toHaveValue('updated_value', { timeout: 15000 })
130+
await expect(featureValueField()).toHaveText('updated_value', { timeout: 15000 })
130131
await closeModal()
131132

132133
log('Verify value via API')

frontend/e2e/tests/mv-options-tests.pw.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const variantCards = (page: Page) => page.locator('#create-feature-modal .varian
2222
test.describe('Multivariate Options', () => {
2323
test('Repeated saves keep the variant set stable @oss', async ({ page }) => {
2424
const {
25+
variationValueField,
2526
closeModal,
2627
createRemoteConfig,
2728
editRemoteConfig,
@@ -62,6 +63,7 @@ test.describe('Multivariate Options', () => {
6263

6364
test('Variants can be added and removed in a single save @oss', async ({ page }) => {
6465
const {
66+
variationValueField,
6567
click,
6668
closeModal,
6769
createRemoteConfig,
@@ -90,7 +92,7 @@ test.describe('Multivariate Options', () => {
9092
await expect(variantCards(page)).toHaveCount(1);
9193
await click(byId('add-variation'));
9294
await page.waitForTimeout(200);
93-
await setText(byId('featureVariationValue1'), 'added');
95+
await setText(variationValueField(1), 'added');
9496
await page.waitForTimeout(500);
9597
await click(byId('update-feature-btn'));
9698
await waitForToast();

frontend/e2e/tests/segment-test.pw.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ const segmentAnyRules = [
8484

8585
test('Segment test 1 - Create, update, and manage segments with multivariate flags @oss', async ({ page }, testInfo) => {
8686
const {
87+
featureValueField,
8788
addSegmentOverride,
8889
assertInputValue,
8990
assertUserFeatureValue,
@@ -204,6 +205,7 @@ test('Segment test 1 - Create, update, and manage segments with multivariate fla
204205

205206
test('Segment test 2 - Test segment priority and overrides @oss', async ({ page }) => {
206207
const {
208+
featureValueField,
207209
addSegmentOverride,
208210
addSegmentOverrideConfig,
209211
assertUserFeatureValue,
@@ -312,6 +314,7 @@ test('Segment test 2 - Test segment priority and overrides @oss', async ({ page
312314

313315
test('Segment test 3 - Test user-specific feature overrides @oss', async ({ page }, testInfo) => {
314316
const {
317+
featureValueField,
315318
assertUserFeatureValue,
316319
click,
317320
clickUserFeature,
@@ -350,7 +353,7 @@ test('Segment test 3 - Test user-specific feature overrides @oss', async ({ page
350353

351354
log('Edit flag for user')
352355
await clickUserFeature(REMOTE_CONFIG_FEATURE)
353-
await setText(byId('featureValue'), 'small')
356+
await setText(featureValueField(), 'small')
354357
await click('#update-feature-btn')
355358
await waitAndRefresh() // wait and refresh to avoid issues with data sync from UK -> US in github workflows
356359
await assertUserFeatureValue(REMOTE_CONFIG_FEATURE, '"small"')
@@ -393,6 +396,7 @@ test('Segment test 4 - Create ANY rule type segment and verify match changes whe
393396
const ANY_FEATURE = 'any_segment_feature'
394397
const ANY_SEGMENT = 'any_segment_test'
395398
const {
399+
featureValueField,
396400
addSegmentOverrideConfig,
397401
assertUserFeatureValue,
398402
click,

frontend/e2e/tests/versioning-tests.pw.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { E2E_USER, PASSWORD } from '../config';
1010

1111
test('Versioning tests - Create, edit, and compare feature versions @oss', async ({ page }, testInfo) => {
1212
const {
13+
variationValueField,
1314
assertNumberOfVersions,
1415
click,
1516
closeModal,
@@ -100,7 +101,7 @@ test('Versioning tests - Create, edit, and compare feature versions @oss', async
100101
await expect(page.locator(byId('featureVariationKey0'))).toHaveText('primary')
101102
await click(byId('add-variation'))
102103
await page.waitForTimeout(200)
103-
await setText(byId('featureVariationValue2'), 'huge')
104+
await setText(variationValueField(2), 'huge')
104105
await page.waitForTimeout(500)
105106
await click(byId('update-feature-btn'))
106107
await waitForToast()

frontend/web/components/SegmentOverrides.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ const SegmentOverrideInner = class Override extends React.Component {
279279
label='Value'
280280
disabled={readOnly}
281281
value={v.value}
282-
data-test={`segment-override-value-${index}`}
283282
onChange={
284283
readOnly
285284
? null
@@ -298,7 +297,6 @@ const SegmentOverrideInner = class Override extends React.Component {
298297
label='Segment Control Value'
299298
labelAfter={<ControlWeightChip percentage={controlPercent} />}
300299
value={v.value}
301-
data-test={`segment-override-value-${index}`}
302300
disabled={readOnly}
303301
onChange={
304302
readOnly

frontend/web/components/ValueEditor/ValueEditor.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import './ValueEditor.scss'
2222

2323
export interface ValueEditorProps {
2424
className?: string
25-
'data-test'?: string
2625
disabled?: boolean
2726
// Renders the field's label and wires it to the editor. Callers used to
2827
// render their own, which is why three different label treatments grew up
@@ -55,7 +54,6 @@ const ValueEditor: FC<ValueEditorProps> = ({
5554
onChange,
5655
onValidityChange,
5756
value,
58-
...rest
5957
}) => {
6058
const [language, setLanguage] = useState<ValueEditorLanguage>(
6159
languageProp ?? 'txt',
@@ -131,7 +129,6 @@ const ValueEditor: FC<ValueEditorProps> = ({
131129
<Highlight
132130
aria-labelledby={label ? labelId : undefined}
133131
aria-readonly={disabled || undefined}
134-
data-test={rest['data-test']}
135132
disabled={disabled}
136133
onChange={disabled ? null : onChange}
137134
onBlur={disabled ? null : onBlur}

frontend/web/components/modals/create-feature/tabs/FeatureValueTab.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ const FeatureValueTab: FC<FeatureValueTabProps> = ({
375375
)
376376
}
377377
labelTooltip={getValueTooltip(hasVariations, isEdit)}
378-
data-test='featureValue'
379378
className={`full-width${hasVariations ? ' code-medium' : ''}`}
380379
value={`${
381380
typeof initial_value === 'undefined' || initial_value === null

frontend/web/components/mv/VariationValueInput/VariationValueInput.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ export const VariationValueInput: React.FC<VariationValueProps> = ({
7373
<ValueEditor
7474
label='Variation Value'
7575
labelTooltip={Constants.strings.REMOTE_CONFIG_DESCRIPTION_VARIATION}
76-
data-test={`featureVariationValue${
77-
Utils.featureStateToValue(value) || index
78-
}`}
7976
className='full-width code-medium'
8077
value={Utils.getTypedValue(Utils.featureStateToValue(value))}
8178
disabled={!canCreateFeature || disabled || readOnly}

0 commit comments

Comments
 (0)