Skip to content

Commit dd5463c

Browse files
Merge pull request #40 from lightpanda-io/chromedp-click
Chromedp click
2 parents f7d6a2b + ebb9508 commit dd5463c

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

chromedp/click/main.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright 2023-2025 Lightpanda (Selecy SAS)
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package main
15+
16+
import (
17+
"context"
18+
"errors"
19+
"flag"
20+
"fmt"
21+
"io"
22+
"log"
23+
"log/slog"
24+
"os"
25+
26+
"github.com/chromedp/chromedp"
27+
)
28+
29+
const (
30+
exitOK = 0
31+
exitFail = 1
32+
)
33+
34+
// main starts interruptable context and runs the program.
35+
func main() {
36+
ctx, cancel := context.WithCancel(context.Background())
37+
defer cancel()
38+
39+
err := run(ctx, os.Args, os.Stdout, os.Stderr)
40+
if err != nil {
41+
fmt.Fprintln(os.Stderr, err.Error())
42+
os.Exit(exitFail)
43+
}
44+
45+
os.Exit(exitOK)
46+
}
47+
48+
const (
49+
CdpWSDefault = "ws://127.0.0.1:9222"
50+
)
51+
52+
func run(ctx context.Context, args []string, stdout, stderr io.Writer) error {
53+
// declare runtime flag parameters.
54+
flags := flag.NewFlagSet(args[0], flag.ExitOnError)
55+
flags.SetOutput(stderr)
56+
57+
var (
58+
verbose = flags.Bool("verbose", false, "enable debug log level")
59+
cdpws = flags.String("cdp", env("CDPCLI_WS", CdpWSDefault), "cdp ws to connect")
60+
)
61+
62+
// usage func declaration.
63+
exec := args[0]
64+
flags.Usage = func() {
65+
fmt.Fprintf(stderr, "usage: %s <url>]\n", exec)
66+
fmt.Fprintf(stderr, "chromedp fetch url and click on `campfire-commerce`.\n")
67+
fmt.Fprintf(stderr, "\nCommand line options:\n")
68+
flags.PrintDefaults()
69+
fmt.Fprintf(stderr, "\nEnvironment vars:\n")
70+
fmt.Fprintf(stderr, "\tCDPCLI_WS\tdefault %s\n", CdpWSDefault)
71+
}
72+
if err := flags.Parse(args[1:]); err != nil {
73+
return err
74+
}
75+
76+
if *verbose {
77+
slog.SetLogLoggerLevel(slog.LevelDebug)
78+
}
79+
80+
args = flags.Args()
81+
if len(args) != 1 {
82+
return errors.New("url is required")
83+
}
84+
url := args[0]
85+
86+
ctx, cancel := chromedp.NewRemoteAllocator(ctx,
87+
*cdpws, chromedp.NoModifyURL,
88+
)
89+
defer cancel()
90+
91+
// build context options
92+
var opts []chromedp.ContextOption
93+
if *verbose {
94+
opts = append(opts, chromedp.WithDebugf(log.Printf))
95+
}
96+
97+
ctx, cancel = chromedp.NewContext(ctx, opts...)
98+
defer cancel()
99+
100+
// ensure the first tab is created
101+
if err := chromedp.Run(ctx); err != nil {
102+
return fmt.Errorf("new tab: %w", err)
103+
}
104+
105+
// Navigate and click on the link
106+
err := chromedp.Run(ctx,
107+
chromedp.Navigate(url),
108+
chromedp.Click("a[href='campfire-commerce/']", chromedp.ByQuery),
109+
)
110+
if err != nil {
111+
return fmt.Errorf("click: %w", err)
112+
}
113+
114+
// Validation
115+
var currentURL string
116+
var priceText string
117+
var reviewNames []string
118+
var reviewTexts []string
119+
err = chromedp.Run(ctx,
120+
chromedp.Location(&currentURL),
121+
chromedp.Text("#product-price", &priceText, chromedp.NodeVisible, chromedp.ByQuery),
122+
chromedp.Evaluate(`Array.from(document.querySelectorAll('#product-reviews > div h4')).map(e => e.textContent)`, &reviewNames),
123+
chromedp.Evaluate(`Array.from(document.querySelectorAll('#product-reviews > div p')).map(e => e.textContent)`, &reviewTexts),
124+
)
125+
if err != nil {
126+
return fmt.Errorf("checks failed: %w", err)
127+
}
128+
if currentURL != "http://127.0.0.1:1234/campfire-commerce/" {
129+
return errors.New("the new page URL is not as expected")
130+
}
131+
if priceText != "$244.99" {
132+
return fmt.Errorf("incorrect product price: %s", priceText)
133+
}
134+
if len(reviewNames) != 3 || len(reviewTexts) != 3 {
135+
return errors.New("incorrect reviews count")
136+
}
137+
138+
return nil
139+
}
140+
141+
// env returns the env value corresponding to the key or the default string.
142+
func env(key, dflt string) string {
143+
val, ok := os.LookupEnv(key)
144+
if !ok {
145+
return dflt
146+
}
147+
148+
return val
149+
}

runner/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func run(ctx context.Context, args []string, stdout, stderr io.Writer) error {
106106
{Bin: "node", Args: []string{"playwright/click.js"}},
107107
{Bin: "go", Args: []string{"run", "fetch/main.go", "http://127.0.0.1:1234/"}, Dir: "chromedp"},
108108
{Bin: "go", Args: []string{"run", "links/main.go", "http://127.0.0.1:1234/"}, Dir: "chromedp"},
109+
{Bin: "go", Args: []string{"run", "click/main.go", "http://127.0.0.1:1234/"}, Dir: "chromedp"},
109110
} {
110111
if *verbose {
111112
t.Stderr = stderr

0 commit comments

Comments
 (0)