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