CSS специфичность тестирования - PullRequest
4 голосов
/ 20 июня 2019

Есть ли хорошие инструменты или методы для автоматического тестирования селекторов CSS?

Я занимаюсь разработкой инфраструктуры SCSS и хотел бы включить в нее автоматизированные тесты. В частности, я хотел бы иметь тесты, чтобы убедиться, что селекторы CSS работают правильно.

Скажем, например, что у меня есть HTML:

<input class="btn" disabled id="test"></input>

и css

.btn {
 color: red;
 ...
}

.btn:disabled {
 color: green;
 ...
}

Я хотел бы иметь тест, который гарантирует, что элемент выше с id = test имеет .btn: disabled в качестве класса css с наивысшим приоритетом (последний класс с наивысшей специфичностью) и .btn в качестве второго наивысшего приоритета. Другими словами, я хотел бы убедиться, что к элементам применяются стиль .btn: disabled и .btn css, а стили в .btn: disabled заменяют стили в .btn.

Я думаю сделать это в селене. Есть ли хорошие способы сделать это? Я не хотел бы жестко кодировать значения css в тестах.

Ответы [ 4 ]

1 голос
/ 02 июля 2019

Метод, с которым я согласился, заключается в использовании getComputedStyle для получения стиля с «наивысшим приоритетом». В CSS я добавляю «тег» к свойству содержимого. Затем в Жасмин я проверяю, является ли нужный тег computedStyle. (Я расширю это в scss так, чтобы свойство content устанавливалось микшином, если режим тестирования используется, а не установлен в производстве.) Это делает модульный тест только для класса с наивысшим приоритетом, но не для второго по величине и т. Д.

Ниже приведены тесты, иллюстрирующие пример (должны пройти только первый и последний).

// specs code
describe("CSS", function() {
  it("Div element of class test should be handled by .test", () => {
    const testdiv = document.getElementById("testdiv")
    m = window.getComputedStyle(testdiv).getPropertyValue("content"); 
   
    expect(m).toEqual('".test"');
  });

 it("Div element of class test should be handled by div", () => {
    const testdiv = document.getElementById("testdiv")
    m = window.getComputedStyle(testdiv).getPropertyValue("content"); 
   
    expect(m).toEqual('"div"');
  });

 it("Div element should be handled by .test", () => {
    const testdiv = document.getElementById("testdiv2")
    m = window.getComputedStyle(testdiv).getPropertyValue("content"); 
   
    expect(m).toEqual('".test"');
  });

 it("Div element of class test should be handled by div", () => {
    const testdiv = document.getElementById("testdiv2")
    m = window.getComputedStyle(testdiv).getPropertyValue("content"); 
   
    expect(m).toEqual('"div"');
  });

});


// load jasmine htmlReporter
(function() {
  var env = jasmine.getEnv();
  env.addReporter(new jasmine.HtmlReporter());
  env.execute();
}());
.test {
    content: '.test';
}

div {
  content: 'div';
}
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
<link href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet"/>
<div class="test" id="testdiv">TestDiv</div>
<div id="testdiv2">TestDiv</div>
0 голосов
/ 28 июня 2019

CSS Specificity

В соответствии с документацией Специфичность - это логика, с помощью которой браузер решает, какие значения свойств CSS являются наиболее релевантными для элемента, если существует два или более противоречивых правила CSS, которые указывают на один и тот же элемент и какие будет применяться. Специфичность рассчитывается на основе правил сопоставления, составленных в соответствии с различными CSS-селекторами .


Как рассчитать специфичность

Есть пара правил для расчета Специфичность на основе следующих пунктов:

  • style атрибут: 1000
  • id атрибут: 100
  • class или pseudo-class: 1

Расчет специфичности CSS

Рассчитаем Специфичность обоих CSS

  • Образец A:

    .btn {
     color: red;
    }
    
    • Объяснение: Содержит класс , т.е. btn. Так что Специфичность составляет 1 .
  • Образец B:

    .btn:disabled {
     color: green;
     ...
    }
    
    • Объяснение: Содержит класс , т. Е. btn и псевдокласс , т. Е. disabled. Так что Специфичность 2 .

Тесты

