gogoogle-chrome-headlesschromedp

Variables assigned in chromedp.ActionFunc cannot be inputted by SendKeys


I want to assign strings to a variables, after some processes, in chromedp.ActionFunc. Refer to below example.
However, chromedp.SendKeys after chromedp.ActionFunc couldn't input the variable to a form.
I confirmed the above with chromedp.CaptureScreenshot.

package main

import (
    "context"
    "fmt"
    "io/ioutil"
    "log"
    "time"

    "github.com/chromedp/chromedp"
)

func main() {
    ctx, cancel := chromedp.NewContext(
        context.Background(),
        chromedp.WithLogf(log.Printf),
    )
    defer cancel()

    ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
    defer cancel()

    var value string
    var buf0 []byte
    var buf1 []byte
    err := chromedp.Run(ctx, chromedp.Tasks{
        chromedp.Navigate(`https://stackoverflow.com/users/login`),
        chromedp.WaitVisible(`//*[@id="submit-button"]`),
        chromedp.CaptureScreenshot(&buf0),
        chromedp.ActionFunc(func(c context.Context) error {
            value = "apple"
            return nil
        }),
        chromedp.SendKeys(`//*[@id="email"]`, value),
        chromedp.CaptureScreenshot(&buf1),
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Print(value)
    ioutil.WriteFile("./capture0.png", buf0, 0644)
    ioutil.WriteFile("./capture1.png", buf1, 0644)
}

It succeeds if chromedp.SendKeys be included in chromedp.ActionFunc as below.
There is no problem with this method.
But I was wondering why the above approach didn't work.
If you have some knowledge of chromedp, please let me know.

        chromedp.ActionFunc(func(c context.Context) error {
            value = "apple"
            chromedp.SendKeys(`//*[@id="email"]`, value).Do(c)
            return nil
        }),

Solution

  • The first approach doesn't work cause at the moment

    chromedp.SendKeys(`//*[@id="email"]`, value)
    

    is called, the value of variable value is empty, so effectively it creates SendKeys action with the empty string. If the variable is initialized before calling chromedp.SendKeys the behavior would be as it was intended, see the fixed code:

    package main
    
    import (
        "context"
        "fmt"
        "io/ioutil"
        "log"
        "time"
    
        "github.com/chromedp/chromedp"
    )
    
    func main() {
        ctx, cancel := chromedp.NewContext(
            context.Background(),
            chromedp.WithLogf(log.Printf),
        )
        defer cancel()
    
        ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
        defer cancel()
    
        var value string = "apple"
        var buf0 []byte
        var buf1 []byte
        err := chromedp.Run(ctx, chromedp.Tasks{
            chromedp.Navigate(`https://stackoverflow.com/users/login`),
            chromedp.WaitVisible(`//*[@id="submit-button"]`),
            chromedp.CaptureScreenshot(&buf0),
            chromedp.SendKeys(`//*[@id="email"]`, value),
            chromedp.CaptureScreenshot(&buf1),
        })
        if err != nil {
            log.Fatal(err)
        }
        fmt.Print(value)
        ioutil.WriteFile("./capture0.png", buf0, 0644)
        ioutil.WriteFile("./capture1.png", buf1, 0644)
    }
    

    EDIT: This will also work as you expected.

        err := chromedp.Run(ctx, chromedp.Tasks{
            chromedp.Navigate(`https://stackoverflow.com/users/login`),
            chromedp.WaitVisible(`//*[@id="submit-button"]`),
            chromedp.CaptureScreenshot(&buf0),
            chromedp.ActionFunc(func(c context.Context) error {
                value = "apple"
                return nil
            }),
        })
        if err != nil {
            log.Fatal(err)
        }
    
        err = chromedp.Run(ctx, chromedp.Tasks{
            chromedp.SendKeys(`//*[@id="email"]`, value),
            chromedp.CaptureScreenshot(&buf1),
        })