blob: 72b3af2c1d8fd7948c8a004fa3b130c3406c4046 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <optional>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/accessibility/accessibility_labels_service.h"
#include "chrome/browser/accessibility/accessibility_labels_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/language/core/browser/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_context.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/scoped_accessibility_mode_override.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "services/image_annotation/public/cpp/image_processor.h"
#include "services/image_annotation/public/mojom/image_annotation.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
#include "url/gurl.h"
constexpr base::FilePath::CharType kDocRoot[] =
FILE_PATH_LITERAL("chrome/test/data");
namespace {
void DescribeNodesWithAnnotations(const ui::AXNode& node,
std::vector<std::string>* descriptions) {
std::string annotation =
node.GetStringAttribute(ax::mojom::StringAttribute::kImageAnnotation);
if (!annotation.empty()) {
std::string role_str = ui::ToString(node.GetRole());
std::string name =
node.GetStringAttribute(ax::mojom::StringAttribute::kName);
if (!name.empty() && node.GetRole() != ax::mojom::Role::kRootWebArea)
descriptions->push_back(role_str + " " + name + " " + annotation);
else
descriptions->push_back(role_str + " " + annotation);
}
for (const ui::AXNode* child : node.children()) {
DescribeNodesWithAnnotations(*child, descriptions);
}
}
std::vector<std::string> DescribeNodesWithAnnotations(
const ui::AXTreeUpdate& tree_update) {
std::vector<std::string> descriptions;
if (tree_update.root_id) {
ui::AXTree tree(tree_update);
DescribeNodesWithAnnotations(*tree.root(), &descriptions);
}
return descriptions;
}
bool HasNodeWithAnnotationStatus(const ui::AXTreeUpdate& tree_update,
ax::mojom::ImageAnnotationStatus status) {
for (const auto& node_data : tree_update.nodes) {
if (node_data.GetImageAnnotationStatus() == status)
return true;
}
return false;
}
// A fake implementation of the Annotator mojo interface that
// returns predictable results based on the filename of the image
// it's asked to annotate. Enables us to test the rest of the
// system without using the real annotator that queries a back-end
// API.
class FakeAnnotator : public image_annotation::mojom::Annotator {
public:
static void SetReturnOcrResults(bool ocr) { return_ocr_results_ = ocr; }
static void SetReturnLabelResults(bool label) {
return_label_results_ = label;
}
static void AddCustomLabelResultMapping(const std::string& filename,
const std::string& label) {
custom_label_result_mapping_[filename] = label;
}
static void SetReturnErrorCode(
image_annotation::mojom::AnnotateImageError error_code) {
return_error_code_ = error_code;
}
FakeAnnotator() = default;
FakeAnnotator(const FakeAnnotator&) = delete;
FakeAnnotator& operator=(const FakeAnnotator&) = delete;
~FakeAnnotator() override = default;
void BindReceiver(
mojo::PendingReceiver<image_annotation::mojom::Annotator> receiver) {
receivers_.Add(this, std::move(receiver));
}
void AnnotateImage(
const std::string& image_id,
const std::string& description_language_tag,
mojo::PendingRemote<image_annotation::mojom::ImageProcessor>
image_processor,
AnnotateImageCallback callback) override {
if (return_error_code_) {
image_annotation::mojom::AnnotateImageResultPtr result =
image_annotation::mojom::AnnotateImageResult::NewErrorCode(
*return_error_code_);
std::move(callback).Run(std::move(result));
return;
}
// Use the filename to create annotation strings. Check a map from filename
// to desired label, otherwise just construct a string based on the
// filename. Adds some trailing whitespace and punctuation to check that
// clean-up happens correctly when combining annotation strings.
std::string image_filename = GURL(image_id).ExtractFileName();
std::string label_text;
if (base::Contains(custom_label_result_mapping_, image_filename)) {
label_text = custom_label_result_mapping_[image_filename];
} else {
label_text = image_filename + " '" + description_language_tag + "' Label";
}
std::string ocr_text = image_filename + " Annotation . ";
image_annotation::mojom::AnnotationPtr ocr_annotation =
image_annotation::mojom::Annotation::New(
image_annotation::mojom::AnnotationType::kOcr, 1.0, ocr_text);
image_annotation::mojom::AnnotationPtr label_annotation =
image_annotation::mojom::Annotation::New(
image_annotation::mojom::AnnotationType::kLabel, 1.0, label_text);
// Return enabled results as an annotation.
std::vector<image_annotation::mojom::AnnotationPtr> annotations;
if (return_ocr_results_)
annotations.push_back(std::move(ocr_annotation));
if (return_label_results_)
annotations.push_back(std::move(label_annotation));
image_annotation::mojom::AnnotateImageResultPtr result =
image_annotation::mojom::AnnotateImageResult::NewAnnotations(
std::move(annotations));
std::move(callback).Run(std::move(result));
}
private:
mojo::ReceiverSet<image_annotation::mojom::Annotator> receivers_;
static bool return_ocr_results_;
static bool return_label_results_;
static std::map<std::string, std::string> custom_label_result_mapping_;
static std::optional<image_annotation::mojom::AnnotateImageError>
return_error_code_;
};
// static
bool FakeAnnotator::return_ocr_results_ = false;
// static
bool FakeAnnotator::return_label_results_ = false;
// static
std::map<std::string, std::string> FakeAnnotator::custom_label_result_mapping_;
// static
std::optional<image_annotation::mojom::AnnotateImageError>
FakeAnnotator::return_error_code_;
// The fake ImageAnnotationService, which handles mojo calls from the renderer
// process and passes them to FakeAnnotator.
class FakeImageAnnotationService
: public image_annotation::mojom::ImageAnnotationService {
public:
FakeImageAnnotationService() = default;
FakeImageAnnotationService(const FakeImageAnnotationService&) = delete;
FakeImageAnnotationService& operator=(const FakeImageAnnotationService&) =
delete;
~FakeImageAnnotationService() override = default;
private:
// image_annotation::mojom::ImageAnnotationService:
void BindAnnotator(mojo::PendingReceiver<image_annotation::mojom::Annotator>
receiver) override {
annotator_.BindReceiver(std::move(receiver));
}
FakeAnnotator annotator_;
};
void BindImageAnnotatorService(
mojo::PendingReceiver<image_annotation::mojom::ImageAnnotationService>
receiver) {
mojo::MakeSelfOwnedReceiver(std::make_unique<FakeImageAnnotationService>(),
std::move(receiver));
}
} // namespace
class ImageAnnotationBrowserTest : public InProcessBrowserTest {
public:
ImageAnnotationBrowserTest()
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
https_server_.AddDefaultHandlers(base::FilePath(kDocRoot));
}
ImageAnnotationBrowserTest(const ImageAnnotationBrowserTest&) = delete;
ImageAnnotationBrowserTest& operator=(const ImageAnnotationBrowserTest&) =
delete;
protected:
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(https_server_.Start());
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
AccessibilityLabelsServiceFactory::GetForProfile(browser()->profile())
->OverrideImageAnnotatorBinderForTesting(
base::BindRepeating(&BindImageAnnotatorService));
scoped_accessibility_mode_.emplace(
web_contents, ui::kAXModeComplete | ui::AXMode::kLabelImages);
SetAcceptLanguages("en,fr");
}
void TearDownOnMainThread() override {
scoped_accessibility_mode_.reset();
AccessibilityLabelsServiceFactory::GetForProfile(browser()->profile())
->OverrideImageAnnotatorBinderForTesting(base::NullCallback());
InProcessBrowserTest::TearDownOnMainThread();
}
void SetAcceptLanguages(const std::string& accept_languages) {
content::BrowserContext* context =
static_cast<content::BrowserContext*>(browser()->profile());
DCHECK(context);
PrefService* prefs = user_prefs::UserPrefs::Get(context);
DCHECK(prefs);
prefs->Set(language::prefs::kSelectedLanguages,
base::Value(accept_languages));
}
protected:
net::EmbeddedTestServer https_server_;
std::optional<content::ScopedAccessibilityModeOverride>
scoped_accessibility_mode_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
AnnotateImageInAccessibilityTree) {
FakeAnnotator::SetReturnOcrResults(true);
FakeAnnotator::SetReturnLabelResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL("/accessibility/image_annotation.html")));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
web_contents,
"Appears to say: red.png Annotation. Appears to be: red.png 'en' Label");
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImagesInLinks) {
FakeAnnotator::SetReturnOcrResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_link.html")));
// Block until the accessibility tree has at least 8 annotations. If
// that never happens, the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
while (10 > DescribeNodesWithAnnotations(
content::GetAccessibilityTreeSnapshot(web_contents))
.size()) {
content::WaitForAccessibilityTreeToChange(web_contents);
}
// All images should be annotated. Only links that contain exactly one image
// should be annotated.
ui::AXTreeUpdate ax_tree_update =
content::GetAccessibilityTreeSnapshot(web_contents);
EXPECT_THAT(
DescribeNodesWithAnnotations(ax_tree_update),
testing::ElementsAre("image Appears to say: red.png Annotation",
"link Appears to say: green.png Annotation",
"image Appears to say: green.png Annotation",
"image Appears to say: red.png Annotation",
"image Appears to say: printer.png Annotation",
"image Appears to say: red.png Annotation",
"link Appears to say: printer.png Annotation",
"image Appears to say: printer.png Annotation",
"link Appears to say: green.png Annotation",
"image Appears to say: green.png Annotation"));
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImagesInIframe) {
FakeAnnotator::SetReturnOcrResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_iframe.html")));
// Block until the accessibility tree has the annotated image from the
// iframe in it. The test times out if it never appears.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
web_contents, "Appears to say: green.png Annotation");
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AugmentImageNames) {
FakeAnnotator::SetReturnLabelResults(true);
FakeAnnotator::AddCustomLabelResultMapping("frog.jpg", "Tadpole");
FakeAnnotator::AddCustomLabelResultMapping("train.png", "Locomotive");
FakeAnnotator::AddCustomLabelResultMapping("cloud.png", "Cumulonimbus");
FakeAnnotator::AddCustomLabelResultMapping("goat.jpg", "Billy goat");
FakeAnnotator::AddCustomLabelResultMapping("dog.jpg", "Puppy");
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_augment.html")));
// Block until the accessibility tree has at least 5 annotations. If
// that never happens, the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
while (5 > DescribeNodesWithAnnotations(
content::GetAccessibilityTreeSnapshot(web_contents))
.size()) {
content::WaitForAccessibilityTreeToChange(web_contents);
}
ui::AXTreeUpdate ax_tree_update =
content::GetAccessibilityTreeSnapshot(web_contents);
EXPECT_THAT(DescribeNodesWithAnnotations(ax_tree_update),
testing::ElementsAre(
"image the Appears to be: Tadpole",
"image photo background Appears to be: Locomotive",
"image 12345678.jpg Appears to be: Cumulonimbus",
"image Sunday, Feb 6, 1966 Appears to be: Billy goat",
"image fotografia bianca e nero Appears to be: Puppy"));
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AugmentImageNamesInLinks) {
FakeAnnotator::SetReturnLabelResults(true);
FakeAnnotator::AddCustomLabelResultMapping("frog.jpg", "Tadpole");
FakeAnnotator::AddCustomLabelResultMapping("train.png", "Locomotive");
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL(
"/accessibility/image_annotation_augment_links.html")));
// Block until the accessibility tree has at least 3 annotations. If
// that never happens, the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ui::AXTreeUpdate ax_tree_update =
content::GetAccessibilityTreeSnapshot(web_contents);
while (3 > DescribeNodesWithAnnotations(ax_tree_update).size()) {
content::WaitForAccessibilityTreeToChange(web_contents);
ax_tree_update = content::GetAccessibilityTreeSnapshot(web_contents);
}
EXPECT_THAT(
DescribeNodesWithAnnotations(ax_tree_update),
testing::ElementsAre("link photo background Appears to be: Locomotive",
"image photo background Appears to be: Locomotive",
"image the Appears to be: Tadpole"));
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageDoc) {
FakeAnnotator::SetReturnOcrResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_doc.html")));
// Block until the accessibility tree has at least 2 annotations. If
// that never happens, the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
while (2 > DescribeNodesWithAnnotations(
content::GetAccessibilityTreeSnapshot(web_contents))
.size()) {
content::WaitForAccessibilityTreeToChange(web_contents);
}
// When a document contains exactly one image, the document should be
// annotated with the image's annotation, too.
ui::AXTreeUpdate ax_tree_update =
content::GetAccessibilityTreeSnapshot(web_contents);
EXPECT_THAT(
DescribeNodesWithAnnotations(ax_tree_update),
testing::ElementsAre("rootWebArea Appears to say: red.png Annotation",
"image Appears to say: red.png Annotation"));
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageUrl) {
FakeAnnotator::SetReturnOcrResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL("/accessibility/red.png")));
// Block until the accessibility tree has at least 2 annotations. If
// that never happens, the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
while (2 > DescribeNodesWithAnnotations(
content::GetAccessibilityTreeSnapshot(web_contents))
.size()) {
content::WaitForAccessibilityTreeToChange(web_contents);
}
// When a document contains exactly one image, the document should be
// annotated with the image's annotation, too.
ui::AXTreeUpdate ax_tree_update =
content::GetAccessibilityTreeSnapshot(web_contents);
EXPECT_THAT(
DescribeNodesWithAnnotations(ax_tree_update),
testing::ElementsAre("rootWebArea Appears to say: red.png Annotation",
"image Appears to say: red.png Annotation"));
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, NoAnnotationsAvailable) {
// Don't return any results.
FakeAnnotator::SetReturnOcrResults(false);
FakeAnnotator::SetReturnLabelResults(false);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_doc.html")));
// Block until the annotation status for the root is empty. If that
// never occurs then the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
while (snapshot.nodes.empty() ||
snapshot.nodes[0].GetImageAnnotationStatus() !=
ax::mojom::ImageAnnotationStatus::kAnnotationEmpty) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AnnotationError) {
// Return an error code.
FakeAnnotator::SetReturnErrorCode(
image_annotation::mojom::AnnotateImageError::kFailure);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_doc.html")));
// Block until the annotation status for the root contains an error code. If
// that never occurs then the test will time out.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
while (snapshot.nodes.empty() ||
snapshot.nodes[0].GetImageAnnotationStatus() !=
ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageWithSrcSet) {
FakeAnnotator::SetReturnOcrResults(true);
FakeAnnotator::SetReturnLabelResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL("/accessibility/image_srcset.html")));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
web_contents,
"Appears to say: red.png Annotation. Appears to be: red.png 'en' Label");
}
// Disabled due to flakiness. http://crbug.com/983404
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
DISABLED_AnnotationLanguages) {
FakeAnnotator::SetReturnOcrResults(true);
FakeAnnotator::SetReturnLabelResults(true);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL("/accessibility/image_annotation.html")));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
web_contents,
"Appears to say: red.png Annotation. Appears to be: red.png 'en' Label");
SetAcceptLanguages("fr,en");
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL("/accessibility/image_annotation.html")));
web_contents = browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
web_contents,
"Appears to say: red.png Annotation. Appears to be: red.png 'fr' Label");
}
// TODO(crbug.com/40928269): Fix flakiness on ChromeOS
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_DoesntAnnotateInternalPages DISABLED_DoesntAnnotateInternalPages
#else
#define MAYBE_DoesntAnnotateInternalPages DoesntAnnotateInternalPages
#endif
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
MAYBE_DoesntAnnotateInternalPages) {
FakeAnnotator::SetReturnLabelResults(true);
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL("chrome://version")));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
std::string svg_image =
"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><circle "
"cx='50' cy='50' r='40' fill='yellow' /></svg>";
const std::string javascript =
"var image = document.createElement('img');"
"image.src = \"" +
svg_image +
"\";"
"var outer = document.getElementById('outer');"
"outer.insertBefore(image, outer.childNodes[0]);";
EXPECT_TRUE(content::ExecJs(web_contents, javascript));
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
// Wait for the accessibility tree to contain an error that the image cannot
// be annotated due to the page url's scheme.
while (!HasNodeWithAnnotationStatus(
snapshot,
ax::mojom::ImageAnnotationStatus::kWillNotAnnotateDueToScheme)) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
TutorMessageOnlyOnFirstImage) {
// We should not promote the image annotation service on more than one image
// in the same renderer.
FakeAnnotator::SetReturnOcrResults(false);
FakeAnnotator::SetReturnLabelResults(false);
// The following test page should have at least two images on it.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server_.GetURL("/accessibility/image_annotation.html")));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
scoped_accessibility_mode_ = content::ScopedAccessibilityModeOverride(
web_contents, ui::kAXModeComplete);
// Block until there are at least two images that have been processed. One of
// them should get the tutor message and the other shouldn't. The annotation
// status for the image that didn't get the tutor message should be
// kSilentlyEligibleForAnnotation whilst the status for the image that did
// should be kEligibleForAnnotation. If that never occurs then the test will
// time out.
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
while (
!HasNodeWithAnnotationStatus(
snapshot,
ax::mojom::ImageAnnotationStatus::kSilentlyEligibleForAnnotation) ||
!HasNodeWithAnnotationStatus(
snapshot, ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation)) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
}
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
TutorMessageOnlyOnFirstImageInLinks) {
// We should not promote the image annotation service on more than one image
// in the same renderer.
FakeAnnotator::SetReturnOcrResults(false);
FakeAnnotator::SetReturnLabelResults(false);
// The following test page should have at least two images on it.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL("/accessibility/image_annotation_link.html")));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
scoped_accessibility_mode_ = content::ScopedAccessibilityModeOverride(
web_contents, ui::kAXModeComplete);
// Block until there are at least two images that have been processed. One of
// them should get the tutor message and the other shouldn't. The annotation
// status for the image that didn't get the tutor message should be
// kSilentlyEligibleForAnnotation whilst the status for the image that did
// should be kEligibleForAnnotation. If that never occurs then the test will
// time out.
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
while (
!HasNodeWithAnnotationStatus(
snapshot,
ax::mojom::ImageAnnotationStatus::kSilentlyEligibleForAnnotation) ||
!HasNodeWithAnnotationStatus(
snapshot, ax::mojom::ImageAnnotationStatus::kEligibleForAnnotation)) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
}