chromium/chrome/browser/ash/extensions/default_keyboard_extension_browser_test.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/extensions/default_keyboard_extension_browser_test.h"

#include "ash/public/cpp/keyboard/keyboard_switches.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.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 "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/common/extension.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/input_method.h"

namespace {
const base::FilePath::CharType kWebuiTestDir[] =
    FILE_PATH_LITERAL("webui/chromeos");

const base::FilePath::CharType kMockController[] =
    FILE_PATH_LITERAL("mock_controller.js");

const char kVirtualKeyboardExtensionTestDir[] =
    "chromeos/virtual_keyboard/default_extension";

const base::FilePath::CharType kMockTimer[] =
    FILE_PATH_LITERAL("mock_timer.js");

const char kBaseKeyboardExtensionTestFramework[] =
    "virtual_keyboard_test_base.js";

const char kExtensionId[] = "mppnpdlheglhdfmldimlhpnegondlapf";

// Loading the virtual keyboard with id=none suppresses asynchronous loading of
// layout and configuration assets. This allows the javascript test code to be
// injected ahead of the keyboard initialization.
const char kVirtualKeyboardURL[] = "chrome://keyboard?id=none";

}  // namespace

DefaultKeyboardExtensionBrowserTestConfig::
    DefaultKeyboardExtensionBrowserTestConfig()
    : base_framework_(kBaseKeyboardExtensionTestFramework),
      extension_id_(kExtensionId),
      test_dir_(kVirtualKeyboardExtensionTestDir),
      url_(kVirtualKeyboardURL) {}

DefaultKeyboardExtensionBrowserTestConfig::
    ~DefaultKeyboardExtensionBrowserTestConfig() {}

void DefaultKeyboardExtensionBrowserTest::SetUpCommandLine(
    base::CommandLine* command_line) {
  command_line->AppendSwitch(keyboard::switches::kEnableVirtualKeyboard);
}

void DefaultKeyboardExtensionBrowserTest::RunTest(
    const base::FilePath& file,
    const DefaultKeyboardExtensionBrowserTestConfig& config) {
  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(config.url_)));
  content::WebContents* web_contents =
      browser()->tab_strip_model()->GetActiveWebContents();
  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
  ASSERT_TRUE(web_contents);

  // Inject testing scripts.
  InjectJavascript(base::FilePath(kWebuiTestDir),
                   base::FilePath(kMockController));
  InjectJavascript(base::FilePath(config.test_dir_),
                   base::FilePath(kMockTimer));
  InjectJavascript(base::FilePath(config.test_dir_),
                   base::FilePath(config.base_framework_));
  InjectJavascript(base::FilePath(config.test_dir_), file);

  ASSERT_TRUE(content::ExecJs(web_contents, utf8_content_));

  // Inject DOM-automation test harness and run tests.
  EXPECT_TRUE(ExecuteWebUIResourceTest(web_contents));
}

content::WebContents*
DefaultKeyboardExtensionBrowserTest::GetKeyboardWebContents(
    const std::string& id) {
  // Ensure the keyboard is shown.
  auto* client = ChromeKeyboardControllerClient::Get();
  client->SetEnableFlag(keyboard::KeyboardEnableFlag::kExtensionEnabled);
  client->ShowKeyboard();

  GURL url = extensions::Extension::GetBaseURLFromExtensionId(id);
  for (content::WebContents* wc : content::GetAllWebContents()) {
    if (url == wc->GetPrimaryMainFrame()->GetSiteInstance()->GetSiteURL()) {
      // Waits for virtual keyboard to load.
      EXPECT_TRUE(content::WaitForLoadStop(wc));
      return wc;
    }
  }

  LOG(ERROR) << "Extension not found:" << url;
  return nullptr;
}

void DefaultKeyboardExtensionBrowserTest::InjectJavascript(
    const base::FilePath& dir,
    const base::FilePath& file) {
  base::FilePath path = ui_test_utils::GetTestFilePath(dir, file);
  std::string library_content;
  {
    base::ScopedAllowBlockingForTesting allow_io;
    ASSERT_TRUE(base::ReadFileToString(path, &library_content)) << path.value();
  }
  utf8_content_.append(library_content);
  utf8_content_.append(";\n");
}

IN_PROC_BROWSER_TEST_F(DefaultKeyboardExtensionBrowserTest, TypingTest) {
  RunTest(base::FilePath(FILE_PATH_LITERAL("typing_test.js")),
          DefaultKeyboardExtensionBrowserTestConfig());
}

IN_PROC_BROWSER_TEST_F(DefaultKeyboardExtensionBrowserTest, LayoutTest) {
  RunTest(base::FilePath(FILE_PATH_LITERAL("layout_test.js")),
          DefaultKeyboardExtensionBrowserTestConfig());
}

IN_PROC_BROWSER_TEST_F(DefaultKeyboardExtensionBrowserTest, ModifierTest) {
  RunTest(base::FilePath(FILE_PATH_LITERAL("modifier_test.js")),
          DefaultKeyboardExtensionBrowserTestConfig());
}

IN_PROC_BROWSER_TEST_F(DefaultKeyboardExtensionBrowserTest,
                       HideKeyboardKeyTest) {
  RunTest(base::FilePath(FILE_PATH_LITERAL("hide_keyboard_key_test.js")),
          DefaultKeyboardExtensionBrowserTestConfig());
}

IN_PROC_BROWSER_TEST_F(DefaultKeyboardExtensionBrowserTest, IsKeyboardLoaded) {
  content::WebContents* keyboard_wc = GetKeyboardWebContents(kExtensionId);
  ASSERT_TRUE(keyboard_wc);
  std::string script = "!!chrome.virtualKeyboardPrivate";
  // Catches the regression in crbug.com/308653.
  ASSERT_EQ(true, content::EvalJs(keyboard_wc, script));
}

IN_PROC_BROWSER_TEST_F(DefaultKeyboardExtensionBrowserTest, EndToEndTest) {
  // Get the virtual keyboard's WebContents.
  content::WebContents* keyboard_wc = GetKeyboardWebContents(kExtensionId);
  ASSERT_TRUE(keyboard_wc);

  // Get the test page's WebContents.
  content::WebContents* browser_wc =
      browser()->tab_strip_model()->GetActiveWebContents();
  ASSERT_TRUE(browser_wc);

  // Set up the test page.
  GURL url = ui_test_utils::GetTestUrl(
      base::FilePath(),
      base::FilePath(FILE_PATH_LITERAL(
          "chromeos/virtual_keyboard/default_extension/end_to_end_test.html")));
  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

  // Press 'a' on keyboard.
  base::FilePath path = ui_test_utils::GetTestFilePath(
      base::FilePath(kVirtualKeyboardExtensionTestDir),
      base::FilePath(FILE_PATH_LITERAL("end_to_end_test.js")));
  std::string script;
  {
    base::ScopedAllowBlockingForTesting allow_io;
    ASSERT_TRUE(base::ReadFileToString(path, &script));
  }
  EXPECT_TRUE(content::ExecJs(keyboard_wc, script));
  // Verify 'a' appeared on test page.
  ASSERT_EQ(true,
            content::EvalJs(browser_wc,
                            "success ? verifyInput('a') : waitForInput('a');"));
}

// TODO(kevers|rsadam|bshe):  Add UI tests for remaining virtual keyboard
// functionality.