scc-universal 1.1.0

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 (271) hide show
  1. package/.claude-plugin/plugin.json +44 -0
  2. package/.cursor/agents/deep-researcher.md +142 -0
  3. package/.cursor/agents/doc-updater.md +219 -0
  4. package/.cursor/agents/eval-runner.md +335 -0
  5. package/.cursor/agents/learning-engine.md +210 -0
  6. package/.cursor/agents/loop-operator.md +245 -0
  7. package/.cursor/agents/refactor-cleaner.md +119 -0
  8. package/.cursor/agents/sf-admin-agent.md +127 -0
  9. package/.cursor/agents/sf-agentforce-agent.md +126 -0
  10. package/.cursor/agents/sf-apex-agent.md +117 -0
  11. package/.cursor/agents/sf-architect.md +426 -0
  12. package/.cursor/agents/sf-aura-reviewer.md +369 -0
  13. package/.cursor/agents/sf-bugfix-agent.md +101 -0
  14. package/.cursor/agents/sf-flow-agent.md +155 -0
  15. package/.cursor/agents/sf-integration-agent.md +141 -0
  16. package/.cursor/agents/sf-lwc-agent.md +123 -0
  17. package/.cursor/agents/sf-review-agent.md +357 -0
  18. package/.cursor/agents/sf-visualforce-reviewer.md +465 -0
  19. package/.cursor/hooks/adapter.js +81 -0
  20. package/.cursor/hooks/after-file-edit.js +26 -0
  21. package/.cursor/hooks/after-mcp-execution.js +12 -0
  22. package/.cursor/hooks/after-shell-execution.js +30 -0
  23. package/.cursor/hooks/after-tab-file-edit.js +12 -0
  24. package/.cursor/hooks/before-mcp-execution.js +11 -0
  25. package/.cursor/hooks/before-read-file.js +13 -0
  26. package/.cursor/hooks/before-shell-execution.js +29 -0
  27. package/.cursor/hooks/before-submit-prompt.js +23 -0
  28. package/.cursor/hooks/pre-compact.js +7 -0
  29. package/.cursor/hooks/session-end.js +10 -0
  30. package/.cursor/hooks/session-start.js +10 -0
  31. package/.cursor/hooks/stop.js +18 -0
  32. package/.cursor/hooks/subagent-start.js +10 -0
  33. package/.cursor/hooks/subagent-stop.js +10 -0
  34. package/.cursor/hooks.json +107 -0
  35. package/.cursor/skills/aside/SKILL.md +115 -0
  36. package/.cursor/skills/checkpoint/SKILL.md +50 -0
  37. package/.cursor/skills/configure-scc/SKILL.md +160 -0
  38. package/.cursor/skills/continuous-agent-loop/SKILL.md +260 -0
  39. package/.cursor/skills/mcp-server-patterns/SKILL.md +142 -0
  40. package/.cursor/skills/model-route/SKILL.md +81 -0
  41. package/.cursor/skills/prompt-optimizer/SKILL.md +366 -0
  42. package/.cursor/skills/refactor-clean/SKILL.md +133 -0
  43. package/.cursor/skills/resume-session/SKILL.md +111 -0
  44. package/.cursor/skills/save-session/SKILL.md +183 -0
  45. package/.cursor/skills/search-first/SKILL.md +140 -0
  46. package/.cursor/skills/security-scan/SKILL.md +142 -0
  47. package/.cursor/skills/sessions/SKILL.md +124 -0
  48. package/.cursor/skills/sf-agentforce-development/SKILL.md +449 -0
  49. package/.cursor/skills/sf-apex-async-patterns/SKILL.md +324 -0
  50. package/.cursor/skills/sf-apex-best-practices/SKILL.md +421 -0
  51. package/.cursor/skills/sf-apex-constraints/SKILL.md +79 -0
  52. package/.cursor/skills/sf-apex-cursor/SKILL.md +336 -0
  53. package/.cursor/skills/sf-apex-enterprise-patterns/SKILL.md +344 -0
  54. package/.cursor/skills/sf-apex-testing/SKILL.md +407 -0
  55. package/.cursor/skills/sf-api-design/SKILL.md +237 -0
  56. package/.cursor/skills/sf-approval-processes/SKILL.md +312 -0
  57. package/.cursor/skills/sf-aura-development/SKILL.md +260 -0
  58. package/.cursor/skills/sf-build-fix/SKILL.md +120 -0
  59. package/.cursor/skills/sf-data-modeling/SKILL.md +274 -0
  60. package/.cursor/skills/sf-debugging/SKILL.md +362 -0
  61. package/.cursor/skills/sf-deployment/SKILL.md +291 -0
  62. package/.cursor/skills/sf-deployment-constraints/SKILL.md +153 -0
  63. package/.cursor/skills/sf-devops-ci-cd/SKILL.md +322 -0
  64. package/.cursor/skills/sf-docs-lookup/SKILL.md +100 -0
  65. package/.cursor/skills/sf-e2e-testing/SKILL.md +321 -0
  66. package/.cursor/skills/sf-experience-cloud/SKILL.md +248 -0
  67. package/.cursor/skills/sf-flow-development/SKILL.md +376 -0
  68. package/.cursor/skills/sf-governor-limits/SKILL.md +319 -0
  69. package/.cursor/skills/sf-harness-audit/SKILL.md +139 -0
  70. package/.cursor/skills/sf-help/SKILL.md +156 -0
  71. package/.cursor/skills/sf-integration/SKILL.md +479 -0
  72. package/.cursor/skills/sf-lwc-constraints/SKILL.md +128 -0
  73. package/.cursor/skills/sf-lwc-development/SKILL.md +302 -0
  74. package/.cursor/skills/sf-lwc-testing/SKILL.md +387 -0
  75. package/.cursor/skills/sf-metadata-management/SKILL.md +285 -0
  76. package/.cursor/skills/sf-platform-events-cdc/SKILL.md +372 -0
  77. package/.cursor/skills/sf-quickstart/SKILL.md +170 -0
  78. package/.cursor/skills/sf-security/SKILL.md +330 -0
  79. package/.cursor/skills/sf-security-constraints/SKILL.md +125 -0
  80. package/.cursor/skills/sf-soql-constraints/SKILL.md +129 -0
  81. package/.cursor/skills/sf-soql-optimization/SKILL.md +353 -0
  82. package/.cursor/skills/sf-tdd-workflow/SKILL.md +332 -0
  83. package/.cursor/skills/sf-testing-constraints/SKILL.md +198 -0
  84. package/.cursor/skills/sf-trigger-constraints/SKILL.md +88 -0
  85. package/.cursor/skills/sf-trigger-frameworks/SKILL.md +343 -0
  86. package/.cursor/skills/sf-visualforce-development/SKILL.md +259 -0
  87. package/.cursor/skills/strategic-compact/SKILL.md +205 -0
  88. package/.cursor/skills/update-docs/SKILL.md +162 -0
  89. package/.cursor/skills/update-platform-docs/SKILL.md +86 -0
  90. package/.cursor-plugin/plugin.json +26 -0
  91. package/LICENSE +21 -0
  92. package/README.md +522 -0
  93. package/agents/deep-researcher.md +145 -0
  94. package/agents/doc-updater.md +222 -0
  95. package/agents/eval-runner.md +340 -0
  96. package/agents/learning-engine.md +211 -0
  97. package/agents/loop-operator.md +247 -0
  98. package/agents/refactor-cleaner.md +122 -0
  99. package/agents/sf-admin-agent.md +131 -0
  100. package/agents/sf-agentforce-agent.md +132 -0
  101. package/agents/sf-apex-agent.md +124 -0
  102. package/agents/sf-architect.md +435 -0
  103. package/agents/sf-aura-reviewer.md +372 -0
  104. package/agents/sf-bugfix-agent.md +105 -0
  105. package/agents/sf-flow-agent.md +159 -0
  106. package/agents/sf-integration-agent.md +146 -0
  107. package/agents/sf-lwc-agent.md +127 -0
  108. package/agents/sf-review-agent.md +366 -0
  109. package/agents/sf-visualforce-reviewer.md +468 -0
  110. package/assets/logo.svg +18 -0
  111. package/docs/ARCHITECTURE.md +133 -0
  112. package/docs/authoring-guide.md +373 -0
  113. package/docs/hook-development.md +578 -0
  114. package/docs/token-optimization.md +139 -0
  115. package/docs/workflow-examples.md +645 -0
  116. package/examples/agentforce-action/README.md +227 -0
  117. package/examples/apex-trigger-handler/README.md +114 -0
  118. package/examples/devops-pipeline/README.md +325 -0
  119. package/examples/flow-automation/README.md +188 -0
  120. package/examples/integration-pattern/README.md +416 -0
  121. package/examples/lwc-component/README.md +180 -0
  122. package/examples/platform-events/README.md +492 -0
  123. package/examples/scratch-org-setup/README.md +138 -0
  124. package/examples/security-audit/README.md +244 -0
  125. package/examples/visualforce-migration/README.md +314 -0
  126. package/hooks/hooks.json +338 -0
  127. package/hooks/memory-persistence/README.md +73 -0
  128. package/manifests/install-modules.json +217 -0
  129. package/manifests/install-profiles.json +17 -0
  130. package/mcp-configs/mcp-servers.json +19 -0
  131. package/package.json +89 -0
  132. package/schemas/hooks.schema.json +123 -0
  133. package/schemas/install-modules.schema.json +76 -0
  134. package/schemas/install-profiles.schema.json +28 -0
  135. package/schemas/install-state.schema.json +73 -0
  136. package/schemas/package-manager.schema.json +18 -0
  137. package/schemas/plugin.schema.json +112 -0
  138. package/schemas/scc-install-config.schema.json +29 -0
  139. package/schemas/state-store.schema.json +111 -0
  140. package/scripts/cli/install-apply.js +170 -0
  141. package/scripts/cli/uninstall.js +193 -0
  142. package/scripts/hooks/check-console-log.js +101 -0
  143. package/scripts/hooks/check-hook-enabled.js +17 -0
  144. package/scripts/hooks/check-platform-docs-age.js +48 -0
  145. package/scripts/hooks/cost-tracker.js +78 -0
  146. package/scripts/hooks/doc-file-warning.js +63 -0
  147. package/scripts/hooks/evaluate-session.js +98 -0
  148. package/scripts/hooks/governor-check.js +220 -0
  149. package/scripts/hooks/learning-observe.sh +206 -0
  150. package/scripts/hooks/mcp-health-check.js +588 -0
  151. package/scripts/hooks/post-bash-build-complete.js +34 -0
  152. package/scripts/hooks/post-bash-pr-created.js +43 -0
  153. package/scripts/hooks/post-edit-console-warn.js +61 -0
  154. package/scripts/hooks/post-edit-format.js +79 -0
  155. package/scripts/hooks/post-edit-typecheck.js +98 -0
  156. package/scripts/hooks/post-write.js +168 -0
  157. package/scripts/hooks/pre-bash-git-push-reminder.js +35 -0
  158. package/scripts/hooks/pre-bash-tmux-reminder.js +47 -0
  159. package/scripts/hooks/pre-compact.js +51 -0
  160. package/scripts/hooks/pre-tool-use.js +163 -0
  161. package/scripts/hooks/pre-write-doc-warn.js +9 -0
  162. package/scripts/hooks/quality-gate.js +251 -0
  163. package/scripts/hooks/run-with-flags-shell.sh +32 -0
  164. package/scripts/hooks/run-with-flags.js +135 -0
  165. package/scripts/hooks/session-end-marker.js +29 -0
  166. package/scripts/hooks/session-end.js +311 -0
  167. package/scripts/hooks/session-start.js +202 -0
  168. package/scripts/hooks/sfdx-scanner-check.js +142 -0
  169. package/scripts/hooks/sfdx-validate.js +119 -0
  170. package/scripts/hooks/stop-hook.js +170 -0
  171. package/scripts/hooks/suggest-compact.js +67 -0
  172. package/scripts/lib/agent-adapter.js +82 -0
  173. package/scripts/lib/apex-analysis.js +194 -0
  174. package/scripts/lib/hook-flags.js +74 -0
  175. package/scripts/lib/install-config.js +73 -0
  176. package/scripts/lib/install-executor.js +363 -0
  177. package/scripts/lib/install-state.js +121 -0
  178. package/scripts/lib/orchestration-session.js +299 -0
  179. package/scripts/lib/package-manager.js +124 -0
  180. package/scripts/lib/project-detect.js +228 -0
  181. package/scripts/lib/schema-validator.js +190 -0
  182. package/scripts/lib/skill-adapter.js +100 -0
  183. package/scripts/lib/state-store.js +376 -0
  184. package/scripts/lib/tmux-worktree-orchestrator.js +598 -0
  185. package/scripts/lib/utils.js +313 -0
  186. package/scripts/scc.js +164 -0
  187. package/skills/_reference/AGENTFORCE_PATTERNS.md +112 -0
  188. package/skills/_reference/APEX_CURSOR.md +159 -0
  189. package/skills/_reference/API_VERSIONS.md +78 -0
  190. package/skills/_reference/APPROVAL_PROCESSES.md +105 -0
  191. package/skills/_reference/ASYNC_PATTERNS.md +163 -0
  192. package/skills/_reference/AURA_COMPONENTS.md +146 -0
  193. package/skills/_reference/DATA_MIGRATION_PATTERNS.md +151 -0
  194. package/skills/_reference/DATA_MODELING.md +124 -0
  195. package/skills/_reference/DEBUGGING_TOOLS.md +140 -0
  196. package/skills/_reference/DEPLOYMENT_CHECKLIST.md +87 -0
  197. package/skills/_reference/DEPRECATIONS.md +79 -0
  198. package/skills/_reference/DOCKER_CI_PATTERNS.md +138 -0
  199. package/skills/_reference/ENTERPRISE_PATTERNS.md +122 -0
  200. package/skills/_reference/EXPERIENCE_CLOUD.md +143 -0
  201. package/skills/_reference/FLOW_PATTERNS.md +113 -0
  202. package/skills/_reference/GOVERNOR_LIMITS.md +77 -0
  203. package/skills/_reference/INTEGRATION_PATTERNS.md +105 -0
  204. package/skills/_reference/LWC_PATTERNS.md +79 -0
  205. package/skills/_reference/METADATA_TYPES.md +115 -0
  206. package/skills/_reference/NAMING_CONVENTIONS.md +84 -0
  207. package/skills/_reference/PACKAGE_DEVELOPMENT.md +150 -0
  208. package/skills/_reference/PLATFORM_EVENTS.md +121 -0
  209. package/skills/_reference/REPORTING_API.md +143 -0
  210. package/skills/_reference/SCRATCH_ORG_PATTERNS.md +126 -0
  211. package/skills/_reference/SECURITY_PATTERNS.md +127 -0
  212. package/skills/_reference/SHARING_MODEL.md +120 -0
  213. package/skills/_reference/SOQL_PATTERNS.md +119 -0
  214. package/skills/_reference/TESTING_STANDARDS.md +96 -0
  215. package/skills/_reference/TRIGGER_PATTERNS.md +114 -0
  216. package/skills/_reference/VISUALFORCE_PATTERNS.md +121 -0
  217. package/skills/aside/SKILL.md +118 -0
  218. package/skills/checkpoint/SKILL.md +53 -0
  219. package/skills/configure-scc/SKILL.md +163 -0
  220. package/skills/continuous-agent-loop/SKILL.md +264 -0
  221. package/skills/mcp-server-patterns/SKILL.md +146 -0
  222. package/skills/model-route/SKILL.md +84 -0
  223. package/skills/prompt-optimizer/SKILL.md +369 -0
  224. package/skills/refactor-clean/SKILL.md +136 -0
  225. package/skills/resume-session/SKILL.md +114 -0
  226. package/skills/save-session/SKILL.md +186 -0
  227. package/skills/search-first/SKILL.md +144 -0
  228. package/skills/security-scan/SKILL.md +146 -0
  229. package/skills/sessions/SKILL.md +127 -0
  230. package/skills/sf-agentforce-development/SKILL.md +450 -0
  231. package/skills/sf-apex-async-patterns/SKILL.md +326 -0
  232. package/skills/sf-apex-best-practices/SKILL.md +425 -0
  233. package/skills/sf-apex-constraints/SKILL.md +81 -0
  234. package/skills/sf-apex-cursor/SKILL.md +338 -0
  235. package/skills/sf-apex-enterprise-patterns/SKILL.md +348 -0
  236. package/skills/sf-apex-testing/SKILL.md +409 -0
  237. package/skills/sf-api-design/SKILL.md +238 -0
  238. package/skills/sf-approval-processes/SKILL.md +315 -0
  239. package/skills/sf-aura-development/SKILL.md +263 -0
  240. package/skills/sf-build-fix/SKILL.md +121 -0
  241. package/skills/sf-data-modeling/SKILL.md +278 -0
  242. package/skills/sf-debugging/SKILL.md +363 -0
  243. package/skills/sf-deployment/SKILL.md +295 -0
  244. package/skills/sf-deployment-constraints/SKILL.md +155 -0
  245. package/skills/sf-devops-ci-cd/SKILL.md +325 -0
  246. package/skills/sf-docs-lookup/SKILL.md +103 -0
  247. package/skills/sf-e2e-testing/SKILL.md +324 -0
  248. package/skills/sf-experience-cloud/SKILL.md +249 -0
  249. package/skills/sf-flow-development/SKILL.md +377 -0
  250. package/skills/sf-governor-limits/SKILL.md +323 -0
  251. package/skills/sf-harness-audit/SKILL.md +142 -0
  252. package/skills/sf-help/SKILL.md +159 -0
  253. package/skills/sf-integration/SKILL.md +483 -0
  254. package/skills/sf-lwc-constraints/SKILL.md +130 -0
  255. package/skills/sf-lwc-development/SKILL.md +303 -0
  256. package/skills/sf-lwc-testing/SKILL.md +388 -0
  257. package/skills/sf-metadata-management/SKILL.md +288 -0
  258. package/skills/sf-platform-events-cdc/SKILL.md +375 -0
  259. package/skills/sf-quickstart/SKILL.md +173 -0
  260. package/skills/sf-security/SKILL.md +334 -0
  261. package/skills/sf-security-constraints/SKILL.md +127 -0
  262. package/skills/sf-soql-constraints/SKILL.md +131 -0
  263. package/skills/sf-soql-optimization/SKILL.md +354 -0
  264. package/skills/sf-tdd-workflow/SKILL.md +336 -0
  265. package/skills/sf-testing-constraints/SKILL.md +200 -0
  266. package/skills/sf-trigger-constraints/SKILL.md +90 -0
  267. package/skills/sf-trigger-frameworks/SKILL.md +347 -0
  268. package/skills/sf-visualforce-development/SKILL.md +260 -0
  269. package/skills/strategic-compact/SKILL.md +208 -0
  270. package/skills/update-docs/SKILL.md +165 -0
  271. package/skills/update-platform-docs/SKILL.md +90 -0
