Skip to content

Commit ea03558

Browse files
chore(atomic): Improve functional component migration prompts (#6621)
1 parent 824fa93 commit ea03558

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

.github/agents/stencil-to-lit-migration-v1.agent.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,15 @@ When opening a PR for a functional component migration:
244244

245245
Before completing a functional component migration, verify:
246246

247+
**Test quality (consensus-based patterns):**
248+
- [ ] Icon properties tested using bracket notation (`iconElement?.['icon']`)
249+
- [ ] Only conditional CSS classes tested (static classes skipped)
250+
- [ ] Children content verified via text content (DOM checks optional)
251+
- [ ] `tw`/`multiClassMap` used only for conditional/dynamic classes
252+
- [ ] Interactive tests use Page API (`page.getByRole()`, not DOM API)
253+
- [ ] Edge cases focus on security and common scenarios (pragmatic scope)
254+
255+
**Migration equivalence:**
247256
- [ ] Functional component migrated to Lit with correct types
248257
- [ ] All imports use `@/*` path aliases (no `../` imports)
249258
- [ ] Original Stencil file renamed with `stencil-` prefix

.github/prompts/generate-vitest-test-atomic-lit-functional-component.prompt.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ it('should handle click', async () => {
9494

9595
### 5. Essential Coverage
9696

97-
Test: (1) Basic rendering, (2) All props/defaults, (3) User interactions, (4) Visual attributes (classes, ARIA), (5) Children if applicable, (6) Error conditions.
97+
Test: (1) Basic rendering, (2) All props/defaults, (3) User interactions, (4) Conditional visual attributes (CSS classes, ARIA), (5) Children if applicable, (6) Error conditions.
98+
99+
**Note:** Static CSS classes and attributes are covered by visual regression tests. Focus unit tests on conditional logic.
98100

99101
### 6. Key Patterns
100102

@@ -135,6 +137,25 @@ it('should render localized text', async () => {
135137
});
136138
```
137139

140+
**Icon properties:**
141+
When components accept icon props (from `@/src/components/common/icon/icon`), test using bracket notation:
142+
```typescript
143+
it('should render with correct icon', async () => {
144+
const element = await renderComponent({icon: ArrowUp});
145+
const iconElement = element.querySelector('atomic-icon');
146+
expect(iconElement?.['icon']).toBe(ArrowUp);
147+
});
148+
```
149+
150+
**Children content:**
151+
Verify children via text content. DOM structure verification is optional:
152+
```typescript
153+
it('should render children', async () => {
154+
const element = await renderComponent({}, html`<span>Child content</span>`);
155+
expect(element).toHaveTextContent('Child content'); // Sufficient
156+
});
157+
```
158+
138159
### 7. Run Tests
139160

140161
```bash
@@ -170,6 +191,38 @@ describe('when disabled', () => {
170191
});
171192
```
172193

194+
**Conditional CSS classes:**
195+
Test classes that change based on props/state. Skip static classes:
196+
```typescript
197+
// ✅ Test conditional classes
198+
it('should apply active class when selected', async () => {
199+
const element = await renderComponent({selected: true});
200+
expect(element.querySelector('button')).toHaveClass('bg-primary');
201+
});
202+
203+
it('should not apply active class when not selected', async () => {
204+
const element = await renderComponent({selected: false});
205+
expect(element.querySelector('button')).not.toHaveClass('bg-primary');
206+
});
207+
208+
// ❌ Skip static classes (covered by visual tests)
209+
it('should have rounded corners', async () => {
210+
const element = await renderComponent();
211+
expect(element.querySelector('button')).toHaveClass('rounded-lg'); // Unnecessary
212+
});
213+
```
214+
215+
**Avoid tw/multiClassMap in test helpers:**
216+
When creating test fixtures, use plain class strings. Reserve `tw`/`multiClassMap` for testing the component's conditional logic, not test setup:
217+
```typescript
218+
// ✅ Good - plain strings in tests
219+
const element = await renderComponent({class: 'test-class'});
220+
221+
// ❌ Avoid - unnecessary complexity in tests
222+
const classNames = tw({'test-class': true});
223+
const element = await renderComponent({class: multiClassMap(classNames)});
224+
```
225+
173226
## Post-Execution Summary
174227

175228
**Mandatory final todo:** Generate `.github/prompts/.executions/generate-vitest-test-atomic-lit-functional-component-[YYYY-MM-DD-HHmmss].prompt-execution.md` following `TEMPLATE.prompt-execution.md`.

.github/prompts/migrate-stencil-functional-component-to-lit.prompt.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,44 @@ html`<input ${props.ref ? ref(props.ref) : nothing} />`
8484

8585
## Tailwind Classes
8686

87-
**Use `tw` + `multiClassMap` for conditional classes:**
87+
**Use `tw` + `multiClassMap` only for conditional or dynamic classes.** For components with only static classes, use plain class strings.
88+
89+
**Conditional classes (use tw/multiClassMap):**
8890
```typescript
8991
import {multiClassMap, tw} from '@/src/directives/multi-class-map';
9092

9193
const classNames = tw({
92-
'rounded-lg border p-4': true,
9394
'border-primary bg-primary-50': props.isHighlighted,
9495
'border-neutral-dark bg-white': !props.isHighlighted,
95-
[props.class ?? '']: Boolean(props.class),
96+
[props.class ?? '']: Boolean(props.class), // Dynamic user classes
9697
});
9798

99+
return html`<div class="rounded-lg border p-4 ${multiClassMap(classNames)}">Content</div>`;
100+
```
101+
102+
**Static classes only (plain strings):**
103+
```typescript
104+
// ✅ Good - no conditional logic
105+
return html`<div class="flex items-center gap-2">Content</div>`;
106+
107+
// ❌ Avoid - unnecessary tw/multiClassMap
108+
const classNames = tw({'flex items-center gap-2': true});
98109
return html`<div class=${multiClassMap(classNames)}>Content</div>`;
99110
```
100111

112+
**Mixed static and conditional:**
113+
```typescript
114+
const dynamicClasses = tw({
115+
'bg-primary': props.isPrimary,
116+
'bg-secondary': !props.isPrimary,
117+
});
118+
119+
// Static classes in string, conditional via multiClassMap
120+
return html`<button class="px-4 py-2 rounded ${multiClassMap(dynamicClasses)}">
121+
${props.label}
122+
</button>`;
123+
```
124+
101125
## Naming Conventions
102126

103127
**Files:** Keep original Stencil file (`facet-placeholder.tsx`), create Lit version with `.ts` extension (`facet-placeholder.ts`). Both coexist; imports reference original until consumers migrate.

0 commit comments

Comments
 (0)