@c8y/websdk 1023.81.3 → 1023.82.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +111 -0
  2. package/dist/ng-add/ai-tools-configure.d.ts +10 -0
  3. package/dist/ng-add/ai-tools-configure.js +318 -0
  4. package/dist/ng-add/ai-tools-configure.js.map +1 -0
  5. package/dist/ng-add/index.js +60 -0
  6. package/dist/ng-add/index.js.map +1 -1
  7. package/dist/ng-add/ng-add.model.d.ts +1 -0
  8. package/dist/templates/ai-configs/claude/CLAUDE.md +98 -0
  9. package/dist/templates/ai-configs/claude/rules/e2e-tests.instructions.md +187 -0
  10. package/dist/templates/ai-configs/claude/rules/frontend.instructions.md +251 -0
  11. package/dist/templates/ai-configs/claude/rules/unit-tests.instructions.md +172 -0
  12. package/dist/templates/ai-configs/cursor/cursor.mdc +98 -0
  13. package/dist/templates/ai-configs/cursor/rules/e2e-tests.instructions.md +187 -0
  14. package/dist/templates/ai-configs/cursor/rules/frontend.instructions.md +251 -0
  15. package/dist/templates/ai-configs/cursor/rules/unit-tests.instructions.md +172 -0
  16. package/dist/templates/ai-configs/gemini/GEMINI.md +98 -0
  17. package/dist/templates/ai-configs/gemini/rules/e2e-tests.instructions.md +181 -0
  18. package/dist/templates/ai-configs/gemini/rules/frontend.instructions.md +247 -0
  19. package/dist/templates/ai-configs/gemini/rules/unit-tests.instructions.md +166 -0
  20. package/dist/templates/ai-configs/github/copilot-instructions.md +98 -0
  21. package/dist/templates/ai-configs/github/instructions/e2e-tests.instructions.md +187 -0
  22. package/dist/templates/ai-configs/github/instructions/frontend.instructions.md +251 -0
  23. package/dist/templates/ai-configs/github/instructions/unit-tests.instructions.md +172 -0
  24. package/dist/templates/ai-configs/jetbrains/guidelines.md +98 -0
  25. package/dist/templates/ai-configs/jetbrains/rules/e2e-tests.instructions.md +181 -0
  26. package/dist/templates/ai-configs/jetbrains/rules/frontend.instructions.md +247 -0
  27. package/dist/templates/ai-configs/jetbrains/rules/unit-tests.instructions.md +166 -0
  28. package/dist/templates/ai-configs/windsurf/guidelines.md +98 -0
  29. package/dist/templates/ai-configs/windsurf/rules/e2e-tests.instructions.md +187 -0
  30. package/dist/templates/ai-configs/windsurf/rules/frontend.instructions.md +251 -0
  31. package/dist/templates/ai-configs/windsurf/rules/unit-tests.instructions.md +172 -0
  32. package/package.json +3 -2
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: "Jest Unit Testing Guide"
3
+ description: "Instructions for Jest unit tests (TypeScript)"
4
+ applyTo: "**/*.spec.ts"
5
+ paths: ["**/*.spec.ts"]
6
+ ---
7
+
8
+ # Unit Testing Guide
9
+
10
+ ## Overview
11
+ Unit tests use Jest with TestBed for Angular component setup and jest.fn() for mocking services.
12
+
13
+ # Common
14
+
15
+ ## Test File Location
16
+ - Unit test files are co-located with the code they test
17
+ - Use `.spec.ts` extension for test files
18
+ - Example: `my-component.ts` → `my-component.spec.ts`
19
+
20
+ ## Basic Test Structure
21
+ ```typescript
22
+ describe('ComponentName', () => {
23
+ let component: ComponentName;
24
+ let fixture: ComponentFixture<ComponentName>;
25
+
26
+ beforeEach(async () => {
27
+ await TestBed.configureTestingModule({
28
+ imports: [ComponentName],
29
+ providers: [/* services */]
30
+ }).compileComponents();
31
+ fixture = TestBed.createComponent(ComponentName);
32
+ component = fixture.componentInstance;
33
+ });
34
+
35
+ test('should do something specific', () => {
36
+ fixture.detectChanges();
37
+ expect(actual).toBe(expected);
38
+ });
39
+ });
40
+ ```
41
+
42
+ **Key points:**
43
+ - Always use `async` on `beforeEach` and `await` + `.compileComponents()` on `configureTestingModule()` to properly compile components
44
+ - Always call `fixture.detectChanges()` before asserting anything about the component (triggers Angular initialization and change detection)
45
+
46
+ ## Angular Testing
47
+ - Test component behavior, not implementation details
48
+ - Test DOM interactions through the fixture using `fixture.detectChanges()`
49
+ - For async operations: use `fixture.whenStable()` to wait for pending async tasks or `async`/`waitForAsync` and `fakeAsync`
50
+
51
+ ## Best Practices
52
+ - **Descriptive test names**: Use "should..." pattern in it() names
53
+ - **Be concise**: Keep tests to as few lines as possible. Avoid unnecessary variable declarations. Use helper functions for common test data.
54
+ - **Structure tests logically**: Group related tests using nested `describe` blocks
55
+ - **Mock external dependencies**: Don't test third-party code
56
+ - **Test user behavior**: Focus on what users experience, not implementation details
57
+ - **Avoid arbitrary sleeps**: Do NOT use `setTimeout` in tests — instead use `fixture.whenStable()` or `await` for async operations
58
+ - **Don't duplicate**: Use `beforeEach` for common setup, or extract helper functions
59
+ - **Avoid brittleness**: Don't depend on exact backend data structure details that may change
60
+ - **Always call `detectChanges()` before assertions**: Angular change detection must run before testing component state or DOM
61
+ - **Mock comprehensively**: If a service has 10 public methods and your component calls 8 of them, mock all 8 in the test setup to avoid runtime errors later
62
+
63
+ ## Common Pitfalls to Avoid
64
+ - ❌ **Forgetting `async` and `.compileComponents()`**: `beforeEach(() => { ... })` without `async`/`await` leaves components uncompiled
65
+ - ❌ **Missing `fixture.detectChanges()`**: Component won't initialize without this; properties will be undefined
66
+ - ❌ **Incomplete service mocks**: Mocking only some methods causes "is not a function" errors on unmocked methods
67
+ - ❌ **Wrong mock return types**: Returning `[]` when the method returns `{ data: [], paging: {} }` causes destructuring errors
68
+ - ❌ **Not providing all dependencies**: Missing providers (e.g., `TranslateService`) causes "No provider found" errors
69
+ - ✅ **DO**: Mock all methods, use correct async patterns, always call `detectChanges()`, verify return types match the real service
70
+
71
+ ## Common Test Patterns
72
+ ```typescript
73
+ // Testing component initialization
74
+ it('should initialize with default values', () => {
75
+ fixture.detectChanges();
76
+ expect(component.propertyName).toBe(expectedValue);
77
+ });
78
+
79
+ // Testing async operations
80
+ it('should load data on init', async () => {
81
+ fixture.detectChanges();
82
+ await fixture.whenStable();
83
+ fixture.detectChanges();
84
+ expect(component.data).toBeDefined();
85
+ });
86
+
87
+ // Testing user interactions
88
+ it('should emit event when button clicked', () => {
89
+ fixture.detectChanges();
90
+ jest.spyOn(component.outputEvent, 'emit');
91
+ fixture.nativeElement.querySelector('button').click();
92
+ expect(component.outputEvent.emit).toHaveBeenCalled();
93
+ });
94
+ ```
95
+
96
+ ## TypeScript in Tests
97
+ - Use proper types, avoid `any`
98
+ - Type your test data and mocks
99
+ - Use interfaces from the application code
100
+ - Enable strict mode for better type safety
101
+
102
+ # Setup & Mocking
103
+
104
+ ## Mocking
105
+
106
+ ### TestBed Setup with jest.fn()
107
+
108
+ Use **TestBed.configureTestingModule** for component setup and **jest.fn()** for mock service objects:
109
+
110
+ ```typescript
111
+ beforeEach(async () => {
112
+ await TestBed.configureTestingModule({
113
+ imports: [MyComponent],
114
+ providers: [
115
+ {
116
+ provide: MyService,
117
+ useValue: {
118
+ getData: jest.fn().mockResolvedValue(data),
119
+ logout: jest.fn()
120
+ }
121
+ }
122
+ ]
123
+ }).compileComponents();
124
+ fixture = TestBed.createComponent(MyComponent);
125
+ component = fixture.componentInstance;
126
+ });
127
+ ```
128
+
129
+ **Important mocking guidelines:**
130
+ - **Mock all public methods** that the component or its children might call, not just a few
131
+ - **Match return types exactly**: If a method returns `Promise<T>`, use `.mockResolvedValue(T)`; if it returns an object with properties, return a properly structured object (e.g., `{ data: [], paging: {} }`)
132
+ - **Use `.mockResolvedValue()` for async methods** to return promises correctly
133
+ - **Use `.mockReturnValue()` for synchronous methods**
134
+ - **Type your mocks** to catch missing methods early: `useValue: {...} as jest.Mocked<MyService>`
135
+
136
+ ### Spying on Component/Service Methods
137
+
138
+ ```typescript
139
+ const service = TestBed.inject(MyService);
140
+ jest.spyOn(service, 'getData').mockReturnValue(value);
141
+
142
+ // Or for component methods:
143
+ jest.spyOn(component, 'onSubmit');
144
+ component.handleForm();
145
+ expect(component.onSubmit).toHaveBeenCalled();
146
+ ```
147
+
148
+ ## Matchers
149
+ - `toBe()` - Strict equality (===)
150
+ - `toEqual()` - Deep equality
151
+ - `toBeTruthy()` / `toBeFalsy()`
152
+ - `toContain()` - Array/string contains
153
+ - `toHaveBeenCalled()` - Spy was called
154
+ - `toHaveBeenCalledWith(args)` - Spy called with specific arguments
155
+ - `toHaveLength(n)` - Array/string length
156
+ - `toThrow()` / `toThrowError()` - Exception testing
157
+ - See [Jest matchers documentation](https://jestjs.io/docs/expect) for complete list
158
+
159
+ ## Running Tests
160
+ - Run specific file: `yarn jest my-component.spec.ts`
161
+ - Run with watch mode: `yarn jest --watch my-component.spec.ts`
162
+ - Run single test suite: `yarn jest my-component.spec.ts -t '^SuiteName(\\s.*)?$'`
163
+ - Debug race conditions: `yarn jest my-component.spec.ts --testNamePattern="Test Name" --maxWorkers=1`
164
+
165
+ ## Coverage
166
+ - Aim for high coverage but focus on meaningful tests
167
+ - Ensure exception cases are covered where possible
168
+ - Focus on critical paths and edge cases
169
+
170
+ ## Resources
171
+ - Jest documentation: https://jestjs.io/
172
+ - Angular testing guide: https://angular.dev/guide/testing
@@ -0,0 +1,98 @@
1
+ ## Project Identity
2
+
3
+ **Cumulocity IoT Web Application** — custom web frontend built with the Cumulocity Web SDK. Extends the Cumulocity IoT platform with custom features and integrations.
4
+
5
+ - **Stack:** Angular 20, TypeScript 5.9.3, RxJS 7.8, Jest 30, Cypress 15, ESLint (airbnb-base + angular-eslint)
6
+ - **Core Libraries:** `@c8y/ngx-components`, `@c8y/client`, `@c8y/toolkit`, `@c8y/devkit`, `@c8y/bootstrap`
7
+ - **Structure:** Standard Angular CLI application scaffolded with `ng add @c8y/websdk`
8
+
9
+ ---
10
+
11
+ ## 🛑 MANDATORY WORKFLOW: UI Planning & Implementation
12
+
13
+ **STOP: Before analyzing, planning, designing, OR implementing ANY UI feature/component, you MUST complete this workflow. No exceptions.**
14
+
15
+ ### Step 1: Fetch Codex Documentation (REQUIRED BEFORE PLANNING)
16
+
17
+ When the user requests ANY UI work (planning, design, implementation), your **FIRST ACTION** must be:
18
+
19
+ 1. **Fetch** https://cumulocity.com/codex/llms.txt
20
+ 2. **Search** the content for relevant component keywords (modal, button, form, table, etc.)
21
+ 3. **If found:** Read the specific `.md` documentation file like `https://cumulocity.com/codex/components/forms/editor.md`
22
+ 4. **Read and analyze** the documentation content
23
+ 5. **Locate examples** in the public tutorial repository:
24
+ e.g. for file path './packages/tutorial/src/selector/asset-selector-example/tree-options/asset-selector-tree-example.component.ts' get file from
25
+ 'https://github.com/Cumulocity-IoT/tutorial/tree/main/src/selector/asset-selector-example/tree-options/asset-selector-tree-example.component.ts'
26
+ 6. **Read example code** to understand the official pattern
27
+
28
+ **⛔ INVALID:**
29
+ - ❌ "I'll list the Codex URL as a resource to review later"
30
+ - ❌ "The plan should include fetching the documentation"
31
+ - ❌ "Before implementation, we need to review the Codex"
32
+ - ❌ Making a plan without actually fetching and reading documentation
33
+
34
+ **✅ VALID:**
35
+ - ✓ Fetch llms.txt → Find modal docs → Read content → Find tutorial examples → Read example code → Then create plan
36
+
37
+ ### Step 2: Check for Existing Components
38
+
39
+ After reviewing documentation:
40
+
41
+ 1. Search `@c8y/ngx-components` for existing implementations
42
+ 2. Use a matching Cumulocity component if one exists — **never build custom equivalents**
43
+ 3. Only proceed with custom solution if nothing suitable exists
44
+
45
+ ### Step 3: Plan or Implement
46
+
47
+ Only after completing Steps 1-2, proceed with planning or implementation.
48
+
49
+ ---
50
+
51
+ ## Universal Rules — TypeScript
52
+
53
+ - Target is ES2022; do not use syntax unavailable in ES2022
54
+ - Enable strict mode where possible; use explicit types or `unknown` with narrowing guards
55
+ - Avoid `any`; prefer explicit types
56
+ - Use path aliases for imports: `@c8y/ngx-components`, `@c8y/client`, `@c8y/devkit`, `@c8y/options`
57
+ - `experimentalDecorators: true` is set globally; Angular decorator syntax is valid as-is
58
+
59
+ ## Universal Rules — Cumulocity Platform
60
+
61
+ ### Other rules
62
+
63
+ - Use `@c8y/client` services for all Cumulocity REST calls — do **not** use `HttpClient` directly for platform endpoints
64
+ - Check `@c8y/ngx-components` before building custom UI components — it exports a large shared library. Search by visual functionality in [Codex](https://cumulocity.com/codex)
65
+ - Wrap every user-facing string with `C8yTranslatePipe` (`| translate`) or `TranslateService`:
66
+ - ✅ `{{ 'Save' | translate }}` ❌ `Save`
67
+
68
+ ## Angular Patterns
69
+
70
+ - All new components must be **standalone** (`standalone: true`) — do not create NgModule-based components
71
+ - Prefer `ChangeDetectionStrategy.OnPush` for new components (no project-wide enforcement, but scale demands it)
72
+ - Constructor injection and `inject()` function are both present; either is acceptable
73
+ - Manage subscriptions with `async` pipe or `takeUntilDestroyed()` — avoid bare `unsubscribe()` without `ngOnDestroy`
74
+ - Use signals for local component state
75
+ - Consider extracting child components when template exceeds ~150 lines or class exceeds ~200 lines
76
+
77
+ ## Code Quality (PR Review Focus)
78
+
79
+ - Remove `console.log` / `console.debug` before commit; `console.error` acceptable in caught exceptions
80
+ - Flag methods exceeding ~40 lines — consider decomposition
81
+ - Remove commented-out code; use git history for recovery
82
+ - New features should have `*.spec.ts` unit tests; new user flows should have Cypress coverage
83
+ - Document types, methods and properties that are not self-explanatory; don't explain ones that are obvious
84
+ - Test use cases that are truly worth testing, do not create test cases just for the sake of tests volume or coverate
85
+
86
+ ## Security Checks
87
+
88
+ - Flag hardcoded tenant IDs, device IDs, credentials, or API tokens — use `Cypress.env()` in tests, env config in production
89
+ - Review components rendering dynamic device/asset data for XSS: prefer `{{ }}` over `[innerHTML]` with unescaped values
90
+ - Treat IoT payload data as untrusted — validate and sanitize before display
91
+ - Do not expose internal hostnames or credentials in client-side code
92
+
93
+ ## What NOT to Flag
94
+
95
+ - **Import order** — managed by ESLint
96
+ - **Quote style / semicolons** — ESLint enforces single quotes and required semicolons
97
+ - **Trailing commas on function parameters** — ESLint explicitly disallows them
98
+ - **`skipLibCheck: true`** in tsconfig — intentional project setting
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: "Cypress E2E & Component Testing Guide"
3
+ description: "Instructions for Cypress end-to-end and component tests in Cumulocity applications"
4
+ applyTo: "**/*.cy.ts"
5
+ paths: ["**/*.cy.ts"]
6
+ ---
7
+
8
+ # Cypress Testing Guide
9
+
10
+ ## Test Types and Locations
11
+
12
+ - **E2E tests** — `cypress/e2e/` — run against a real or intercepted Cumulocity tenant
13
+ - **Component tests** — `cypress/component/` — mount Angular components in isolation via `cy.mount()`
14
+ - **Fixtures** — `cypress/fixtures/` — mocked BE responses for component tests
15
+ - **Support** — `cypress/support/` — custom commands (`cy.login()`, `cy.createDevice()`, etc.) and global configuration; auto-imported before every test
16
+ - **Snapshots** — `cypress/snapshots/` — baseline, actual, and diff images for visual regression tests (see Visual Testing)
17
+
18
+ ## E2E Tests
19
+
20
+ ### Authentication and navigation
21
+
22
+ ```typescript
23
+ beforeEach(() => {
24
+ cy.login(Cypress.env('username'), Cypress.env('password'));
25
+ });
26
+
27
+ cy.visit('/apps/cockpit/index.html#/group/123');
28
+ ```
29
+
30
+ Always use `Cypress.env('username')` / `Cypress.env('password')` — never hardcode credentials.
31
+
32
+ ### API interception
33
+
34
+ ```typescript
35
+ cy.intercept('GET', '/inventory/managedObjects/123', mockedObject).as('getMO');
36
+ cy.wait('@getMO');
37
+
38
+ // Query-parameter matching
39
+ cy.intercept(
40
+ { pathname: '/inventory/managedObjects', query: { pageSize: '5' } },
41
+ { managedObjects: [] }
42
+ );
43
+ ```
44
+
45
+ Use `cy.intercept()` to stub slow or unpredictable backend calls; never use fixed `cy.wait(number)`.
46
+
47
+ ### Creating and cleaning up test data
48
+
49
+ Use `cy.request()` for setup. Always clean up in `afterEach`:
50
+
51
+ ```typescript
52
+ afterEach(() => {
53
+ createdIds.forEach(id => {
54
+ cy.request({
55
+ url: `/inventory/managedObjects/${id}?cascade=true`,
56
+ method: 'DELETE',
57
+ failOnStatusCode: false
58
+ });
59
+ });
60
+ });
61
+ ```
62
+
63
+ Use `Cypress._.now()` to generate unique names: `e2eDevice${Cypress._.now()}`.
64
+
65
+ ## Component Tests
66
+
67
+ ### Mounting
68
+
69
+ ```typescript
70
+ cy.mount(MyComponent, {
71
+ imports: [CoreModule.forRoot(), CommonModule, ...],
72
+ providers: [
73
+ { provide: MyService, useValue: stubService }
74
+ ],
75
+ componentProperties: { myInput: value }
76
+ });
77
+ ```
78
+
79
+ All components should be standalone — import them directly, no NgModule wrapping needed.
80
+
81
+ ### Mocked backend with fixtures
82
+
83
+ Component tests that need BE responses can use recorded fixtures:
84
+
85
+ ```typescript
86
+ it('should load data', () => {
87
+ cy.intercept('GET', '/inventory/managedObjects/*', {
88
+ fixture: 'device.json'
89
+ }).as('getDevice');
90
+
91
+ cy.mount(MyComponent, { ... });
92
+ cy.wait('@getDevice');
93
+ cy.get('[data-cy="result"]').should('be.visible');
94
+ });
95
+ ```
96
+
97
+ Store fixture files in `cypress/fixtures/`.
98
+
99
+ ## Selectors
100
+
101
+ Prefer `data-cy` attributes, then role/title attributes. Avoid CSS class selectors unless the class is part of the component's public contract (e.g. icon class names from the design system).
102
+
103
+ Use consistent `data-cy` selectors with pattern: `<component-selector>--<element>-<details>`
104
+
105
+ - Double hyphens (`--`) separate component selector from element
106
+ - Single hyphens connect element type with descriptive details
107
+ - Don't hesitate to use longer names for precision
108
+
109
+ **Example:**
110
+ ```html
111
+ <!-- In component template -->
112
+ <button data-cy="c8y-custom-element-example--reset-button">Reset</button>
113
+ <button data-cy="c8y-custom-element-example--submit">Submit</button>
114
+ ```
115
+
116
+ **Usage:**
117
+ ```typescript
118
+ cy.get('[data-cy="c8y-custom-element-example--reset-button"]').click(); // preferred
119
+ cy.get('[title="Save"]').should('be.visible'); // acceptable for titled elements
120
+ cy.get('c8y-ui-empty-state').should('be.visible'); // OK for component element selectors
121
+ cy.get('.my-layout-class').should(...) // avoid unless class is stable/intentional
122
+ ```
123
+
124
+ ## Assertions
125
+
126
+ ```typescript
127
+ .should('be.visible')
128
+ .should('contain.text', 'expected')
129
+ .should('have.attr', 'href', '#/group/123')
130
+ .should('not.exist')
131
+ .should('be.disabled')
132
+ .should('be.enabled')
133
+ ```
134
+
135
+ Use `.should()` for all assertions (auto-retries). Avoid `.then()` for assertions.
136
+
137
+ ## Helper functions
138
+
139
+ Extract repeated selection and assertion logic into named helper functions at the top of the spec or in a describe-level scope:
140
+
141
+ ```typescript
142
+ function assertBreadcrumb(index: number, text: string) {
143
+ cy.get('[data-cy="breadcrumb-item"]').eq(index).should('contain.text', text);
144
+ }
145
+ ```
146
+
147
+ For component tests with multiple mounting configurations, create a named `mount*` function per variant.
148
+
149
+ ## Visual Testing
150
+
151
+ ```typescript
152
+ cy.compareSnapshot('my-identifier'); // strict
153
+ cy.compareSnapshot('my-identifier', 0.05); // with threshold
154
+ ```
155
+
156
+ Run component tests in the dev container for snapshot consistency with CI:
157
+
158
+ ```bash
159
+ yarn dc:up
160
+ yarn dc:run:spec "cypress/component/path/to/spec.cy.ts"
161
+ yarn dc:base:spec "cypress/component/path/to/spec.cy.ts" # regenerate baseline
162
+ ```
163
+
164
+ Snapshots: `cypress/snapshots/{base,actual,diff}/`
165
+
166
+ To regenerate baseline snapshots, use your project's snapshot regeneration command or manually replace files in `cypress/snapshots/base/`.
167
+
168
+ ## Running Tests
169
+
170
+ ```bash
171
+ # Open Cypress runner
172
+ npx cypress open --config baseUrl=https://<tenant>.cumulocity.com --env username=<u>,password=<p>
173
+
174
+ # Run headless
175
+ npx cypress run --config baseUrl=https://<tenant>.cumulocity.com --e2e --env username=<u>,password=<p> --browser chrome
176
+
177
+ # Filter by title substring (with cypress-grep plugin)
178
+ npx cypress run --env grep=breadcrumb
179
+ ```
180
+
181
+ ## What NOT to Do
182
+
183
+ - No `cy.wait(number)` — use `cy.wait('@alias')` or `.should()` retry
184
+ - No hardcoded tenant IDs, credentials, or device IDs — use `Cypress.env()` (except cases related to e.g. password changes; make sure to document these exceptions clearly in the code and not use credentials of real users)
185
+ - No `it.only` / `describe.only` / `context.only` committed to the repo
186
+ - Use `cy.visit()` for navigation; add custom wait utilities if needed
187
+ - Don't test trivial things just for coverage — test meaningful user-facing behavior