| title | description |
|---|---|
Development Guide |
How to build, test, and contribute to go-webview -- prerequisites, test patterns, coding standards, and extension guides. |
Go 1.26 or later is required. The module path is dappco.re/go/core/webview.
A running Chrome or Chromium instance with the remote debugging port enabled is required for any tests or usage that exercises the CDP connection. The package does not launch Chrome itself.
Start Chrome with the remote debugging port:
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222
# Headless (suitable for CI)
google-chrome \
--headless=new \
--remote-debugging-port=9222 \
--no-sandbox \
--disable-gpuThe default debug URL is http://localhost:9222. Verify it is reachable by visiting http://localhost:9222/json in a browser or with curl.
The only runtime dependency is github.com/gorilla/websocket v1.5.3, declared in go.mod. Fetch dependencies with:
go mod downloadgo test ./...Tests must pass before committing. The integration tests in webview_test.go that reference a live browser (TestNew_Bad_InvalidDebugURL) are designed to fail gracefully -- they assert that the error is non-nil when connecting to an unavailable port.
# Run a specific test
go test -v -run TestActionSequence_Good ./...
# Run all tests with verbose output
go test -v ./...gofmt -w .
go vet ./...Tests follow the _Good, _Bad, _Ugly suffix pattern, consistent with the broader Core Go ecosystem:
_Good-- happy path, verifies correct behaviour under valid input._Bad-- expected error conditions, verifies that errors are returned and have the correct shape._Ugly-- panic/edge cases, unexpected or degenerate inputs.
All test functions use the standard testing.T interface; the project does not use a test framework.
To add tests that exercise the full CDP stack in CI:
- Start Chrome in headless mode in the CI job before running
go test. - Serve test fixtures using
net/http/httptestso tests do not depend on external URLs. - Use
WithTimeoutto set conservative deadlines appropriate for the CI environment.
New source files belong in the root package (package webview). The package is intentionally a single flat package; do not create sub-packages.
Keep separation between layers:
| Layer | File | Guidance |
|---|---|---|
| CDP transport | cdp.go |
Do not put browser-level logic here. |
| High-level API | webview.go |
Methods here should be safe to call from application code without CDP knowledge. |
| Action types | actions.go |
Add new action types here; keep each action focused on a single interaction. |
| Diagnostics | console.go |
Console and exception capture live here. |
| SPA helpers | angular.go |
Framework-specific helpers belong here or in a new file named after the framework (e.g. react.go, vue.go). |
UK English throughout all source comments, documentation, commit messages, and identifiers where natural language appears. Use "colour", "organisation", "behaviour", "initialise", not their American equivalents.
Standard gofmt formatting is mandatory. Run before committing:
gofmt -w .- All exported functions must have Go doc comments.
- Use
fmt.Errorf("context: %w", err)for error wrapping so callers can useerrors.Isanderrors.As. - Return errors; do not panic in library code.
- Use
context.Contextfor all operations that involve I/O or waiting so callers can impose deadlines.
- Protect shared mutable state with
sync.RWMutex(read lock for reads, write lock for writes). - Do not call handlers or callbacks while holding a lock. Copy the slice of handlers, release the lock, then call them.
- CDP WebSocket writes are serialised with a dedicated mutex in
CDPClient; do not write toconndirectly from outsidecdp.go.
Every Go source file must begin with:
// SPDX-License-Identifier: EUPL-1.2The project is licenced under the European Union Public Licence 1.2 (EUPL-1.2).
Use conventional commits:
type(scope): description
Common types: feat, fix, docs, test, refactor, chore.
Example scopes: cdp, angular, console, actions.
All commits must include the co-author trailer:
Co-Authored-By: Virgil <[email protected]>
Full example:
feat(console): add ExceptionWatcher with stack trace capture
Subscribes to Runtime.exceptionThrown events and exposes a reactive
WaitForException API consistent with ConsoleWatcher.
Co-Authored-By: Virgil <[email protected]>
- Define a struct in
actions.gowith exported fields for the action's parameters. - Implement
Execute(ctx context.Context, wv *Webview) erroron the struct. - Add a builder method on
ActionSequencethat appends the new action. - Add a
_Goodtest inwebview_test.gothat verifies the struct fields are set correctly.
Example:
// SubmitAction submits a form element.
type SubmitAction struct {
Selector string
}
func (a SubmitAction) Execute(ctx context.Context, wv *Webview) error {
script := fmt.Sprintf("document.querySelector(%q)?.submit()", a.Selector)
_, err := wv.evaluate(ctx, script)
return err
}
func (s *ActionSequence) Submit(selector string) *ActionSequence {
return s.Add(SubmitAction{Selector: selector})
}Add methods to AngularHelper in angular.go. Follow the established pattern:
- Obtain a context with the helper's timeout using
context.WithTimeout. - Build the JavaScript as a self-invoking function expression
(function() { ... })(). - Call
ah.wv.evaluate(ctx, script)to execute it. - After state-modifying operations, call
TriggerChangeDetection()or inlineappRef.tick(). - For polling-based waits, use a
time.NewTickerat 100 ms and select overctx.Done().
To add support for a different single-page application framework (e.g. React, Vue):
- Create a new file named after the framework (e.g.
react.go). - Define a helper struct that holds a
*Webviewreference and a configurable timeout. - Use
evaluate()to inject JavaScript that probes framework-specific globals and APIs. - Follow the same
context.WithTimeout+ polling pattern established inangular.go.
Push to the canonical remote via SSH:
git push ssh://[email protected]:2223/core/go-webview.git HEAD:mainHTTPS authentication is not available on this remote.