handleContentMessage function exported
Last updated: 2026-03-05T10:53:28.853Z
Metrics
LOC: 503
Complexity: 99
Params: 2
Signature
handleContentMessage(
message: ExtensionMessage,
): : Promise<unknown>
Architecture violations
- [warning] max-cyclomatic-complexity: 'handleContentMessage' has cyclomatic complexity 99 (max 10)
- [warning] max-lines: 'handleContentMessage' has 503 lines (max 80)
Source Code
export async function handleContentMessage(
message: ExtensionMessage,
): Promise<unknown> {
switch (message.type) {
case "FILL_ALL_FIELDS": {
const override =
message.payload != null &&
typeof message.payload === "object" &&
"fillEmptyOnly" in (message.payload as object)
? {
fillEmptyOnly: (message.payload as { fillEmptyOnly: boolean })
.fillEmptyOnly,
}
: undefined;
const results = await fillAllFields(override);
showNotification(`✓ ${results.length} campos preenchidos`);
return { success: true, filled: results.length };
}
case "FILL_CONTEXTUAL_AI": {
const context = message.payload as AIContextPayload | undefined;
const results = await fillContextualAI(context);
showNotification(
`✓ ${results.length} campos preenchidos com IA contextual`,
);
return { success: true, filled: results.length };
}
case "SAVE_FORM": {
const values = await captureFormValues();
const formData: SavedForm = {
id: generateId(),
name: `Form - ${new URL(window.location.href).hostname} - ${new Date().toLocaleDateString("pt-BR")}`,
urlPattern: `${window.location.origin}${window.location.pathname}*`,
fields: values,
createdAt: Date.now(),
updatedAt: Date.now(),
};
await saveForm(formData);
showNotification(
`✓ Formulário salvo com ${Object.keys(values).length} campos`,
);
return { success: true, form: formData };
}
case "LOAD_SAVED_FORM": {
const form = parseSavedFormPayload(message.payload);
if (!form) return { error: "Invalid payload for LOAD_SAVED_FORM" };
// filter out ignored selectors so applyTemplate won't touch them
const ignoredFields = await getIgnoredFieldsForUrl(window.location.href);
const ignoredSelectors = new Set(ignoredFields.map((f) => f.selector));
const sanitizedFields: typeof form.fields = {};
for (const [key, value] of Object.entries(form.fields)) {
// we only know selector-level ignores; if a key equals a selector, drop it
if (ignoredSelectors.has(key)) continue;
sanitizedFields[key] = value;
}
const sanitizedForm: SavedForm = { ...form, fields: sanitizedFields };
const { filled } = await applyTemplate(sanitizedForm);
showNotification(`✓ ${filled} campos carregados do template`);
return { success: true, filled };
}
case "APPLY_TEMPLATE": {
const form = parseSavedFormPayload(message.payload);
if (!form) return { error: "Invalid payload for APPLY_TEMPLATE" };
const { filled } = await applyTemplate(form);
showNotification(`✓ Template "${form.name}" aplicado: ${filled} campos`);
return { success: true, filled };
}
case "FILL_SINGLE_FIELD": {
const fields = detectFormFields();
const targetField = findSingleFieldTarget(fields);
if (!targetField) return { error: "No target field found" };
const result = await fillSingleField(targetField);
if (result) {
showNotification(
`✓ Campo "${targetField.label || targetField.name || targetField.id || targetField.selector}" preenchido`,
);
return { success: true, ...result };
}
return { error: "Failed to fill field" };
}
case "GET_FORM_FIELDS": {
const fields = detectFormFields();
const mapped = fields.map((f) => ({
selector: f.selector,
fieldType: f.fieldType,
label: f.label,
name: f.name,
id: f.id,
placeholder: f.placeholder,
required: f.required,
}));
return { count: mapped.length, fields: mapped };
}
case "DETECT_FIELDS": {
const { fields: detected } = await detectAllFieldsAsync();
return {
count: detected.length,
fields: detected.map((f): DetectedFieldSummary => {
const item: DetectedFieldSummary = {
selector: f.selector,
fieldType: f.fieldType,
label: f.label || f.name || f.id || "unknown",
name: f.name,
id: f.id,
placeholder: f.placeholder,
required: f.required,
contextualType: f.contextualType,
detectionMethod: f.detectionMethod,
detectionConfidence: f.detectionConfidence,
};
if (f.element instanceof HTMLSelectElement) {
item.options = Array.from(f.element.options).map((o) => ({
value: o.value,
text: o.text.trim(),
}));
}
if (
f.element instanceof HTMLInputElement &&
(f.element.type === "checkbox" || f.element.type === "radio")
) {
item.checkboxValue = f.element.value;
item.checkboxChecked = f.element.checked;
}
return item;
}),
};
}
case "FILL_FIELD_BY_SELECTOR": {
const selector = parseStringPayload(message.payload);
if (!selector)
return { error: "Invalid payload for FILL_FIELD_BY_SELECTOR" };
const fields = detectFormFields();
const field = fields.find((f) => f.selector === selector);
if (!field) return { error: "Field not found" };
const result = await fillSingleField(field);
if (result) {
showNotification(`✓ Campo "${field.label || selector}" preenchido`);
}
return result ?? { error: "Failed to fill field" };
}
case "RECLASSIFY_FIELD": {
const selector = parseStringPayload(message.payload);
if (!selector) return { error: "Invalid payload for RECLASSIFY_FIELD" };
const classified = await reclassifyFieldBySelector(selector);
if (!classified)
return { error: "Field not found or could not be classified" };
const summary: DetectedFieldSummary = {
selector: classified.selector,
fieldType: classified.fieldType,
label:
classified.label || classified.name || classified.id || "unknown",
name: classified.name,
id: classified.id,
placeholder: classified.placeholder,
required: classified.required,
contextualType: classified.contextualType,
detectionMethod: classified.detectionMethod,
detectionConfidence: classified.detectionConfidence,
};
if (classified.element instanceof HTMLSelectElement) {
summary.options = Array.from(classified.element.options).map((o) => ({
value: o.value,
text: o.text.trim(),
}));
}
return summary;
}
case "START_WATCHING": {
const payload = parseStartWatchingPayload(message.payload);
if (!payload) return { error: "Invalid payload for START_WATCHING" };
// If debounceMs/shadowDOM not provided in payload, read from settings
let config: WatcherConfig;
if (payload.debounceMs == null && payload.shadowDOM == null) {
const settings = await getSettings();
config = {
autoRefill: payload.autoRefill ?? settings.watcherAutoRefill ?? true,
debounceMs: settings.watcherDebounceMs,
shadowDOM: settings.watcherShadowDOM,
};
} else {
config = {
autoRefill: payload.autoRefill ?? true,
debounceMs: payload.debounceMs,
shadowDOM: payload.shadowDOM,
};
}
startWatching(
(newFieldsCount) => {
if (newFieldsCount > 0) {
showNotification(
`🔄 ${newFieldsCount} novo(s) campo(s) detectado(s) — re-preenchendo...`,
);
}
},
config.autoRefill,
config,
);
return { success: true, watching: true };
}
case "STOP_WATCHING": {
stopWatching();
return { success: true, watching: false };
}
case "GET_WATCHER_STATUS": {
return {
watching: isWatcherActive(),
config: isWatcherActive() ? getWatcherConfig() : null,
};
}
case "INVALIDATE_CLASSIFIER": {
invalidateClassifier();
return { success: true };
}
case "RELOAD_CLASSIFIER": {
void reloadClassifier();
return { success: true };
}
case "EXPORT_E2E": {
const parsed = parseExportE2EPayload(message.payload);
if (!parsed) return { error: "Invalid payload for EXPORT_E2E" };
const framework = parsed.framework as E2EFramework;
const { fields } = await detectAllFieldsAsync();
const results = await fillAllFields();
const actions = buildCapturedActions(fields, results);
// Detect submit buttons and append to actions
const submitActions = detectSubmitActions();
const allActions = [...actions, ...submitActions];
// Detect assertions from the page
const pageUrl = window.location.href;
const assertions = detectAssertions(allActions, pageUrl);
const negativeAssertions = detectNegativeAssertions(allActions);
const options: E2EGenerateOptions = {
pageUrl,
includeAssertions: true,
includeNegativeTest: true,
useSmartSelectors: true,
assertions: [...assertions, ...negativeAssertions],
};
const script = generateE2EScript(framework, allActions, options);
if (!script) return { error: `Unsupported framework: ${framework}` };
showNotification(
`✓ Script ${framework} gerado (${allActions.length} ações)`,
);
return { success: true, script, actionsCount: allActions.length };
}
case "START_RECORDING": {
startRecording();
setOnStepAdded((step, index) => {
chrome.runtime
.sendMessage({
type: "RECORDING_STEP_ADDED",
payload: {
step: {
type: step.type,
selector: step.selector,
value: step.value,
url: step.url,
label: step.label,
assertion: step.assertion,
},
index,
},
})
.catch(() => {});
});
setOnStepUpdated((step, index) => {
chrome.runtime
.sendMessage({
type: "RECORDING_STEP_UPDATED",
payload: {
step: {
type: step.type,
selector: step.selector,
value: step.value,
url: step.url,
label: step.label,
assertion: step.assertion,
},
index,
},
})
.catch(() => {});
});
showNotification("🔴 Gravação iniciada");
return { success: true };
}
case "STOP_RECORDING": {
const session = stopRecording();
if (!session) return { error: "No recording in progress" };
showNotification(
`⏹ Gravação finalizada (${session.steps.length} passos)`,
);
return { success: true, stepsCount: session.steps.length };
}
case "PAUSE_RECORDING": {
pauseRecording();
showNotification("⏸ Gravação pausada");
return { success: true };
}
case "RESUME_RECORDING": {
resumeRecording();
showNotification("🔴 Gravação retomada");
return { success: true };
}
case "GET_RECORDING_STATUS": {
return { success: true, status: getRecordingStatus() };
}
case "GET_RECORDING_STEPS": {
const session = getRecordingSession();
if (!session) return { success: true, steps: [] };
return {
success: true,
steps: session.steps.map((s, i, arr) => ({
type: s.type,
selector: s.selector,
value: s.value,
waitMs: i > 0 ? s.timestamp - arr[i - 1].timestamp : 0,
url: s.url,
})),
};
}
case "EXPORT_RECORDING": {
const recPayload = parseExportRecordingPayload(message.payload);
if (!recPayload) return { error: "Invalid payload for EXPORT_RECORDING" };
const session = getRecordingSession();
if (!session || session.steps.length === 0) {
return { error: "No recorded steps available" };
}
const recOptions: RecordingGenerateOptions = {
testName: recPayload.testName,
pageUrl: session.startUrl,
includeAssertions: true,
minWaitThreshold: 500,
};
const recScript = generateE2EFromRecording(
recPayload.framework as E2EFramework,
session.steps,
recOptions,
);
if (!recScript) {
return { error: `Unsupported framework: ${recPayload.framework}` };
}
showNotification(
`✓ Script ${recPayload.framework} gerado (${session.steps.length} passos gravados)`,
);
return {
success: true,
script: recScript,
stepsCount: session.steps.length,
};
}
case "REMOVE_RECORDING_STEP": {
const payload = message.payload as { index?: number } | undefined;
if (typeof payload?.index !== "number") {
return { error: "Invalid index" };
}
const removed = removeStep(payload.index);
return { success: removed };
}
case "UPDATE_RECORDING_STEP": {
const payload = message.payload as
| { index?: number; patch?: { value?: string; waitTimeout?: number } }
| undefined;
if (typeof payload?.index !== "number" || !payload.patch) {
return { error: "Invalid payload" };
}
const updated = updateStep(payload.index, payload.patch);
return { success: updated };
}
case "CLEAR_RECORDING": {
clearSession();
return { success: true };
}
case "CLEAR_FORM": {
const fields = detectFormFields();
let cleared = 0;
for (const field of fields) {
const el = field.element;
if (el instanceof HTMLInputElement) {
if (el.type === "checkbox" || el.type === "radio") {
el.checked = false;
} else {
el.value = "";
}
cleared++;
el.dispatchEvent(new Event("input", { bubbles: true }));
el.dispatchEvent(new Event("change", { bubbles: true }));
} else if (el instanceof HTMLSelectElement) {
el.value = "";
cleared++;
el.dispatchEvent(new Event("change", { bubbles: true }));
} else if (el instanceof HTMLTextAreaElement) {
el.value = "";
cleared++;
el.dispatchEvent(new Event("input", { bubbles: true }));
el.dispatchEvent(new Event("change", { bubbles: true }));
}
}
showNotification(`✓ ${cleared} campo(s) limpo(s)`);
return { success: true, cleared };
}
case "DEMO_EXECUTE_STEP": {
const payload = message.payload as ExecuteStepPayload | undefined;
if (!payload?.step) {
return { error: "Invalid payload for DEMO_EXECUTE_STEP" };
}
const result = await executeStep(payload);
return { result };
}
case "DEMO_CURSOR_MOVE": {
const cfg = message.payload as
| { selector?: string; durationMs?: number }
| undefined;
if (cfg?.selector) {
initCursorOverlay();
showCursor();
await moveCursorTo(cfg.selector, cfg.durationMs ?? 400);
}
return { success: true };
}
case "DEMO_CURSOR_CLICK": {
initCursorOverlay();
showCursor();
await clickEffect();
return { success: true };
}
case "DEMO_CURSOR_DESTROY": {
hideCursor();
destroyCursorOverlay();
return { success: true };
}
case "DEMO_HIGHLIGHT_ELEMENT": {
const hlPayload = message.payload as
| { step?: unknown; durationMs?: number }
| undefined;
if (hlPayload?.step) {
highlightElement(
hlPayload.step as Parameters<typeof highlightElement>[0],
hlPayload.durationMs ?? 300,
);
}
return { success: true };
}
case "PING":
return { pong: true };
default:
return { error: `Unknown message type: ${message.type}` };
}
}
Dependencies (Outgoing)
| Target | Type |
|---|---|
| showNotification | calls |
| generateId | calls |
| findSingleFieldTarget | calls |
Impact (Incoming)
| Source | Type |
|---|---|
| FillableElement | calls |