Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .cursor/agents/typescript-unit-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: typescript-unit-testing
description: Expert in creating and improving TypeScript unit tests. Use proactively when writing or modifying .ts/.spec.ts files, adding tests for components/services/pipes, or when asked for unit tests in Angular/TypeScript.
---

You are a TypeScript unit testing specialist. **Primary focus: Angular interaction** (components, templates, Spectator, TestBed). In **SDK and similar non-Angular folders**, use plain Jest and the stack appropriate to that code (no Spectator/Angular unless it's Angular SDK code).

## Required Reading

**Before writing any Angular test, read `docs/frontend/TESTING_FRONTEND.md`** for complete patterns including:
- Spectator API (all factories: `createComponentFactory`, `createServiceFactory`, `createDirectiveFactory`, etc.)
- `byTestId()` for element selection (required)
- `setInput()` for component inputs
- `mockProvider()` for dependencies
- `@dotcms/utils-testing` createFake functions for domain objects
- Signal conventions (`$` prefix)
- User-centric testing principles
- Common pitfalls to avoid

## When invoked

1. **Read `docs/frontend/TESTING_FRONTEND.md`** to get current patterns.
2. **Detect context**: Is the file under `libs/sdk/*` (or similar non-Angular libs)? If yes → use non-Angular rules. If no → use Angular rules.
3. Read the source file(s) that need tests.
4. Check for an existing `.spec.ts` file next to the source.
5. Create or extend tests following the patterns from the documentation.
6. Run or suggest the test command to verify.

## Project context (core-web / dotCMS)

- **Location**: Tests live in `core-web/`; `*.spec.ts` files sit alongside source files.
- **Angular code**: Jest + Spectator (`@ngneat/spectator/jest`). Follow `TESTING_FRONTEND.md`.
- **SDK / non-Angular code** (e.g. `libs/sdk/client`, `libs/sdk/analytics`): Plain Jest; no Spectator or TestBed.
- **Runner**: Nx — e.g. `cd core-web && yarn nx run <project>:test` or `yarn nx run <project>:test -t ComponentName`.

## Critical Rules Summary

| Rule | Angular | SDK/non-Angular |
|------|---------|-----------------|
| Framework | Spectator + Jest | Plain Jest |
| Selection | `byTestId()` only | N/A |
| Inputs | `setInput()` | N/A |
| Mocks | `mockProvider()`, `SpyObject<T>` | `jest.fn()` |
| Domain data | `createFake*` from `@dotcms/utils-testing` | As needed |
| Focus | User-visible behavior | Public API |

## Output format

1. **Context**: Angular or SDK/non-Angular (and why).
2. **Summary**: What is under test and scenarios covered.
3. **Test file**: Full `.spec.ts` following `TESTING_FRONTEND.md` patterns.
4. **Run command**: `yarn nx run <project>:test -t ComponentName`.
5. **Checklist**: Verify `byTestId()`, `setInput()`, `mockProvider`, `createFake*`, user flow focus.

If the source file is missing `data-testid` attributes, suggest the minimal template changes.
10 changes: 10 additions & 0 deletions core-web/.gemini/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"mcpServers": {
"nx-mcp": {
"type": "stdio",
"command": "npx",
"args": ["nx-mcp"]
}
},
"contextFileName": "AGENTS.md"
}
9 changes: 9 additions & 0 deletions core-web/.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"mcpServers": {
"nx-mcp": {
"type": "stdio",
"command": "npx",
"args": ["nx-mcp"]
}
}
}
13 changes: 7 additions & 6 deletions core-web/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

# General Guidelines for working with Nx

- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
- You have access to the Nx MCP server and its tools, use them to help the user
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
- You have access to the Nx MCP server and its tools, use them to help the user
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
- For Nx plugin best practices, check `node_modules/@nx/<plugin>/PLUGIN.md`. Not all plugins have this file - proceed without it if unavailable.

<!-- nx configuration end-->
151 changes: 76 additions & 75 deletions core-web/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,33 +91,33 @@ nx run-many --target=test --projects=sdk-client,sdk-react

