Skip to content

Commit f2761fb

Browse files
committed
feat: add fix && tests
1 parent 36c7f00 commit f2761fb

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

images/chromium-headless/image/wrapper.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ if [ -z "${CHROMIUM_FLAGS:-}" ]; then
7070
--no-first-run \
7171
--no-sandbox \
7272
--no-service-autorun \
73-
--no-startup-window \
7473
--ozone-platform=headless \
7574
--password-store=basic \
7675
--unsafely-disable-devtools-self-xss-warnings \

server/e2e/e2e_chromium_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,3 +810,77 @@ func TestPlaywrightExecuteAPI(t *testing.T) {
810810

811811
logger.Info("[test]", "result", "playwright execute API test passed")
812812
}
813+
814+
// TestCDPTargetCreation tests that headless browsers can create new targets via CDP.
815+
func TestCDPTargetCreation(t *testing.T) {
816+
image := headlessImage
817+
name := containerName + "-cdp-target"
818+
819+
logger := slog.New(slog.NewTextHandler(t.Output(), &slog.HandlerOptions{Level: slog.LevelInfo}))
820+
baseCtx := logctx.AddToContext(context.Background(), logger)
821+
822+
if _, err := exec.LookPath("docker"); err != nil {
823+
require.NoError(t, err, "docker not available: %v", err)
824+
}
825+
826+
// Clean slate
827+
_ = stopContainer(baseCtx, name)
828+
829+
// Start container
830+
width, height := 1024, 768
831+
_, exitCh, err := runContainer(baseCtx, image, name, map[string]string{"WIDTH": strconv.Itoa(width), "HEIGHT": strconv.Itoa(height)})
832+
require.NoError(t, err, "failed to start container: %v", err)
833+
defer stopContainer(baseCtx, name)
834+
835+
ctx, cancel := context.WithTimeout(baseCtx, 2*time.Minute)
836+
defer cancel()
837+
838+
logger.Info("[test]", "action", "waiting for API")
839+
require.NoError(t, waitHTTPOrExit(ctx, apiBaseURL+"/spec.yaml", exitCh), "api not ready")
840+
841+
// Wait for CDP endpoint to be ready (via the devtools proxy)
842+
logger.Info("[test]", "action", "waiting for CDP endpoint")
843+
require.NoError(t, waitTCP(ctx, "127.0.0.1:9222"), "CDP endpoint not ready")
844+
845+
// Wait for Chromium to be fully initialized by checking if CDP responds
846+
logger.Info("[test]", "action", "waiting for Chromium to be fully ready")
847+
var initialTargets []map[string]interface{}
848+
targets, err := listCDPTargets(ctx)
849+
if err == nil {
850+
initialTargets = targets
851+
}
852+
853+
// Use CDP HTTP API to list targets (avoids Playwright's implicit page creation)
854+
logger.Info("[test]", "action", "listing initial targets via CDP HTTP API")
855+
initialPageCount := 0
856+
for _, target := range initialTargets {
857+
if targetType, ok := target["type"].(string); ok && targetType == "page" {
858+
initialPageCount++
859+
}
860+
}
861+
logger.Info("[test]", "initial_page_count", initialPageCount, "total_targets", len(initialTargets))
862+
863+
// Headless browser should start with at least 1 page target.
864+
// If --no-startup-window is enabled, the browser will start with 0 pages,
865+
// which will cause Target.createTarget to fail with "no browser is open (-32000)".
866+
require.GreaterOrEqual(t, initialPageCount, 1,
867+
"headless browser should start with at least 1 page target (got %d). "+
868+
"This usually means --no-startup-window flag is enabled in wrapper.sh, "+
869+
"which causes browsers to start without any pages.", initialPageCount)
870+
}
871+
872+
// listCDPTargets lists all CDP targets via the HTTP API (inside the container)
873+
func listCDPTargets(ctx context.Context) ([]map[string]interface{}, error) {
874+
// Use the internal CDP HTTP endpoint (port 9223) inside the container
875+
stdout, err := execCombinedOutput(ctx, "curl", []string{"-s", "http://localhost:9223/json/list"})
876+
if err != nil {
877+
return nil, fmt.Errorf("curl failed: %w, output: %s", err, stdout)
878+
}
879+
880+
var targets []map[string]interface{}
881+
if err := json.Unmarshal([]byte(stdout), &targets); err != nil {
882+
return nil, fmt.Errorf("failed to parse targets JSON: %w, output: %s", err, stdout)
883+
}
884+
885+
return targets, nil
886+
}

0 commit comments

Comments
 (0)