You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.
- Use strict type checking
- Prefer type inference when the type is obvious
- Avoid the
anytype; useunknownwhen type is uncertain
- Always use standalone components over NgModules
- Must NOT set
standalone: trueinside Angular decorators. It's the default. - Use signals for state management
- Implement lazy loading for feature routes
- Do NOT use the
@HostBindingand@HostListenerdecorators. Put host bindings inside thehostobject of the@Componentor@Directivedecorator instead
- Keep components small and focused on a single responsibility
- Use
input()andoutput()functions instead of decorators - Use
computed()for derived state - Set
changeDetection: ChangeDetectionStrategy.OnPushin@Componentdecorator - Prefer inline templates for small components
- Prefer Reactive forms instead of Template-driven ones
- Do NOT use
ngClass, useclassbindings instead - Do NOT use
ngStyle, usestylebindings instead
- Test through the component's public API and rendered DOM, not private methods or internal implementation details
- Prefer creating the component directly with
TestBed. Use signalinputBindingandoutputBindingbindings instead of test host / wrapper components when wiring inputs and outputs - Only introduce a test host / wrapper component when testing content projection, template composition, or integration behavior that cannot be expressed through direct bindings
- Keep test setup minimal. Mock only the component's direct dependencies and prefer lightweight spies or stubs over large testing modules
- Prefer assertions on user-observable behavior such as rendered text, attributes, ARIA state, CSS classes that are part of the public contract, and emitted outputs
- Prefer
await fixture.whenStable()after interactions or async state changes instead of repeatedly callingfixture.detectChanges(). Usefixture.detectChanges()deliberately for the initial render or when the change detection boundary itself is under test - Keep each test focused on a single behavior with clear arrange / act / assert phases
- Cover happy paths, boundary conditions, and regression-prone branches. Avoid broad snapshot-style assertions that do not explain the intended behavior
- Prefer
await fixture.whenStable()over repeatedfixture.detectChanges()calls after interactions or async state changes whenStable()waits for pending microtasks, timers, and zone activity to settle, producing more reliable tests than manually pumping change detection- Use
fixture.detectChanges()deliberately for the initial render or when the change detection boundary itself is under test - Do NOT chain multiple
detectChanges()calls hoping to flush async work — usewhenStable()instead
- Prefer Vitest's semantic assertion matchers over generic
.toBe()with manual property access — they produce clearer failure messages and more readable tests - Use
toHaveLength(n)instead of accessing.lengthmanually:expect(items).toHaveLength(3)notexpect(items.length).toBe(3) - Use
toContain(item)instead ofexpect(array.includes(item)).toBe(true) - Use
toMatchObject(subset)to assert on a subset of properties instead of multiple individual.toBe()assertions
Infer the correct test command from the file path being edited. After implementation changes, run the matching unit test command to verify.
All unit tests use Vitest. Do NOT use npx ng test or Karma/Jasmine commands.
| File path prefix | Command |
|---|---|
projects/element-ng/ |
npm run lib:test |
projects/charts-ng/ |
npm run charts:test |
projects/native-charts-ng/ |
npm run native-charts:test |
projects/maps-ng/ |
npm run maps:test |
projects/dashboards-ng/ |
npm run dashboards:test |
projects/element-translate-ng/ |
npm run translate:test |
To run a specific test file, use --include and --no-watch:
npm run lib:test -- --include='**/component-name/component-name.component.spec.ts' --no-watchOnly these CLI flags are supported: --include (glob filter) and --no-watch (run once).
Do NOT use --reporter, --watch=false, or any other flags.
Run npm run schematics:test (uses Vitest). Config: projects/element-ng/vitest.config.schematics.ts.
E2E tests require Docker and a running dev server. They are executed via ./e2e-local.sh.
# 1. Start the dev server (in one terminal)
npm run start -- --allowed-hosts true --host 0.0.0.0
# 2. For dashboards tests, also start dashboards artifacts
npm run dashboards-demo:build-and-run-all # webpack
npm run dashboards-demo:build-and-run-all:esm # ESM
# 3. Run e2e tests (in another terminal)
./e2e-local.sh # run all
./e2e-local.sh run '--project=dashboards-demo/*' # specific project
./e2e-local.sh run '--project=dashboards-demo-esm/*' # ESM project
./e2e-local.sh vrt # visual regression only
./e2e-local.sh a11y # accessibility only
# Update snapshots
./e2e-local.sh update # changed snapshots
./e2e-local.sh update-all # all snapshots
./e2e-local.sh update <test-file-name> # specific test (glob supported)
# Run specific static test
PLAYWRIGHT_staticTest=buttons/buttons:badges/badges ./e2e-local.sh run static
# Use Podman instead of Docker (Linux)
DOCKER=podman ./e2e-local.sh- Use signals for local component state
- Use
computed()for derived state - Keep state transformations pure and predictable
- Do NOT use
mutateon signals, useupdateorsetinstead
- Keep templates simple and avoid complex logic
- Use native control flow (
@if,@for,@switch) instead of*ngIf,*ngFor,*ngSwitch - Use the async pipe to handle observables
- Design services around a single responsibility
- Use the
providedIn: 'root'option for singleton services - Use the
inject()function instead of constructor injection
The live-preview demo app runs on http://localhost:4200/.
If not online, ask to start the server. Do not run it yourself.
Load examples using this URL schema:
http://localhost:4200/#/viewer/preview?e=<relative-example-path>
<relative-example-path> is resolved against examplesBaseUrl (app/examples/, see src/app/app.config.ts:132) and omits the file extension.
Example for si-form:
http://localhost:4200/#/viewer/preview?e=si-form/si-form
Supported query params (see projects/live-preview/components/si-example-viewer/si-example-viewer.component.ts)
Unless specifically requested, only use the example path.
e— example pathbase— prefix prepended to eachetheme—light|darklocale— e.g.en,deisRTL— truthy for RTLmode— device mode for mobile viewportrfs— root font size in pxt— inline template overrideframework—react|vue|js