testing-d8-theme



testing-d8-theme

1 1


testing-d8-theme

Slides and Demo for "Testing Your Style Guide and Theme in Drupal 8" Talk

On Github backlineint / testing-d8-theme

Chasing The Dream of Style Guide Driven Development

Chasing The Dream of Style Guide Driven Development in Drupal 8

Brian Perry

HS2 Solutions

Brian Perry

@bricomedy / brianperry

http://www.hs2solutions.com/

Slides:

http://brianperryinteractive.com/testing-d8-theme

Example Repo:

https://github.com/backlineint/testing-d8-theme

So what exactly is Style Guide Driven Development anyway?

Decoupling of front and back end development

* SGDD is an approach to development that de-couples front end and back end development. * Look and feel can be developed before functionality actually exists. * Style guide components can be applied to newly developed functionality right away.

Theming doesn't have to come last

* I'm sure many have experienced this - your site is built out, and then at the end we try to tack on theming.

Perception

 

 

 

 

 

 

* We think it will look like this - tack on styling at the end, and the finished product will look great.

Reality

 

 

 

 

 

 

* But in reality it is more like this - some things dont get finished, and it is can be ugly and painful.

(Mario Kart Version)

 

 

 

 

 

 

* Or the Mario Kart version - you're just about to cross the finish line, but you get hit with a blue shell.

The Living Style Guide

* Key component of SGDD is the creation and maintenence of a living style guide.
* US Web Design Standards Style Guide. * Starbucks was another early example - http://www.starbucks.com/static/reference/styleguide/ * Consider converting this to a video.
* Search bar component

A Living Style Guide

Is modular and re-usable
* Atomic Design is a methodology to construct design systems created by Brad Frost. * Design systems of components, not pages.
* Atoms - basic html elements * Molecules - small combinations of html elements - search box for example. * Organisms - more complex components of molecules - header for example. * Templates - a full page or screen made up of components. * Page - An instance of a template with content in it. Don't design individual pages. * The methodolgy doesn't matter to me as much as the idea of re-usable modular components.

A Living Style Guide

Is modular and re-usable Uses real world css and markup Is always kept up to date Is testable * The style guide should use the actual css and markup that is in production on your site. * As much as possible at least. The CSS should be easy, but in some cases the markup can be difficult. * Generate your style guide automatagically - we'll look at a few approaches. * Make it part of your workflow - when you update your code, update your documentation. * Testable - SGDD sets up a framework that makes it possible to test for visual regressions.

Has this ever happened to you?

* So many fun options for infomercial fail gifs...

One tiny css change causes a regression deep in the outer reaches of your site

(and, it goes unnoticed for lord knows how long)

* Maybe it's an honest mistake * Maybe someone new to the codebase is working in the theme layer and doesn't have the context you do.
* This is an example of a screenshot of a screenshot diff after a change in style. * * We've got all the tools we need for some life saving visual regression testing. and we'll walk all the way getting this process up on its feet. * Image Source: https://css-tricks.com/visual-regression-testing-with-phantomcss/

Get to the Drupal Already...

Drupal 8 wants you to build better themes

Cleaner Markup

Base Themes

  • Classy
  • Stable
* So much effort in the past related to slimming down Drupal's markup - stuff like fences for example. * Classy sensible default classes and markup, improved from D7 * Stable - only essential classes. * Defaults to stable as a base theme. * See https://www.lullabot.com/articles/a-tale-of-two-base-themes-in-drupal-8-core

Clearer seperation between logic and display

{%
	set classes = [
		'block',
		'block-' ~ configuration.provider|clean_class,
		'block-' ~ plugin_id|clean_class,
	]
%}
< div {{ attributes.addClass(classes) }}>

(From block.html.twig)

