auth-ui: rewrite ui
Change-Id: I6f00867015ec77aa7e336e89da4dc1b081e330c6
diff --git a/core/auth/ui/e2e/browser.go b/core/auth/ui/e2e/browser.go
index 19949f5..a21753a 100644
--- a/core/auth/ui/e2e/browser.go
+++ b/core/auth/ui/e2e/browser.go
@@ -99,6 +99,34 @@
Cleanup(func())
}
+type browserSize struct {
+ Width int `json:"width"`
+ Height int `json:"height"`
+}
+
+type browserSessionOptions struct {
+ Viewport browserSize
+ VideoSize browserSize
+ ReducedMotion bool
+}
+
+func defaultBrowserSessionOptions() browserSessionOptions {
+ return browserSessionOptions{
+ Viewport: browserSize{Width: 1280, Height: 720},
+ VideoSize: browserSize{Width: 1280, Height: 720},
+ }
+}
+
+func validateBrowserSessionOptions(options browserSessionOptions) error {
+ if options.Viewport.Width <= 0 || options.Viewport.Height <= 0 {
+ return fmt.Errorf("browser viewport must have positive dimensions")
+ }
+ if options.VideoSize.Width <= 0 || options.VideoSize.Height <= 0 {
+ return fmt.Errorf("browser video must have positive dimensions")
+ }
+ return nil
+}
+
type browserSession struct {
Page playwright.Page
Context playwright.BrowserContext
@@ -106,6 +134,8 @@
dir string
video playwright.Video
started time.Time
+ viewport browserSize
+ videoSize browserSize
screenshots []string
checkpoint int
finalize sync.Once
@@ -117,6 +147,8 @@
blocked []string
requestsMu sync.Mutex
requests []requestMetadata
+ diagnosticsMu sync.Mutex
+ diagnostics []string
tracingStarted bool
screenshotOp func(string) error
stopTraceOp func(string) error
@@ -126,10 +158,18 @@
}
func newBrowserSession(t testReporter, browser playwright.Browser, root string, allowedOrigins []string) (*browserSession, error) {
+ return newBrowserSessionWithOptions(t, browser, root, allowedOrigins, defaultBrowserSessionOptions())
+}
+
+func newBrowserSessionWithOptions(t testReporter, browser playwright.Browser, root string, allowedOrigins []string, options browserSessionOptions) (*browserSession, error) {
+ if err := validateBrowserSessionOptions(options); err != nil {
+ return nil, err
+ }
session, err := newBrowserSessionOwner(t, root, browser.Version())
if err != nil {
return nil, err
}
+ assignBrowserSessionMetadata(session, options)
// Register while holding the construction/finalization lock. A watchdog
// either snapshots this ownership and waits here, or rejects construction
// before any external Playwright context exists.
@@ -144,11 +184,15 @@
}
defer session.lifecycleMu.Unlock()
videoDir := filepath.Join(session.dir, ".video")
- context, err := browser.NewContext(playwright.BrowserNewContextOptions{
- Viewport: &playwright.Size{Width: 1280, Height: 720},
- RecordVideo: &playwright.RecordVideo{Dir: playwright.String(videoDir), Size: &playwright.Size{Width: 1280, Height: 720}},
+ contextOptions := playwright.BrowserNewContextOptions{
+ Viewport: &playwright.Size{Width: options.Viewport.Width, Height: options.Viewport.Height},
+ RecordVideo: &playwright.RecordVideo{Dir: playwright.String(videoDir), Size: &playwright.Size{Width: options.VideoSize.Width, Height: options.VideoSize.Height}},
ServiceWorkers: playwright.ServiceWorkerPolicyBlock,
- })
+ }
+ if options.ReducedMotion {
+ contextOptions.ReducedMotion = playwright.ReducedMotionReduce
+ }
+ context, err := browser.NewContext(contextOptions)
if err != nil {
return nil, err
}
@@ -169,6 +213,14 @@
page.OnResponse(func(response playwright.Response) {
session.recordRequest(response.Request().Method(), response.Status(), response.Request().URL())
})
+ page.OnConsole(func(message playwright.ConsoleMessage) {
+ if message.Type() == "error" && !isExpectedFormStatusConsoleError(message.Text()) {
+ session.recordDiagnostic("console error: " + message.Text())
+ }
+ })
+ page.OnPageError(func(err error) {
+ session.recordDiagnostic("page error: " + err.Error())
+ })
s := session
s.Page = page
s.video = page.Video()
@@ -189,6 +241,11 @@
return s, nil
}
+func assignBrowserSessionMetadata(session *browserSession, options browserSessionOptions) {
+ session.viewport = options.Viewport
+ session.videoSize = options.VideoSize
+}
+
func newBrowserSessionOwner(t testReporter, root, browserVersion string) (*browserSession, error) {
dir := filepath.Join(root, sanitizeName(t.Name()))
if err := os.MkdirAll(filepath.Join(dir, "screenshots"), 0o700); err != nil {
@@ -197,7 +254,8 @@
if err := os.MkdirAll(filepath.Join(dir, ".video"), 0o700); err != nil {
return nil, err
}
- session := &browserSession{t: t, dir: dir, started: time.Now().UTC(), browserVer: browserVersion}
+ defaults := defaultBrowserSessionOptions()
+ session := &browserSession{t: t, dir: dir, started: time.Now().UTC(), browserVer: browserVersion, viewport: defaults.Viewport, videoSize: defaults.VideoSize}
session.installDefaultArtifactOps()
// Own metadata and all available partial artifacts before Playwright context
// construction. If Playwright cannot create a context/page/trace, cleanup
@@ -275,6 +333,28 @@
return sortedStrings(s.blocked)
}
+func isExpectedFormStatusConsoleError(message string) bool {
+ switch message {
+ case "Failed to load resource: the server responded with a status of 409 (Conflict)",
+ "Failed to load resource: the server responded with a status of 422 (Unprocessable Entity)":
+ return true
+ default:
+ return false
+ }
+}
+
+func (s *browserSession) recordDiagnostic(message string) {
+ s.diagnosticsMu.Lock()
+ s.diagnostics = append(s.diagnostics, message)
+ s.diagnosticsMu.Unlock()
+}
+
+func (s *browserSession) BrowserDiagnostics() []string {
+ s.diagnosticsMu.Lock()
+ defer s.diagnosticsMu.Unlock()
+ return append([]string(nil), s.diagnostics...)
+}
+
func (s *browserSession) Checkpoint(name string) error {
s.lifecycleMu.Lock()
defer s.lifecycleMu.Unlock()
@@ -369,7 +449,7 @@
if s.t.Failed() || s.forcedFailure || len(errs) > 0 {
outcome = "failed"
}
- metadata := sessionMetadata{TestName: s.t.Name(), StartedAt: s.started, FinishedAt: time.Now().UTC(), Outcome: outcome, BindingVersion: playwrightVersion, CLIVersion: playwrightCLIVersion, ChromiumRevision: chromiumRevision, BrowserVersion: s.browserVer, Screenshots: s.screenshots, FinalURL: finalURL}
+ metadata := sessionMetadata{TestName: s.t.Name(), StartedAt: s.started, FinishedAt: time.Now().UTC(), Outcome: outcome, BindingVersion: playwrightVersion, CLIVersion: playwrightCLIVersion, ChromiumRevision: chromiumRevision, BrowserVersion: s.browserVer, Viewport: s.viewport, VideoSize: s.videoSize, Screenshots: s.screenshots, FinalURL: finalURL}
data, err := json.MarshalIndent(metadata, "", " ")
if err == nil {
err = os.WriteFile(filepath.Join(s.dir, "session.json"), append(data, '\n'), 0o600)
@@ -394,23 +474,19 @@
return "passed", false
}
-const expectedExternalFontRequest = "https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/hack.min.css"
-
-func isExpectedBlockedBrowserRequest(request string) bool {
- return request == expectedExternalFontRequest
-}
-
type sessionMetadata struct {
- TestName string `json:"test_name"`
- StartedAt time.Time `json:"started_at"`
- FinishedAt time.Time `json:"finished_at"`
- Outcome string `json:"outcome"`
- BindingVersion string `json:"binding_version"`
- CLIVersion string `json:"playwright_cli_version"`
- ChromiumRevision string `json:"chromium_revision"`
- BrowserVersion string `json:"browser_version"`
- Screenshots []string `json:"screenshots"`
- FinalURL string `json:"final_url"`
+ TestName string `json:"test_name"`
+ StartedAt time.Time `json:"started_at"`
+ FinishedAt time.Time `json:"finished_at"`
+ Outcome string `json:"outcome"`
+ BindingVersion string `json:"binding_version"`
+ CLIVersion string `json:"playwright_cli_version"`
+ ChromiumRevision string `json:"chromium_revision"`
+ BrowserVersion string `json:"browser_version"`
+ Viewport browserSize `json:"viewport"`
+ VideoSize browserSize `json:"video_size"`
+ Screenshots []string `json:"screenshots"`
+ FinalURL string `json:"final_url"`
}
var unsafeName = regexp.MustCompile(`[^A-Za-z0-9._-]+`)