blob: 35811588309838e58ca2228870e9d0b484168249 [file] [log] [blame]
// Copyright 2021 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 screenshot contains code to test the screenshot library.
package screenshot
import (
"context"
"strings"
"time"
"chromiumos/tast/errors"
"chromiumos/tast/local/chrome/uiauto"
"chromiumos/tast/local/chrome/uiauto/filesapp"
"chromiumos/tast/local/chrome/uiauto/nodewith"
"chromiumos/tast/local/chrome/uiauto/role"
"chromiumos/tast/local/screenshot"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: ScreenDiff,
Desc: "Test to confirm that the screen diffing library works as intended",
Contacts: []string{"msta@google.com", "chrome-engprod@google.com"},
SoftwareDeps: []string{"chrome"},
Attr: []string{"group:mainline", "informational"},
Vars: screenshot.ScreenDiffVars,
})
}
// expectError returns an error if the error returned doesn't match the expectation.
func expectError(err error, expectation string) error {
if err == nil {
return errors.New("expected an error but didn't get it")
}
if !strings.Contains(err.Error(), expectation) {
return errors.Wrapf(err, "expected an error containing the string %s, but got the error: ", expectation)
}
return nil
}
func takeScreenshots(ctx context.Context, d screenshot.Differ) error {
_, err := filesapp.Launch(ctx, d.Tconn())
if err != nil {
return err
}
noRetries := screenshot.Timeout(500 * time.Millisecond)
if err := expectError(
d.Diff(ctx, "nomatches", nodewith.ClassName("MissingClassName"), noRetries)(ctx),
"failed to find node"); err != nil {
return errors.Wrap(err, "diffing with no matching elements succeeded")
}
if err := expectError(
d.Diff(ctx, "nomatchesinwindow", nodewith.ClassName("UnifiedSystemTray"), noRetries)(ctx),
"failed to find node"); err != nil {
return errors.Wrap(err, "diffing with the matching element outside of the window succeeded")
}
if err := expectError(
d.Diff(ctx, "multiplematches", nodewith.Name("My Files"), noRetries)(ctx),
"failed to find node"); err != nil {
return errors.Wrap(err, "diffing with multiple matching elements succeeded")
}
ui := uiauto.New(d.Tconn())
// We take various screenshots to test various different things:
// * System UI elements,
// * Icons with no text
// * Standalone text
// * Text with icons
// * Elements that may or may not have a fixed size
// * Elements with dynamic content inside them
// This should not be done by other users of the screen diff library.
// We only do this to attempt to determine how screenshots of different types
// of elements are affected by device-specific configuration.
ejectButton := nodewith.Name("Eject device").Role(role.Button).First()
if err := uiauto.Combine("take screenshots of files app",
// Device ejection is reset upon chrome start. The next test will still have the device.
ui.IfSuccessThen(ui.Exists(ejectButton),
uiauto.Combine("Eject device", ui.LeftClick(ejectButton), ui.WaitUntilGone(ejectButton))),
d.Diff(ctx, "minMaxClose",
nodewith.ClassName("FrameCaptionButtonContainerView")),
d.Diff(ctx, "searchButton", nodewith.Name("Search").Role(role.Button)),
d.Diff(ctx, "recentText", nodewith.Name("Recent").Role(role.StaticText)),
d.Diff(ctx, "recentItem", nodewith.Name("Recent").Role(role.TreeItem)),
d.Diff(ctx, "tree", nodewith.Role(role.Tree)),
ui.WaitUntilGone(nodewith.Role(role.ProgressIndicator)),
d.Diff(ctx, "welcomeMessage", nodewith.ClassName("holding-space-welcome")),
d.Diff(ctx, "tableHeader", nodewith.ClassName("table-header")),
d.Diff(ctx, "tableRow", nodewith.ClassName("table-row directory")),
d.DiffWindow(ctx, "filesApp"))(ctx); err != nil {
return err
}
if err := expectError(
d.Diff(ctx, "filesApp", nodewith.First())(ctx),
"screenshot has already been taken"); err != nil {
return errors.Wrap(err, "sending the same diff twice succeeded: ")
}
return nil
}
func ScreenDiff(ctx context.Context, s *testing.State) {
screenDiffConfig := screenshot.Config{
DefaultOptions: screenshot.Options{
WindowWidthDP: 1000,
WindowHeightDP: 632,
RemoveElements: []*nodewith.Finder{nodewith.ClassName("date")}},
NameSuffix: "V2"}
// Normally the next line would be "defer d.DieOnFailedDiffs()"
// However, in our case, we want to run both this and DiffPerConfig.
d, err := screenshot.NewDiffer(ctx, s, screenDiffConfig)
if err != nil {
s.Fatal("Failed to initialize differ: ", err)
}
if err := expectError(
d.Diff(ctx, "nowindowopen", nodewith.ClassName("FrameCaptionButton"), screenshot.Timeout(500*time.Millisecond))(ctx),
"unable to find focused window"); err != nil {
s.Fatal("Diffing with no window open succeeded: ", err)
}
if err := takeScreenshots(ctx, d); err != nil {
s.Fatal("Failed to screenshot with single config: ", err)
}
failedSingle := d.GetFailedDiffs()
// Unfortunately, it's not possible to test that images fail on gold, because
// gold would then comment on everyone's CLs saying that they failed this test.
// TODO(crbug.com/1173812): Once ThoroughConfigs has more than one element, switch to ThoroughConfigs()
failedMulti := screenshot.DiffPerConfig(ctx, s, screenshot.WithBase(screenDiffConfig, []screenshot.Config{}), func(d screenshot.Differ) {
if err := takeScreenshots(ctx, d); err != nil {
s.Fatal("Failed to take screenshot with multiple configs: ", err)
}
})
if failedSingle != nil && failedMulti != nil {
s.Fatalf("Failed both single and multi-config diffs: single-config %s AND multi-config %s", failedSingle, failedMulti)
} else if failedSingle != nil {
s.Fatal("Failed single-config diffs: ", failedSingle)
} else if failedMulti != nil {
s.Fatal("Failed multi-config diffs: ", failedMulti)
}
}