{% if attributes.hasClass('myClass') %}
  {# do stuff #}
{% endif %}
* More classes and markup in templates, less in preprocessor and theme functions. So much easier to find stuff and create cleaner, well organized markup. * No PHP in templates * Don't preprocess to add classes, use Twig helper function. * Todo: Screen shot this.

Tools to Create Modular, Re-usable components

CSS Coding Standards

SMACSS

Base Layout Component (aka Module) State Theme (aka Skin) * Scalable and Modular Architecture for CSS * Approach to organizing your styles * Base — CSS reset/normalize plus HTML element styling. * Layout — macro arrangement of a web page, including any grid systems. * Component — discrete, reusable UI elements. SMACCS calls this modules. * State — styles that deal with client-side changes to components. Typically defined with the component in Drupal. * Theme — purely visual styling (“look-and-feel”) for a component. Drupal sometimes calls this 'skin'

BEM

Naming convention for components

  • Block
  • Element
  • Modifier
.block {}
.block__element {}
.block--modifier {}
.block__element--modifier {}
* Block - object (component) on your website * Element - Sub-component of a block that performs a particular function. Should only make sense within the context of the block * Modifier - Variations of block or element

Twig Include

links--node.html.twig (classy)

{% if links %}
  <div class="node__links">
    {% include "links.html.twig" %}
  </div>
{% endif %}

links.html.twig (classy)

{% if links -%}
  {%- if heading -%}
    {%- if heading.level -%}
      <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}<!--{{ heading.level }}-->
    {%- else -%}
      <h2{{ heading.attributes="" }}="">{{ heading.text }}
    {%- endif -%}
  {%- endif -%}
  <ul{{ attributes="" }}="">
    {%- for item in links -%}
      <li{{ item.attributes="" }}="">
        {%- if item.link -%}
          {{ item.link }}
        {%- elseif item.text_attributes -%}
          <span{{ item.text_attributes="" }}="">{{ item.text }}
        {%- else -%}
          {{ item.text }}
        {%- endif -%}
                            
                            {%- endfor -%}
                            
                            {%- endif %}
                        </span{{></li{{></ul{{></h2{{>
* Have access to variables and can map them

Twig Extends

field.html.twig

* Twig allows you to extend templates, which can really help with re-use. * Imagine you want to wrap the field in a different tag. In D7 if you wanted to do this in the template, you'd have to create a copy of the entire field template * Todo: fix image overflow or use code.

Twig Blocks

Custom field.html.twig

* If you define elements as blocks, you can extend them. * Here I've created a custom version of the field template where I've defined blocks. * Todo: fix image overflow or use code.

Twig Extends

field--field-hero-header.html.twig

* Now for a specific field template I can re-define the blocks, not the entire template.

Twig Embed

Combines Include and Extends

{% embed "teasers_skeleton.twig" %}
    {# These blocks are defined in "teasers_skeleton.twig" #}
    {# and we override them right here:                    #}
    {% block left_teaser %}
        Some content for the left teaser box
    {% endblock %}
    {% block right_teaser %}
        Some content for the right teaser box
    {% endblock %}
{% endembed %}
* Can use multiple embeds

attach_library()

Can now add libraries within twig templates

{{ attach_library('contextual/drupal.contextual-links') }}
<div>Some markup {{ message }}</div>

Careful - can impact aggregation / performance

Creating Your Style Guide

* Here's a demo - a table of links and a long scrolling page of examples. * Quick way to see the things you haven't styled or missed. * I feel like the style guide module Doesn't get the credit it deserves. * TODO: Add additional encodings for non-webkit browsers or convert to a gif..

Style Guide D8 Alpha Available

https://www.drupal.org/project/styleguide

Style Guide Generators

Many options

  • Pattern Lab
  • Hologram
  • KSS
* A number of style guide generators exist to fill this need. * Pattern Lab follows Atomic Design approach, but doesn't work as easily with Drupal as some other options. * Hologram is a Ruby Gem * But I've been using KSS.

KSS

  • Human readable documentation syntax
  • Any flavor of CSS
  • Node JS implementation
  • Plays nicely with Grunt and Gulp
* Knyle Style Sheets

Install

npm install kss --save-dev

npm install grunt-kss --save-dev

Example

* Let's look at an example - a view of articles in card view mode

KSS Syntax

// Cards
//
// Multiple cards included in a grid
//
// Markup: cards.twig
//
// Style Guide: Patterns.Cards
.cards {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
* Name * Description * Markup - can be file location (html, handlebars, twig) or inline if simple markup * Category in Style Guide

Build Style Guide

grunt kss

or:

kss-node --source sass --destination styleguide --css ../css/style.css --builder=builder/twig

* Here's an example of KSS output for the Cards Grid * See the element included in the TOC, rendered, and the necessary markup included below.

Testing Your Style Guide and Theme

* With all of these pieces in place we now have a solid framework to test our theme. * I've tried a number of options, and some fit the task better than others.

Behat

Behavior Driven Development Framework

@javascript
Scenario: Footer style matches style guide
  Given I am an anonymous user
  And I am on "assessments/practice-assessments"
  When I am browsing using a "phone"
  Then "body" should have a "background-color" css value of "rgb(112, 84, 125)"
  And "#page" should have a "background-color" css value of "rgb(255, 255, 255)"
  And "footer" should have a "padding-top" css value of "50px"
  And "footer" should have a "padding-bottom" css value of "30px"

View Gist for detail of steps

* Great for functional testing, not as great for testing look and feel. * Screenshot options are limited, especially comparison * Created custom rules to test computed CSS values, but have to get really specific and values can drift when things like scrollbars are introduced.

Wraith

Screenshot Comparison Tool

  • Compares two URLs
  • Simple configuration
  • Typically 'all or nothing' diffs
* Another option for a screenshot comparison tool is Wraith, created by the BBC team. * Full page screenshots can be can be of limited usefulness in my opinion. One diff can onbscure the rest of the page.
* Selenium wraith has some worthwhile enhancements like browser to browser testing, but component comparisons are still immature. * Summary report is cool. And this is way better than not doing visual regression testing at all.

WebdriverIO

Selenium Bindings for NodeJS

  • Selenium - Browser Automation
  • WebdriverIO - Node library to drive selenium
  • WebdriverCSS - CSS Regression Testing

Strengths: interactivity, easier to target components.

Install

npm install webdriverio@3.4.0 webdrivercss@2.0.0beta-rc1 selenium-standalone --save-dev

./node-modules/.bin/selenium-standalone install

Also requires graphicsmagick

* Have considered using the mainline version, but the Grunt version works so well and is so easy to set up...

Creating a Test

wdio-tests.js

var wdio = require("webdriverio");
var webdrivercss = require("webdrivercss");
var assert = require("assert");

var options = {
  desiredCapabilities: {
    browserName: "chrome"
  }
}
var browser = wdio.remote(options);
webdrivercss.init(browser, {
  screenshotRoot: "screenshots"
});

function assertShots (err, shots) {
  assert.ifError(err);

  Object.keys(shots).forEach(function(element) {
    shots[element].forEach(function(shot) {
      assert.ok(shot.isWithinMisMatchTolerance, shot.message);
    })
  });
};
* Can execute js before screenshots - chaning out fonts or content * Takes a named screenshot based on a selector.
browser
    .init()
    .url("http://testing-d8-theme.dd:8083/cards")
    .webdrivercss("cards", [
      {
        name: "cards",
        elem: ".cards"
      }
    ], assertShots)
    .end();
* Can execute js before screenshots - chaning out fonts or content * Takes a named screenshot based on a selector.

Some simple interactivity

browser
  .init()
  .url(config.url)
  .click(".fa-bars")
  .webdrivercss("navigation", [
    {
      name: "Off Canvas Menu",
      elem: ".sidebar-offcanvas"
    }
  ], assertShots)
  .end();
* Can execute js before screenshots - chaning out fonts or content * Takes a named screenshot based on a selector.

Chasing the dream?

* So why did I call this chasing the dream? I mean, it isn't a very good title, right? * To some extent, I'm still trying to better incorporate this into my regular workflow - sometimes I have to cut corners - work with what I have, don't follow standards, fold this in too late, etc. * Things also feel a little transitional in D8 - some of the tools are different, many of them not Drupal specific.

Still Chasing...

  • My workflow - tools continue to evolve
  • Drupal and Style Guide Sharing Markup
  • Component Based Rendering in Drupal
* Even my workflow is evolving pretty quickly - phantom vs webdriver, specific versions, etc

* Requires Components Module *

The Style Guide Component

card.twig

<div class="card">
  <div class="card-image">
    <img src="{{ img_src }}" alt="{{ img_alt }}">
  </div>
  <div class="card-header">
    {{ header }}
  </div>
  <div class="card-copy">
    <p>{{ copy }}</p>
  </div>
</div>

The Drupal Template (Presenter)

node--article--card.twig

{%  include "@components/card/card.twig"
  with {
    "img_src": file_url(node.field_image.entity.fileuri),
    "img_alt": content.field_image.0['#item'].alt,
    "header": label,
    "copy": content.body
  }
%}

Questions?

Chasing The Dream of Style Guide Driven Development in Drupal 8 Brian Perry HS2 Solutions