From d92a591c2a57eb0cdbf84f95bc096766b0e18278 Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Mon, 9 Mar 2026 13:27:18 +0100 Subject: [PATCH 1/9] test: testing ai instructions --- AGENTS.md | 13 +++++++ docs/API_DOCS.md | 10 ++++++ docs/CODE_STYLE.md | 18 ++++++++++ docs/COMPONENT_CONVENTIONS.md | 65 +++++++++++++++++++++++++++++++++++ docs/DEV_PAGES.md | 11 ++++++ docs/INTERNALS.md | 16 +++++++++ docs/STYLING.md | 26 ++++++++++++++ docs/TESTING.md | 37 ++++++++++++++++++++ docs/WRITING_TESTS.md | 31 +++++++++++++++++ 9 files changed, 227 insertions(+) create mode 100644 AGENTS.md create mode 100644 docs/API_DOCS.md create mode 100644 docs/CODE_STYLE.md create mode 100644 docs/COMPONENT_CONVENTIONS.md create mode 100644 docs/DEV_PAGES.md create mode 100644 docs/INTERNALS.md create mode 100644 docs/STYLING.md create mode 100644 docs/TESTING.md create mode 100644 docs/WRITING_TESTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..23d67e7d15 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,13 @@ +React component library for [Cloudscape Design System](https://cloudscape.design/) — an open source design system for building accessible, inclusive web experiences at scale. + +To install dependencies use `npm install` +Build with `npm run quick-build` for dev, or `npm run build` for a full production build. + +For component structure, props, events, and refs, see docs/COMPONENT_CONVENTIONS.md. +For design tokens, CSS rules, and RTL support, see docs/STYLING.md. +For test commands, see docs/TESTING.md. +For writing tests and test utils, see docs/WRITING_TESTS.md. +For prettier, stylelint, and eslint (`npm run lint`), see docs/CODE_STYLE.md. +For dev/test pages, see docs/DEV_PAGES.md. +For API documentation comments, see docs/API_DOCS.md. +For internal shared utilities, see docs/INTERNALS.md. \ No newline at end of file diff --git a/docs/API_DOCS.md b/docs/API_DOCS.md new file mode 100644 index 0000000000..e5a2c65592 --- /dev/null +++ b/docs/API_DOCS.md @@ -0,0 +1,10 @@ +# API Documentation Comments + +This project uses `@cloudscape-design/documenter` to generate API docs from JSDoc comments in component interface files (`src//interfaces.ts`). + +## Special tags + +- `@i18n` — marks internationalization properties +- `@analytics` — marks analytics metadata properties +- `@deprecated` — marks deprecated properties (include replacement info) +- `@displayname` — overrides the display name (e.g. `children` → `text`) diff --git a/docs/CODE_STYLE.md b/docs/CODE_STYLE.md new file mode 100644 index 0000000000..cce901bf1f --- /dev/null +++ b/docs/CODE_STYLE.md @@ -0,0 +1,18 @@ +# Code Style + +This project enforces formatting and linting via prettier, stylelint, and eslint. Run `npm run lint` to check everything. + +Before writing or modifying code, read the relevant config files: + +- Prettier: `.prettierrc` +- Stylelint: `.stylelintrc` +- ESLint: `eslint.config.mjs` + +Follow whatever rules are defined there. Do not guess — read the configs. + +All source files must include the license header: + +``` +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +``` diff --git a/docs/COMPONENT_CONVENTIONS.md b/docs/COMPONENT_CONVENTIONS.md new file mode 100644 index 0000000000..79cb490235 --- /dev/null +++ b/docs/COMPONENT_CONVENTIONS.md @@ -0,0 +1,65 @@ +# Component Conventions + +## Ground Rules + +- Always read existing code for the component you're working on before writing new code. For new components, pick a similar one as your template. +- Inner HTML structure and class names are not public API — don't rely on them. + +## Component Structure + +Each public component lives in `src//index.tsx` and must: + +- Assign default prop values in the destructuring signature (not `defaultProps`), then pass them explicitly to the internal component +- Call `useBaseComponent` for telemetry — pass `props` (primitive/enum values with defaults applied) and optionally `metadata` (derived counters or booleans). No state props, no PII, no user input strings. +- Use `getExternalProps` or `getBaseProps` to strip internal `__`-prefixed props +- Call `applyDisplayName` at the bottom of the file +- Export the props interface as `${ComponentName}Props` + +Each public component has a private counterpart at `src//internal.tsx` for composition. Internal props are prefixed with `__`. The public component must not add behavior beyond what the internal component provides. + +Shared hooks, components, contexts, and helpers live in `src/internal/`. Always check there before building new shared code. + +## Props & Interfaces + +- Props interface: `${ComponentName}Props`, namespace sub-types under it (e.g. `${ComponentName}Props.Variant`) +- Union types must be type aliases (no inline unions) +- Array types must use `ReadonlyArray` +- Cast string props to string at runtime if rendered in JSX — React accepts JSX content there +- Component return type must be exactly `JSX.Element` — `null` or arrays break the doc generator +- Components exported as default from `index.tsx` are public; everything else is private + +## Events + +- Use `CancelableEventHandler` or `NonCancelableEventHandler` from `../internal/events` +- All `on*` props must use these interfaces (build fails otherwise) + +## Refs + +- Expose via `${ComponentName}Props.Ref` interface +- Use `useForwardFocus(ref, elementRef)` for simple focus delegation +- For `React.forwardRef` generics, create a `${ComponentName}ForwardRefType` interface + +## Controllable Components + +- Controlled: requires `value` + `onChange` (e.g. Input) +- Uncontrolled: internal state only (e.g. dropdown open) +- Controllable: uncontrolled by default, controlled when `value` is set + +Use `useControllable` — read existing components for the pattern. + +## Element Queries + +Use `useContainerBreakpoints` instead of CSS media queries. Handle `null` on first render. + +## I18n + +Three string categories: +- Static → `i18nStrings` property +- Dynamic → functions in `i18nStrings` returning strings +- Context-dependent → top-level props (out of scope for i18n provider) + +Use `useInternalI18n('')` to consume. Test with `TestI18nProvider` from `src/i18n/testing`. + +## Dependencies + +Before adding any dependency: must support React 16.8+ and latest 3 major Chrome/Firefox/Edge, no global state, ESM preferred, no external resources (CSP). diff --git a/docs/DEV_PAGES.md b/docs/DEV_PAGES.md new file mode 100644 index 0000000000..0393712295 --- /dev/null +++ b/docs/DEV_PAGES.md @@ -0,0 +1,11 @@ +# Dev Pages + +Dev and test pages live in `pages//`. They are used for local development, integration tests, and visual regression tests. + +## Rules + +- Export a default function component +- Import components via `~components/` (not relative paths to `src/`) +- For visual regression content, either use `SimplePage` from `pages/app/templates` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea` from `pages/utils/screenshot-area` with a manual `

` +- Use `createPermutations` and `PermutationsView` from `pages/utils/` for permutation pages +- If multiple pages share data (like `i18nStrings`), put it in a `common.tsx` in the same directory diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md new file mode 100644 index 0000000000..390a4526f7 --- /dev/null +++ b/docs/INTERNALS.md @@ -0,0 +1,16 @@ +# Internal Utilities + +Shared infrastructure lives in `src/internal/`. + +## What's in there + +- `hooks/` — shared React hooks (component telemetry, controllable state, focus management, container/element queries, visual mode detection, intersection observers, debounce/throttle, etc.) +- `components/` — shared internal UI building blocks (dropdowns, options, focus locks, tooltips, chart primitives, transitions, screen-reader utilities, drag handles, etc.) +- `context/` — React contexts for cross-component communication (form fields, modals, split panels, container headers, etc.) +- `utils/` — pure helper functions (DOM helpers, key handling, date/time, locale, display names, prop stripping, etc.) +- `events/` — event handler type definitions used by all component `on*` props +- `base-component/` — base prop extraction utilities +- `styles/` — shared SCSS mixins +- `analytics/` — telemetry and funnel metrics + +Always check `src/internal/` before introducing new utilities, hooks, or shared components. diff --git a/docs/STYLING.md b/docs/STYLING.md new file mode 100644 index 0000000000..2100b931d0 --- /dev/null +++ b/docs/STYLING.md @@ -0,0 +1,26 @@ +# Styling + +Never hardcode CSS spacing, colors, borders, shadows, typography, or motion values. This project uses design tokens and custom CSS properties. + +## Design Tokens + +Tokens are defined in `style-dictionary/` and consumed in SCSS via the `awsui` namespace. + +## Custom CSS Properties + +Custom CSS properties are defined in `build-tools/utils/custom-css-properties.js`. Read this file to see what's available. + +## Rules + +- Apply `styles-reset` mixin on every root element — prevents parent styles from leaking in +- Root elements must not have outer margins — spacing is managed by parent components +- No descendant combinators (`.a .b` with a space) — breaks CSS scoping +- Wrap all animations in the `with-motion` mixin — ensures motion can be toggled +- Use logical properties only — no `left`/`right`/`top`/`bottom`/`width`/`height` in CSS. Use `inline-start`/`inline-end`/`block-start`/`block-end`/`inline-size`/`block-size` instead. This is required for RTL support. + +## RTL Support + +For bidirectional layout support, use the internal RTL utilities in `src/internal/`: + +- SCSS: `with-direction` mixin for direction-aware styles +- JS: `getIsRtl` for detecting direction, `handleKey` for direction-aware key handling, `getLogicalBoundingClientRect` / `getOffsetInlineStart` / `getScrollInlineStart` for direction-aware measurements diff --git a/docs/TESTING.md b/docs/TESTING.md new file mode 100644 index 0000000000..5197b2d716 --- /dev/null +++ b/docs/TESTING.md @@ -0,0 +1,37 @@ +# Testing + +## Quick Reference + +``` +npm test # all tests (unit + integ + a11y) +npm run test:unit # unit + build-tool tests +npm run test:integ # integration tests (starts dev server automatically) +npm run test:motion # motion tests (starts dev server automatically) +npm run test:a11y # accessibility tests +``` + +The npm scripts use gulp tasks that handle env vars (`TZ=UTC`, `NODE_OPTIONS=--experimental-vm-modules`) and dev server lifecycle automatically. + +## Targeting Specific Files + +For running a specific test file or folder, call jest directly with the appropriate config: + +``` +# Unit +TZ=UTC node_modules/.bin/jest -c jest.unit.config.js src/button/__tests__/button.test.tsx + +# Integration (requires dev server running via `npm start`) +NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.integ.config.js src/input/__integ__/ + +# Motion (requires dev server running via `npm start`) +NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.motion.config.js src/flashbar/__motion__/ + +# Build-tool / stylelint +NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.build-tools.config.js build-tools/stylelint +``` + +## Updating Snapshots + +``` +TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ +``` diff --git a/docs/WRITING_TESTS.md b/docs/WRITING_TESTS.md new file mode 100644 index 0000000000..803e977687 --- /dev/null +++ b/docs/WRITING_TESTS.md @@ -0,0 +1,31 @@ +# Writing Tests + +## Test Utils + +Use the project's test utils in `src/test-utils/` — don't query the DOM directly. + +- `src/test-utils/dom/` — unit test wrappers (JSDOM) +- `src/test-utils/selectors/` — integration test wrappers (real browser) + +Read the wrapper for the component you're testing to see available `find*` methods. + +### Authoring Test Utils + +Each wrapper extends `ComponentWrapper`, has a static `rootSelector`, and explicit return types on all methods. Test-util CSS classes go in `src//test-classes/styles.scss`. Read existing wrappers for the pattern. + +## Unit Tests + +Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for public interactions, react-testing-library for internal corner cases. Read an existing test file for the setup pattern. + +## Integration Tests + +Use `useBrowser` from `@amzn/awsui-browser-test-tools/use-browser`. Use a `setupTest` wrapper with `waitForVisible`. Don't wait on tag name selectors — they're visible before JS loads. Multiple assertions per test are fine (e2e tests are slow). Use page object pattern for files with many tests. + +## I18n Testing + +Test `useInternalI18n` with `TestI18nProvider` from `src/i18n/testing`. Read existing i18n tests for the pattern. + +## Gotchas + +- `findAll`/`findAllByClassName` with `.get()` uses `:nth-child()` — only works if items share the same parent node +- All dev pages are axe-checked automatically. A11y violations fail the build. Checks run in dark mode only. From 11af693961ddb9009a6a887ad724563a9e1a84de Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Thu, 26 Mar 2026 06:28:10 +0100 Subject: [PATCH 2/9] chore: improve docs --- AGENTS.md | 30 ++++++++++++++++++---- docs/API_DOCS.md | 30 +++++++++++++++++++++- docs/COMPONENT_CONVENTIONS.md | 33 ++++++++++++++++++++++-- docs/DEV_PAGES.md | 47 ++++++++++++++++++++++++++++++++--- docs/STYLING.md | 46 +++++++++++++++++++++++++++++++--- docs/TESTING.md | 8 ++++++ docs/WRITING_TESTS.md | 18 ++++++++++++-- 7 files changed, 195 insertions(+), 17 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 23d67e7d15..a43e7ca195 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,13 +1,33 @@ React component library for [Cloudscape Design System](https://cloudscape.design/) — an open source design system for building accessible, inclusive web experiences at scale. -To install dependencies use `npm install` -Build with `npm run quick-build` for dev, or `npm run build` for a full production build. +## Setup + +``` +npm install +``` + +## Building + +- `npm run quick-build` — fast dev build (compiles TS, SCSS, generates icons/i18n/test-utils). Use this for local development. +- `npm run build` — full production build (quick-build + dev pages, theming, docs, size-limit). Use this before publishing or to verify everything works end-to-end. +- `npm run build:react18` — production build targeting React 18. + +## Running Locally + +``` +npm start # starts watcher + dev server (React 16, default) +npm run start:react18 # starts watcher + dev server (React 18) +``` + +The dev server runs at `http://localhost:8080`. Pages are served from `pages//`. + +## Docs Index For component structure, props, events, and refs, see docs/COMPONENT_CONVENTIONS.md. For design tokens, CSS rules, and RTL support, see docs/STYLING.md. -For test commands, see docs/TESTING.md. +For test commands and configs, see docs/TESTING.md. For writing tests and test utils, see docs/WRITING_TESTS.md. For prettier, stylelint, and eslint (`npm run lint`), see docs/CODE_STYLE.md. -For dev/test pages, see docs/DEV_PAGES.md. +For dev/test pages and running in the browser, see docs/DEV_PAGES.md. For API documentation comments, see docs/API_DOCS.md. -For internal shared utilities, see docs/INTERNALS.md. \ No newline at end of file +For internal shared utilities, see docs/INTERNALS.md. diff --git a/docs/API_DOCS.md b/docs/API_DOCS.md index e5a2c65592..19bfce2fd0 100644 --- a/docs/API_DOCS.md +++ b/docs/API_DOCS.md @@ -2,9 +2,37 @@ This project uses `@cloudscape-design/documenter` to generate API docs from JSDoc comments in component interface files (`src//interfaces.ts`). -## Special tags +## Writing Prop Descriptions + +Every public prop must have a JSDoc comment describing its purpose. For union/enum props, list the available options and their meanings inline in the description: + +```ts +/** Determines the general styling of the button as follows: + * * `primary` for primary buttons. + * * `normal` for secondary buttons. + * * `link` for tertiary buttons. + */ +variant?: ButtonProps.Variant; +``` + +Do not use `@default` tags — default values are documented by the component implementation (destructuring defaults in `index.tsx`), not in the interface comments. + +## Special Tags - `@i18n` — marks internationalization properties - `@analytics` — marks analytics metadata properties - `@deprecated` — marks deprecated properties (include replacement info) - `@displayname` — overrides the display name (e.g. `children` → `text`) +- `@awsuiSystem core` — marks properties that are part of the core system (style API, native attributes) + +## Sub-types + +Define union types as named type aliases in the component's namespace, not as inline unions on the prop: + +```ts +export namespace ButtonProps { + export type Variant = 'normal' | 'primary' | 'link' | 'icon' | 'inline-icon' | 'inline-link'; +} +``` + +Then reference them in the interface: `variant?: ButtonProps.Variant`. diff --git a/docs/COMPONENT_CONVENTIONS.md b/docs/COMPONENT_CONVENTIONS.md index 79cb490235..e90548651e 100644 --- a/docs/COMPONENT_CONVENTIONS.md +++ b/docs/COMPONENT_CONVENTIONS.md @@ -7,7 +7,28 @@ ## Component Structure -Each public component lives in `src//index.tsx` and must: +A typical component directory looks like: + +``` +src// + index.tsx # public component (default export) + internal.tsx # internal component for composition (optional, for complex components) + interfaces.ts # props interface and sub-types + styles.scss # component styles + style.tsx # style API helpers (optional) + test-classes/ # CSS classes used only by test-utils (optional) + styles.scss + __tests__/ # unit tests + __integ__/ # integration tests (optional) + __a11y__/ # accessibility tests (optional) + __motion__/ # motion tests (optional) +``` + +Each component also has dev pages in `pages//` (see docs/DEV_PAGES.md). + +## Public Component (`index.tsx`) + +Each public component must: - Assign default prop values in the destructuring signature (not `defaultProps`), then pass them explicitly to the internal component - Call `useBaseComponent` for telemetry — pass `props` (primitive/enum values with defaults applied) and optionally `metadata` (derived counters or booleans). No state props, no PII, no user input strings. @@ -15,7 +36,11 @@ Each public component lives in `src//index.tsx` and must: - Call `applyDisplayName` at the bottom of the file - Export the props interface as `${ComponentName}Props` -Each public component has a private counterpart at `src//internal.tsx` for composition. Internal props are prefixed with `__`. The public component must not add behavior beyond what the internal component provides. +## Internal Component (`internal.tsx`) + +For components used in composition, a private counterpart lives at `internal.tsx`. Internal props are prefixed with `__`. The public component must not add behavior beyond what the internal component provides. + +## Shared Utilities Shared hooks, components, contexts, and helpers live in `src/internal/`. Always check there before building new shared code. @@ -47,6 +72,10 @@ Shared hooks, components, contexts, and helpers live in `src/internal/`. Always Use `useControllable` — read existing components for the pattern. +## Test Utils + +Components with interactive elements should provide test-util wrappers in `src/test-utils/dom//` (for unit tests) and `src/test-utils/selectors//` (for integration tests). CSS classes used exclusively by test-utils go in `src//test-classes/styles.scss`. See docs/WRITING_TESTS.md for details. + ## Element Queries Use `useContainerBreakpoints` instead of CSS media queries. Handle `null` on first render. diff --git a/docs/DEV_PAGES.md b/docs/DEV_PAGES.md index 0393712295..8e0c8d56b3 100644 --- a/docs/DEV_PAGES.md +++ b/docs/DEV_PAGES.md @@ -2,10 +2,51 @@ Dev and test pages live in `pages//`. They are used for local development, integration tests, and visual regression tests. +## Running Dev Pages + +``` +npm run quick-build # build first (required before starting) +npm start # starts watcher + dev server at http://localhost:8080 +npm run start:react18 # same, but with React 18 +``` + +Navigate to `http://localhost:8080/#/light//` to view a page. The sidebar lists all available pages. + ## Rules - Export a default function component - Import components via `~components/` (not relative paths to `src/`) -- For visual regression content, either use `SimplePage` from `pages/app/templates` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea` from `pages/utils/screenshot-area` with a manual `

` -- Use `createPermutations` and `PermutationsView` from `pages/utils/` for permutation pages -- If multiple pages share data (like `i18nStrings`), put it in a `common.tsx` in the same directory +- File names must end with `.page.tsx` to be discovered by the dev server + +## Visual Regression Pages + +For pages used in visual regression tests, wrap content so screenshots are consistent: + +- `SimplePage` from `pages/app/templates` — preferred for most pages. Handles heading, screenshot area, i18n provider, and layout padding automatically. Accepts `title`, `settings`, `screenshotArea`, and `i18n` props. +- `ScreenshotArea` from `pages/utils/screenshot-area` — use when you need more control over layout. Requires a manual `

` heading. + +Use `SimplePage` for new pages unless you have a specific reason to use `ScreenshotArea` directly. + +## Permutation Pages + +Use `createPermutations` and `PermutationsView` from `pages/utils/` for pages that show all prop combinations. Use `PermutationsPage` from `pages/app/templates` as the page wrapper (it extends `SimplePage` with screenshot area enabled by default). + +## Controlling State via URL (App Context) + +Use `useAppContext` from `pages/app/app-context` to read and write URL parameters for interactive dev pages. This lets you control component state (e.g. color, variant, size) via the URL and settings UI. + +```tsx +import { useAppContext } from '../app/app-context'; + +export default function MyPage() { + const { urlParams, setUrlParams } = useAppContext<'color'>(); + const color = urlParams.color ?? 'blue'; + // Use setUrlParams({ color: 'red' }) to update +} +``` + +Built-in URL params include `density`, `direction`, `visualRefresh`, and `motionDisabled`. + +## Shared Data + +If multiple pages share data (like `i18nStrings`), put it in a `common.tsx` in the same directory. diff --git a/docs/STYLING.md b/docs/STYLING.md index 2100b931d0..0b511f8928 100644 --- a/docs/STYLING.md +++ b/docs/STYLING.md @@ -4,12 +4,38 @@ Never hardcode CSS spacing, colors, borders, shadows, typography, or motion valu ## Design Tokens -Tokens are defined in `style-dictionary/` and consumed in SCSS via the `awsui` namespace. +Tokens are defined in `style-dictionary/` and consumed in SCSS via the `awsui` namespace: + +```scss +@use '../internal/styles/tokens' as awsui; + +.my-element { + color: awsui.$color-text-body-default; + padding-block: awsui.$space-scaled-s; +} +``` + +Browse `style-dictionary/` for available token names. Tokens cover colors, spacing, borders, shadows, typography, and motion durations. ## Custom CSS Properties Custom CSS properties are defined in `build-tools/utils/custom-css-properties.js`. Read this file to see what's available. +## Shared SCSS Mixins + +Shared mixins live in `src/internal/styles/`. Import them as needed: + +- `styles-reset` — resets inherited styles on root elements. Apply on every component root. +- `with-motion` — wraps animations/transitions so they respect `prefers-reduced-motion` and the motion-disabled flag. +- `form-focus-element` — focus ring for form inputs. +- `form-disabled-element` — disabled state for form inputs (background, border, color, cursor). +- `form-invalid-control` — invalid state styling (error border, left accent border). +- `form-warning-control` — warning state styling. +- `form-readonly-element` — read-only state for form inputs. +- `focus-highlight` — focus ring using a pseudo-element (for non-form elements). +- `text-wrapping`, `text-overflow-ellipsis` — text overflow helpers. +Read the mixin files for parameters and usage. + ## Rules - Apply `styles-reset` mixin on every root element — prevents parent styles from leaking in @@ -18,9 +44,21 @@ Custom CSS properties are defined in `build-tools/utils/custom-css-properties.js - Wrap all animations in the `with-motion` mixin — ensures motion can be toggled - Use logical properties only — no `left`/`right`/`top`/`bottom`/`width`/`height` in CSS. Use `inline-start`/`inline-end`/`block-start`/`block-end`/`inline-size`/`block-size` instead. This is required for RTL support. +## Component States + +For form-like components, use the shared form mixins for consistent state styling: + +- Default state: standard border and background from tokens +- Hover state: use token-based hover colors (e.g. `awsui.$color-background-button-normal-hover`) +- Focus state: use `form-focus-element` or `focus-highlight` mixin +- Disabled state: use `form-disabled-element` mixin +- Invalid state: use `form-invalid-control` mixin (adds left accent border) +- Warning state: use `form-warning-control` mixin +- Read-only state: use `form-readonly-element` mixin + ## RTL Support -For bidirectional layout support, use the internal RTL utilities in `src/internal/`: +Use logical CSS properties (see Rules above). For cases that need direction-aware logic: -- SCSS: `with-direction` mixin for direction-aware styles -- JS: `getIsRtl` for detecting direction, `handleKey` for direction-aware key handling, `getLogicalBoundingClientRect` / `getOffsetInlineStart` / `getScrollInlineStart` for direction-aware measurements +- SCSS: `with-direction` mixin in `src/internal/styles/direction.scss` +- JS: `getIsRtl`, `handleKey`, `getLogicalBoundingClientRect`, `getOffsetInlineStart`, `getScrollInlineStart` in `src/internal/` diff --git a/docs/TESTING.md b/docs/TESTING.md index 5197b2d716..a59aafaced 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -35,3 +35,11 @@ NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.build-tool ``` TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ ``` + +## Testing in the Browser + +Integration and motion tests run against dev pages served by the dev server (see docs/DEV_PAGES.md for setup). When running individual test files with jest directly, start the dev server first (`npm start`). The `npm run test:integ` and `npm run test:motion` scripts handle the dev server automatically. + +## A11y Tests + +All dev pages are axe-checked automatically. A11y violations fail the build. Checks run in dark mode only. diff --git a/docs/WRITING_TESTS.md b/docs/WRITING_TESTS.md index 803e977687..a10e122c19 100644 --- a/docs/WRITING_TESTS.md +++ b/docs/WRITING_TESTS.md @@ -11,16 +11,30 @@ Read the wrapper for the component you're testing to see available `find*` metho ### Authoring Test Utils -Each wrapper extends `ComponentWrapper`, has a static `rootSelector`, and explicit return types on all methods. Test-util CSS classes go in `src//test-classes/styles.scss`. Read existing wrappers for the pattern. +Each wrapper extends `ComponentWrapper`, has a static `rootSelector`, and explicit return types on all methods. Test-util CSS classes go in `src//test-classes/styles.scss` — these classes are only used for test targeting, not visual styling. Read existing wrappers for the pattern. ## Unit Tests -Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for public interactions, react-testing-library for internal corner cases. Read an existing test file for the setup pattern. +Location: `src//__tests__/` + +Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for public interactions, react-testing-library for internal corner cases. Read an existing test file (e.g. `src/button/__tests__/button.test.tsx`) for the setup pattern. ## Integration Tests +Location: `src//__integ__/` + +Integration tests run in a real browser against dev pages (see docs/DEV_PAGES.md). Each integration test navigates to a dev page and interacts with it. + Use `useBrowser` from `@amzn/awsui-browser-test-tools/use-browser`. Use a `setupTest` wrapper with `waitForVisible`. Don't wait on tag name selectors — they're visible before JS loads. Multiple assertions per test are fine (e2e tests are slow). Use page object pattern for files with many tests. +## Snapshot Tests + +Snapshot tests live in `src/__tests__/snapshot-tests/`. To update snapshots after intentional changes: + +``` +TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ +``` + ## I18n Testing Test `useInternalI18n` with `TestI18nProvider` from `src/i18n/testing`. Read existing i18n tests for the pattern. From 92871decebe693a49cb34f6991bda99182ba8cf2 Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Thu, 26 Mar 2026 17:58:32 +0100 Subject: [PATCH 3/9] chore: improve docs according to feedback --- AGENTS.md | 2 +- docs/API_DOCS.md | 18 ++++---- docs/CODE_STYLE.md | 13 +----- docs/COMPONENT_CONVENTIONS.md | 83 ++++++++++------------------------- docs/DEV_PAGES.md | 40 ++--------------- docs/INTERNALS.md | 15 ++----- docs/STYLING.md | 64 +++++++-------------------- docs/TESTING.md | 16 +++---- docs/WRITING_TESTS.md | 44 +++++++------------ 9 files changed, 76 insertions(+), 219 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a43e7ca195..ac02ecca50 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ npm install ## Running Locally ``` -npm start # starts watcher + dev server (React 16, default) +npm start # starts watcher + dev server npm run start:react18 # starts watcher + dev server (React 18) ``` diff --git a/docs/API_DOCS.md b/docs/API_DOCS.md index 19bfce2fd0..5e6488aac9 100644 --- a/docs/API_DOCS.md +++ b/docs/API_DOCS.md @@ -1,10 +1,10 @@ # API Documentation Comments -This project uses `@cloudscape-design/documenter` to generate API docs from JSDoc comments in component interface files (`src//interfaces.ts`). +Documentation is generated from JSDoc comments in component interface files (`src//interfaces.ts`). ## Writing Prop Descriptions -Every public prop must have a JSDoc comment describing its purpose. For union/enum props, list the available options and their meanings inline in the description: +Every public prop must have a JSDoc comment. For union/enum props, list available options inline: ```ts /** Determines the general styling of the button as follows: @@ -15,19 +15,13 @@ Every public prop must have a JSDoc comment describing its purpose. For union/en variant?: ButtonProps.Variant; ``` -Do not use `@default` tags — default values are documented by the component implementation (destructuring defaults in `index.tsx`), not in the interface comments. - ## Special Tags -- `@i18n` — marks internationalization properties -- `@analytics` — marks analytics metadata properties -- `@deprecated` — marks deprecated properties (include replacement info) -- `@displayname` — overrides the display name (e.g. `children` → `text`) -- `@awsuiSystem core` — marks properties that are part of the core system (style API, native attributes) +- `@displayname` — overrides the display name for children slots (e.g. `children` → `text`) ## Sub-types -Define union types as named type aliases in the component's namespace, not as inline unions on the prop: +Define union types as named type aliases in the component's namespace, not as inline unions: ```ts export namespace ButtonProps { @@ -36,3 +30,7 @@ export namespace ButtonProps { ``` Then reference them in the interface: `variant?: ButtonProps.Variant`. + +## Related + +- For component props and interface conventions, see [COMPONENT_CONVENTIONS.md](COMPONENT_CONVENTIONS.md). diff --git a/docs/CODE_STYLE.md b/docs/CODE_STYLE.md index cce901bf1f..196ed67f9a 100644 --- a/docs/CODE_STYLE.md +++ b/docs/CODE_STYLE.md @@ -1,18 +1,7 @@ # Code Style -This project enforces formatting and linting via prettier, stylelint, and eslint. Run `npm run lint` to check everything. - -Before writing or modifying code, read the relevant config files: +Run `npm run lint` to check formatting and linting (prettier, stylelint, eslint). See the config files for rules: - Prettier: `.prettierrc` - Stylelint: `.stylelintrc` - ESLint: `eslint.config.mjs` - -Follow whatever rules are defined there. Do not guess — read the configs. - -All source files must include the license header: - -``` -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -``` diff --git a/docs/COMPONENT_CONVENTIONS.md b/docs/COMPONENT_CONVENTIONS.md index e90548651e..b7e9081924 100644 --- a/docs/COMPONENT_CONVENTIONS.md +++ b/docs/COMPONENT_CONVENTIONS.md @@ -1,48 +1,14 @@ # Component Conventions -## Ground Rules - -- Always read existing code for the component you're working on before writing new code. For new components, pick a similar one as your template. -- Inner HTML structure and class names are not public API — don't rely on them. - ## Component Structure -A typical component directory looks like: - -``` -src// - index.tsx # public component (default export) - internal.tsx # internal component for composition (optional, for complex components) - interfaces.ts # props interface and sub-types - styles.scss # component styles - style.tsx # style API helpers (optional) - test-classes/ # CSS classes used only by test-utils (optional) - styles.scss - __tests__/ # unit tests - __integ__/ # integration tests (optional) - __a11y__/ # accessibility tests (optional) - __motion__/ # motion tests (optional) -``` - -Each component also has dev pages in `pages//` (see docs/DEV_PAGES.md). - -## Public Component (`index.tsx`) - -Each public component must: - -- Assign default prop values in the destructuring signature (not `defaultProps`), then pass them explicitly to the internal component -- Call `useBaseComponent` for telemetry — pass `props` (primitive/enum values with defaults applied) and optionally `metadata` (derived counters or booleans). No state props, no PII, no user input strings. -- Use `getExternalProps` or `getBaseProps` to strip internal `__`-prefixed props -- Call `applyDisplayName` at the bottom of the file -- Export the props interface as `${ComponentName}Props` - -## Internal Component (`internal.tsx`) +Each component is exposed from `src//index.tsx`. -For components used in composition, a private counterpart lives at `internal.tsx`. Internal props are prefixed with `__`. The public component must not add behavior beyond what the internal component provides. +- `applyDisplayName` — readable name in consumers' devtools -## Shared Utilities +### Internal Component (`internal.tsx`) -Shared hooks, components, contexts, and helpers live in `src/internal/`. Always check there before building new shared code. +For components used in composition, a private counterpart lives at `internal.tsx`. The public component must not add behavior beyond what the internal component provides. ## Props & Interfaces @@ -51,44 +17,41 @@ Shared hooks, components, contexts, and helpers live in `src/internal/`. Always - Array types must use `ReadonlyArray` - Cast string props to string at runtime if rendered in JSX — React accepts JSX content there - Component return type must be exactly `JSX.Element` — `null` or arrays break the doc generator -- Components exported as default from `index.tsx` are public; everything else is private + +For how to document props, see [API_DOCS.md](API_DOCS.md). ## Events -- Use `CancelableEventHandler` or `NonCancelableEventHandler` from `../internal/events` -- All `on*` props must use these interfaces (build fails otherwise) +Use `CancelableEventHandler` or `NonCancelableEventHandler`. All `on*` props must use these interfaces (build fails otherwise). + +Events are similar to native events with `event.preventDefault()` for cancelable events, but are not dispatched via DOM. ## Refs -- Expose via `${ComponentName}Props.Ref` interface - Use `useForwardFocus(ref, elementRef)` for simple focus delegation - For `React.forwardRef` generics, create a `${ComponentName}ForwardRefType` interface ## Controllable Components -- Controlled: requires `value` + `onChange` (e.g. Input) -- Uncontrolled: internal state only (e.g. dropdown open) -- Controllable: uncontrolled by default, controlled when `value` is set - -Use `useControllable` — read existing components for the pattern. - -## Test Utils +Use the same behavior as built-in React components: -Components with interactive elements should provide test-util wrappers in `src/test-utils/dom//` (for unit tests) and `src/test-utils/selectors//` (for integration tests). CSS classes used exclusively by test-utils go in `src//test-classes/styles.scss`. See docs/WRITING_TESTS.md for details. +1. If only `onChange` is provided → uncontrolled (component manages its own state, `onChange` fires for side effects) +2. If `value` is provided → controlled (with or without `onChange`; without `onChange` it's read-only) -## Element Queries - -Use `useContainerBreakpoints` instead of CSS media queries. Handle `null` on first render. +Implementation: +1. Create a controlled component first +2. Use `useControllable` to wrap customer-provided properties — gives you a `[value, setValue]` pair +3. If `value` is provided without `onChange`, `useControllable` emits a console warning ## I18n -Three string categories: -- Static → `i18nStrings` property -- Dynamic → functions in `i18nStrings` returning strings -- Context-dependent → top-level props (out of scope for i18n provider) - -Use `useInternalI18n('')` to consume. Test with `TestI18nProvider` from `src/i18n/testing`. +Centralize all translatable strings under a skippable property (e.g. `i18nStrings`). ## Dependencies -Before adding any dependency: must support React 16.8+ and latest 3 major Chrome/Firefox/Edge, no global state, ESM preferred, no external resources (CSP). +Before adding any dependency: must support React 16.8+ and latest 3 major Chrome/Firefox/Edge, no global state, ESM preferred. + +## Related + +- For styling rules and design tokens, see [STYLING.md](STYLING.md). +- For internal shared utilities, see [INTERNALS.md](INTERNALS.md). diff --git a/docs/DEV_PAGES.md b/docs/DEV_PAGES.md index 8e0c8d56b3..3e95bf7f03 100644 --- a/docs/DEV_PAGES.md +++ b/docs/DEV_PAGES.md @@ -7,46 +7,14 @@ Dev and test pages live in `pages//`. They are used for local de ``` npm run quick-build # build first (required before starting) npm start # starts watcher + dev server at http://localhost:8080 -npm run start:react18 # same, but with React 18 ``` -Navigate to `http://localhost:8080/#/light//` to view a page. The sidebar lists all available pages. - ## Rules -- Export a default function component - Import components via `~components/` (not relative paths to `src/`) -- File names must end with `.page.tsx` to be discovered by the dev server - -## Visual Regression Pages - -For pages used in visual regression tests, wrap content so screenshots are consistent: - -- `SimplePage` from `pages/app/templates` — preferred for most pages. Handles heading, screenshot area, i18n provider, and layout padding automatically. Accepts `title`, `settings`, `screenshotArea`, and `i18n` props. -- `ScreenshotArea` from `pages/utils/screenshot-area` — use when you need more control over layout. Requires a manual `

` heading. - -Use `SimplePage` for new pages unless you have a specific reason to use `ScreenshotArea` directly. - -## Permutation Pages - -Use `createPermutations` and `PermutationsView` from `pages/utils/` for pages that show all prop combinations. Use `PermutationsPage` from `pages/app/templates` as the page wrapper (it extends `SimplePage` with screenshot area enabled by default). - -## Controlling State via URL (App Context) - -Use `useAppContext` from `pages/app/app-context` to read and write URL parameters for interactive dev pages. This lets you control component state (e.g. color, variant, size) via the URL and settings UI. - -```tsx -import { useAppContext } from '../app/app-context'; - -export default function MyPage() { - const { urlParams, setUrlParams } = useAppContext<'color'>(); - const color = urlParams.color ?? 'blue'; - // Use setUrlParams({ color: 'red' }) to update -} -``` - -Built-in URL params include `density`, `direction`, `visualRefresh`, and `motionDisabled`. +- For visual regression content, either use `SimplePage` from `pages/app/templates` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea` from `pages/utils/screenshot-area`. +- Use `createPermutations` and `PermutationsView` from `pages/utils/` for permutation pages. -## Shared Data +## Related -If multiple pages share data (like `i18nStrings`), put it in a `common.tsx` in the same directory. +- For integration tests that use dev pages, see [TESTING.md](TESTING.md). diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 390a4526f7..9f2f5b222f 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -1,16 +1,7 @@ # Internal Utilities -Shared infrastructure lives in `src/internal/`. +Shared infrastructure lives in `src/internal/`. Always check there before introducing new utilities, hooks, or internal shared components. -## What's in there +## Related -- `hooks/` — shared React hooks (component telemetry, controllable state, focus management, container/element queries, visual mode detection, intersection observers, debounce/throttle, etc.) -- `components/` — shared internal UI building blocks (dropdowns, options, focus locks, tooltips, chart primitives, transitions, screen-reader utilities, drag handles, etc.) -- `context/` — React contexts for cross-component communication (form fields, modals, split panels, container headers, etc.) -- `utils/` — pure helper functions (DOM helpers, key handling, date/time, locale, display names, prop stripping, etc.) -- `events/` — event handler type definitions used by all component `on*` props -- `base-component/` — base prop extraction utilities -- `styles/` — shared SCSS mixins -- `analytics/` — telemetry and funnel metrics - -Always check `src/internal/` before introducing new utilities, hooks, or shared components. +- For component conventions that use internal utilities, see [COMPONENT_CONVENTIONS.md](COMPONENT_CONVENTIONS.md). diff --git a/docs/STYLING.md b/docs/STYLING.md index 0b511f8928..a24ae54e77 100644 --- a/docs/STYLING.md +++ b/docs/STYLING.md @@ -1,64 +1,30 @@ # Styling -Never hardcode CSS spacing, colors, borders, shadows, typography, or motion values. This project uses design tokens and custom CSS properties. +Prefer design tokens and custom CSS properties over hardcoded values (colors, spacing, font sizes, etc.). This keeps styles consistent across themes and modes. ## Design Tokens -Tokens are defined in `style-dictionary/` and consumed in SCSS via the `awsui` namespace: - -```scss -@use '../internal/styles/tokens' as awsui; - -.my-element { - color: awsui.$color-text-body-default; - padding-block: awsui.$space-scaled-s; -} -``` - -Browse `style-dictionary/` for available token names. Tokens cover colors, spacing, borders, shadows, typography, and motion durations. - -## Custom CSS Properties - -Custom CSS properties are defined in `build-tools/utils/custom-css-properties.js`. Read this file to see what's available. - -## Shared SCSS Mixins - -Shared mixins live in `src/internal/styles/`. Import them as needed: - -- `styles-reset` — resets inherited styles on root elements. Apply on every component root. -- `with-motion` — wraps animations/transitions so they respect `prefers-reduced-motion` and the motion-disabled flag. -- `form-focus-element` — focus ring for form inputs. -- `form-disabled-element` — disabled state for form inputs (background, border, color, cursor). -- `form-invalid-control` — invalid state styling (error border, left accent border). -- `form-warning-control` — warning state styling. -- `form-readonly-element` — read-only state for form inputs. -- `focus-highlight` — focus ring using a pseudo-element (for non-form elements). -- `text-wrapping`, `text-overflow-ellipsis` — text overflow helpers. -Read the mixin files for parameters and usage. +Tokens are defined in `style-dictionary/` and consumed in SCSS via the `awsui` namespace. ## Rules -- Apply `styles-reset` mixin on every root element — prevents parent styles from leaking in - Root elements must not have outer margins — spacing is managed by parent components -- No descendant combinators (`.a .b` with a space) — breaks CSS scoping -- Wrap all animations in the `with-motion` mixin — ensures motion can be toggled -- Use logical properties only — no `left`/`right`/`top`/`bottom`/`width`/`height` in CSS. Use `inline-start`/`inline-end`/`block-start`/`block-end`/`inline-size`/`block-size` instead. This is required for RTL support. +- No descendant combinators (`.a .b` with a space) — breaks CSS scoping because it applies to all `.class-b` elements at unlimited depth +- Wrap animations in the `with-motion` mixin to ensure motion can be toggled on and off +- Use logical properties only — no `left`/`right`/`top`/`bottom`/`width`/`height` in CSS. Use `inline-start`/`inline-end`/`block-start`/`block-end`/`inline-size`/`block-size` instead. Required for RTL support. -## Component States +References: +- [Mappings for sizing](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values/Sizing#mappings_for_dimensions) +- [Mappings for margins, borders, and padding](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values/Margins_borders_padding#mappings_for_margins_borders_and_padding) +- [Mappings for floating and positioning](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values/Floating_and_positioning#mapped_properties_and_values) -For form-like components, use the shared form mixins for consistent state styling: +## RTL Support -- Default state: standard border and background from tokens -- Hover state: use token-based hover colors (e.g. `awsui.$color-background-button-normal-hover`) -- Focus state: use `form-focus-element` or `focus-highlight` mixin -- Disabled state: use `form-disabled-element` mixin -- Invalid state: use `form-invalid-control` mixin (adds left accent border) -- Warning state: use `form-warning-control` mixin -- Read-only state: use `form-readonly-element` mixin +For cases that need direction-aware logic beyond CSS logical properties: -## RTL Support +- In SCSS, use the `with-direction` mixin in `src/internal/styles/direction.scss` +- In TypeScript, `@cloudscape-design/component-toolkit/internal` provides direction detection and logical geometry helpers that replace physical DOM properties -Use logical CSS properties (see Rules above). For cases that need direction-aware logic: +## Related -- SCSS: `with-direction` mixin in `src/internal/styles/direction.scss` -- JS: `getIsRtl`, `handleKey`, `getLogicalBoundingClientRect`, `getOffsetInlineStart`, `getScrollInlineStart` in `src/internal/` +- For linting rules (stylelint), see [CODE_STYLE.md](CODE_STYLE.md). diff --git a/docs/TESTING.md b/docs/TESTING.md index a59aafaced..8e71342147 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -3,7 +3,7 @@ ## Quick Reference ``` -npm test # all tests (unit + integ + a11y) +npm test # all tests npm run test:unit # unit + build-tool tests npm run test:integ # integration tests (starts dev server automatically) npm run test:motion # motion tests (starts dev server automatically) @@ -14,7 +14,7 @@ The npm scripts use gulp tasks that handle env vars (`TZ=UTC`, `NODE_OPTIONS=--e ## Targeting Specific Files -For running a specific test file or folder, call jest directly with the appropriate config: +Call jest directly with the appropriate config: ``` # Unit @@ -25,9 +25,6 @@ NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.integ.conf # Motion (requires dev server running via `npm start`) NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.motion.config.js src/flashbar/__motion__/ - -# Build-tool / stylelint -NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.build-tools.config.js build-tools/stylelint ``` ## Updating Snapshots @@ -36,10 +33,7 @@ NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.build-tool TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ ``` -## Testing in the Browser - -Integration and motion tests run against dev pages served by the dev server (see docs/DEV_PAGES.md for setup). When running individual test files with jest directly, start the dev server first (`npm start`). The `npm run test:integ` and `npm run test:motion` scripts handle the dev server automatically. - -## A11y Tests +## Related -All dev pages are axe-checked automatically. A11y violations fail the build. Checks run in dark mode only. +- For writing tests, test utils, and test conventions, see [WRITING_TESTS.md](WRITING_TESTS.md). +- For dev/test pages used by integration tests, see [DEV_PAGES.md](DEV_PAGES.md). diff --git a/docs/WRITING_TESTS.md b/docs/WRITING_TESTS.md index a10e122c19..98fad947a0 100644 --- a/docs/WRITING_TESTS.md +++ b/docs/WRITING_TESTS.md @@ -2,44 +2,32 @@ ## Test Utils -Use the project's test utils in `src/test-utils/` — don't query the DOM directly. +Test-utils core is a separate package: https://github.com/cloudscape-design/test-utils -- `src/test-utils/dom/` — unit test wrappers (JSDOM) -- `src/test-utils/selectors/` — integration test wrappers (real browser) - -Read the wrapper for the component you're testing to see available `find*` methods. - -### Authoring Test Utils - -Each wrapper extends `ComponentWrapper`, has a static `rootSelector`, and explicit return types on all methods. Test-util CSS classes go in `src//test-classes/styles.scss` — these classes are only used for test targeting, not visual styling. Read existing wrappers for the pattern. +- Test-utils should not have any dependencies — they can be used with any tech stack. +- Test-utils extend `ComponentWrapper`. `ElementWrapper` is only a return type when no more specific type is available. +- Methods must have explicitly declared return types (enforced via ESLint). +- Wrapper classes must have a static `rootSelector` property. +- For methods that always return a value, add a non-null assertion. +- Adding `null` as a return type is a breaking change. Removing `null` is not. ## Unit Tests Location: `src//__tests__/` -Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for public interactions, react-testing-library for internal corner cases. Read an existing test file (e.g. `src/button/__tests__/button.test.tsx`) for the setup pattern. +Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for querying and interacting with components — use react-testing-library directly only for internal edge cases not covered by test-utils. Read an existing test file (e.g. `src/button/__tests__/button.test.tsx`) for the setup pattern. -## Integration Tests - -Location: `src//__integ__/` +### Snapshot Tests -Integration tests run in a real browser against dev pages (see docs/DEV_PAGES.md). Each integration test navigates to a dev page and interacts with it. +Snapshot tests guard generated artifacts (API definitions, test-util wrappers, design tokens, etc.) against unintended changes. Running the unit and integration tests will update the snapshots accordingly. -Use `useBrowser` from `@amzn/awsui-browser-test-tools/use-browser`. Use a `setupTest` wrapper with `waitForVisible`. Don't wait on tag name selectors — they're visible before JS loads. Multiple assertions per test are fine (e2e tests are slow). Use page object pattern for files with many tests. - -## Snapshot Tests - -Snapshot tests live in `src/__tests__/snapshot-tests/`. To update snapshots after intentional changes: - -``` -TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ -``` +## Integration Tests -## I18n Testing +Location: `src//__integ__/` -Test `useInternalI18n` with `TestI18nProvider` from `src/i18n/testing`. Read existing i18n tests for the pattern. +Integration tests run in a real browser against dev pages (see [DEV_PAGES.md](DEV_PAGES.md)). Use `createWrapper` from `test-utils/selectors` (not `test-utils/dom` — selectors generate CSS selectors for browser tests, while dom wrappers operate on DOM nodes for unit tests). -## Gotchas +## Related -- `findAll`/`findAllByClassName` with `.get()` uses `:nth-child()` — only works if items share the same parent node -- All dev pages are axe-checked automatically. A11y violations fail the build. Checks run in dark mode only. +- For test commands and configs, see [TESTING.md](TESTING.md). +- For dev/test pages, see [DEV_PAGES.md](DEV_PAGES.md). From 6bb83232899a3113ee202542be3056c51d71f6ff Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Thu, 26 Mar 2026 18:06:36 +0100 Subject: [PATCH 4/9] chore: removing relations in docs/ files --- docs/API_DOCS.md | 4 ---- docs/COMPONENT_CONVENTIONS.md | 5 ----- docs/DEV_PAGES.md | 4 ---- docs/INTERNALS.md | 4 ---- docs/STYLING.md | 4 ---- docs/TESTING.md | 5 ----- docs/WRITING_TESTS.md | 5 ----- 7 files changed, 31 deletions(-) diff --git a/docs/API_DOCS.md b/docs/API_DOCS.md index 5e6488aac9..8fab534a1f 100644 --- a/docs/API_DOCS.md +++ b/docs/API_DOCS.md @@ -30,7 +30,3 @@ export namespace ButtonProps { ``` Then reference them in the interface: `variant?: ButtonProps.Variant`. - -## Related - -- For component props and interface conventions, see [COMPONENT_CONVENTIONS.md](COMPONENT_CONVENTIONS.md). diff --git a/docs/COMPONENT_CONVENTIONS.md b/docs/COMPONENT_CONVENTIONS.md index b7e9081924..c6ca94b5a9 100644 --- a/docs/COMPONENT_CONVENTIONS.md +++ b/docs/COMPONENT_CONVENTIONS.md @@ -50,8 +50,3 @@ Centralize all translatable strings under a skippable property (e.g. `i18nString ## Dependencies Before adding any dependency: must support React 16.8+ and latest 3 major Chrome/Firefox/Edge, no global state, ESM preferred. - -## Related - -- For styling rules and design tokens, see [STYLING.md](STYLING.md). -- For internal shared utilities, see [INTERNALS.md](INTERNALS.md). diff --git a/docs/DEV_PAGES.md b/docs/DEV_PAGES.md index 3e95bf7f03..a5c6443707 100644 --- a/docs/DEV_PAGES.md +++ b/docs/DEV_PAGES.md @@ -14,7 +14,3 @@ npm start # starts watcher + dev server at http://localhost:8080 - Import components via `~components/` (not relative paths to `src/`) - For visual regression content, either use `SimplePage` from `pages/app/templates` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea` from `pages/utils/screenshot-area`. - Use `createPermutations` and `PermutationsView` from `pages/utils/` for permutation pages. - -## Related - -- For integration tests that use dev pages, see [TESTING.md](TESTING.md). diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 9f2f5b222f..899fef6022 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -1,7 +1,3 @@ # Internal Utilities Shared infrastructure lives in `src/internal/`. Always check there before introducing new utilities, hooks, or internal shared components. - -## Related - -- For component conventions that use internal utilities, see [COMPONENT_CONVENTIONS.md](COMPONENT_CONVENTIONS.md). diff --git a/docs/STYLING.md b/docs/STYLING.md index a24ae54e77..4be01b4b1e 100644 --- a/docs/STYLING.md +++ b/docs/STYLING.md @@ -24,7 +24,3 @@ For cases that need direction-aware logic beyond CSS logical properties: - In SCSS, use the `with-direction` mixin in `src/internal/styles/direction.scss` - In TypeScript, `@cloudscape-design/component-toolkit/internal` provides direction detection and logical geometry helpers that replace physical DOM properties - -## Related - -- For linting rules (stylelint), see [CODE_STYLE.md](CODE_STYLE.md). diff --git a/docs/TESTING.md b/docs/TESTING.md index 8e71342147..79941e2031 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -32,8 +32,3 @@ NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.motion.con ``` TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ ``` - -## Related - -- For writing tests, test utils, and test conventions, see [WRITING_TESTS.md](WRITING_TESTS.md). -- For dev/test pages used by integration tests, see [DEV_PAGES.md](DEV_PAGES.md). diff --git a/docs/WRITING_TESTS.md b/docs/WRITING_TESTS.md index 98fad947a0..cf69fc2f3b 100644 --- a/docs/WRITING_TESTS.md +++ b/docs/WRITING_TESTS.md @@ -26,8 +26,3 @@ Snapshot tests guard generated artifacts (API definitions, test-util wrappers, d Location: `src//__integ__/` Integration tests run in a real browser against dev pages (see [DEV_PAGES.md](DEV_PAGES.md)). Use `createWrapper` from `test-utils/selectors` (not `test-utils/dom` — selectors generate CSS selectors for browser tests, while dom wrappers operate on DOM nodes for unit tests). - -## Related - -- For test commands and configs, see [TESTING.md](TESTING.md). -- For dev/test pages, see [DEV_PAGES.md](DEV_PAGES.md). From 17d948749b67747d31818e5eed5114d197f7bea6 Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Thu, 26 Mar 2026 18:48:23 +0100 Subject: [PATCH 5/9] chore: clean up docs to make it more structured --- AGENTS.md | 4 ++-- docs/API_DOCS.md | 30 ++++++------------------------ docs/DEV_PAGES.md | 9 +-------- docs/STYLING.md | 4 ---- docs/TESTING.md | 2 +- 5 files changed, 10 insertions(+), 39 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ac02ecca50..2c9db51010 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ npm install ## Running Locally ``` -npm start # starts watcher + dev server +npm run start # starts watcher + dev server for development pages npm run start:react18 # starts watcher + dev server (React 18) ``` @@ -25,7 +25,7 @@ The dev server runs at `http://localhost:8080`. Pages are served from `pages//interfaces.ts`). - -## Writing Prop Descriptions - -Every public prop must have a JSDoc comment. For union/enum props, list available options inline: - -```ts -/** Determines the general styling of the button as follows: - * * `primary` for primary buttons. - * * `normal` for secondary buttons. - * * `link` for tertiary buttons. - */ -variant?: ButtonProps.Variant; -``` +This project uses `@cloudscape-design/documenter` to generate API docs from JSDoc comments in component interface files (`src//interfaces.ts`). ## Special Tags -- `@displayname` — overrides the display name for children slots (e.g. `children` → `text`) +- `@i18n` — marks internationalization properties +- `@analytics` — marks analytics metadata properties +- `@deprecated` — marks deprecated properties (include replacement info) +- `@displayname` — overrides the display name (e.g. `children` → `text`) ## Sub-types -Define union types as named type aliases in the component's namespace, not as inline unions: - -```ts -export namespace ButtonProps { - export type Variant = 'normal' | 'primary' | 'link' | 'icon' | 'inline-icon' | 'inline-link'; -} -``` - -Then reference them in the interface: `variant?: ButtonProps.Variant`. +Define union types as named type aliases in the component's namespace, not as inline unions. Then reference them in the interface: `variant?: ButtonProps.Variant`. diff --git a/docs/DEV_PAGES.md b/docs/DEV_PAGES.md index a5c6443707..0f767897cd 100644 --- a/docs/DEV_PAGES.md +++ b/docs/DEV_PAGES.md @@ -2,15 +2,8 @@ Dev and test pages live in `pages//`. They are used for local development, integration tests, and visual regression tests. -## Running Dev Pages - -``` -npm run quick-build # build first (required before starting) -npm start # starts watcher + dev server at http://localhost:8080 -``` - ## Rules - Import components via `~components/` (not relative paths to `src/`) -- For visual regression content, either use `SimplePage` from `pages/app/templates` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea` from `pages/utils/screenshot-area`. +- For visual regression content, either use `SimplePage` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea`. - Use `createPermutations` and `PermutationsView` from `pages/utils/` for permutation pages. diff --git a/docs/STYLING.md b/docs/STYLING.md index 4be01b4b1e..f8dfee9646 100644 --- a/docs/STYLING.md +++ b/docs/STYLING.md @@ -2,10 +2,6 @@ Prefer design tokens and custom CSS properties over hardcoded values (colors, spacing, font sizes, etc.). This keeps styles consistent across themes and modes. -## Design Tokens - -Tokens are defined in `style-dictionary/` and consumed in SCSS via the `awsui` namespace. - ## Rules - Root elements must not have outer margins — spacing is managed by parent components diff --git a/docs/TESTING.md b/docs/TESTING.md index 79941e2031..1780d1375d 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -1,4 +1,4 @@ -# Testing +# Running Tests ## Quick Reference From 1f02410be0c0a577c1599906a787753f122874c5 Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Fri, 27 Mar 2026 09:34:00 +0100 Subject: [PATCH 6/9] chore: rename file to make it more descriptive --- AGENTS.md | 2 +- docs/{TESTING.md => RUNNING_TESTS.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{TESTING.md => RUNNING_TESTS.md} (100%) diff --git a/AGENTS.md b/AGENTS.md index 2c9db51010..ffde7b4b72 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,7 +25,7 @@ The dev server runs at `http://localhost:8080`. Pages are served from `pages/ Date: Fri, 27 Mar 2026 10:15:59 +0100 Subject: [PATCH 7/9] chore: simplify by removing file paths --- docs/CODE_STYLE.md | 10 ++++++---- docs/DEV_PAGES.md | 4 +--- docs/STYLING.md | 2 +- docs/WRITING_TESTS.md | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/CODE_STYLE.md b/docs/CODE_STYLE.md index 196ed67f9a..a4cbaef445 100644 --- a/docs/CODE_STYLE.md +++ b/docs/CODE_STYLE.md @@ -1,7 +1,9 @@ # Code Style -Run `npm run lint` to check formatting and linting (prettier, stylelint, eslint). See the config files for rules: +Run `npm run lint` to check formatting and linting. The project uses: -- Prettier: `.prettierrc` -- Stylelint: `.stylelintrc` -- ESLint: `eslint.config.mjs` +- **Prettier** for code formatting +- **Stylelint** for CSS/SCSS linting +- **ESLint** for JavaScript/TypeScript linting + +See the respective config files in the project root for rules. diff --git a/docs/DEV_PAGES.md b/docs/DEV_PAGES.md index 0f767897cd..b730008858 100644 --- a/docs/DEV_PAGES.md +++ b/docs/DEV_PAGES.md @@ -3,7 +3,5 @@ Dev and test pages live in `pages//`. They are used for local development, integration tests, and visual regression tests. ## Rules - -- Import components via `~components/` (not relative paths to `src/`) - For visual regression content, either use `SimplePage` (handles heading, screenshot area, i18n, and layout) or wrap content in `ScreenshotArea`. -- Use `createPermutations` and `PermutationsView` from `pages/utils/` for permutation pages. +- Use `createPermutations` and `PermutationsView` for permutation pages. \ No newline at end of file diff --git a/docs/STYLING.md b/docs/STYLING.md index f8dfee9646..fa1b1e54b8 100644 --- a/docs/STYLING.md +++ b/docs/STYLING.md @@ -18,5 +18,5 @@ References: For cases that need direction-aware logic beyond CSS logical properties: -- In SCSS, use the `with-direction` mixin in `src/internal/styles/direction.scss` +- In SCSS, use the `with-direction` mixin - In TypeScript, `@cloudscape-design/component-toolkit/internal` provides direction detection and logical geometry helpers that replace physical DOM properties diff --git a/docs/WRITING_TESTS.md b/docs/WRITING_TESTS.md index cf69fc2f3b..8e2a0971e6 100644 --- a/docs/WRITING_TESTS.md +++ b/docs/WRITING_TESTS.md @@ -15,7 +15,7 @@ Test-utils core is a separate package: https://github.com/cloudscape-design/test Location: `src//__tests__/` -Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for querying and interacting with components — use react-testing-library directly only for internal edge cases not covered by test-utils. Read an existing test file (e.g. `src/button/__tests__/button.test.tsx`) for the setup pattern. +Use `react-testing-library` to render, combined with test-utils. Prefer test-utils for querying and interacting with components — use react-testing-library directly only for internal edge cases not covered by test-utils. ### Snapshot Tests From 26d495caec7c5420322da750ec2f3f5bf6581d40 Mon Sep 17 00:00:00 2001 From: Amanuel Sisay Date: Fri, 27 Mar 2026 11:16:01 +0100 Subject: [PATCH 8/9] chore: centralize the import for the common guide --- AGENTS.md | 8 +------- docs/CLOUDSCAPE_COMPONENTS_GUIDE.md | 11 +++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 docs/CLOUDSCAPE_COMPONENTS_GUIDE.md diff --git a/AGENTS.md b/AGENTS.md index ffde7b4b72..537a3fc27c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,11 +23,5 @@ The dev server runs at `http://localhost:8080`. Pages are served from `pages/ Date: Fri, 27 Mar 2026 14:26:03 +0100 Subject: [PATCH 9/9] chore: modularize CONTRIBUTING.md --- CONTRIBUTING.md | 186 ++-------------------------- docs/CLOUDSCAPE_COMPONENTS_GUIDE.md | 16 +-- docs/DIRECTORY_LAYOUT.md | 41 ++++++ docs/GENERAL_GUIDE.md | 32 +++++ docs/RUNNING_TESTS.md | 36 +++++- 5 files changed, 126 insertions(+), 185 deletions(-) create mode 100644 docs/DIRECTORY_LAYOUT.md create mode 100644 docs/GENERAL_GUIDE.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 01f9daa99f..e5086486a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,38 +4,9 @@ Use this repository to [create bug reports or feature requests](https://github.com/cloudscape-design/components/issues/new/choose). You can also [start a discussion](https://github.com/cloudscape-design/components/discussions) to ask a question. We will do our best to reply. To minimize duplicates, we recommend that you search for existing bug reports, feature requests, or discussions before initiating a new thread. -## Versioning +## Documentation -We release patch versions on a daily basis to release bug fixes and new features and components. Patch versions do not contain breaking changes. - -### Public APIs - -Our public API consists of - -- [Components APIs](https://cloudscape.design/components) (properties, slots, events, functions) -- [Test utilities](https://cloudscape.design/get-started/testing/introduction/) -- Typescript definitions -- [Design tokens](https://cloudscape.design/foundation/visual-foundation/design-tokens) - -The inner HTML structure and class names of our components are not part of our APIs. Modifications to those are not considered breaking changes. - -## Frameworks support - -We support - -- React 16.8+ -- Jest 25+ - -## Browsers support - -We support the latest 3 *major* versions of these browsers for desktop: -- Google Chrome -- Mozilla Firefox -- Microsoft Edge - -and the latest three *minor* versions of Apple Safari for macOS for desktop. - -We do not support Microsoft Internet Explorer or mobile browsers. We support all viewport sizes across desktop browsers. +For detailed guides on component conventions, styling, writing tests, supported platforms, and more, see the [General Guide](docs/GENERAL_GUIDE.md). ## How to contribute code @@ -82,163 +53,26 @@ Then, start the dev-server by running: npm start ``` -This will open a webpack-dev-server at http://localhost:8080 and watch -for file changes. +This will open a webpack-dev-server at http://localhost:8080 and watch for file changes. ### Quick rebuild -To quickly rebuild this package, run `npm run quick-build`. This runs only the source code build, skipping -documentation and screenshot testing builds. +To quickly rebuild this package, run `npm run quick-build`. This runs only the source code build, skipping documentation and screenshot testing builds. ### Running tests -The package contains three types of tests: - -- **Build-tool tests** test the build-tools code in a NodeJS context. -- **Unit tests** emulate a browser environment using JSDOM. -- **Integration tests** test against real browser behavior on Chrome, with motion disabled. -- **Motion tests** run a specific set of tests on Chrome, with motion enabled. - -#### Run all tests: - -``` -npm test -``` - -#### Run build tool and unit tests: - ``` -npm run test:unit +npm test # all tests +npm run test:unit # unit + build-tool tests +npm run test:integ # integration tests +npm run test:motion # motion tests ``` -#### Run integration tests: - -If you're running integration tests on a Mac, make sure you have ChromeDriver: - -``` -npm i -g chromedriver -``` - -Then, run the dev server and integration tests in separate terminals: - -``` -npm start -``` - -``` -npm run test:integ -``` - -#### Run motion tests: - -As in integration tests, make sure you have ChromeDriver installed and start the dev server: - -``` -npm i -g chromedriver -npm start -``` - -Then, run the motion tests in a separate terminal: - -``` -npm test:motion -``` - -#### Run a single test suite - -To run a single test suite, you can call Jest directly using the appropriate config: - -``` -# Run a single button unit test suite -npx jest -c jest.unit.config.js src/button/__tests__/button.test.tsx - -# Run all input integration tests -npx jest -c jest.integ.config.js src/input - -# Run motion tests for the flashbar component -npx jest -c jest.motion.config.js src/flashbar - -# Test all stylelint rules -npx jest -c jest.build-tools.config.js build-tools/stylelint -``` - -Note: when running jest directly you may see errors about `--experimental-vm-modules`, to fix this you can set this NodeJS flag as follows: - -``` -export NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" -``` - -Alternatively, you can set the flag inline with the command: - -``` -# Run a single integration test file -NODE_OPTIONS='--experimental-vm-modules' npx jest -c jest.integ.config.js src/input/__integ__/input.test.ts -``` - -#### Updating all snapshots - -When component APIs change, you may need to update test snapshots. Use the `-u` flag to update snapshots: - -``` -npx jest -u snapshot -c jest.unit.config.js src/ -``` - -### Run visual regression tests - -Visual regression tests for the permutation pages are automatically run when opening a pull request in GitHub. - -#### Checking results in a pull requests - -To look at the results of the tests, check the details of the "Visual Regression Tests" action in the pull request. -The logs of the "Test for regressions" step should indicate what pages failed the regression tests. - -To check the full report in a browser, go to the action summary and download the `visual-regression-results` artifacts. -Unzip the downloaded archive and open the `html_report/index.html` file in your browser. - -If there are unexpected regressions, fix your pull request. -If the changes are expected, call this out in your pull request comments. +For targeting specific files, updating snapshots, ChromeDriver setup, and visual regression tests, see [docs/RUNNING_TESTS.md](docs/RUNNING_TESTS.md). ### Directory layout -``` -├── __mocks__ - jest mocks for external dependencies -│ -├── build-tools - build tasks and configuration for gulp -│ -├── pages - react pages for development, scenario and permutation testing -│ └── .page.tsx -│ -├── src -│ ├── __a11y__ - global a11y tests for all components -│ ├── __integ__ - global integ tests for all components -│ ├── __tests__ - global unit tests for all components -| | -│ ├── -│ │ ├── __tests__ - jest unit tests -│ │ ├── __integ__ - jest integration tests -│ │ ├── __motion__ - jest motion tests -│ │ ├── index.tsx - main component file (imports other files and styles) -│ │ └── styles.scss - main SCSS file -| │ -| ├── test-utils - test utils for components -│ │ ├── dom - main source code for test utils -│ │ └── selectors - utils for integration testing, generated from the code in `dom` folder -| | -| └── internal - library internals -| ├── base-component - necessary declarations for every public component -| ├── components - internal utility components -| ├── events - utilities for firing public events -| ├── hooks - internal utility hooks -| └── generated - generated code from style-dictionary -| └── styles - base styles and SCSS-mixins -│ -├── lib - build output -| ├── components - the primary components package -| ├── components-definitions – generated metadata for components -| └── design-tokens - exported design tokens -| -└── style-dictionary - style dictionary tokens and roles -``` +See [docs/DIRECTORY_LAYOUT.md](docs/DIRECTORY_LAYOUT.md) for the full repo structure. ## Code of Conduct diff --git a/docs/CLOUDSCAPE_COMPONENTS_GUIDE.md b/docs/CLOUDSCAPE_COMPONENTS_GUIDE.md index 0e91c3ef7b..34c4edd5c3 100644 --- a/docs/CLOUDSCAPE_COMPONENTS_GUIDE.md +++ b/docs/CLOUDSCAPE_COMPONENTS_GUIDE.md @@ -2,10 +2,12 @@ Reference docs for contributing to [cloudscape-design/components](https://github.com/cloudscape-design/components). -- [Component Conventions](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/COMPONENT_CONVENTIONS.md) — component structure, props, events, refs -- [Styling](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/STYLING.md) — design tokens, CSS rules, RTL support -- [Writing Tests](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/WRITING_TESTS.md) — test utils, unit and integration tests -- [Code Style](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/CODE_STYLE.md) — prettier, stylelint, eslint -- [Dev Pages](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/DEV_PAGES.md) — dev/test pages and running in the browser -- [API Docs](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/API_DOCS.md) — API documentation comments -- [Internals](https://raw.githubusercontent.com/cloudscape-design/components/dev-v3-amanabiy-ai-instructions/docs/INTERNALS.md) — internal shared utilities +- [General Guide](GENERAL_GUIDE.md) — browsers, frameworks, public APIs, versioning +- [Component Conventions](COMPONENT_CONVENTIONS.md) — component structure, props, events, refs +- [Styling](STYLING.md) — design tokens, CSS rules, RTL support +- [Writing Tests](WRITING_TESTS.md) — test utils, unit and integration tests +- [Running Tests](RUNNING_TESTS.md) — commands, configs, visual regression tests +- [Code Style](CODE_STYLE.md) — prettier, stylelint, eslint +- [Dev Pages](DEV_PAGES.md) — dev/test pages and running in the browser +- [API Docs](API_DOCS.md) — API documentation comments +- [Internals](INTERNALS.md) — internal shared utilities diff --git a/docs/DIRECTORY_LAYOUT.md b/docs/DIRECTORY_LAYOUT.md new file mode 100644 index 0000000000..d74fd6c439 --- /dev/null +++ b/docs/DIRECTORY_LAYOUT.md @@ -0,0 +1,41 @@ +# Directory Layout + +``` +├── __mocks__ - jest mocks for external dependencies +│ +├── build-tools - build tasks and configuration for gulp +│ +├── pages - react pages for development, scenario and permutation testing +│ └── .page.tsx +│ +├── src +│ ├── __a11y__ - global a11y tests for all components +│ ├── __integ__ - global integ tests for all components +│ ├── __tests__ - global unit tests for all components +│ │ +│ ├── +│ │ ├── __tests__ - jest unit tests +│ │ ├── __integ__ - jest integration tests +│ │ ├── __motion__ - jest motion tests +│ │ ├── index.tsx - main component file (imports other files and styles) +│ │ └── styles.scss - main SCSS file +│ │ +│ ├── test-utils - test utils for components +│ │ ├── dom - main source code for test utils +│ │ └── selectors - utils for integration testing, generated from the code in `dom` folder +│ │ +│ └── internal - library internals +│ ├── base-component - necessary declarations for every public component +│ ├── components - internal utility components +│ ├── events - utilities for firing public events +│ ├── hooks - internal utility hooks +│ ├── generated - generated code from style-dictionary +│ └── styles - base styles and SCSS-mixins +│ +├── lib - build output +│ ├── components - the primary components package +│ ├── components-definitions - generated metadata for components +│ └── design-tokens - exported design tokens +│ +└── style-dictionary - style dictionary tokens and roles +``` diff --git a/docs/GENERAL_GUIDE.md b/docs/GENERAL_GUIDE.md new file mode 100644 index 0000000000..d44691b85a --- /dev/null +++ b/docs/GENERAL_GUIDE.md @@ -0,0 +1,32 @@ +# General Guide + +## Frameworks + +- React 16.8+ +- Jest 25+ + +## Browsers + +Latest 3 major versions of these desktop browsers: +- Google Chrome +- Mozilla Firefox +- Microsoft Edge + +Latest 3 minor versions of Apple Safari for macOS. + +Mobile browsers and Microsoft Internet Explorer are not supported. All viewport sizes across desktop browsers are supported. + +## Public APIs + +Our public API consists of: + +- [Components APIs](https://cloudscape.design/components) (properties, slots, events, functions) +- [Test utilities](https://cloudscape.design/get-started/testing/introduction/) +- TypeScript definitions +- [Design tokens](https://cloudscape.design/foundation/visual-foundation/design-tokens) + +The inner HTML structure and class names of our components are not part of our APIs. Modifications to those are not considered breaking changes. + +## Versioning + +We release patch versions on a daily basis for bug fixes, new features, and components. Patch versions do not contain breaking changes. diff --git a/docs/RUNNING_TESTS.md b/docs/RUNNING_TESTS.md index 1780d1375d..38717d73e1 100644 --- a/docs/RUNNING_TESTS.md +++ b/docs/RUNNING_TESTS.md @@ -12,6 +12,13 @@ npm run test:a11y # accessibility tests The npm scripts use gulp tasks that handle env vars (`TZ=UTC`, `NODE_OPTIONS=--experimental-vm-modules`) and dev server lifecycle automatically. +## Test Types + +- **Build-tool tests** — test the build-tools code in a NodeJS context. +- **Unit tests** — emulate a browser environment using JSDOM. +- **Integration tests** — test against real browser behavior on Chrome, with motion disabled. +- **Motion tests** — run a specific set of tests on Chrome, with motion enabled. + ## Targeting Specific Files Call jest directly with the appropriate config: @@ -27,8 +34,33 @@ NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.integ.conf NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.motion.config.js src/flashbar/__motion__/ ``` -## Updating Snapshots +> **Note:** When running jest directly you may see errors about `--experimental-vm-modules`. The npm scripts handle this automatically, but when calling jest directly you need to set the flag yourself (see examples above). + +## ChromeDriver (macOS) + +Integration and motion tests require ChromeDriver: + +``` +npm i -g chromedriver +``` + +#### Updating all snapshots + +When component APIs change, you may need to update test snapshots. Use the `-u` flag to update snapshots: ``` -TZ=UTC node_modules/.bin/jest -u -c jest.unit.config.js src/__tests__/snapshot-tests/ +TZ=UTC npx jest -u snapshot -c jest.unit.config.js src/ ``` + +## Visual Regression Tests + +Visual regression tests for permutation pages run automatically when opening a pull request in GitHub. + +To check results: look at the "Visual Regression Tests" action in the PR. The "Test for regressions" step logs which pages failed. For a full report, download the `visual-regression-results` artifact from the action summary and open `html_report/index.html` in your browser. + +If changes are expected, call it out in your PR comments. + + +### Run visual regression tests + +Visual regression tests for the permutation pages are automatically run when opening a pull request in GitHub. \ No newline at end of file