lwc-convert 1.0.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.
- package/LICENSE +21 -0
- package/README.md +719 -0
- package/dist/cli/commands/aura.d.ts +6 -0
- package/dist/cli/commands/aura.d.ts.map +1 -0
- package/dist/cli/commands/aura.js +225 -0
- package/dist/cli/commands/aura.js.map +1 -0
- package/dist/cli/commands/vf.d.ts +6 -0
- package/dist/cli/commands/vf.d.ts.map +1 -0
- package/dist/cli/commands/vf.js +218 -0
- package/dist/cli/commands/vf.js.map +1 -0
- package/dist/cli/interactive.d.ts +20 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +577 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/options.d.ts +21 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +24 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/generators/full-conversion.d.ts +41 -0
- package/dist/generators/full-conversion.d.ts.map +1 -0
- package/dist/generators/full-conversion.js +538 -0
- package/dist/generators/full-conversion.js.map +1 -0
- package/dist/generators/scaffolding.d.ts +40 -0
- package/dist/generators/scaffolding.d.ts.map +1 -0
- package/dist/generators/scaffolding.js +716 -0
- package/dist/generators/scaffolding.js.map +1 -0
- package/dist/generators/test-comparison.d.ts +47 -0
- package/dist/generators/test-comparison.d.ts.map +1 -0
- package/dist/generators/test-comparison.js +855 -0
- package/dist/generators/test-comparison.js.map +1 -0
- package/dist/generators/test-generator.d.ts +27 -0
- package/dist/generators/test-generator.d.ts.map +1 -0
- package/dist/generators/test-generator.js +385 -0
- package/dist/generators/test-generator.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +226 -0
- package/dist/index.js.map +1 -0
- package/dist/mappings/aura-to-lwc.json +321 -0
- package/dist/mappings/vf-to-lwc.json +354 -0
- package/dist/parsers/aura/controller-parser.d.ts +36 -0
- package/dist/parsers/aura/controller-parser.d.ts.map +1 -0
- package/dist/parsers/aura/controller-parser.js +269 -0
- package/dist/parsers/aura/controller-parser.js.map +1 -0
- package/dist/parsers/aura/helper-parser.d.ts +21 -0
- package/dist/parsers/aura/helper-parser.d.ts.map +1 -0
- package/dist/parsers/aura/helper-parser.js +173 -0
- package/dist/parsers/aura/helper-parser.js.map +1 -0
- package/dist/parsers/aura/markup-parser.d.ts +59 -0
- package/dist/parsers/aura/markup-parser.d.ts.map +1 -0
- package/dist/parsers/aura/markup-parser.js +279 -0
- package/dist/parsers/aura/markup-parser.js.map +1 -0
- package/dist/parsers/aura/style-parser.d.ts +37 -0
- package/dist/parsers/aura/style-parser.d.ts.map +1 -0
- package/dist/parsers/aura/style-parser.js +151 -0
- package/dist/parsers/aura/style-parser.js.map +1 -0
- package/dist/parsers/vf/apex-parser.d.ts +51 -0
- package/dist/parsers/vf/apex-parser.d.ts.map +1 -0
- package/dist/parsers/vf/apex-parser.js +251 -0
- package/dist/parsers/vf/apex-parser.js.map +1 -0
- package/dist/parsers/vf/page-parser.d.ts +61 -0
- package/dist/parsers/vf/page-parser.d.ts.map +1 -0
- package/dist/parsers/vf/page-parser.js +403 -0
- package/dist/parsers/vf/page-parser.js.map +1 -0
- package/dist/transformers/aura-to-lwc/controller.d.ts +36 -0
- package/dist/transformers/aura-to-lwc/controller.d.ts.map +1 -0
- package/dist/transformers/aura-to-lwc/controller.js +372 -0
- package/dist/transformers/aura-to-lwc/controller.js.map +1 -0
- package/dist/transformers/aura-to-lwc/events.d.ts +47 -0
- package/dist/transformers/aura-to-lwc/events.d.ts.map +1 -0
- package/dist/transformers/aura-to-lwc/events.js +262 -0
- package/dist/transformers/aura-to-lwc/events.js.map +1 -0
- package/dist/transformers/aura-to-lwc/markup.d.ts +51 -0
- package/dist/transformers/aura-to-lwc/markup.d.ts.map +1 -0
- package/dist/transformers/aura-to-lwc/markup.js +465 -0
- package/dist/transformers/aura-to-lwc/markup.js.map +1 -0
- package/dist/transformers/vf-to-lwc/components.d.ts +40 -0
- package/dist/transformers/vf-to-lwc/components.d.ts.map +1 -0
- package/dist/transformers/vf-to-lwc/components.js +374 -0
- package/dist/transformers/vf-to-lwc/components.js.map +1 -0
- package/dist/transformers/vf-to-lwc/data-binding.d.ts +53 -0
- package/dist/transformers/vf-to-lwc/data-binding.d.ts.map +1 -0
- package/dist/transformers/vf-to-lwc/data-binding.js +660 -0
- package/dist/transformers/vf-to-lwc/data-binding.js.map +1 -0
- package/dist/transformers/vf-to-lwc/markup.d.ts +44 -0
- package/dist/transformers/vf-to-lwc/markup.d.ts.map +1 -0
- package/dist/transformers/vf-to-lwc/markup.js +816 -0
- package/dist/transformers/vf-to-lwc/markup.js.map +1 -0
- package/dist/utils/confidence-scorer.d.ts +100 -0
- package/dist/utils/confidence-scorer.d.ts.map +1 -0
- package/dist/utils/confidence-scorer.js +358 -0
- package/dist/utils/confidence-scorer.js.map +1 -0
- package/dist/utils/file-io.d.ts +62 -0
- package/dist/utils/file-io.d.ts.map +1 -0
- package/dist/utils/file-io.js +248 -0
- package/dist/utils/file-io.js.map +1 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +130 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/open-folder.d.ts +9 -0
- package/dist/utils/open-folder.d.ts.map +1 -0
- package/dist/utils/open-folder.js +76 -0
- package/dist/utils/open-folder.js.map +1 -0
- package/dist/utils/path-resolver.d.ts +29 -0
- package/dist/utils/path-resolver.d.ts.map +1 -0
- package/dist/utils/path-resolver.js +240 -0
- package/dist/utils/path-resolver.js.map +1 -0
- package/dist/utils/session-store.d.ts +158 -0
- package/dist/utils/session-store.d.ts.map +1 -0
- package/dist/utils/session-store.js +518 -0
- package/dist/utils/session-store.js.map +1 -0
- package/dist/utils/vf-controller-resolver.d.ts +36 -0
- package/dist/utils/vf-controller-resolver.d.ts.map +1 -0
- package/dist/utils/vf-controller-resolver.js +162 -0
- package/dist/utils/vf-controller-resolver.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Test Comparison Generator
|
|
4
|
+
* Creates before/after tests for conversion verification
|
|
5
|
+
*
|
|
6
|
+
* Before Tests: Document the expected behaviors of the original Aura component
|
|
7
|
+
* After Tests: Verify the converted LWC preserves those behaviors
|
|
8
|
+
* Comparison: Run both and compare outputs
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.generateTestComparison = generateTestComparison;
|
|
12
|
+
const file_io_1 = require("../utils/file-io");
|
|
13
|
+
/**
|
|
14
|
+
* Extract behaviors from Aura component and generate comparison tests
|
|
15
|
+
*/
|
|
16
|
+
function generateTestComparison(markup, transformedMarkup, controller, helper) {
|
|
17
|
+
const lwcName = (0, file_io_1.toLwcName)(markup.componentName);
|
|
18
|
+
const className = (0, file_io_1.toPascalCase)(markup.componentName);
|
|
19
|
+
const behaviorTests = [];
|
|
20
|
+
let testId = 1;
|
|
21
|
+
// 1. Lifecycle behaviors
|
|
22
|
+
const lifecycleTests = extractLifecycleBehaviors(markup, controller, helper, testId);
|
|
23
|
+
behaviorTests.push(...lifecycleTests);
|
|
24
|
+
testId += lifecycleTests.length;
|
|
25
|
+
// 2. Data binding behaviors
|
|
26
|
+
const dataTests = extractDataBindingBehaviors(markup, transformedMarkup, controller, testId);
|
|
27
|
+
behaviorTests.push(...dataTests);
|
|
28
|
+
testId += dataTests.length;
|
|
29
|
+
// 3. Event handling behaviors
|
|
30
|
+
const eventTests = extractEventBehaviors(markup, controller, helper, testId);
|
|
31
|
+
behaviorTests.push(...eventTests);
|
|
32
|
+
testId += eventTests.length;
|
|
33
|
+
// 4. UI rendering behaviors
|
|
34
|
+
const uiTests = extractUIBehaviors(markup, transformedMarkup, testId);
|
|
35
|
+
behaviorTests.push(...uiTests);
|
|
36
|
+
testId += uiTests.length;
|
|
37
|
+
// 5. LMS behaviors
|
|
38
|
+
const lmsTests = extractLMSBehaviors(transformedMarkup, controller, testId);
|
|
39
|
+
behaviorTests.push(...lmsTests);
|
|
40
|
+
testId += lmsTests.length;
|
|
41
|
+
// 6. Apex/server call behaviors
|
|
42
|
+
const apexTests = extractApexBehaviors(markup, controller, helper, testId);
|
|
43
|
+
behaviorTests.push(...apexTests);
|
|
44
|
+
// Generate test files
|
|
45
|
+
const beforeTestFile = generateBeforeTestFile(markup.componentName, behaviorTests);
|
|
46
|
+
const afterTestFile = generateAfterTestFile(lwcName, className, behaviorTests, transformedMarkup);
|
|
47
|
+
const comparisonReport = generateComparisonReport(markup.componentName, lwcName, behaviorTests);
|
|
48
|
+
return {
|
|
49
|
+
componentName: markup.componentName,
|
|
50
|
+
lwcName,
|
|
51
|
+
behaviorTests,
|
|
52
|
+
beforeTestFile,
|
|
53
|
+
afterTestFile,
|
|
54
|
+
comparisonReport,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extract lifecycle-related behaviors (init, render, destroy)
|
|
59
|
+
*/
|
|
60
|
+
function extractLifecycleBehaviors(markup, controller, helper, startId = 1) {
|
|
61
|
+
const tests = [];
|
|
62
|
+
let id = startId;
|
|
63
|
+
// Init handler
|
|
64
|
+
const initHandler = markup.handlers.find(h => h.name === 'init');
|
|
65
|
+
if (initHandler) {
|
|
66
|
+
const funcName = initHandler.action.replace('{!c.', '').replace('}', '');
|
|
67
|
+
const initFunc = controller?.functions.find(f => f.name === funcName);
|
|
68
|
+
// Analyze what init does
|
|
69
|
+
const setsAttributes = [];
|
|
70
|
+
const callsServer = initFunc?.serverCalls.length ? true : false;
|
|
71
|
+
const callsHelper = [];
|
|
72
|
+
if (initFunc) {
|
|
73
|
+
// Find component.set calls
|
|
74
|
+
const setMatches = initFunc.body.matchAll(/component\.set\s*\(\s*["']v\.(\w+)["']/g);
|
|
75
|
+
for (const match of setMatches) {
|
|
76
|
+
setsAttributes.push(match[1]);
|
|
77
|
+
}
|
|
78
|
+
// Find helper calls
|
|
79
|
+
const helperMatches = initFunc.body.matchAll(/helper\.(\w+)\s*\(/g);
|
|
80
|
+
for (const match of helperMatches) {
|
|
81
|
+
callsHelper.push(match[1]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
tests.push({
|
|
85
|
+
id: `behavior-${id++}`,
|
|
86
|
+
category: 'lifecycle',
|
|
87
|
+
name: 'Component Initialization',
|
|
88
|
+
description: `When component initializes, ${funcName} is called`,
|
|
89
|
+
auraBehavior: {
|
|
90
|
+
pattern: `aura:handler name="init" action="{!c.${funcName}}"`,
|
|
91
|
+
code: initFunc?.body,
|
|
92
|
+
attributes: { handler: funcName },
|
|
93
|
+
},
|
|
94
|
+
lwcBehavior: {
|
|
95
|
+
pattern: 'connectedCallback()',
|
|
96
|
+
properties: { lifecycle: 'connectedCallback' },
|
|
97
|
+
},
|
|
98
|
+
testCode: {
|
|
99
|
+
before: generateInitBeforeTest(funcName, setsAttributes, callsServer, callsHelper),
|
|
100
|
+
after: generateInitAfterTest(setsAttributes, callsServer),
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
// If init sets specific attributes, add individual tests
|
|
104
|
+
for (const attr of setsAttributes) {
|
|
105
|
+
tests.push({
|
|
106
|
+
id: `behavior-${id++}`,
|
|
107
|
+
category: 'lifecycle',
|
|
108
|
+
name: `Init sets ${attr}`,
|
|
109
|
+
description: `On init, ${attr} property is set`,
|
|
110
|
+
auraBehavior: {
|
|
111
|
+
pattern: `component.set("v.${attr}", ...)`,
|
|
112
|
+
},
|
|
113
|
+
lwcBehavior: {
|
|
114
|
+
pattern: `this.${attr} = ...`,
|
|
115
|
+
},
|
|
116
|
+
testCode: {
|
|
117
|
+
before: `// Aura: After init, v.${attr} should be set\nexpect(component.get("v.${attr}")).toBeDefined();`,
|
|
118
|
+
after: `test('should set ${attr} on init', async () => {\n document.body.appendChild(element);\n await Promise.resolve();\n // LWC: After connectedCallback, ${attr} should be set\n expect(element.${attr}).toBeDefined();\n});`,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Render handler
|
|
124
|
+
const renderHandler = markup.handlers.find(h => h.name === 'render' || h.name === 'afterRender');
|
|
125
|
+
if (renderHandler) {
|
|
126
|
+
tests.push({
|
|
127
|
+
id: `behavior-${id++}`,
|
|
128
|
+
category: 'lifecycle',
|
|
129
|
+
name: 'After Render Callback',
|
|
130
|
+
description: 'Code runs after component renders',
|
|
131
|
+
auraBehavior: {
|
|
132
|
+
pattern: `aura:handler name="${renderHandler.name}" action="${renderHandler.action}"`,
|
|
133
|
+
},
|
|
134
|
+
lwcBehavior: {
|
|
135
|
+
pattern: 'renderedCallback()',
|
|
136
|
+
},
|
|
137
|
+
testCode: {
|
|
138
|
+
before: `// Aura: ${renderHandler.name} handler is called after render`,
|
|
139
|
+
after: `// LWC: renderedCallback is called after each render\n// Note: Add isRendered flag to prevent repeated execution`,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Destroy handler
|
|
144
|
+
const destroyHandler = markup.handlers.find(h => h.name === 'destroy');
|
|
145
|
+
if (destroyHandler) {
|
|
146
|
+
tests.push({
|
|
147
|
+
id: `behavior-${id++}`,
|
|
148
|
+
category: 'lifecycle',
|
|
149
|
+
name: 'Component Cleanup',
|
|
150
|
+
description: 'Cleanup runs when component is destroyed',
|
|
151
|
+
auraBehavior: {
|
|
152
|
+
pattern: `aura:handler name="destroy" action="${destroyHandler.action}"`,
|
|
153
|
+
},
|
|
154
|
+
lwcBehavior: {
|
|
155
|
+
pattern: 'disconnectedCallback()',
|
|
156
|
+
},
|
|
157
|
+
testCode: {
|
|
158
|
+
before: `// Aura: destroy handler cleans up resources`,
|
|
159
|
+
after: `test('should cleanup on disconnect', () => {\n document.body.appendChild(element);\n document.body.removeChild(element);\n // Verify cleanup occurred\n});`,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return tests;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Extract data binding behaviors (attributes, getters)
|
|
167
|
+
*/
|
|
168
|
+
function extractDataBindingBehaviors(markup, transformedMarkup, controller, startId = 1) {
|
|
169
|
+
const tests = [];
|
|
170
|
+
let id = startId;
|
|
171
|
+
// Public attributes
|
|
172
|
+
for (const attr of markup.attributes) {
|
|
173
|
+
const isPublic = !attr.access || attr.access === 'public' || attr.access === 'global';
|
|
174
|
+
if (isPublic) {
|
|
175
|
+
tests.push({
|
|
176
|
+
id: `behavior-${id++}`,
|
|
177
|
+
category: 'data',
|
|
178
|
+
name: `Public property: ${attr.name}`,
|
|
179
|
+
description: `${attr.name} is exposed as a public property`,
|
|
180
|
+
auraBehavior: {
|
|
181
|
+
pattern: `<aura:attribute name="${attr.name}" type="${attr.type}" access="${attr.access || 'public'}"/>`,
|
|
182
|
+
attributes: {
|
|
183
|
+
name: attr.name,
|
|
184
|
+
type: attr.type,
|
|
185
|
+
default: attr.default || '',
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
lwcBehavior: {
|
|
189
|
+
pattern: `@api ${attr.name}`,
|
|
190
|
+
properties: {
|
|
191
|
+
decorator: '@api',
|
|
192
|
+
type: attr.type,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
testCode: {
|
|
196
|
+
before: `// Aura: v.${attr.name} is accessible from parent\nexpect(component.get("v.${attr.name}")).toBeDefined();`,
|
|
197
|
+
after: generatePropertyAfterTest(attr.name, attr.type, attr.default),
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// force:recordData bindings
|
|
203
|
+
for (const rds of transformedMarkup.recordDataServices) {
|
|
204
|
+
tests.push({
|
|
205
|
+
id: `behavior-${id++}`,
|
|
206
|
+
category: 'data',
|
|
207
|
+
name: `Wire record data: ${rds.auraId}`,
|
|
208
|
+
description: `Record data loaded via ${rds.recordIdBinding}`,
|
|
209
|
+
auraBehavior: {
|
|
210
|
+
pattern: `<force:recordData aura:id="${rds.auraId}" recordId="{!v.${rds.recordIdBinding}}" fields="[${rds.fields.join(', ')}]"/>`,
|
|
211
|
+
attributes: {
|
|
212
|
+
recordIdBinding: rds.recordIdBinding,
|
|
213
|
+
fields: rds.fields.join(', '),
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
lwcBehavior: {
|
|
217
|
+
pattern: `@wire(getRecord, { recordId: '$${rds.recordIdBinding}', fields: [${rds.fields.map(f => `'${f}'`).join(', ')}] })`,
|
|
218
|
+
},
|
|
219
|
+
testCode: {
|
|
220
|
+
before: `// Aura: force:recordData loads record when recordId changes`,
|
|
221
|
+
after: generateWireAfterTest(rds.recordIdBinding, rds.fields),
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return tests;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Extract event handling behaviors
|
|
229
|
+
*/
|
|
230
|
+
function extractEventBehaviors(markup, controller, helper, startId = 1) {
|
|
231
|
+
const tests = [];
|
|
232
|
+
let id = startId;
|
|
233
|
+
// Registered events (component events)
|
|
234
|
+
for (const event of markup.registeredEvents) {
|
|
235
|
+
tests.push({
|
|
236
|
+
id: `behavior-${id++}`,
|
|
237
|
+
category: 'event',
|
|
238
|
+
name: `Fires event: ${event.name}`,
|
|
239
|
+
description: `Component can fire ${event.name} event`,
|
|
240
|
+
auraBehavior: {
|
|
241
|
+
pattern: `<aura:registerEvent name="${event.name}" type="${event.type}"/>`,
|
|
242
|
+
code: `component.getEvent("${event.name}").fire()`,
|
|
243
|
+
},
|
|
244
|
+
lwcBehavior: {
|
|
245
|
+
pattern: `this.dispatchEvent(new CustomEvent('${event.name.toLowerCase()}'))`,
|
|
246
|
+
},
|
|
247
|
+
testCode: {
|
|
248
|
+
before: `// Aura: Component fires ${event.name} event\nconst evt = component.getEvent("${event.name}");\nevt.fire();`,
|
|
249
|
+
after: generateEventAfterTest(event.name),
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
// Event handlers from controller
|
|
254
|
+
if (controller) {
|
|
255
|
+
for (const func of controller.functions) {
|
|
256
|
+
// Skip init handler (already covered in lifecycle)
|
|
257
|
+
if (func.name === 'doInit')
|
|
258
|
+
continue;
|
|
259
|
+
// Check if it's an event handler (starts with handle, on, or is called from markup)
|
|
260
|
+
if (func.name.startsWith('handle') || func.name.startsWith('on')) {
|
|
261
|
+
const eventName = func.name.replace(/^(handle|on)/, '').toLowerCase();
|
|
262
|
+
tests.push({
|
|
263
|
+
id: `behavior-${id++}`,
|
|
264
|
+
category: 'event',
|
|
265
|
+
name: `Handle: ${func.name}`,
|
|
266
|
+
description: `${func.name} handles user interaction`,
|
|
267
|
+
auraBehavior: {
|
|
268
|
+
pattern: `{!c.${func.name}}`,
|
|
269
|
+
code: func.body,
|
|
270
|
+
},
|
|
271
|
+
lwcBehavior: {
|
|
272
|
+
pattern: `${func.name}(event)`,
|
|
273
|
+
},
|
|
274
|
+
testCode: {
|
|
275
|
+
before: `// Aura: ${func.name} is called on ${eventName} event`,
|
|
276
|
+
after: generateHandlerAfterTest(func.name, eventName, func),
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return tests;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Extract UI rendering behaviors
|
|
286
|
+
*/
|
|
287
|
+
function extractUIBehaviors(markup, transformedMarkup, startId = 1) {
|
|
288
|
+
const tests = [];
|
|
289
|
+
let id = startId;
|
|
290
|
+
// Conditional rendering (aura:if)
|
|
291
|
+
const conditionalExpressions = markup.expressions.filter(e => e.original.includes('isTrue') || e.original.includes('isFalse'));
|
|
292
|
+
for (const component of transformedMarkup.usedComponents) {
|
|
293
|
+
tests.push({
|
|
294
|
+
id: `behavior-${id++}`,
|
|
295
|
+
category: 'ui',
|
|
296
|
+
name: `Renders ${component}`,
|
|
297
|
+
description: `Component includes ${component}`,
|
|
298
|
+
auraBehavior: {
|
|
299
|
+
pattern: `<${component.replace('lightning-', 'lightning:')}>`,
|
|
300
|
+
},
|
|
301
|
+
lwcBehavior: {
|
|
302
|
+
pattern: `<${component}>`,
|
|
303
|
+
},
|
|
304
|
+
testCode: {
|
|
305
|
+
before: `// Aura: ${component.replace('lightning-', 'lightning:')} is rendered`,
|
|
306
|
+
after: `test('should render ${component}', () => {\n document.body.appendChild(element);\n const comp = element.shadowRoot.querySelector('${component}');\n expect(comp).toBeTruthy();\n});`,
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
// Iteration rendering
|
|
311
|
+
if (transformedMarkup.usedDirectives.includes('for:each')) {
|
|
312
|
+
tests.push({
|
|
313
|
+
id: `behavior-${id++}`,
|
|
314
|
+
category: 'ui',
|
|
315
|
+
name: 'List rendering',
|
|
316
|
+
description: 'Component renders a list of items',
|
|
317
|
+
auraBehavior: {
|
|
318
|
+
pattern: '<aura:iteration items="{!v.items}" var="item">',
|
|
319
|
+
},
|
|
320
|
+
lwcBehavior: {
|
|
321
|
+
pattern: '<template for:each={items} for:item="item">',
|
|
322
|
+
},
|
|
323
|
+
testCode: {
|
|
324
|
+
before: `// Aura: aura:iteration renders list items`,
|
|
325
|
+
after: `test('should render list items', async () => {\n element.items = [{Id: '1', Name: 'Test'}];\n document.body.appendChild(element);\n await Promise.resolve();\n // Verify items rendered\n});`,
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
// Conditional rendering
|
|
330
|
+
if (transformedMarkup.usedDirectives.includes('lwc:if')) {
|
|
331
|
+
tests.push({
|
|
332
|
+
id: `behavior-${id++}`,
|
|
333
|
+
category: 'ui',
|
|
334
|
+
name: 'Conditional rendering',
|
|
335
|
+
description: 'Component conditionally shows/hides content',
|
|
336
|
+
auraBehavior: {
|
|
337
|
+
pattern: '<aura:if isTrue="{!v.condition}">',
|
|
338
|
+
},
|
|
339
|
+
lwcBehavior: {
|
|
340
|
+
pattern: '<template lwc:if={condition}>',
|
|
341
|
+
},
|
|
342
|
+
testCode: {
|
|
343
|
+
before: `// Aura: Content shown/hidden based on condition`,
|
|
344
|
+
after: `test('should conditionally render content', async () => {\n element.condition = false;\n document.body.appendChild(element);\n await Promise.resolve();\n // Verify content hidden\n \n element.condition = true;\n await Promise.resolve();\n // Verify content shown\n});`,
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return tests;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Extract LMS (Lightning Message Service) behaviors
|
|
352
|
+
*/
|
|
353
|
+
function extractLMSBehaviors(transformedMarkup, controller, startId = 1) {
|
|
354
|
+
const tests = [];
|
|
355
|
+
let id = startId;
|
|
356
|
+
for (const lms of transformedMarkup.lmsChannels) {
|
|
357
|
+
if (lms.isPublisherOnly) {
|
|
358
|
+
// Publisher pattern
|
|
359
|
+
tests.push({
|
|
360
|
+
id: `behavior-${id++}`,
|
|
361
|
+
category: 'lms',
|
|
362
|
+
name: `LMS Publisher: ${lms.channelName}`,
|
|
363
|
+
description: `Publishes messages to ${lms.channelName}`,
|
|
364
|
+
auraBehavior: {
|
|
365
|
+
pattern: `<lightning:messageChannel type="${lms.channelName}" aura:id="${lms.auraId}"/>`,
|
|
366
|
+
code: `component.find('${lms.auraId}').publish(payload)`,
|
|
367
|
+
},
|
|
368
|
+
lwcBehavior: {
|
|
369
|
+
pattern: `publish(this.messageContext, CHANNEL, message)`,
|
|
370
|
+
},
|
|
371
|
+
testCode: {
|
|
372
|
+
before: `// Aura: Publishes to ${lms.channelName}`,
|
|
373
|
+
after: generateLmsPublisherAfterTest(lms.channelName),
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
// Subscriber pattern
|
|
379
|
+
tests.push({
|
|
380
|
+
id: `behavior-${id++}`,
|
|
381
|
+
category: 'lms',
|
|
382
|
+
name: `LMS Subscriber: ${lms.channelName}`,
|
|
383
|
+
description: `Subscribes to ${lms.channelName} messages`,
|
|
384
|
+
auraBehavior: {
|
|
385
|
+
pattern: `<lightning:messageChannel type="${lms.channelName}" onMessage="{!c.${lms.onMessageHandler}}"/>`,
|
|
386
|
+
},
|
|
387
|
+
lwcBehavior: {
|
|
388
|
+
pattern: `subscribe(messageContext, CHANNEL, handleMessage) in connectedCallback`,
|
|
389
|
+
},
|
|
390
|
+
testCode: {
|
|
391
|
+
before: `// Aura: Receives messages from ${lms.channelName}`,
|
|
392
|
+
after: generateLmsSubscriberAfterTest(lms.channelName, lms.onMessageHandler || 'handleMessage'),
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
// Unsubscribe test
|
|
396
|
+
tests.push({
|
|
397
|
+
id: `behavior-${id++}`,
|
|
398
|
+
category: 'lms',
|
|
399
|
+
name: `LMS Unsubscribe: ${lms.channelName}`,
|
|
400
|
+
description: `Unsubscribes from ${lms.channelName} on destroy`,
|
|
401
|
+
auraBehavior: {
|
|
402
|
+
pattern: 'Automatic cleanup by Aura framework',
|
|
403
|
+
},
|
|
404
|
+
lwcBehavior: {
|
|
405
|
+
pattern: 'unsubscribe(subscription) in disconnectedCallback',
|
|
406
|
+
},
|
|
407
|
+
testCode: {
|
|
408
|
+
before: `// Aura: Framework handles cleanup automatically`,
|
|
409
|
+
after: `test('should unsubscribe on disconnect', () => {\n document.body.appendChild(element);\n document.body.removeChild(element);\n expect(unsubscribe).toHaveBeenCalled();\n});`,
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return tests;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Extract Apex/server call behaviors
|
|
418
|
+
*/
|
|
419
|
+
function extractApexBehaviors(markup, controller, helper, startId = 1) {
|
|
420
|
+
const tests = [];
|
|
421
|
+
let id = startId;
|
|
422
|
+
// Find all server calls
|
|
423
|
+
const serverCalls = [];
|
|
424
|
+
if (controller) {
|
|
425
|
+
for (const func of controller.functions) {
|
|
426
|
+
for (const call of func.serverCalls) {
|
|
427
|
+
if (call.controllerMethod) {
|
|
428
|
+
serverCalls.push({ method: call.controllerMethod, calledFrom: func.name });
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (helper) {
|
|
434
|
+
for (const func of helper.functions) {
|
|
435
|
+
for (const call of func.serverCalls) {
|
|
436
|
+
serverCalls.push({ method: call, calledFrom: `helper.${func.name}` });
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// Create unique server call tests
|
|
441
|
+
const uniqueMethods = [...new Set(serverCalls.map(c => c.method))];
|
|
442
|
+
for (const method of uniqueMethods) {
|
|
443
|
+
const callers = serverCalls.filter(c => c.method === method).map(c => c.calledFrom);
|
|
444
|
+
tests.push({
|
|
445
|
+
id: `behavior-${id++}`,
|
|
446
|
+
category: 'apex',
|
|
447
|
+
name: `Apex call: ${method}`,
|
|
448
|
+
description: `Calls ${markup.controller}.${method} from ${callers.join(', ')}`,
|
|
449
|
+
auraBehavior: {
|
|
450
|
+
pattern: `component.get("c.${method}")`,
|
|
451
|
+
code: `var action = component.get("c.${method}");\naction.setParams({...});\n$A.enqueueAction(action);`,
|
|
452
|
+
},
|
|
453
|
+
lwcBehavior: {
|
|
454
|
+
pattern: `@wire(${method}) or await ${method}({...})`,
|
|
455
|
+
},
|
|
456
|
+
testCode: {
|
|
457
|
+
before: `// Aura: Server action ${method} is called`,
|
|
458
|
+
after: generateApexAfterTest(method, markup.controller || ''),
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return tests;
|
|
463
|
+
}
|
|
464
|
+
// ============ Test Generation Helpers ============
|
|
465
|
+
function generateInitBeforeTest(funcName, setsAttributes, callsServer, callsHelper) {
|
|
466
|
+
let test = `// Aura: When component loads, ${funcName} is invoked\n`;
|
|
467
|
+
test += `// Expected behaviors:\n`;
|
|
468
|
+
if (setsAttributes.length > 0) {
|
|
469
|
+
test += `// - Sets attributes: ${setsAttributes.join(', ')}\n`;
|
|
470
|
+
}
|
|
471
|
+
if (callsServer) {
|
|
472
|
+
test += `// - Makes server call\n`;
|
|
473
|
+
}
|
|
474
|
+
if (callsHelper.length > 0) {
|
|
475
|
+
test += `// - Calls helper: ${callsHelper.join(', ')}\n`;
|
|
476
|
+
}
|
|
477
|
+
return test;
|
|
478
|
+
}
|
|
479
|
+
function generateInitAfterTest(setsAttributes, callsServer) {
|
|
480
|
+
let test = `test('should initialize component state', async () => {\n`;
|
|
481
|
+
test += ` document.body.appendChild(element);\n`;
|
|
482
|
+
test += ` await Promise.resolve(); // Wait for connectedCallback\n\n`;
|
|
483
|
+
if (setsAttributes.length > 0) {
|
|
484
|
+
test += ` // Verify initial state is set\n`;
|
|
485
|
+
for (const attr of setsAttributes) {
|
|
486
|
+
test += ` expect(element.${attr}).toBeDefined();\n`;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (callsServer) {
|
|
490
|
+
test += ` // Verify data loading was triggered\n`;
|
|
491
|
+
test += ` // (Check wire adapter or Apex mock was called)\n`;
|
|
492
|
+
}
|
|
493
|
+
test += `});`;
|
|
494
|
+
return test;
|
|
495
|
+
}
|
|
496
|
+
function generatePropertyAfterTest(name, type, defaultVal) {
|
|
497
|
+
let test = `test('should expose ${name} as @api property', () => {\n`;
|
|
498
|
+
test += ` const testValue = ${getTestValueForType(type)};\n`;
|
|
499
|
+
test += ` element.${name} = testValue;\n`;
|
|
500
|
+
test += ` document.body.appendChild(element);\n`;
|
|
501
|
+
test += ` expect(element.${name}).toEqual(testValue);\n`;
|
|
502
|
+
test += `});`;
|
|
503
|
+
if (defaultVal && defaultVal.trim()) {
|
|
504
|
+
test += `\n\ntest('should have default value for ${name}', () => {\n`;
|
|
505
|
+
test += ` document.body.appendChild(element);\n`;
|
|
506
|
+
test += ` expect(element.${name}).toEqual(${defaultVal});\n`;
|
|
507
|
+
test += `});`;
|
|
508
|
+
}
|
|
509
|
+
return test;
|
|
510
|
+
}
|
|
511
|
+
function generateWireAfterTest(recordIdBinding, fields) {
|
|
512
|
+
let test = `test('should wire record data when ${recordIdBinding} is set', async () => {\n`;
|
|
513
|
+
test += ` element.${recordIdBinding} = '001xx000003DGbYAAW';\n`;
|
|
514
|
+
test += ` document.body.appendChild(element);\n`;
|
|
515
|
+
test += ` \n`;
|
|
516
|
+
test += ` // Emit mock wire data\n`;
|
|
517
|
+
test += ` // const mockRecord = { data: { fields: { ${fields.map(f => `${f}: { value: 'test' }`).join(', ')} }}};\n`;
|
|
518
|
+
test += ` // Use @salesforce/sfdx-lwc-jest emit() to send wire data\n`;
|
|
519
|
+
test += ` \n`;
|
|
520
|
+
test += ` await Promise.resolve();\n`;
|
|
521
|
+
test += ` // Verify getters return field values\n`;
|
|
522
|
+
test += `});`;
|
|
523
|
+
return test;
|
|
524
|
+
}
|
|
525
|
+
function generateEventAfterTest(eventName) {
|
|
526
|
+
let test = `test('should dispatch ${eventName} event', () => {\n`;
|
|
527
|
+
test += ` const handler = jest.fn();\n`;
|
|
528
|
+
test += ` element.addEventListener('${eventName.toLowerCase()}', handler);\n`;
|
|
529
|
+
test += ` document.body.appendChild(element);\n`;
|
|
530
|
+
test += ` \n`;
|
|
531
|
+
test += ` // Trigger action that fires event\n`;
|
|
532
|
+
test += ` // e.g., click a button, call a method\n`;
|
|
533
|
+
test += ` \n`;
|
|
534
|
+
test += ` expect(handler).toHaveBeenCalled();\n`;
|
|
535
|
+
test += ` expect(handler.mock.calls[0][0].detail).toBeDefined();\n`;
|
|
536
|
+
test += `});`;
|
|
537
|
+
return test;
|
|
538
|
+
}
|
|
539
|
+
function generateHandlerAfterTest(funcName, eventName, func) {
|
|
540
|
+
let test = `test('should handle ${eventName} event', async () => {\n`;
|
|
541
|
+
test += ` document.body.appendChild(element);\n`;
|
|
542
|
+
test += ` \n`;
|
|
543
|
+
test += ` // Find element that triggers ${funcName}\n`;
|
|
544
|
+
test += ` // const button = element.shadowRoot.querySelector('lightning-button');\n`;
|
|
545
|
+
test += ` // button.click();\n`;
|
|
546
|
+
test += ` \n`;
|
|
547
|
+
test += ` await Promise.resolve();\n`;
|
|
548
|
+
test += ` // Verify expected outcome\n`;
|
|
549
|
+
test += `});`;
|
|
550
|
+
return test;
|
|
551
|
+
}
|
|
552
|
+
function generateLmsPublisherAfterTest(channelName) {
|
|
553
|
+
const channelVar = channelName.replace(/__c$/i, '').toUpperCase() + '_CHANNEL';
|
|
554
|
+
let test = `test('should publish to ${channelName}', () => {\n`;
|
|
555
|
+
test += ` document.body.appendChild(element);\n`;
|
|
556
|
+
test += ` \n`;
|
|
557
|
+
test += ` // Call method that publishes\n`;
|
|
558
|
+
test += ` element.publishMessage({ recordId: '001xx000003DGbY' });\n`;
|
|
559
|
+
test += ` \n`;
|
|
560
|
+
test += ` expect(publish).toHaveBeenCalledWith(\n`;
|
|
561
|
+
test += ` expect.anything(),\n`;
|
|
562
|
+
test += ` ${channelVar},\n`;
|
|
563
|
+
test += ` expect.objectContaining({ recordId: '001xx000003DGbY' })\n`;
|
|
564
|
+
test += ` );\n`;
|
|
565
|
+
test += `});`;
|
|
566
|
+
return test;
|
|
567
|
+
}
|
|
568
|
+
function generateLmsSubscriberAfterTest(channelName, handlerName) {
|
|
569
|
+
const channelVar = channelName.replace(/__c$/i, '').toUpperCase() + '_CHANNEL';
|
|
570
|
+
let test = `test('should subscribe to ${channelName} on connect', () => {\n`;
|
|
571
|
+
test += ` document.body.appendChild(element);\n`;
|
|
572
|
+
test += ` \n`;
|
|
573
|
+
test += ` expect(subscribe).toHaveBeenCalledWith(\n`;
|
|
574
|
+
test += ` expect.anything(),\n`;
|
|
575
|
+
test += ` ${channelVar},\n`;
|
|
576
|
+
test += ` expect.any(Function)\n`;
|
|
577
|
+
test += ` );\n`;
|
|
578
|
+
test += `});\n\n`;
|
|
579
|
+
test += `test('should handle incoming message', async () => {\n`;
|
|
580
|
+
test += ` document.body.appendChild(element);\n`;
|
|
581
|
+
test += ` const messageHandler = subscribe.mock.calls[0][2];\n`;
|
|
582
|
+
test += ` \n`;
|
|
583
|
+
test += ` // Simulate message\n`;
|
|
584
|
+
test += ` messageHandler({ recordId: '001xx000003DGbY' });\n`;
|
|
585
|
+
test += ` await Promise.resolve();\n`;
|
|
586
|
+
test += ` \n`;
|
|
587
|
+
test += ` // Verify component state updated\n`;
|
|
588
|
+
test += `});`;
|
|
589
|
+
return test;
|
|
590
|
+
}
|
|
591
|
+
function generateApexAfterTest(method, controller) {
|
|
592
|
+
let test = `test('should call ${method} Apex method', async () => {\n`;
|
|
593
|
+
test += ` // Mock Apex response\n`;
|
|
594
|
+
test += ` ${method}.mockResolvedValue({ /* expected data */ });\n`;
|
|
595
|
+
test += ` \n`;
|
|
596
|
+
test += ` document.body.appendChild(element);\n`;
|
|
597
|
+
test += ` await Promise.resolve();\n`;
|
|
598
|
+
test += ` \n`;
|
|
599
|
+
test += ` // If using @wire, data loads automatically\n`;
|
|
600
|
+
test += ` // If imperative, call the method that triggers it\n`;
|
|
601
|
+
test += ` \n`;
|
|
602
|
+
test += ` // Verify Apex was called\n`;
|
|
603
|
+
test += ` // expect(${method}).toHaveBeenCalled();\n`;
|
|
604
|
+
test += `});`;
|
|
605
|
+
return test;
|
|
606
|
+
}
|
|
607
|
+
function getTestValueForType(type) {
|
|
608
|
+
switch (type.toLowerCase()) {
|
|
609
|
+
case 'string': return "'test-value'";
|
|
610
|
+
case 'boolean': return 'true';
|
|
611
|
+
case 'integer':
|
|
612
|
+
case 'decimal':
|
|
613
|
+
case 'double':
|
|
614
|
+
case 'number': return '42';
|
|
615
|
+
case 'list':
|
|
616
|
+
case 'object[]': return '[]';
|
|
617
|
+
case 'object':
|
|
618
|
+
case 'map': return '{}';
|
|
619
|
+
default: return "'test-value'";
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
// ============ Test File Generators ============
|
|
623
|
+
function generateBeforeTestFile(componentName, tests) {
|
|
624
|
+
let content = `/**
|
|
625
|
+
* BEFORE CONVERSION: Expected Behaviors for ${componentName}
|
|
626
|
+
*
|
|
627
|
+
* This document describes the expected behaviors of the original Aura component.
|
|
628
|
+
* These behaviors should be preserved in the converted LWC.
|
|
629
|
+
*
|
|
630
|
+
* Generated by lwc-convert
|
|
631
|
+
*/
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Behavior Inventory
|
|
635
|
+
* ==================
|
|
636
|
+
*
|
|
637
|
+
* The following behaviors were identified in the Aura component:
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
`;
|
|
641
|
+
const categories = [...new Set(tests.map(t => t.category))];
|
|
642
|
+
for (const category of categories) {
|
|
643
|
+
const categoryTests = tests.filter(t => t.category === category);
|
|
644
|
+
content += `// ============ ${category.toUpperCase()} BEHAVIORS ============\n\n`;
|
|
645
|
+
for (const test of categoryTests) {
|
|
646
|
+
content += `/**
|
|
647
|
+
* ${test.id}: ${test.name}
|
|
648
|
+
* ${test.description}
|
|
649
|
+
*
|
|
650
|
+
* Aura Pattern:
|
|
651
|
+
* ${test.auraBehavior.pattern}
|
|
652
|
+
*/
|
|
653
|
+
${test.testCode.before}
|
|
654
|
+
|
|
655
|
+
`;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
content += `
|
|
659
|
+
/**
|
|
660
|
+
* Summary
|
|
661
|
+
* =======
|
|
662
|
+
*
|
|
663
|
+
* Total behaviors identified: ${tests.length}
|
|
664
|
+
* - Lifecycle: ${tests.filter(t => t.category === 'lifecycle').length}
|
|
665
|
+
* - Data: ${tests.filter(t => t.category === 'data').length}
|
|
666
|
+
* - Events: ${tests.filter(t => t.category === 'event').length}
|
|
667
|
+
* - UI: ${tests.filter(t => t.category === 'ui').length}
|
|
668
|
+
* - LMS: ${tests.filter(t => t.category === 'lms').length}
|
|
669
|
+
* - Apex: ${tests.filter(t => t.category === 'apex').length}
|
|
670
|
+
*
|
|
671
|
+
* Run the "after" tests to verify all behaviors are preserved.
|
|
672
|
+
*/
|
|
673
|
+
`;
|
|
674
|
+
return content;
|
|
675
|
+
}
|
|
676
|
+
function generateAfterTestFile(lwcName, className, tests, transformedMarkup) {
|
|
677
|
+
const imports = [
|
|
678
|
+
`import { createElement } from 'lwc';`,
|
|
679
|
+
`import ${className} from 'c/${lwcName}';`,
|
|
680
|
+
];
|
|
681
|
+
const mocks = [];
|
|
682
|
+
// Add LMS mocks if needed
|
|
683
|
+
if (tests.some(t => t.category === 'lms')) {
|
|
684
|
+
imports.push(`import { publish, subscribe, unsubscribe, MessageContext } from 'lightning/messageService';`);
|
|
685
|
+
for (const lms of transformedMarkup.lmsChannels) {
|
|
686
|
+
const channelVar = lms.channelName.replace(/__c$/i, '').toUpperCase() + '_CHANNEL';
|
|
687
|
+
imports.push(`import ${channelVar} from '@salesforce/messageChannel/${lms.channelName}';`);
|
|
688
|
+
}
|
|
689
|
+
mocks.push(`jest.mock(
|
|
690
|
+
'lightning/messageService',
|
|
691
|
+
() => ({
|
|
692
|
+
publish: jest.fn(),
|
|
693
|
+
subscribe: jest.fn(() => ({ unsubscribe: jest.fn() })),
|
|
694
|
+
unsubscribe: jest.fn(),
|
|
695
|
+
MessageContext: jest.fn()
|
|
696
|
+
}),
|
|
697
|
+
{ virtual: true }
|
|
698
|
+
);`);
|
|
699
|
+
}
|
|
700
|
+
// Add wire mocks if needed
|
|
701
|
+
if (tests.some(t => t.category === 'data' && t.lwcBehavior.pattern.includes('@wire'))) {
|
|
702
|
+
imports.push(`import { getRecord, getFieldValue } from 'lightning/uiRecordApi';`);
|
|
703
|
+
}
|
|
704
|
+
// Add Apex mocks if needed
|
|
705
|
+
const apexTests = tests.filter(t => t.category === 'apex');
|
|
706
|
+
for (const test of apexTests) {
|
|
707
|
+
const method = test.name.replace('Apex call: ', '');
|
|
708
|
+
// Extract controller name from description: "Calls ControllerName.method from ..."
|
|
709
|
+
const controllerMatch = test.description.match(/Calls\s+([\w]+)\./);
|
|
710
|
+
const controller = controllerMatch ? controllerMatch[1] : 'ApexController';
|
|
711
|
+
// Add import for the Apex method
|
|
712
|
+
imports.push(`import ${method} from '@salesforce/apex/${controller}.${method}';`);
|
|
713
|
+
mocks.push(`jest.mock(
|
|
714
|
+
'@salesforce/apex/${controller}.${method}',
|
|
715
|
+
() => ({ default: jest.fn() }),
|
|
716
|
+
{ virtual: true }
|
|
717
|
+
);`);
|
|
718
|
+
}
|
|
719
|
+
let content = `/**
|
|
720
|
+
* AFTER CONVERSION: Jest Tests for ${lwcName}
|
|
721
|
+
* Converted from Aura component
|
|
722
|
+
*
|
|
723
|
+
* These tests verify that the converted LWC preserves all original behaviors.
|
|
724
|
+
* Each test is linked to a specific behavior from the "before" document.
|
|
725
|
+
*
|
|
726
|
+
* Generated by lwc-convert
|
|
727
|
+
*/
|
|
728
|
+
|
|
729
|
+
${imports.join('\n')}
|
|
730
|
+
|
|
731
|
+
${mocks.length > 0 ? '\n// Mocks\n' + mocks.join('\n\n') + '\n' : ''}
|
|
732
|
+
|
|
733
|
+
describe('${lwcName} - Behavior Verification', () => {
|
|
734
|
+
let element;
|
|
735
|
+
|
|
736
|
+
beforeEach(() => {
|
|
737
|
+
element = createElement('c-${lwcName}', {
|
|
738
|
+
is: ${className}
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
afterEach(() => {
|
|
743
|
+
while (document.body.firstChild) {
|
|
744
|
+
document.body.removeChild(document.body.firstChild);
|
|
745
|
+
}
|
|
746
|
+
jest.clearAllMocks();
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
`;
|
|
750
|
+
const categories = [...new Set(tests.map(t => t.category))];
|
|
751
|
+
for (const category of categories) {
|
|
752
|
+
const categoryTests = tests.filter(t => t.category === category);
|
|
753
|
+
content += ` // ============ ${category.toUpperCase()} TESTS ============\n`;
|
|
754
|
+
content += ` describe('${category.charAt(0).toUpperCase() + category.slice(1)} Behaviors', () => {\n`;
|
|
755
|
+
for (const test of categoryTests) {
|
|
756
|
+
content += ` /**
|
|
757
|
+
* ${test.id}: ${test.name}
|
|
758
|
+
* LWC Pattern: ${test.lwcBehavior.pattern}
|
|
759
|
+
*/
|
|
760
|
+
${test.testCode.after}
|
|
761
|
+
|
|
762
|
+
`;
|
|
763
|
+
}
|
|
764
|
+
content += ` });\n\n`;
|
|
765
|
+
}
|
|
766
|
+
content += `});
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Test Results Comparison
|
|
770
|
+
* =======================
|
|
771
|
+
*
|
|
772
|
+
* Run these tests with: npm test -- --testPathPattern="${lwcName}"
|
|
773
|
+
*
|
|
774
|
+
* Expected: All ${tests.length} behavior tests should pass
|
|
775
|
+
*
|
|
776
|
+
* If a test fails, compare with the corresponding "before" behavior
|
|
777
|
+
* to understand what the original Aura component did.
|
|
778
|
+
*/
|
|
779
|
+
`;
|
|
780
|
+
return content;
|
|
781
|
+
}
|
|
782
|
+
function generateComparisonReport(componentName, lwcName, tests) {
|
|
783
|
+
let report = `# Conversion Behavior Comparison Report
|
|
784
|
+
|
|
785
|
+
## Component: ${componentName} → ${lwcName}
|
|
786
|
+
|
|
787
|
+
This report documents the behavioral mapping between the original Aura component
|
|
788
|
+
and the converted LWC. Use this to verify the conversion is complete and correct.
|
|
789
|
+
|
|
790
|
+
## Behavior Summary
|
|
791
|
+
|
|
792
|
+
| Category | Count | Status |
|
|
793
|
+
|----------|-------|--------|
|
|
794
|
+
`;
|
|
795
|
+
const categories = ['lifecycle', 'data', 'event', 'ui', 'lms', 'apex'];
|
|
796
|
+
for (const cat of categories) {
|
|
797
|
+
const count = tests.filter(t => t.category === cat).length;
|
|
798
|
+
const status = count > 0 ? '⏳ Pending verification' : '✓ N/A';
|
|
799
|
+
report += `| ${cat.charAt(0).toUpperCase() + cat.slice(1)} | ${count} | ${status} |\n`;
|
|
800
|
+
}
|
|
801
|
+
report += `| **Total** | **${tests.length}** | |\n`;
|
|
802
|
+
report += `
|
|
803
|
+
## Detailed Behavior Mapping
|
|
804
|
+
|
|
805
|
+
`;
|
|
806
|
+
for (const cat of categories) {
|
|
807
|
+
const categoryTests = tests.filter(t => t.category === cat);
|
|
808
|
+
if (categoryTests.length === 0)
|
|
809
|
+
continue;
|
|
810
|
+
report += `### ${cat.charAt(0).toUpperCase() + cat.slice(1)} Behaviors
|
|
811
|
+
|
|
812
|
+
`;
|
|
813
|
+
for (const test of categoryTests) {
|
|
814
|
+
report += `#### ${test.id}: ${test.name}
|
|
815
|
+
|
|
816
|
+
- **Description**: ${test.description}
|
|
817
|
+
- **Aura Pattern**: \`${test.auraBehavior.pattern}\`
|
|
818
|
+
- **LWC Pattern**: \`${test.lwcBehavior.pattern}\`
|
|
819
|
+
- **Test Status**: ⬜ Not run
|
|
820
|
+
|
|
821
|
+
`;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
report += `
|
|
825
|
+
## Verification Checklist
|
|
826
|
+
|
|
827
|
+
Run the test suite and update this checklist:
|
|
828
|
+
|
|
829
|
+
`;
|
|
830
|
+
for (const test of tests) {
|
|
831
|
+
report += `- [ ] ${test.id}: ${test.name}\n`;
|
|
832
|
+
}
|
|
833
|
+
report += `
|
|
834
|
+
## How to Run Tests
|
|
835
|
+
|
|
836
|
+
\`\`\`bash
|
|
837
|
+
# Run all tests for this component
|
|
838
|
+
npm test -- --testPathPattern="${lwcName}"
|
|
839
|
+
|
|
840
|
+
# Run with coverage
|
|
841
|
+
npm test -- --testPathPattern="${lwcName}" --coverage
|
|
842
|
+
|
|
843
|
+
# Run in watch mode
|
|
844
|
+
npm test -- --testPathPattern="${lwcName}" --watch
|
|
845
|
+
\`\`\`
|
|
846
|
+
|
|
847
|
+
## Notes
|
|
848
|
+
|
|
849
|
+
- Tests marked with "⏳ Pending verification" need manual review
|
|
850
|
+
- If a test fails, compare the Aura and LWC patterns to understand the difference
|
|
851
|
+
- Some behaviors may require manual implementation (marked as TODO in tests)
|
|
852
|
+
`;
|
|
853
|
+
return report;
|
|
854
|
+
}
|
|
855
|
+
//# sourceMappingURL=test-comparison.js.map
|