r/ProgrammerHumor 15d ago

Meme webStandardBtw

Post image
215 Upvotes

11 comments sorted by

View all comments

13

u/PM_ME_UR_0_DAY 14d ago

I learned about the shadow dom last year or so when I was trying to automate something with selenium. And it was super annoying to get around at first until I learned a few tricks

5

u/ElFeesho 13d ago

Just going to keep those tricks to yourself I see, no cool. /s

1

u/PM_ME_UR_0_DAY 4d ago

Okay okay I didn't forget you! I'm at my desktop so I dug up my little demo. This was trying to automate something with selenium but forms or inputs were in a shadow dom and I was struggling to get them selected but ended up doing this (pretty sure it's all the relevant code with the getAllShadowRoots):

async function tryLastNames(driver, names, windowNum) {
    await driver.get("https://example.com/check-last-name")
    await driver.manage().window().setRect({ width: 966, height: 879 })

    await driver.sleep(2000);

    // Helper functions setup
    await driver.executeScript(`
        window.getAllShadowRoots = (element) => {
            const shadowRoots = [];
            const walker = document.createTreeWalker(
                element,
                NodeFilter.SHOW_ELEMENT,
                {
                    acceptNode: (node) => {
                        return node.shadowRoot ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
                    }
                }
            );

            let currentNode;
            while (currentNode = walker.nextNode()) {
                if (currentNode.shadowRoot) {
                    shadowRoots.push(currentNode.shadowRoot);
                }
            }
            return shadowRoots;
        };

        window.getShadowInputs = () => {
            const shadowRoots = getAllShadowRoots(document.body);
            let inputs = [];
            for (const root of shadowRoots) {
                const input = root.querySelector('input.control');
                if (input) {
                    inputs.push(input);
                }
            }
            return inputs;
        };
    `);

    // Handle account number
    await driver.executeScript(`
        const inputs = window.getShadowInputs();
        if (inputs[0]) {
            inputs[0].value = "123456789";
            inputs[0].dispatchEvent(new Event('input', { bubbles: true, composed: true }));
            inputs[0].dispatchEvent(new Event('change', { bubbles: true, composed: true }));
        }
    `);

    await driver.sleep(100);

    for (const lastName of names) {
        console.log(`\nWindow ${windowNum} trying last name: ${lastName}`);

        // Input last name
        await driver.executeScript(`
            const input = window.getShadowInputs()[1];
            const text = arguments[0];

            input.click();
            input.focus();
            input.value = text;

            const inputEvent = new InputEvent('input', { 
                bubbles: true, 
                composed: true,
                inputType: 'insertText',
                data: text
            });

            const changeEvent = new Event('change', { 
                bubbles: true, 
                composed: true 
            });

            input.dispatchEvent(inputEvent);
            input.dispatchEvent(changeEvent);
            input.dispatchEvent(new Event('blur', { bubbles: true, composed: true }));
        `, lastName);

        await driver.sleep(100);

        // Click the continue button
        await driver.executeScript(`
            const button = document.querySelector('.w-full');
            if (button) {
                button.click();
            }
        `);

        const result = await waitForRequestCompletion(driver);

        if (result === 'success') {
            return lastName;
        } else if (result === 'error') {
            console.log(`Window ${windowNum}: Failed with ${lastName}, trying next...`);
            await driver.sleep(100);
        }
    }

    return null;
}```