From ee9905d997dcae285dd3524ab1ebb4fd028aac17 Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Thu, 5 Mar 2026 12:28:41 +0100 Subject: [PATCH 1/2] add warning in attribute-editor --- src/attribute-editor/internal.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/attribute-editor/internal.tsx b/src/attribute-editor/internal.tsx index 7f9acd1006..048393b1fc 100644 --- a/src/attribute-editor/internal.tsx +++ b/src/attribute-editor/internal.tsx @@ -3,7 +3,7 @@ import React, { useImperativeHandle, useRef, useState } from 'react'; import clsx from 'clsx'; -import { useMergeRefs, useUniqueId } from '@cloudscape-design/component-toolkit/internal'; +import { useMergeRefs, useUniqueId, warnOnce } from '@cloudscape-design/component-toolkit/internal'; import { ButtonProps } from '../button/interfaces'; import { InternalButton } from '../button/internal'; @@ -92,6 +92,16 @@ const InternalAttributeEditor = React.forwardRef( // eslint-disable-next-line react-hooks/exhaustive-deps }, [items, i18nStrings?.itemRemovedAriaLive]); + for (const def of definition) { + if (!def.label) { + warnOnce( + 'AttributeEditor', + 'A `label` should be provided for each field definition. It is used as `aria-label` for accessibility.' + ); + break; + } + } + if (!gridLayout) { gridLayout = gridDefaults[definition.length]; if (!gridLayout) { From 93e44b69ebe6a49ae4ce73412a8cf633bdb24495 Mon Sep 17 00:00:00 2001 From: Philipp Schneider Date: Thu, 5 Mar 2026 12:40:16 +0100 Subject: [PATCH 2/2] added tesst --- .../__tests__/warnings.test.tsx | 53 +++++++++++++++++++ src/attribute-editor/internal.tsx | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/attribute-editor/__tests__/warnings.test.tsx diff --git a/src/attribute-editor/__tests__/warnings.test.tsx b/src/attribute-editor/__tests__/warnings.test.tsx new file mode 100644 index 0000000000..0ad4b44e71 --- /dev/null +++ b/src/attribute-editor/__tests__/warnings.test.tsx @@ -0,0 +1,53 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React from 'react'; +import { render } from '@testing-library/react'; + +import AttributeEditor from '../../../lib/components/attribute-editor'; + +jest.mock('@cloudscape-design/component-toolkit', () => ({ + ...jest.requireActual('@cloudscape-design/component-toolkit'), + useContainerQuery: jest.fn().mockImplementation(() => ['m', () => {}]), +})); + +let consoleWarnSpy: jest.SpyInstance; +beforeEach(() => { + consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(); +}); +afterEach(() => { + consoleWarnSpy?.mockRestore(); +}); + +/** + * This test suite is in a separate file, because it needs a clean messageCache (inside `warnOnce()`). + * Otherwise, warnings would not appear at the expected time in the test, because they have been issued before. + */ +describe('AttributeEditor component', () => { + test('warns when a definition has no label', () => { + render( + 'key' }]} + items={[{}]} + gridLayout={[{ rows: [[1]] }]} + /> + ); + expect(console.warn).not.toHaveBeenCalled(); + + render( + 'key' }, { control: () => 'value' }]} + items={[{}]} + gridLayout={[{ rows: [[1, 1]] }]} + /> + ); + + expect(console.warn).toHaveBeenCalledTimes(1); + expect(console.warn).toHaveBeenCalledWith( + '[AwsUi] [AttributeEditor] A `label` should be provided for each field definition. It is used as `aria-label` for accessibility.' + ); + }); +}); diff --git a/src/attribute-editor/internal.tsx b/src/attribute-editor/internal.tsx index 048393b1fc..24f3229736 100644 --- a/src/attribute-editor/internal.tsx +++ b/src/attribute-editor/internal.tsx @@ -93,7 +93,7 @@ const InternalAttributeEditor = React.forwardRef( }, [items, i18nStrings?.itemRemovedAriaLive]); for (const def of definition) { - if (!def.label) { + if (def && !def.label) { warnOnce( 'AttributeEditor', 'A `label` should be provided for each field definition. It is used as `aria-label` for accessibility.'