blob: 114235ca7a783469072f09f50152d8a0d4718e9f [file]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package sshot supports taking screenshots on devices during testing.
package sshot
import (
"context"
"image/png"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"time"
"chromiumos/tast/errors"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/colorcmp"
"chromiumos/tast/testing"
)
// SShot opens a new tab in Chrome which will retrieve a page from a local
// webserver we instantiate which renders just a solid orange background. We then
// use the passed in function to take a screenshot which we then check for having
// a majority of the pixels match our target color.
func SShot(ctx context.Context, s *testing.State, cr *chrome.Chrome, capture func(ctx context.Context, path string) error) error {
// Show a page with orange background.
const html = "<style>body { background-color: #c84; }</style>"
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/html")
io.WriteString(w, html)
}))
defer server.Close()
conn, err := cr.NewConn(ctx, server.URL)
if err != nil {
s.Fatal("Creating renderer failed: ", err)
}
defer conn.Close()
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Creating test API connection failed: ", err)
}
if err := tconn.Call(ctx, nil, `async() => {
const window = await tast.promisify(chrome.windows.getLastFocused)({});
await tast.promisify(chrome.windows.update)(window.id, {state: 'maximized'});
}`); err != nil {
s.Fatal("Maximizing the window failed: ", err)
}
const screenshotName = "screenshot.png"
path := filepath.Join(s.OutDir(), screenshotName)
// The largest differing color known to date and is #ba8b4a on sumo in
// comparison to a target of #cc8844, so this value should be no less than
// 0x12.
const maxKnownColorDiff = 0x13
expectedColor := colorcmp.RGB(0xcc, 0x88, 0x44)
// Allow up to 10 seconds for the target screen to render.
return testing.Poll(ctx, func(ctx context.Context) error {
if err := capture(ctx, path); err != nil {
return err
}
f, err := os.Open(path)
if err != nil {
s.Fatal("Failed opening the screenshot image: ", err)
}
defer f.Close()
im, err := png.Decode(f)
if err != nil {
s.Fatal("Failed decoding the screenshot image: ", err)
}
color, ratio := colorcmp.DominantColor(im)
if ratio >= 0.5 && colorcmp.ColorsMatch(color, expectedColor, maxKnownColorDiff) {
s.Logf("Got close-enough color %v at ratio %0.2f (expected %v)",
colorcmp.ColorStr(color), ratio, colorcmp.ColorStr(expectedColor))
return nil
}
return errors.Errorf("screenshot did not have matching dominant color; expected %v but got %v at ratio %0.2f",
colorcmp.ColorStr(expectedColor), colorcmp.ColorStr(color), ratio)
}, &testing.PollOptions{Timeout: 10 * time.Second})
}