mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-09-07 15:07:17 +00:00
test(player): add browser-level compatibility tests via chromedp
Adds two opt-in tests (build tag "browsertest", run via `make test-browser`) that drive a real headless Chrome instead of only asserting on the raw HTML/JS source: - TestPlayerRendersNatively confirms the shipped page still renders normally and never injects es-module-shims on a browser with native import map support. - TestPlayerRendersUnderForcedShimMode forces es-module-shims into its own shimMode (importmap-shim/module-shim, per the library's docs), routing the real app.js and vendored dependencies through the library's actual polyfill resolution. This exercises the old-Safari code path directly in CI/local headless Chrome, without needing physical iPadOS 15 hardware. Not wired into `test`/`check`/CI yet, since chromedp has not previously been exercised as part of this repo's test suite (only in the standalone doc-screenshot tool) and needs a Chrome/Chromium binary available to the runner. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
966d9962a5
commit
efcb96998f
@@ -1,4 +1,4 @@
|
||||
.PHONY: all build build-cli test test-coverage test-http-client test-http-client-rotate check fmt vet lint clean dev help screenshots build-stockholm-image prepare-stockholm update-static-deps dev-docs dev-docs-tidy hugo
|
||||
.PHONY: all build build-cli test test-coverage test-browser test-http-client test-http-client-rotate check fmt vet lint clean dev help screenshots build-stockholm-image prepare-stockholm update-static-deps dev-docs dev-docs-tidy hugo
|
||||
|
||||
# Load .env if present (simple KEY=VALUE format, no shell quoting)
|
||||
-include .env
|
||||
@@ -147,6 +147,15 @@ test-coverage:
|
||||
$(GOCMD) tool cover -html=coverage.out -o coverage.html
|
||||
@echo "Coverage report generated: coverage.html"
|
||||
|
||||
# Browser-level regression tests for the embedded player's static assets
|
||||
# (see pkg/service/soundtouchweb/browser_compatibility_test.go). Opt-in via
|
||||
# the "browsertest" build tag, not part of `test`/`check`, since they need a
|
||||
# Chrome/Chromium binary that chromedp can find on PATH or in a standard
|
||||
# install location.
|
||||
test-browser:
|
||||
@echo "Running browser-level compatibility tests..."
|
||||
$(GOTEST) -tags browsertest -v ./pkg/service/soundtouchweb/...
|
||||
|
||||
check: fmt vet test test-http-client
|
||||
|
||||
# Archive any existing tests/integration/testdata/ to a timestamped sibling
|
||||
@@ -501,6 +510,7 @@ help:
|
||||
@echo " build-linux-armv7 - Build for Linux ARMv7 (kernel 3.14+ compatible, CGO_ENABLED=0)"
|
||||
@echo " test - Run tests"
|
||||
@echo " test-coverage - Run tests with coverage report"
|
||||
@echo " test-browser - Run browser-level (chromedp) player compatibility tests"
|
||||
@echo " test-http-client - Run .http integration tests via Docker Compose"
|
||||
@echo " test-http-client-rotate - Archive tests/integration/testdata/ before a fresh run (non-destructive)"
|
||||
@echo " check - Run fmt, vet, and tests"
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
//go:build browsertest
|
||||
|
||||
// Package soundtouchweb browser-level regression tests for #649. These drive
|
||||
// a real headless Chrome via chromedp (already a project dependency, used
|
||||
// today for the doc-screenshot tool) instead of only asserting on the raw
|
||||
// HTML/JS source. They are opt-in (build tag "browsertest", run via `make
|
||||
// test-browser`) rather than part of the default `go test ./...`/`make
|
||||
// check` path, since they require a Chrome/Chromium binary to be present --
|
||||
// see CONTRIBUTING or the Makefile for how to run them locally or in CI.
|
||||
package soundtouchweb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/chromedp"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// newHeadlessChromeContext returns a context bound to a fresh headless
|
||||
// Chrome instance, torn down automatically at the end of the test.
|
||||
func newHeadlessChromeContext(t *testing.T) context.Context {
|
||||
t.Helper()
|
||||
|
||||
allocCtx, cancelAlloc := chromedp.NewExecAllocator(context.Background(),
|
||||
append(chromedp.DefaultExecAllocatorOptions[:],
|
||||
chromedp.Flag("headless", true),
|
||||
chromedp.Flag("disable-gpu", true),
|
||||
// CI runners commonly execute as a user without the namespace
|
||||
// permissions Chrome's sandbox needs; harmless to also set
|
||||
// locally.
|
||||
chromedp.Flag("no-sandbox", true),
|
||||
)...,
|
||||
)
|
||||
t.Cleanup(cancelAlloc)
|
||||
|
||||
ctx, cancelCtx := chromedp.NewContext(allocCtx)
|
||||
t.Cleanup(cancelCtx)
|
||||
|
||||
ctx, cancelTimeout := context.WithTimeout(ctx, 30*time.Second)
|
||||
t.Cleanup(cancelTimeout)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// TestPlayerRendersNatively confirms the shipped page (native import maps,
|
||||
// es-module-shims left uninjected) still renders in an ordinary modern
|
||||
// browser -- i.e. that restoring import maps for #649 didn't break the
|
||||
// common case for the vast majority of users who never need the shim.
|
||||
func TestPlayerRendersNatively(t *testing.T) {
|
||||
app := NewWebApp()
|
||||
r := chi.NewRouter()
|
||||
app.Mount(r, nil)
|
||||
|
||||
server := httptest.NewServer(r)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
ctx := newHeadlessChromeContext(t)
|
||||
|
||||
var shimInjected bool
|
||||
if err := chromedp.Run(ctx,
|
||||
chromedp.Navigate(server.URL+"/app"),
|
||||
chromedp.WaitVisible(`.nav-discover-icon`, chromedp.ByQuery),
|
||||
chromedp.Evaluate(`document.querySelectorAll('script[src*="es-module-shims"]').length > 0`, &shimInjected),
|
||||
); err != nil {
|
||||
t.Fatalf("chromedp run: %v", err)
|
||||
}
|
||||
|
||||
if shimInjected {
|
||||
t.Error("es-module-shims should not be injected on a browser with native import map support")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerRendersUnderForcedShimMode exercises the actual old-Safari code
|
||||
// path -- es-module-shims resolving the same import map and vendored files
|
||||
// the real app uses -- without needing physical iPadOS 15 hardware. It
|
||||
// serves a variant of index.html that forces es-module-shims into shimMode
|
||||
// (see the library's README: shimMode is triggered by
|
||||
// window.esmsInitOptions.shimMode or by using importmap-shim/module-shim
|
||||
// script types), which routes every browser -- including this ordinary
|
||||
// headless Chrome -- through the library's own polyfill resolution instead
|
||||
// of native import map support.
|
||||
func TestPlayerRendersUnderForcedShimMode(t *testing.T) {
|
||||
app := NewWebApp()
|
||||
r := chi.NewRouter()
|
||||
app.MountWeb(r, nil) // only need /app/static/* and /api/control/*
|
||||
|
||||
const shimModePage = `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>window.esmsInitOptions = { shimMode: true };</script>
|
||||
<script src="/app/static/lib/es-module-shims.js"></script>
|
||||
<script type="importmap-shim">
|
||||
{
|
||||
"imports": {
|
||||
"preact": "/app/static/lib/preact.module.js",
|
||||
"preact/hooks": "/app/static/lib/preact-hooks.module.js",
|
||||
"htm": "/app/static/lib/htm.module.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="/app/static/css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module-shim" src="/app/static/js/app.js"></script>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
r.Get("/test-shim-mode", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
_, _ = w.Write([]byte(shimModePage))
|
||||
})
|
||||
|
||||
server := httptest.NewServer(r)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
ctx := newHeadlessChromeContext(t)
|
||||
|
||||
var rendered bool
|
||||
if err := chromedp.Run(ctx,
|
||||
chromedp.Navigate(server.URL+"/test-shim-mode"),
|
||||
chromedp.WaitVisible(`.nav-discover-icon`, chromedp.ByQuery),
|
||||
chromedp.Evaluate(`document.getElementById('app').children.length > 0`, &rendered),
|
||||
); err != nil {
|
||||
t.Fatalf("chromedp run (forced shim mode): %v", err)
|
||||
}
|
||||
|
||||
if !rendered {
|
||||
t.Error("app did not render under forced es-module-shims shim mode")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user