chromium/ios/chrome/browser/web/model/font_size/font_size_js_unittest.mm

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

#import <Foundation/Foundation.h>
#import <stddef.h>

#import "base/ios/ios_util.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/web/public/test/fakes/fake_web_client.h"
#import "ios/web/public/test/js_test_util.h"
#import "ios/web/public/test/scoped_testing_web_client.h"
#import "ios/web/public/test/web_state_test_util.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "ui/base/device_form_factor.h"

// Test fixture for accessibility.js testing.
class FontSizeJsTest : public PlatformTest {
 public:
  FontSizeJsTest() : web_client_(std::make_unique<web::FakeWebClient>()) {
    PlatformTest::SetUp();

    browser_state_ = TestChromeBrowserState::Builder().Build();

    web::WebState::CreateParams params(browser_state_.get());
    web_state_ = web::WebState::Create(params);
    web_state_->GetView();
    web_state_->SetKeepRenderProcessAlive(true);
  }

  FontSizeJsTest(const FontSizeJsTest&) = delete;
  FontSizeJsTest& operator=(const FontSizeJsTest&) = delete;

  // Find DOM element by `element_id` and get computed font size in px.
  float GetElementFontSize(NSString* element_id) {
    NSNumber* res = web::test::ExecuteJavaScript(
        [NSString
            stringWithFormat:
                @"parseFloat(getComputedStyle(document.getElementById('%@'))."
                @"getPropertyValue('font-size'));",
                element_id],
        web_state());
    return res.floatValue;
  }

  // Wraps `html` in <html> and loads. Adds <meta name='viewport'
  // content='initial-scale=1.0'> to avoid implicit font size inflation (e.g.
  // for <div style='font-size:10px'>d<div style='font-size:10px'>d</div></div>
  // the `GetElementFontSize` returns 17px instead of 10px under default
  // viewport and '-webkit-text-size-adjust=auto'). Setting
  // '-webkit-text-size-adjust=none' also works.
  void LoadHtml(NSString* html) {
    web::test::LoadHtml(
        [NSString stringWithFormat:@"<html><style>"
                                   @"html { -webkit-text-size-adjust: none }"
                                   @"</style><meta name='viewport' "
                                   @"content='initial-scale=1.0'>%@</html>",
                                   html],
        web_state());

    // Main web injection should have occurred.
    ASSERT_NSEQ(@"object",
                web::test::ExecuteJavaScript(@"typeof __gCrWeb", web_state()));
    web::test::ExecuteJavaScript(web::test::GetPageScript(@"font_size"),
                                 web_state());
  }

  // Executes JavaScript "__gCrWeb.font_size.adjustFontSize(`scale`)" to
  // adjust font size to `scale`% and return if it is executed without
  // exception.
  [[nodiscard]] bool AdjustFontSize(int scale) {
    id script_result = web::test::ExecuteJavaScript(
        [NSString
            stringWithFormat:@"__gCrWeb.font_size.adjustFontSize(%d); true;",
                             scale],
        web_state());
    return [script_result isEqual:@YES];
  }

 protected:
  web::WebState* web_state() { return web_state_.get(); }

  web::ScopedTestingWebClient web_client_;
  web::WebTaskEnvironment task_environment_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<web::WebState> web_state_;
};

// Tests that __gCrWeb.font_size.adjustFontSize works for any scale.
TEST_F(FontSizeJsTest, TestAdjustFontSizeForScale) {
  float original_size = 0;
  float current_size = 0;

  LoadHtml(@"<div id='e'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(20));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 20 / 100);

  LoadHtml(@"<div id='e'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(50));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 50 / 100);

  LoadHtml(@"<div id='e'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(90));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 90 / 100);

  LoadHtml(@"<div id='e'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(150));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 150 / 100);

  LoadHtml(@"<div id='e'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(200));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 200 / 100);

  LoadHtml(@"<h1 id='e'>h</h1>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(20));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 20 / 100);

  LoadHtml(@"<h1 id='e'>h</h1>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(50));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 50 / 100);

  LoadHtml(@"<h1 id='e'>h</h1>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(90));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 90 / 100);

  LoadHtml(@"<h1 id='e'>h</h1>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<h1 id='e'>h</h1>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(150));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 150 / 100);

  LoadHtml(@"<h1 id='e'>h</h1>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(200));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 200 / 100);

  LoadHtml(@"<span id='e'>s</span>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(20));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 20 / 100);

  LoadHtml(@"<span id='e'>s</span>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(50));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 50 / 100);

  LoadHtml(@"<span id='e'>s</span>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(90));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 90 / 100);

  LoadHtml(@"<span id='e'>s</span>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<span id='e'>s</span>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(150));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 150 / 100);

  LoadHtml(@"<span id='e'>s</span>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(200));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 200 / 100);
}

// Tests that __gCrWeb.font_size.adjustFontSize works for any CSS unit.
TEST_F(FontSizeJsTest, TestAdjustFontSizeForUnit) {
  float original_size = 0;
  float current_size = 0;

  LoadHtml(@"<div id='e' style='font-size: xx-large'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 1cm'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 5mm'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 1in'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 10px'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 18pt'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 2pc'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 2.5em'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 0.8rem'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);

  LoadHtml(@"<div id='e' style='font-size: 70%'>d</div>");
  original_size = GetElementFontSize(@"e");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size = GetElementFontSize(@"e");
  EXPECT_FLOAT_EQ(current_size, original_size * 110 / 100);
}

// Tests that __gCrWeb.font_size.adjustFontSize works for nested elements.
TEST_F(FontSizeJsTest, TestAdjustFontSizeForNestedElements) {
  float original_size_1 = 0;
  float original_size_2 = 0;
  float current_size_1 = 0;
  float current_size_2 = 0;

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:xx-large'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:1cm'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:5mm'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:1in'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:18pt'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:2pc'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:2.5em'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:0.8rem'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:70%'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:10px'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:xx-large'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);

  LoadHtml(@"<div id='e1' style='font-size: 10px'>d<div id='e2' "
           @"style='font-size:inherit'>d</div></div>");
  original_size_1 = GetElementFontSize(@"e1");
  original_size_2 = GetElementFontSize(@"e2");
  ASSERT_TRUE(AdjustFontSize(110));
  current_size_1 = GetElementFontSize(@"e1");
  current_size_2 = GetElementFontSize(@"e2");
  EXPECT_FLOAT_EQ(current_size_1, original_size_1 * 110 / 100);
  EXPECT_FLOAT_EQ(current_size_2, original_size_2 * 110 / 100);
}