0

Printing: Create view PPD integration test

This test:
- Sets up a server to serve PPDs
- Manually creates a printer using the fake PPD
- Views the PPD for the printer in the browser

Bug: b/329704831, b/307385730
Include-Ci-Only-Tests: true
Change-Id: Ie30c987499cf23435d4d97746f51f555164bf327
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5346169
Reviewed-by: Piotr Pawliczek <pawliczek@chromium.org>
Commit-Queue: Gavin Williams <gavinwill@chromium.org>
Reviewed-by: Michael Checo <michaelcheco@google.com>
Cr-Commit-Position: refs/heads/main@{#1277853}
This commit is contained in:
Gavin Williams
2024-03-25 19:41:18 +00:00
committed by Chromium LUCI CQ
parent 31d068c455
commit 83a5b89d1b
4 changed files with 306 additions and 0 deletions
chrome
browser
ui
webui
ash
settings
pages
printing
test
chromeos/ash/components/dbus/printscanmgr

@ -0,0 +1,293 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <string_view>
#include "ash/constants/ash_switches.h"
#include "ash/webui/settings/public/constants/routes.mojom-forward.h"
#include "base/command_line.h"
#include "base/json/string_escape.h"
#include "base/strings/pattern.h"
#include "base/strings/strcat.h"
#include "chrome/browser/ash/login/test/session_manager_state_waiter.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/settings_window_manager_chromeos.h"
#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
#include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "chromeos/ash/components/dbus/printscanmgr/fake_printscanmgr_client.h"
#include "chromeos/ash/components/dbus/printscanmgr/printscanmgr_client.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
namespace ash {
namespace {
constexpr char kDefaultPpd[] = R"(
*PPD-Adobe: "4.3"
*FormatVersion: "4.3"
*FileVersion: "1.0"
*LanguageVersion: English
*LanguageEncoding: ISOLatin1
*PCFileName: "SAMPLE.PPD"
*Product: "Sample"
*PSVersion: "(1) 1"
*ModelName: "Sample"
*ShortNickName: "Sample"
*NickName: "Sample"
*Manufacturer: "Sample"
*OpenUI *PageSize: PickOne
*DefaultPageSize: A4
*PageSize A4/A4: "<</PageSize[595.20 841.68]>>setpagedevice"
*CloseUI: *PageSize
*OpenUI *PageRegion: PickOne
*DefaultPageRegion: A4
*PageRegion A4/A4: "<</PageRegion[595.20 841.68]>>setpagedevice"
*CloseUI: *PageRegion
*DefaultImageableArea: A4
*ImageableArea A4/A4: "8.40 8.40 586.80 833.28"
*DefaultPaperDimension: A4
*PaperDimension A4/A4: "595.20 841.68"
)";
constexpr int kPpdServerPortNumber = 7002;
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSettingsWebContentsId);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kChromeBrowserWebContentsId);
class PrinterSettingsIntegrationTest : public AshIntegrationTest {
public:
const DeepQuery kPrinterSettingsPage{
"os-settings-ui", "os-settings-main", "main-page-container",
"settings-device-page", "settings-cups-printers"};
const DeepQuery kAddManualPrinterButton =
kPrinterSettingsPage + "#addManualPrinterButton";
const DeepQuery kAddPrinterManuallyDialog = kPrinterSettingsPage +
"#addPrinterDialog" +
"add-printer-manually-dialog";
const DeepQuery kSavePrinterButton =
kAddPrinterManuallyDialog + "#addPrinterButton";
const DeepQuery kNameInputQuery =
kAddPrinterManuallyDialog + "#printerNameInput";
const DeepQuery kAddressInputQuery =
kAddPrinterManuallyDialog + "#printerAddressInput";
const DeepQuery kProtocolDropdownQuery = kAddPrinterManuallyDialog + "select";
const DeepQuery kManufacturerModelDialogQuery =
kPrinterSettingsPage + "#addPrinterDialog" +
"add-printer-manufacturer-model-dialog";
const DeepQuery kManufacturerDropdownQuery = kManufacturerModelDialogQuery +
"#manufacturerDropdown" +
"#search" + "#input";
const DeepQuery kBrotherManufacturerButtonQuery =
kManufacturerModelDialogQuery + "#manufacturerDropdown" +
"#dropdown > div > button";
const DeepQuery kModelDropdownQuery =
kManufacturerModelDialogQuery + "#modelDropdown" + "#search" + "#input";
const DeepQuery kBrotherPrinterButtonQuery = kManufacturerModelDialogQuery +
"#modelDropdown" +
"#dropdown > div > button";
const DeepQuery kAddPrinterButtonQuery =
kManufacturerModelDialogQuery + "#addPrinterButton";
const DeepQuery kMoreActionsButtonQuery =
kPrinterSettingsPage + "#savedPrinters" + "#frb0" + "#moreActions";
const DeepQuery kEditButtonQuery =
kPrinterSettingsPage + "#savedPrinters" + "#editButton";
const DeepQuery kViewPpdButtonQuery = kPrinterSettingsPage +
"#editPrinterDialog" +
"#ppdLabel > div > cr-button";
PrinterSettingsIntegrationTest() {
// Keep test running after dismissing login screen.
set_exit_when_last_browser_closes(false);
login_mixin().SetMode(ChromeOSIntegrationLoginMixin::Mode::kTestLogin);
}
// AshIntegrationTest:
void SetUp() override {
ASSERT_TRUE(
embedded_test_server()->InitializeAndListen(kPpdServerPortNumber));
embedded_test_server()->RegisterRequestHandler(
base::BindRepeating(&PrinterSettingsIntegrationTest::HandleRequest,
base::Unretained(this)));
embedded_test_server()->StartAcceptingConnections();
AshIntegrationTest::SetUp();
}
// AshIntegrationTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
AshIntegrationTest::SetUpCommandLine(command_line);
command_line->AppendSwitchNative(ash::switches::kPrintingPpdChannel,
"localhost");
}
std::unique_ptr<net::test_server::BasicHttpResponse> CreateHttpResponse(
std::string_view content) {
std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_OK);
http_response->set_content_type("application/json");
http_response->set_content(content);
return http_response;
}
std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
const net::test_server::HttpRequest& request) {
const std::string request_path = request.GetURL().path();
std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_OK);
http_response->set_content_type("application/json");
if (request_path == "/metadata_v3/locales.json") {
return CreateHttpResponse("{\"locales\":[\"en\"]}");
} else if (request_path == "/metadata_v3/manufacturers-en.json") {
return CreateHttpResponse(
"{\"filesMap\": {\"Brother\": \"Brother-en.json\"}}");
} else if (request_path == "/metadata_v3/Brother-en.json") {
return CreateHttpResponse(
"{\"printers\": [{\"name\": \"Brother Printer\",\"emm\": "
"\"brother-printer\"}]}");
} else if (base::MatchPattern(request_path, "/metadata_v3/index*.json")) {
return CreateHttpResponse(
"{\"ppdIndex\": {\"brother-printer\": {\"ppdMetadata\": [ {\"name\": "
"\"default-ppd.ppd\"}]}}}");
} else if (request_path == "/ppds_for_metadata_v3/default-ppd.ppd") {
return CreateHttpResponse(kDefaultPpd);
} else if (base::MatchPattern(request_path,
"/metadata_v3/reverse_index-en*.json")) {
return CreateHttpResponse(
"{\"locale\": \"en\", \"reverseIndex\": {\"brother-printer\": "
"{\"manufacturer\": \"Brother\", \"model\": \"Brother Printer\"}}}");
}
return nullptr;
}
auto WaitForCrInputTextContains(
const ui::ElementIdentifier& element_id,
const WebContentsInteractionTestUtil::DeepQuery& query,
std::string_view expected) {
DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kInputTextFound);
WebContentsInteractionTestUtil::StateChange state_change;
state_change.type = WebContentsInteractionTestUtil::StateChange::Type::
kExistsAndConditionTrue;
state_change.where = query;
state_change.test_function =
base::StrCat({"function(el) { return el.value.indexOf(",
base::GetQuotedJSONString(expected), ") >= 0; }"});
state_change.event = kInputTextFound;
return WaitForStateChange(element_id, state_change);
}
auto LaunchOsPrinterSettings() {
return Steps(
InstrumentNextTab(kSettingsWebContentsId, AnyBrowser()), Do([&]() {
chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
GetActiveUserProfile(),
chromeos::settings::mojom::kPrintingDetailsSubpagePath);
}),
WaitForShow(kSettingsWebContentsId),
WaitForWebContentsReady(
kSettingsWebContentsId,
chrome::GetOSSettingsUrl(
chromeos::settings::mojom::kPrintingDetailsSubpagePath)));
}
auto AddPrinterManually(std::string_view printer_name) {
return Steps(
Log("Opening the add printer dialog"),
ClickElement(kSettingsWebContentsId, kAddManualPrinterButton),
Log("Inserting the printer name"),
ExecuteJsAt(
kSettingsWebContentsId, kNameInputQuery,
base::StrCat({"(el) => { el.value = '", printer_name, "'; }"})),
WaitForCrInputTextContains(kSettingsWebContentsId, kNameInputQuery,
printer_name),
Log("Inserting the address"),
ExecuteJsAt(kSettingsWebContentsId, kAddressInputQuery,
"(el) => { el.value = 'address'; }"),
WaitForCrInputTextContains(kSettingsWebContentsId, kAddressInputQuery,
"address"),
Log("Updating the protocol"),
ExecuteJsAt(kSettingsWebContentsId, kProtocolDropdownQuery,
"(el) => {el.selectedIndex = 4; el.dispatchEvent(new "
"Event('change'));}"),
Log("Click the save button"),
ClickElement(kSettingsWebContentsId, kSavePrinterButton),
Log("Adding the manufacturer"),
WaitForElementExists(kSettingsWebContentsId,
kManufacturerDropdownQuery),
ClickElement(kSettingsWebContentsId, kManufacturerDropdownQuery),
WaitForElementExists(kSettingsWebContentsId,
kBrotherManufacturerButtonQuery),
WaitForElementToRender(kSettingsWebContentsId,
kBrotherManufacturerButtonQuery),
ClickElement(kSettingsWebContentsId, kBrotherManufacturerButtonQuery),
Log("Adding the model"),
WaitForElementExists(kSettingsWebContentsId, kModelDropdownQuery),
ClickElement(kSettingsWebContentsId, kModelDropdownQuery),
WaitForElementExists(kSettingsWebContentsId,
kBrotherPrinterButtonQuery),
WaitForElementToRender(kSettingsWebContentsId,
kBrotherPrinterButtonQuery),
ClickElement(kSettingsWebContentsId, kBrotherPrinterButtonQuery),
Log("Saving the printer"),
ClickElement(kSettingsWebContentsId, kAddPrinterButtonQuery));
}
};
IN_PROC_BROWSER_TEST_F(PrinterSettingsIntegrationTest, ViewPpd) {
SetupContextWidget();
login_mixin().Login();
// Waits for the primary user session to start.
ash::test::WaitForPrimaryUserSessionStart();
InstallSystemApps();
// Set fake data for clicking "View PPD" to return.
PrintscanmgrClient::InitializeFakeForTest();
RunTestSequence(
Log("Launching printer settings"), LaunchOsPrinterSettings(),
AddPrinterManually("First Printer"),
WaitForElementExists(kSettingsWebContentsId, kMoreActionsButtonQuery),
Log("Opening the edit dialog"),
WaitForElementToRender(kSettingsWebContentsId, kMoreActionsButtonQuery),
ClickElement(kSettingsWebContentsId, kMoreActionsButtonQuery),
WaitForElementToRender(kSettingsWebContentsId, kEditButtonQuery),
ClickElement(kSettingsWebContentsId, kEditButtonQuery),
WaitForElementExists(kSettingsWebContentsId, kViewPpdButtonQuery),
Log("Clicking the View PPD button"),
ScrollIntoView(kSettingsWebContentsId, kViewPpdButtonQuery),
InstrumentNextTab(kChromeBrowserWebContentsId, AnyBrowser()),
ClickElement(kSettingsWebContentsId, kViewPpdButtonQuery),
Log("Verifying the PPD contents"),
WaitForShow(kChromeBrowserWebContentsId),
CheckJsResult(kChromeBrowserWebContentsId,
"() => document.body.textContent", kDefaultPpd));
}
} // namespace
} // namespace ash

