Update browser extension form detector logic (#2051)

This commit is contained in:
Leendert de Borst
2026-05-21 20:36:42 +02:00
committed by Leendert de Borst
parent f5847cbc25
commit de18a205df
3 changed files with 98 additions and 5 deletions

View File

@@ -853,16 +853,30 @@ export class FormDetector {
// Check for parent label and table cell structure
let currentElement: HTMLElement | null = input;
for (let depth = 0; depth < 5 && currentElement; depth++) {
for (let depth = 0; depth < 7 && currentElement; depth++) {
// Stop if we have too many child elements (near body)
if (currentElement.children.length > 15) {
break;
}
// Check for label - search both parent and child elements
const childLabel = currentElement.querySelector('label');
if (childLabel) {
attributesToCheck.push(childLabel.textContent?.toLowerCase() ?? '');
/*
* Check for label - search both parent and child elements.
* Prefer the first label with non-empty text content; some component
* frameworks (e.g. Salesforce LWC, Lightning) nest an empty
* slot-only <label for="..."> next to the input while the visible
* label sits higher up in the wrapper.
*/
const childLabels = currentElement.querySelectorAll('label');
let labelTextFound: string | null = null;
for (const lbl of Array.from(childLabels)) {
const text = lbl.textContent?.trim() ?? '';
if (text.length > 0) {
labelTextFound = text.toLowerCase();
break;
}
}
if (labelTextFound !== null) {
attributesToCheck.push(labelTextFound);
break;
}

View File

@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest';
import { FormDetector } from '../FormDetector';
import { FormField, testField, createTestDom } from './TestUtils';
describe('FormDetector German tests', () => {
it('contains tests for German form field detection', () => {
expect(true).toBe(true);
});
describe('German login form 1 detection (o2 business / Salesforce Lightning)', () => {
const htmlFile = 'de-login-form1.html';
/*
* The visible label "Benutzername:" sits at the wrapper level with
* for="username" while the actual input id is "input-17". The label that
* does match (for="input-17") is nested deeper but contains only empty
* <slot> elements. Detection must look past the empty nested label to
* the visible outer one.
*/
testField(FormField.Username, 'input-17', htmlFile);
testField(FormField.Password, 'input-18', htmlFile);
it('should detect the form as a login form', () => {
const dom = createTestDom(htmlFile);
const document = dom.window.document;
const formDetector = new FormDetector(document);
expect(formDetector.containsLoginForm()).toBe(true);
});
});
});

View File

@@ -0,0 +1,47 @@
<html>
<body>
<form id="login-form">
<div data-aura-rendered-by="786:0">
<div class="slds-form-element__control" data-aura-rendered-by="787:0">
<label for="username" class="slds-form-element__label" data-aura-rendered-by="788:0">Benutzername:</label>
<lightning-input data-aura-rendered-by="790:0" class="slds-form-element">
<lightning-primitive-input-simple exportparts="input-text, input-container, input, required, label" variant="standard">
<div part="input-text">
<label class="slds-form-element__label slds-no-flex" for="input-17" part="label">
<slot name="label-end">
<slot name="label-end" slot="label-end"></slot>
</slot>
</label>
<div class="slds-form-element__control slds-grow" part="input-container" type="text">
<input class="slds-input" part="input" autocomplete="off" id="input-17" placeholder="" type="text" aria-describedby="help-message-17" data-av-autocomplete="on">
</div>
</div>
<div class="slds-form-element__help slds-m-left_none" id="help-message-17" data-help-message="" part="help-text" aria-live="polite"></div>
</lightning-primitive-input-simple>
</lightning-input>
</div>
<div class="slds-form-element__control" data-aura-rendered-by="795:0">
<label for="password" class="slds-form-element__label" data-aura-rendered-by="796:0">Kennwort:</label>
<lightning-input data-aura-rendered-by="798:0" class="slds-form-element">
<lightning-primitive-input-simple exportparts="input-text, input-container, input, required, label" variant="standard">
<div part="input-text" populated="">
<label class="slds-form-element__label slds-no-flex" for="input-18" part="label">
<slot name="label-end">
<slot name="label-end" slot="label-end"></slot>
</slot>
</label>
<div class="slds-form-element__control slds-grow" part="input-container" type="password">
<input class="slds-input" part="input" id="input-18" placeholder="" type="password" aria-describedby="help-message-18" autocomplete="off" data-av-field-type="password" data-av-autocomplete="off" aria-invalid="false">
</div>
</div>
<div class="slds-form-element__help slds-m-left_none" id="help-message-18" data-help-message="" part="help-text" aria-live="polite"></div>
</lightning-primitive-input-simple>
</lightning-input>
</div>
<div class="form-group buttonBoxEcare">
<button type="button" class="form-button">Anmelden</button>
</div>
</div>
</form>
</body>
</html>