Специфичность CSS также можно проверить визуально с помощью Калькулятор специфичности :

Specificity


Заключение

Поскольку образец B CSS имеет большую специфичность, образец B B CSS будет применен к элементу:

<input class="btn" disabled id="test"></input>

Outro

Однако существуют более детальные правила специфичности CSS:

  • Равная специфичность: учитывается последнее правило.
  • Селекторы идентификаторов имеют более высокую специфичность, чем селекторы атрибутов.
  • Контекстные селекторы более специфичны, чем одноэлементный селектор.
  • Селектор класса бьет любое количество селекторов элементов.

Подробную документацию можно найти в Особенности CSS

0 голосов
/ 02 июля 2019

Если я правильно понимаю вопрос, вы в основном запрашиваете тест (для вашего примера), например:

if -> Element.ComputedStyle.color = green

then -> test passed

else -> test failed (you have CSS structure errors)

Очевидно, что браузер правильно интерпретирует специфичность.Таким образом, вы действительно проверяете, не привели ли изменения, внесенные вами путем добавления / переопределения CSS, к непредвиденным визуальным последствиям.

Это кажется довольно ручным вопросом, на который нужно ответить, так как вам нужно будет решить, каково каждое из этих правильных состоянийа затем поддерживать тесты.Если вы пойдете по этому пути, я бы посмотрел что-то вроде Backstop.js .Хотя визуальное регрессионное тестирование CSS ДЕЙСТВИТЕЛЬНО сложно, будьте осторожны, сколько вы ожидаете от него.


Ручной путь

Не могли бы вы решить проблему вручную, создав переменную SCSS, которая обычноtransparent?Затем, когда вы добавляете / меняете код, добавляете эту переменную и меняете цвет на что-то вроде pink, это действительно очевидно?На этом этапе вы должны увидеть, где что-то переопределяется при рендеринге страницы.

Если вы создаете CSS-фреймворк, я бы протестировал вашу документацию, поскольку в ней должны быть показаны предыдущие примеры, которые могут быть переопределены.


Блоки CSS

Вы также можете заглянуть в API CSS Blocks .Это точно не будет «тест», но API предоставляет ошибки определения объема и компиляции, которые могут помочь вам обнаружить некоторые из этих проблем раньше, чем позже.

Вот соответствующая часть:

С новой системой разрешения CSS Blocks, каскадные конфликты будут обнаружены для вас, прежде чем вы даже узнаете, что они существуют, и вам больше никогда не придется вести войну специфичности.

0 голосов
/ 20 июня 2019

Как вы уже упоминали, вы можете достичь этого с помощью Selenium. С точки зрения методологии, если вы хотите сохранить этот долгосрочный срок, я бы порекомендовал следовать объектной модели страницы. Официальная документация по этому вопросу доступна здесь , и есть несколько других статей на различных языках здесь , здесь и здесь .

По сути, все сводится к созданию классов или моделей для страниц (или разделов / компонентов страницы (как в форме, имеющей несколько элементов управления)), тогда этот класс будет иметь свойства / поля для каждого из элементов в страница, с которой вы хотите взаимодействовать. Преимущества этого подхода:

  • Одно место для изменения, если вам нужно обновить селектор (ремонтопригодность)
  • Подстилающий код, который может быть уродливым, может быть представлен через красивый интерфейс, который использует свободный синтаксис (удобочитаемость)

Как это выглядит (поскольку вы не указали язык, я пойду с C #:

public class LoginPage
{
    // FindBy attributes should decorate each property to specify the selector
    public WebElement UsernameInput { get; set; }
    public WebElement PasswordInput { get; set; }
    public WebElement LoginButton { get; set; }

    public LoginPage()
    {
        ...
    }

    public LoginPage Load(this LoginPage page)
    {
        // code to navigate to the login page
    }

    public LoginPage EnterCredentials(this LoginPage page, string username, string password)
    {
        // code to fill out inputs
    }

    public HomePage Login(this LoginPage page)
    {
        // code to click login button
    }

    // Other methods
}

Как это выглядит при использовании:

HomePage homePage =
    new LoginPage()
    .Load()
    .EnterCredentials("user", "pass")
    .Login();

// Now you can perform operations on the HomePage
...