@ -1142,6 +1142,7 @@ if (is_chromeos && is_chromeos_device) {
"../browser/ash/web_handwriting_integration_test.cc",
"../browser/ui/ash/quick_settings_integration_test.cc",
"../browser/ui/ash/shelf/shelf_integration_test.cc",
"../browser/ui/webui/ash/settings/pages/printing/integration_tests/printer_settings_integration_test.cc",
"base/chromeos/crosier/helper/test_sudo_helper_client_test.cc",
"base/chromeos/crosier/upstart_test.cc",
@ -1172,10 +1173,12 @@ if (is_chromeos && is_chromeos_device) {
"//chrome/browser/ash:test_support",
"//chrome/test/base/chromeos/crosier:proto",
"//chrome/test/base/chromeos/crosier/helper:common",
"//chromeos/ash/components/dbus/printscanmgr:printscanmgr",
"//chromeos/ash/components/standalone_browser",
"//chromeos/ash/components/standalone_browser:test_support",
"//chromeos/ash/services/assistant/public/cpp",
"//chromeos/services/machine_learning/public/cpp",
"//ui/events:test_support",
]
data_deps += [

@ -253,6 +253,12 @@ void PrintscanmgrClient::InitializeFake() {
g_instance->Init(nullptr);
}
// static
void PrintscanmgrClient::InitializeFakeForTest() {
g_instance = new FakePrintscanmgrClient();
g_instance->Init(nullptr);
}
// static
void PrintscanmgrClient::Shutdown() {
CHECK(g_instance);

@ -27,6 +27,10 @@ class COMPONENT_EXPORT(PRINTSCANMGR) PrintscanmgrClient
// Creates and initializes a fake global instance.
static void InitializeFake();
// Creates and overrides any existing instance with a fake global instance for
// tests.
static void InitializeFakeForTest();
// Destroys the global instance if it has been initialized.
static void Shutdown();