### Monorepo Organization

- **apps/** - Main applications (dotcms-ui, dotcms-block-editor, dotcms-binary-field-builder, mcp-server)
- **libs/sdk/** - External-facing SDKs (client, react, angular, analytics, experiments, uve)
- **libs/data-access/** - Angular services for API communication
- **libs/ui/** - Shared UI components and patterns
- **libs/portlets/** - Feature-specific portlets (analytics, experiments, locales, etc.)
- **libs/dotcms-models/** - TypeScript interfaces and types
- **libs/block-editor/** - TipTap-based rich text editor
- **libs/template-builder/** - Template construction utilities
- **apps/** - Main applications (dotcms-ui, dotcms-block-editor, dotcms-binary-field-builder, mcp-server)
- **libs/sdk/** - External-facing SDKs (client, react, angular, analytics, experiments, uve)
- **libs/data-access/** - Angular services for API communication
- **libs/ui/** - Shared UI components and patterns
- **libs/portlets/** - Feature-specific portlets (analytics, experiments, locales, etc.)
- **libs/dotcms-models/** - TypeScript interfaces and types
- **libs/block-editor/** - TipTap-based rich text editor
- **libs/template-builder/** - Template construction utilities

### Technology Stack

- **Angular 19.2.9** with standalone components
- **Nx 20.5.1** for monorepo management
- **PrimeNG 17.18.11** UI components
- **TipTap 2.14.0** for rich text editing
- **NgRx 19.2.1** for state management
- **Jest 29.7.0** for testing
- **Playwright** for E2E testing
- **Node.js >=v22.15.0** requirement
- **Angular 19.2.9** with standalone components
- **Nx 20.5.1** for monorepo management
- **PrimeNG 17.18.11** UI components
- **TipTap 2.14.0** for rich text editing
- **NgRx 19.2.1** for state management
- **Jest 29.7.0** for testing
- **Playwright** for E2E testing
- **Node.js >=v22.15.0** requirement

### Component Conventions

- **Prefix**: All Angular components use `dot-` prefix
- **Naming**: Follow Angular style guide with kebab-case
- **Architecture**: Feature modules with lazy loading
- **State**: Component-store pattern with NgRx signals
- **Testing**: Jest unit tests + Playwright E2E
- **Prefix**: All Angular components use `dot-` prefix
- **Naming**: Follow Angular style guide with kebab-case
- **Architecture**: Feature modules with lazy loading
- **State**: Component-store pattern with NgRx signals
- **Testing**: Jest unit tests + Playwright E2E

### Modern Angular Syntax (REQUIRED)

Expand All @@ -141,10 +141,10 @@ const button = spectator.query('[data-testid="submit-button"]');

### Backend Integration

- **Development Proxy**: `proxy-dev.conf.mjs` routes `/api/*` to port 8080
- **API Services**: Centralized in `libs/data-access`
- **Authentication**: Bearer token-based with `DotcmsConfigService`
- **Content Management**: Full CRUD through `DotHttpService`
- **Development Proxy**: `proxy-dev.conf.mjs` routes `/api/*` to port 8080
- **API Services**: Centralized in `libs/data-access`
- **Authentication**: Bearer token-based with `DotcmsConfigService`
- **Content Management**: Full CRUD through `DotHttpService`

## Development Workflows

Expand All @@ -167,99 +167,100 @@ const button = spectator.query('[data-testid="submit-button"]');

### SDK Development

- **Client SDK**: Core API client in `libs/sdk/client`
- **React SDK**: React components in `libs/sdk/react`
- **Angular SDK**: Angular services in `libs/sdk/angular`
- **Publishing**: Automated via npm with proper versioning
- **Client SDK**: Core API client in `libs/sdk/client`
- **React SDK**: React components in `libs/sdk/react`
- **Angular SDK**: Angular services in `libs/sdk/angular`
- **Publishing**: Automated via npm with proper versioning

### Testing Strategy

- **Unit Tests**: Jest with comprehensive mocking utilities
- **E2E Tests**: Playwright for critical user workflows
- **Coverage**: Reports generated to `../../../target/core-web-reports/`
- **Mock Data**: Extensive mock utilities in `libs/utils-testing`
- **Unit Tests**: Jest with comprehensive mocking utilities
- **E2E Tests**: Playwright for critical user workflows
- **Coverage**: Reports generated to `../../../target/core-web-reports/`
- **Mock Data**: Extensive mock utilities in `libs/utils-testing`

### Build Targets & Configurations

- **Development**: Proxy configuration with source maps
- **Production**: Optimized builds with tree shaking
- **Library**: Rollup/Vite builds for SDK packages
- **Web Components**: Stencil.js compilation for `dotcms-webcomponents`
- **Development**: Proxy configuration with source maps
- **Production**: Optimized builds with tree shaking
- **Library**: Rollup/Vite builds for SDK packages
- **Web Components**: Stencil.js compilation for `dotcms-webcomponents`

## Important Notes

### TypeScript Configuration

- **Strict Mode**: Enabled across all projects
- **Path Mapping**: Extensive use of `@dotcms/*` barrel exports
- **Types**: Centralized in `libs/dotcms-models` and `libs/sdk/types`
- **Strict Mode**: Enabled across all projects
- **Path Mapping**: Extensive use of `@dotcms/*` barrel exports
- **Types**: Centralized in `libs/dotcms-models` and `libs/sdk/types`

### State Management

- **NgRx**: Component stores with signals pattern
- **Global Store**: Centralized state in `libs/global-store`
- **Services**: Angular services for data access and business logic
- **NgRx**: Component stores with signals pattern
- **Global Store**: Centralized state in `libs/global-store`
- **Services**: Angular services for data access and business logic

### Web Components

- **Stencil.js**: Framework-agnostic components in `libs/dotcms-webcomponents`
- **Legacy**: `libs/dotcms-field-elements` (deprecated, use Stencil components)
- **Integration**: Used across Angular, React, and vanilla JS contexts
- **Stencil.js**: Framework-agnostic components in `libs/dotcms-webcomponents`
- **Legacy**: `libs/dotcms-field-elements` (deprecated, use Stencil components)
- **Integration**: Used across Angular, React, and vanilla JS contexts

### Performance Considerations

- **Lazy Loading**: Feature modules loaded on demand
- **Tree Shaking**: Proper barrel exports for optimal bundles
- **Caching**: Nx task caching for faster builds
- **Affected**: Only build/test changed projects in CI
- **Lazy Loading**: Feature modules loaded on demand
- **Tree Shaking**: Proper barrel exports for optimal bundles
- **Caching**: Nx task caching for faster builds
- **Affected**: Only build/test changed projects in CI

## Debugging & Troubleshooting

### Common Issues

- **Proxy Errors**: Ensure backend is running on port 8080
- **Build Failures**: Check TypeScript paths and circular dependencies
- **Test Failures**: Verify mock data and async handling
- **Linting**: Follow component naming conventions with `dot-` prefix
- **Proxy Errors**: Ensure backend is running on port 8080
- **Build Failures**: Check TypeScript paths and circular dependencies
- **Test Failures**: Verify mock data and async handling
- **Linting**: Follow component naming conventions with `dot-` prefix

### Development Tools

- **Nx Console**: VS Code extension for Nx commands
- **Angular DevTools**: Browser extension for debugging
- **Coverage Reports**: Check `target/core-web-reports/` for test coverage
- **Dependency Graph**: Use `nx dep-graph` to visualize project relationships
- **Nx Console**: VS Code extension for Nx commands
- **Angular DevTools**: Browser extension for debugging
- **Coverage Reports**: Check `target/core-web-reports/` for test coverage
- **Dependency Graph**: Use `nx dep-graph` to visualize project relationships

This codebase emphasizes consistency, testability, and maintainability through its monorepo architecture and established patterns.

## Summary Checklist

### Angular/TypeScript Development

- ✅ Use modern control flow: `@if`, `@for` (NOT `*ngIf`, `*ngFor`)
- ✅ Use modern inputs/outputs: `input<T>()`, `output<T>()` (NOT `@Input()`, `@Output()`)
- ✅ Use `data-testid` attributes for all testable elements
- ✅ Use `spectator.setInput()` for testing component inputs
- ✅ Follow `dot-` prefix convention for all components
- ✅ Use standalone components with lazy loading
- ✅ Use NgRx signals for state management
- ❌ Avoid legacy Angular syntax (`*ngIf`, `@Input()`, etc.)
- ❌ Avoid direct DOM queries without `data-testid`
- ❌ Never skip unit tests for new components
- ✅ Use modern control flow: `@if`, `@for` (NOT `*ngIf`, `*ngFor`)
- ✅ Use modern inputs/outputs: `input<T>()`, `output<T>()` (NOT `@Input()`, `@Output()`)
- ✅ Use `data-testid` attributes for all testable elements
- ✅ Use `spectator.setInput()` for testing component inputs
- ✅ Follow `dot-` prefix convention for all components
- ✅ Use standalone components with lazy loading
- ✅ Use NgRx signals for state management
- ❌ Avoid legacy Angular syntax (`*ngIf`, `@Input()`, etc.)
- ❌ Avoid direct DOM queries without `data-testid`
- ❌ Never skip unit tests for new components

### For Backend/Java Development

- See **[../CLAUDE.md](../CLAUDE.md)** for Java, Maven, REST API, and Git workflow standards
- See **[../CLAUDE.md](../CLAUDE.md)** for Java, Maven, REST API, and Git workflow standards

<!-- nx configuration start-->
<!-- Leave the start & end comments to automatically receive updates. -->

# General Guidelines for working with Nx

- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
- You have access to the Nx MCP server and its tools, use them to help the user
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
- You have access to the Nx MCP server and its tools, use them to help the user
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
- For Nx plugin best practices, check `node_modules/@nx/<plugin>/PLUGIN.md`. Not all plugins have this file - proceed without it if unavailable.

<!-- nx configuration end-->
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[ngClass]="{
'editor-wrapper--fullscreen': isFullscreen,
'editor-wrapper--default': !isFullscreen,
'editor-wrapper--disabled': disabled
'editor-wrapper--disabled': disabled,
'editor-wrapper--error': hasError
}"
[style]="customStyles"
class="editor-wrapper"
Expand All @@ -25,12 +26,31 @@
<i class="pi pi-ellipsis-v"></i>
</div>

@if (showCharData) {
<dot-editor-count-bar
[charLimit]="charLimit"
[characterCount]="characterCount"
[readingTime]="readingTime"
data-testid="editor-count-bar" />
@if (showCharData || charLimitError || requiredError) {
<div class="flex align-items-center mt-3 gap-2">
<div class="flex-1">
@if (requiredError) {
<small class="p-invalid" data-testid="required-error">
{{ 'dot.edit.content.form.field.required' | dm }}
</small>
}
@if (charLimitError) {
<small class="p-invalid" data-testid="char-limit-error">
{{
'dot.edit.content.form.field.charLimitExceeded'
| dm: [charLimitError.max]
}}
</small>
}
</div>
@if (showCharData) {
<dot-editor-count-bar
[charLimit]="charLimit"
[characterCount]="characterCount"
[readingTime]="readingTime"
data-testid="editor-count-bar" />
}
</div>
}

<dot-editor-context-menu [editor]="editor" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
pointer-events: none;
}

.editor-wrapper--error {
outline-color: $color-palette-red;
}

.dot-drag-handle {
cursor: grab;
color: $color-palette-gray-500;
Expand Down Expand Up @@ -97,6 +101,10 @@
transform: rotate(360deg);
}
}

dot-editor-count-bar {
margin-top: 0;
}
}

tiptap-editor::ng-deep .ProseMirror {
Expand Down
Loading
Loading