@@ -0,0 +1,302 @@
1
+ ---
2
+ name: sf-lwc-development
3
+ description: >-
4
+ LWC development — components, reactive properties, wire service, Apex integration, events, lifecycle hooks. Use when building LWC components or debugging wire/reactivity. Do NOT use for Aura, Visualforce, or Flow.
5
+ ---
6
+
7
+ # LWC Development
8
+
9
+ Lightning Web Components (LWC) is Salesforce's modern component model based on web standards — Custom Elements, Shadow DOM, and ES modules.
10
+
11
+ ## When to Use
12
+
13
+ - When building new Lightning Web Components from scratch
14
+ - When migrating Aura components to LWC
15
+ - When debugging reactive property or wire service issues
16
+ - When implementing parent-child communication with events or @api
17
+ - When adding LWC components to record pages, app pages, or Experience Cloud sites
18
+
19
+ @../_reference/LWC_PATTERNS.md
20
+
21
+ ---
22
+
23
+ ## Component Creation Procedure
24
+
25
+ Every LWC component is a folder with at minimum an HTML template and a JavaScript class.
26
+
27
+ ```
28
+ force-app/main/default/lwc/
29
+ accountList/
30
+ accountList.html <- Template
31
+ accountList.js <- Component class
32
+ accountList.css <- Component-scoped styles (optional)
33
+ accountList.js-meta.xml <- Metadata (targets, properties)
34
+ ```
35
+
36
+ ### Step 1 — HTML Template
37
+
38
+ ```html
39
+ <template>
40
+ <lightning-card title="Accounts" icon-name="standard:account">
41
+ <template lwc:if={isLoading}>
42
+ <lightning-spinner alternative-text="Loading" size="small"></lightning-spinner>
43
+ </template>
44
+ <template lwc:elseif={hasError}>
45
+ <p class="slds-text-color_error">{errorMessage}</p>
46
+ </template>
47
+ <template lwc:else>
48
+ <template for:each={accounts} for:item="account">
49
+ <div key={account.Id} class="account-row">
50
+ <span>{account.Name}</span>
51
+ <lightning-button label="View" data-id={account.Id}
52
+ onclick={handleViewAccount}></lightning-button>
53
+ </div>
54
+ </template>
55
+ </template>
56
+ </lightning-card>
57
+ </template>
58
+ ```
59
+
60
+ ### Step 2 — JavaScript Class
61
+
62
+ ```javascript
63
+ import { LightningElement, api, wire } from 'lwc';
64
+ import { ShowToastEvent } from 'lightning/platformShowToastEvent';
65
+ import { NavigationMixin } from 'lightning/navigation';
66
+ import getAccounts from '@salesforce/apex/AccountsController.getAccounts';
67
+
68
+ export default class AccountList extends NavigationMixin(LightningElement) {
69
+ @api recordId;
70
+ @api maxRecords = 10;
71
+
72
+ accounts = [];
73
+ isLoading = false;
74
+ error;
75
+
76
+ get hasError() { return this.error !== undefined; }
77
+ get isEmpty() { return !this.isLoading && this.accounts.length === 0; }
78
+ get errorMessage() {
79
+ return this.error?.body?.message ?? this.error?.message ?? 'An unknown error occurred.';
80
+ }
81
+
82
+ connectedCallback() { this.loadAccounts(); }
83
+
84
+ handleViewAccount(event) {
85
+ this[NavigationMixin.Navigate]({
86
+ type: 'standard__recordPage',
87
+ attributes: { recordId: event.currentTarget.dataset.id,
88
+ objectApiName: 'Account', actionName: 'view' }
89
+ });
90
+ }
91
+
92
+ async loadAccounts() {
93
+ this.isLoading = true;
94
+ this.error = undefined;
95
+ try {
96
+ this.accounts = await getAccounts({
97
+ searchTerm: this.searchTerm, maxRecords: this.maxRecords
98
+ });
99
+ } catch (error) {
100
+ this.error = error;
101
+ } finally {
102
+ this.isLoading = false;
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### Step 3 — Meta XML
109
+
110
+ ```xml
111
+ <?xml version="1.0" encoding="UTF-8"?>
112
+ <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
113
+ <apiVersion>66.0</apiVersion>
114
+ <isExposed>true</isExposed>
115
+ <targets>
116
+ <target>lightning__RecordPage</target>
117
+ <target>lightning__AppPage</target>
118
+ <target>lightning__HomePage</target>
119
+ </targets>
120
+ <targetConfigs>
121
+ <targetConfig targets="lightning__RecordPage">
122
+ <property name="maxRecords" type="Integer" default="10"
123
+ label="Maximum Records to Display" />
124
+ </targetConfig>
125
+ </targetConfigs>
126
+ </LightningComponentBundle>
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Wire Service Usage
132
+
133
+ The wire service declaratively connects components to Salesforce data and re-runs when reactive parameters change.
134
+
135
+ ### Wire with Apex
136
+
137
+ ```javascript
138
+ import { LightningElement, wire, api } from 'lwc';
139
+ import { refreshApex } from '@salesforce/apex';
140
+ import getAccountDetails from '@salesforce/apex/AccountsController.getAccountDetails';
141
+
142
+ export default class AccountDetails extends LightningElement {
143
+ @api recordId;
144
+ _wiredResult;
145
+
146
+ @wire(getAccountDetails, { accountId: '$recordId' })
147
+ wiredAccount(result) {
148
+ this._wiredResult = result;
149
+ if (result.data) {
150
+ this.account = result.data;
151
+ this.error = undefined;
152
+ } else if (result.error) {
153
+ this.error = result.error;
154
+ this.account = undefined;
155
+ }
156
+ }
157
+
158
+ async handleSave(event) {
159
+ await updateAccount({ accountId: this.recordId, fields: event.detail.fields });
160
+ await refreshApex(this._wiredResult);
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Wire with Lightning Data Service
166
+
167
+ ```javascript
168
+ import { LightningElement, api, wire } from 'lwc';
169
+ import { getRecord, getFieldValue, updateRecord } from 'lightning/uiRecordApi';
170
+ import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
171
+ import ACCOUNT_INDUSTRY from '@salesforce/schema/Account.Industry';
172
+
173
+ export default class AccountHeader extends LightningElement {
174
+ @api recordId;
175
+
176
+ @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME, ACCOUNT_INDUSTRY] })
177
+ account;
178
+
179
+ get name() { return getFieldValue(this.account.data, ACCOUNT_NAME); }
180
+ get industry() { return getFieldValue(this.account.data, ACCOUNT_INDUSTRY); }
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Event Handling — Component Communication
187
+
188
+ ### Child to Parent: Custom Events
189
+
190
+ ```javascript
191
+ // child: opportunityCard.js
192
+ handleSelect() {
193
+ this.dispatchEvent(new CustomEvent('opportunityselect', {
194
+ detail: { opportunityId: this.opportunity.Id },
195
+ bubbles: false, composed: false
196
+ }));
197
+ }
198
+ ```
199
+
200
+ ```html
201
+ <!-- parent template -->
202
+ <c-opportunity-card opportunity={opp}
203
+ onopportunityselect={handleOpportunitySelect}></c-opportunity-card>
204
+ ```
205
+
206
+ ### Cross-Component: Lightning Message Service
207
+
208
+ ```javascript
209
+ import { publish, subscribe, unsubscribe, MessageContext, APPLICATION_SCOPE }
210
+ from 'lightning/messageService';
211
+ import CHANNEL from '@salesforce/messageChannel/OpportunitySelected__c';
212
+
213
+ // Publisher
214
+ @wire(MessageContext) messageContext;
215
+ handleSelect(event) {
216
+ publish(this.messageContext, CHANNEL, { opportunityId: event.target.dataset.id });
217
+ }
218
+
219
+ // Subscriber
220
+ connectedCallback() {
221
+ this.subscription = subscribe(this.messageContext, CHANNEL,
222
+ (msg) => this.handleMessage(msg), { scope: APPLICATION_SCOPE });
223
+ }
224
+ disconnectedCallback() { unsubscribe(this.subscription); }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Slots — Composition Patterns
230
+
231
+ ```html
232
+ <!-- child: modalWrapper.html -->
233
+ <template>
234
+ <div class="modal-header"><slot name="header"><h2>Default Header</h2></slot></div>
235
+ <div class="modal-body"><slot></slot></div>
236
+ <div class="modal-footer"><slot name="footer"></slot></div>
237
+ </template>
238
+
239
+ <!-- parent usage -->
240
+ <c-modal-wrapper>
241
+ <span slot="header">Edit Account</span>
242
+ <lightning-record-edit-form record-id={recordId} object-api-name="Account">
243
+ <lightning-input-field field-name="Name"></lightning-input-field>
244
+ </lightning-record-edit-form>
245
+ <div slot="footer">
246
+ <lightning-button label="Save" variant="brand" onclick={handleSave}></lightning-button>
247
+ </div>
248
+ </c-modal-wrapper>
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Light DOM
254
+
255
+ Renders component markup directly into the parent DOM (no shadow boundary).
256
+
257
+ ```javascript
258
+ export default class ThemedComponent extends LightningElement {
259
+ static renderMode = 'light';
260
+ }
261
+ ```
262
+
263
+ Use for: global CSS theming, third-party library integration, Experience Cloud sites, simple leaf components. Query with `this.querySelector()` instead of `this.template.querySelector()`.
264
+
265
+ ---
266
+
267
+ ## Spring '26 Features
268
+
269
+ ### SLDS 2.0
270
+
271
+ Use `--slds-c-*` styling hooks (replaces `--lwc-*` design tokens). Run `npx slds-lint` to check compliance.
272
+
273
+ ### TypeScript Support
274
+
275
+ ```bash
276
+ npm install --save-dev @salesforce/lightning-types
277
+ ```
278
+
279
+ ### Complex Template Expressions (Beta)
280
+
281
+ ```html
282
+ <p>{account.Name ?? 'Unknown Account'}</p>
283
+ <p>{formatRevenue(account.AnnualRevenue)}</p>
284
+ ```
285
+
286
+ Use getters for production code until this reaches GA.
287
+
288
+ ### LWC in Screen Flows
289
+
290
+ Expose components as Flow screen actions via `lightning__FlowScreen` target. Implement `@api validate()` for Flow navigation validation.
291
+
292
+ ---
293
+
294
+ ## Related
295
+
296
+ ### Guardrails
297
+
298
+ - **sf-lwc-constraints** — Enforced rules for LWC naming, reactivity, security, and accessibility
299
+
300
+ ### Agents
301
+
302
+ - **sf-lwc-agent** — For interactive, in-depth LWC review guidance
@@ -0,0 +1,387 @@
1
+ ---
2
+ name: sf-lwc-testing
3
+ description: >-
4
+ LWC Jest testing — component mounting, wire/Apex mocking, user interaction simulation, toast/navigation verification. Use when writing or debugging LWC Jest tests. Do NOT use for Apex or Flow testing.
5
+ ---
6
+
7
+ # LWC Testing with Jest
8
+
9
+ LWC uses Jest as its test runner. Salesforce provides `@salesforce/sfdx-lwc-jest` to handle Salesforce-specific imports. Tests run in Node.js — no browser, no Salesforce org.
10
+
11
+ ## When to Use
12
+
13
+ - When writing Jest unit tests for Lightning Web Components
14
+ - When mocking Wire adapters, Apex imperative calls, or navigation in LWC tests
15
+ - When debugging flaky or async LWC tests
16
+ - When setting up LWC test infrastructure for a new project
17
+
18
+ @../_reference/LWC_PATTERNS.md
19
+ @../_reference/TESTING_STANDARDS.md
20
+
21
+ ---
22
+
23
+ ## Setup Procedure
24
+
25
+ ### Step 1 — Install
26
+
27
+ ```bash
28
+ npm install --save-dev @salesforce/sfdx-lwc-jest
29
+ ```
30
+
31
+ ### Step 2 — jest.config.js
32
+
33
+ ```javascript
34
+ const { jestConfig } = require('@salesforce/sfdx-lwc-jest/config');
35
+ module.exports = {
36
+ ...jestConfig,
37
+ modulePathIgnorePatterns: ['<rootDir>/.localdevserver'],
38
+ testEnvironment: 'jsdom',
39
+ testMatch: ['**/__tests__/**/*.test.js'],
40
+ setupFiles: ['<rootDir>/jest.setup.js']
41
+ };
42
+ ```
43
+
44
+ ### Step 3 — jest.setup.js
45
+
46
+ ```javascript
47
+ global.ResizeObserver = jest.fn().mockImplementation(() => ({
48
+ observe: jest.fn(), unobserve: jest.fn(), disconnect: jest.fn()
49
+ }));
50
+ ```
51
+
52
+ ### Step 4 — Test File Location
53
+
54
+ ```
55
+ lwc/accountSearch/
56
+ accountSearch.html
57
+ accountSearch.js
58
+ __tests__/
59
+ accountSearch.test.js
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Basic Component Rendering
65
+
66
+ ```javascript
67
+ import { createElement } from 'lwc';
68
+ import AccountSearch from 'c/accountSearch';
69
+
70
+ describe('c-account-search', () => {
71
+ afterEach(() => {
72
+ while (document.body.firstChild) {
73
+ document.body.removeChild(document.body.firstChild);
74
+ }
75
+ jest.clearAllMocks();
76
+ });
77
+
78
+ it('renders the search input', () => {
79
+ const element = createElement('c-account-search', { is: AccountSearch });
80
+ document.body.appendChild(element);
81
+
82
+ const input = element.shadowRoot.querySelector('lightning-input[type="search"]');
83
+ expect(input).not.toBeNull();
84
+ expect(input.label).toBe('Search Accounts');
85
+ });
86
+
87
+ it('renders with public @api property', () => {
88
+ const element = createElement('c-account-search', { is: AccountSearch });
89
+ element.maxRecords = 25;
90
+ document.body.appendChild(element);
91
+ expect(element.maxRecords).toBe(25);
92
+ });
93
+ });
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Wire Adapter Mocking (Modern Pattern)
99
+
100
+ Use `jest.mock()` with the wire adapter directly. The deprecated `registerApexTestWireAdapter` pattern should not be used in new projects.
101
+
102
+ ```javascript
103
+ import { createElement } from 'lwc';
104
+ import AccountDetails from 'c/accountDetails';
105
+ import getAccountDetails from '@salesforce/apex/AccountsController.getAccountDetails';
106
+
107
+ jest.mock(
108
+ '@salesforce/apex/AccountsController.getAccountDetails',
109
+ () => ({ default: jest.fn() }),
110
+ { virtual: true }
111
+ );
112
+
113
+ describe('c-account-details wire', () => {
114
+ afterEach(() => {
115
+ while (document.body.firstChild) {
116
+ document.body.removeChild(document.body.firstChild);
117
+ }
118
+ jest.clearAllMocks();
119
+ });
120
+
121
+ it('displays account name when wire returns data', async () => {
122
+ getAccountDetails.mockResolvedValue({
123
+ Id: '001000000000001AAA', Name: 'Acme Corporation'
124
+ });
125
+ const element = createElement('c-account-details', { is: AccountDetails });
126
+ element.recordId = '001000000000001AAA';
127
+ document.body.appendChild(element);
128
+
129
+ await Promise.resolve();
130
+ await Promise.resolve();
131
+
132
+ expect(element.shadowRoot.querySelector('.account-name').textContent)
133
+ .toBe('Acme Corporation');
134
+ });
135
+
136
+ it('displays error state when wire returns error', async () => {
137
+ getAccountDetails.mockRejectedValue({
138
+ body: { message: 'Record not found' }, status: 404
139
+ });
140
+ const element = createElement('c-account-details', { is: AccountDetails });
141
+ element.recordId = '001000000000001AAA';
142
+ document.body.appendChild(element);
143
+
144
+ await Promise.resolve();
145
+ await Promise.resolve();
146
+
147
+ expect(element.shadowRoot.querySelector('.error-container')).not.toBeNull();
148
+ });
149
+ });
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Apex Imperative Call Mocking
155
+
156
+ ```javascript
157
+ jest.mock(
158
+ '@salesforce/apex/AccountSearchController.searchAccounts',
159
+ () => jest.fn(), // imperative: module IS the function
160
+ { virtual: true }
161
+ );
162
+
163
+ import searchAccounts from '@salesforce/apex/AccountSearchController.searchAccounts';
164
+
165
+ it('calls Apex on search and displays results', async () => {
166
+ searchAccounts.mockResolvedValue([
167
+ { Id: '001000000000001AAA', Name: 'Acme Corp' }
168
+ ]);
169
+ const element = createElement('c-account-search', { is: AccountSearch });
170
+ document.body.appendChild(element);
171
+
172
+ // Trigger search
173
+ const input = element.shadowRoot.querySelector('lightning-input');
174
+ input.dispatchEvent(new CustomEvent('change', { detail: { value: 'Acme' } }));
175
+ element.shadowRoot.querySelector('lightning-button[label="Search"]').click();
176
+
177
+ await flushPromises();
178
+
179
+ expect(searchAccounts).toHaveBeenCalledWith({ searchTerm: 'Acme' });
180
+ const rows = element.shadowRoot.querySelectorAll('.account-row');
181
+ expect(rows).toHaveLength(1);
182
+ });
183
+ ```
184
+
185
+ Key distinction: for imperative Apex, mock as `() => jest.fn()`. For wired Apex, mock as `() => ({ default: jest.fn() })`.
186
+
187
+ ---
188
+
189
+ ## Async Testing — flushPromises
190
+
191
+ LWC re-renders are asynchronous. Use `flushPromises` instead of chaining multiple `Promise.resolve()` calls.
192
+
193
+ ```javascript
194
+ function flushPromises() {
195
+ return new Promise(resolve => setTimeout(resolve, 0));
196
+ }
197
+ ```
198
+
199
+ ---
200
+
201
+ ## User Interaction Simulation
202
+
203
+ ### Click Events and Custom Event Assertions
204
+
205
+ ```javascript
206
+ it('dispatches select event when button clicked', () => {
207
+ const element = createElement('c-account-card', { is: AccountCard });
208
+ element.account = { Id: '001000000000001AAA', Name: 'Test Corp' };
209
+ document.body.appendChild(element);
210
+
211
+ const handler = jest.fn();
212
+ element.addEventListener('accountselect', handler);
213
+
214
+ element.shadowRoot.querySelector('[data-id="view-btn"]').click();
215
+
216
+ expect(handler).toHaveBeenCalledTimes(1);
217
+ expect(handler.mock.calls[0][0].detail).toEqual({
218
+ accountId: '001000000000001AAA', accountName: 'Test Corp'
219
+ });
220
+ });
221
+ ```
222
+
223
+ ### Input Value Changes
224
+
225
+ ```javascript
226
+ const input = element.shadowRoot.querySelector('lightning-input[type="search"]');
227
+ input.dispatchEvent(new CustomEvent('change', { detail: { value: 'Acme' } }));
228
+ await Promise.resolve();
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Toast Notification Testing
234
+
235
+ ```javascript
236
+ import { ShowToastEventName } from 'lightning/platformShowToastEvent';
237
+
238
+ it('shows success toast after save', async () => {
239
+ const toastHandler = jest.fn();
240
+ element.addEventListener(ShowToastEventName, toastHandler);
241
+
242
+ element.shadowRoot.querySelector('[data-id="save-btn"]').click();
243
+ await flushPromises();
244
+
245
+ expect(toastHandler).toHaveBeenCalledTimes(1);
246
+ expect(toastHandler.mock.calls[0][0].detail.variant).toBe('success');
247
+ });
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Navigation Mocking
253
+
254
+ ```javascript
255
+ it('navigates to record page on view', () => {
256
+ const { navigate } = require('lightning/navigation');
257
+ const element = createElement('c-account-card', { is: AccountCard });
258
+ element.account = { Id: '001000000000001AAA' };
259
+ document.body.appendChild(element);
260
+
261
+ element.shadowRoot.querySelector('[data-id="view"]').click();
262
+
263
+ expect(navigate).toHaveBeenCalledWith(
264
+ expect.objectContaining({
265
+ type: 'standard__recordPage',
266
+ attributes: expect.objectContaining({ recordId: '001000000000001AAA' })
267
+ })
268
+ );
269
+ });
270
+ ```
271
+
272
+ ---
273
+
274
+ ## What to Test vs What Not to Test
275
+
276
+ ### Test These
277
+
278
+ - Business logic in computed properties and event handlers
279
+ - Correct Apex method called with correct arguments
280
+ - Component response to wire data and errors
281
+ - User interactions and their effects on component state
282
+ - Edge cases: empty arrays, null values, error states
283
+
284
+ ### Do Not Test These
285
+
286
+ - LWC framework behavior (that `for:each` renders items)
287
+ - Base component rendering (that `lightning-button` shows text)
288
+ - CSS styling or implementation details (internal variable names)
289
+
290
+ ---
291
+
292
+ ## Spring '26: Local Component Testing
293
+
294
+ Test LWC components in isolation without deploying to a scratch org.
295
+
296
+ ```bash
297
+ npm install --save-dev @lwc/jest-preset
298
+ npx lwc-jest --watchAll=false
299
+ ```
300
+
301
+ ---
302
+
303
+ ## TypeScript LWC Testing (Spring '26 Experimental)
304
+
305
+ Spring '26 introduces experimental TypeScript support for LWC. Test `.ts` component files with these adjustments.
306
+
307
+ ### Jest Configuration
308
+
309
+ ```javascript
310
+ // jest.config.js — add ts transform
311
+ const { jestConfig } = require('@salesforce/sfdx-lwc-jest/config');
312
+ module.exports = {
313
+ ...jestConfig,
314
+ transform: {
315
+ ...jestConfig.transform,
316
+ '^.+\\.ts$': ['@swc/jest'] // or 'ts-jest'
317
+ },
318
+ moduleFileExtensions: ['ts', 'js', 'html'],
319
+ testMatch: ['**/__tests__/**/*.test.(js|ts)']
320
+ };
321
+ ```
322
+
323
+ Install: `npm install --save-dev @swc/jest @swc/core` (faster) or `npm install --save-dev ts-jest typescript`.
324
+
325
+ ### Typed Wire Adapter Mocking
326
+
327
+ ```typescript
328
+ import { createElement } from 'lwc';
329
+ import AccountList from 'c/accountList';
330
+ import getAccounts from '@salesforce/apex/AccountController.getAccounts';
331
+
332
+ jest.mock('@salesforce/apex/AccountController.getAccounts',
333
+ () => ({ default: jest.fn() }), { virtual: true });
334
+
335
+ const mockGetAccounts = getAccounts as jest.MockedFunction<typeof getAccounts>;
336
+
337
+ describe('c-account-list (TypeScript)', () => {
338
+ afterEach(() => {
339
+ while (document.body.firstChild) document.body.removeChild(document.body.firstChild);
340
+ jest.clearAllMocks();
341
+ });
342
+
343
+ it('renders typed account data', async () => {
344
+ mockGetAccounts.mockResolvedValue([
345
+ { Id: '001xx0001', Name: 'Typed Corp', Industry: 'Technology' }
346
+ ]);
347
+ const element = createElement('c-account-list', { is: AccountList });
348
+ document.body.appendChild(element);
349
+
350
+ await Promise.resolve();
351
+ await Promise.resolve();
352
+
353
+ const rows = element.shadowRoot.querySelectorAll('.account-row');
354
+ expect(rows).toHaveLength(1);
355
+ });
356
+ });
357
+ ```
358
+
359
+ ### Typed Event Detail Assertions
360
+
361
+ ```typescript
362
+ it('dispatches typed custom event', () => {
363
+ const element = createElement('c-account-card', { is: AccountCard });
364
+ document.body.appendChild(element);
365
+
366
+ const handler = jest.fn();
367
+ element.addEventListener('select', handler);
368
+ element.shadowRoot.querySelector('[data-id="select-btn"]').click();
369
+
370
+ const detail = handler.mock.calls[0][0].detail as { accountId: string };
371
+ expect(detail.accountId).toBeDefined();
372
+ });
373
+ ```
374
+
375
+ > **Note:** TypeScript LWC support is experimental in Spring '26. Type definitions and tooling may change in future releases. Pin `@salesforce/sfdx-lwc-jest` to a known-good version.
376
+
377
+ ---
378
+
379
+ ## Related
380
+
381
+ ### Guardrails
382
+
383
+ - **sf-testing-constraints** — Enforced rules for test coverage, assertions, and test data patterns
384
+
385
+ ### Agents
386
+
387
+ - **sf-lwc-agent** — For interactive, in-depth LWC review guidance