Run prettier

This commit is contained in:
Oliver Davies 2020-03-14 23:39:56 +00:00
parent 49b98d0681
commit 81640d24ed
8 changed files with 398 additions and 437 deletions

View file

@ -1,4 +1,5 @@
- Demonstrate plugins
- Writing own source/process plugins
- Core source plugins (Drupal to Drupal)
- Demo `hook_migrate_prepare_row()` and `hook_migrate_MIGRATION_ID_prepare_row()`
- Demo `hook_migrate_prepare_row()` and
`hook_migrate_MIGRATION_ID_prepare_row()`

View file

@ -1,14 +1,11 @@
autoscale: true
build-lists: true
code: line-height(1.2)
header-emphasis: #53B0EB
text: alignment(left)
theme: simple, 8
autoscale: true build-lists: true code: line-height(1.2) header-emphasis:
#53B0EB text: alignment(left) theme: simple, 8
# [fit] **Deploying PHP applications** <br>using Ansible, Ansible Vault <br>and Ansistrano
^ I work primarily with PHP, and there will be some PHP-isms in this talk (LAMP stack, Composer).
Will be using a Drupal 8 application as the example, but the tools are tool and language agnostic.
^ I work primarily with PHP, and there will be some PHP-isms in this talk (LAMP
stack, Composer). Will be using a Drupal 8 application as the example, but the
tools are tool and language agnostic.
---
@ -18,14 +15,13 @@ Will be using a Drupal 8 application as the example, but the tools are tool and
## **What we'll be looking at**
* **Ansible** crash course
* Keeping secrets with **Ansible Vault**
* Deployments with **Ansistrano**
- **Ansible** crash course
- Keeping secrets with **Ansible Vault**
- Deployments with **Ansistrano**
---
[.build-lists: false]
[.header: #111111]
[.build-lists: false][.header: #111111]
![right 500%](../images/me-phpnw-inviqa.jpg)
@ -37,31 +33,28 @@ Will be using a Drupal 8 application as the example, but the tools are tool and
- @opdavies
- www.oliverdavies.uk
^ Maintain Drupal modules, PHP CLI tools and libraries, Ansible roles
Blog on my website
I work primarily with Drupal and Symfony
I work for Inviqa, but this based on my personal and side projects.
I've been using Ansible for a number of years, initially only for provisioning and setting up my laptop, and later for application deployments
^ Maintain Drupal modules, PHP CLI tools and libraries, Ansible roles Blog on my
website I work primarily with Drupal and Symfony I work for Inviqa, but this
based on my personal and side projects. I've been using Ansible for a number of
years, initially only for provisioning and setting up my laptop, and later for
application deployments
---
![350% inline](images/logo-platformsh.png)
![150% inline](images/logo-acquia.png)
![130% inline](images/logo-pantheon.png)
![150% inline](images/logo-acquia.png) ![130% inline](images/logo-pantheon.png)
^ Large, well-known managed hosting companies
Optimised servers for PHP/Drupal applications
Include some sort of deployment system
This workflow doesn't apply to this scenario
^ Large, well-known managed hosting companies Optimised servers for PHP/Drupal
applications Include some sort of deployment system This workflow doesn't apply
to this scenario
---
![100%](images/logo-digital-ocean.png)
![30%](images/logo-linode.png)
![100%](images/logo-digital-ocean.png) ![30%](images/logo-linode.png)
![30%](images/logo-vultr.png)
^ More applicable to virtual or dedicated servers with no existing deployment process
Not enough budget for fully-managed, or using internal infrastructure
^ More applicable to virtual or dedicated servers with no existing deployment
process Not enough budget for fully-managed, or using internal infrastructure
This is where the this workflow would be useful
---
@ -82,17 +75,18 @@ This is where the this workflow would be useful
### **What is Ansible?**
* CLI tool
* Written in Python
* Configured with YAML
* Executes ad-hoc remote commands
* Installs software packages
* Performs deployment steps
* Batteries included
- CLI tool
- Written in Python
- Configured with YAML
- Executes ad-hoc remote commands
- Installs software packages
- Performs deployment steps
- Batteries included
^ Written in Python but you don't need to write or know Python to use it
Drupal, Symfony and a lot of other projects use YAML
First-party modules (SSH keys, file and directory management, package repositories, stopping/starting/restarting services, DO/Linode/AWS integration)
^ Written in Python but you don't need to write or know Python to use it Drupal,
Symfony and a lot of other projects use YAML First-party modules (SSH keys, file
and directory management, package repositories, stopping/starting/restarting
services, DO/Linode/AWS integration)
---
@ -100,15 +94,15 @@ First-party modules (SSH keys, file and directory management, package repositori
### **What is Ansible?**
* Hosts/Inventories
* Commands
* Playbooks
* Tasks
* Roles
- Hosts/Inventories
- Commands
- Playbooks
- Tasks
- Roles
^ Hosts: where your managed nodes/hosts are. Can be static or dynamic.
Commands: run from a control node onto managed nodes
Playbooks and Tasks: YAML representation of a series of commands/steps
^ Hosts: where your managed nodes/hosts are. Can be static or dynamic. Commands:
run from a control node onto managed nodes Playbooks and Tasks: YAML
representation of a series of commands/steps
---
@ -116,17 +110,16 @@ Playbooks and Tasks: YAML representation of a series of commands/steps
### **Why Ansible?**
* Familiar syntax
* Easily readable
* No server dependencies
* Easy to add to an existing project
* Includes relevant modules (e.g. Composer)
* Idempotency
- Familiar syntax
- Easily readable
- No server dependencies
- Easy to add to an existing project
- Includes relevant modules (e.g. Composer)
- Idempotency
^ Drupal 8, Symfony, Ansible all use YAML
Runs on any server with Python
Plugins into Drupal via CLI apps like Drush and Drupal Console
Changes are only made when needed (once)
^ Drupal 8, Symfony, Ansible all use YAML Runs on any server with Python Plugins
into Drupal via CLI apps like Drush and Drupal Console Changes are only made
when needed (once)
---
@ -175,7 +168,7 @@ webservers | SUCCESS => {
---
# `ansible all `<br>`-i hosts.yml `<br>`-m command `<br>`-a 'git pull `<br>`--chdir=/app'`
# `ansible all`<br>`-i hosts.yml`<br>`-m command`<br>`-a 'git pull`<br>`--chdir=/app'`
---
@ -206,7 +199,7 @@ webservers | SUCCESS => {
---
# `ansible-playbook `<br>`playbook.yml -i hosts.yml`
# `ansible-playbook`<br>`playbook.yml -i hosts.yml`
---
@ -313,7 +306,7 @@ ok: [webservers]
TASK [geerlingguy.apache : Include OS-specific variables.] *************************************************************
ok: [webservers]
TASK [geerlingguy.apache : Include variables for Amazon Linux.]
TASK [geerlingguy.apache : Include variables for Amazon Linux.]
skipping: [webservers]
TASK [geerlingguy.apache : Define apache_packages.] ********************************************************************
@ -444,9 +437,9 @@ $ANSIBLE_VAULT;1.1;AES256
```yaml
# vars/vars.yml
---
database_name: "{{ vault_database_name }}"
database_user: "{{ vault_database_user }}"
database_password: "{{ vault_database_password }}"
database_name: '{{ vault_database_name }}'
database_user: '{{ vault_database_user }}'
database_password: '{{ vault_database_password }}'
```
---
@ -488,7 +481,7 @@ tasks:
- name: Uploading application
synchronize:
src: "{{ playbook_dir }}/../"
src: '{{ playbook_dir }}/../'
dest: /app
- name: Installing Composer dependencies
@ -501,9 +494,9 @@ tasks:
# Disadvantages
* Single point of failure
* No ability to roll back
* Sensitive data stored in plain text
- Single point of failure
- No ability to roll back
- Sensitive data stored in plain text
---
@ -513,20 +506,19 @@ tasks:
![full inline](images/ansistrano.png)
^ Just another role, specifically for deployments
Ansible port of Capistrano
^ Just another role, specifically for deployments Ansible port of Capistrano
---
# Features
* Multiple release directories
* Shared paths and files
* Customisable
* Multiple deployment strategies
* Multi-stage environments
* Prune old releases
* Rollbacks
- Multiple release directories
- Shared paths and files
- Customisable
- Multiple deployment strategies
- Multi-stage environments
- Prune old releases
- Rollbacks
^ rsync, Git, SVN etc
@ -544,7 +536,6 @@ Ansible port of Capistrano
```yaml
# deploy.yml
---
- hosts: all
@ -557,14 +548,14 @@ Ansible port of Capistrano
```yaml
# deploy.yml
---
# ...
vars:
project_deploy_dir: /app
# ...
vars:
project_deploy_dir: /app
ansistrano_deploy_to: '{{ project_deploy_dir }}'
ansistrano_deploy_via: git
ansistrano_git_branch: master
ansistrano_git_repo: 'git@github.com:opdavies/dransible'
ansistrano_deploy_to: '{{ project_deploy_dir }}'
ansistrano_deploy_via: git
ansistrano_git_branch: master
ansistrano_git_repo: 'git@github.com:opdavies/dransible'
```
---
@ -673,10 +664,9 @@ drwxr-xr-x 9 4096 Jul 22 20:30 20190722203038Z
![inline 140%](images/ansistrano-flow.png)
^ Shared = files directory, logs
Before/after symlink shared = run tests
Symlink = 'current' symlink, site is live
Clean up = remove node_modules, database export, sqlite testing DB
^ Shared = files directory, logs Before/after symlink shared = run tests Symlink
= 'current' symlink, site is live Clean up = remove node_modules, database
export, sqlite testing DB
---
@ -685,16 +675,19 @@ Clean up = remove node_modules, database export, sqlite testing DB
---
# ...
ansistrano_after_symlink_shared_tasks_file: '{{ playbook_dir }}/deploy/after-symlink-shared.yml'
ansistrano_after_symlink_tasks_file: '{{ playbook_dir }}/deploy/after-symlink.yml'
ansistrano_after_update_code_tasks_file: '{{ playbook_dir }}/deploy/after-update-code.yml'
ansistrano_after_symlink_shared_tasks_file:
'{{ playbook_dir }}/deploy/after-symlink-shared.yml'
ansistrano_after_symlink_tasks_file:
'{{ playbook_dir }}/deploy/after-symlink.yml'
ansistrano_after_update_code_tasks_file:
'{{ playbook_dir }}/deploy/after-update-code.yml'
release_web_path: '{{ ansistrano_release_path.stdout }}/web'
release_drush_path: '{{ ansistrano_release_path.stdout }}/vendor/bin/drush'
```
^ Each step has a 'before' and 'after' step
Ansistrano allows us to add more things by providing a path to a playbook and adding additional steps.
^ Each step has a 'before' and 'after' step Ansistrano allows us to add more
things by providing a path to a playbook and adding additional steps.
---
@ -722,7 +715,8 @@ Ansistrano allows us to add more things by providing a path to a playbook and ad
# deploy/after-symlink.yml
---
- name: Clear Drupal cache
command: '{{ release_drush_path }} --root {{ release_web_path }} cache-rebuild'
command:
'{{ release_drush_path }} --root {{ release_web_path }} cache-rebuild'
```
---
@ -741,7 +735,7 @@ Ansistrano allows us to add more things by providing a path to a playbook and ad
vars:
# ...
ansistrano_shared_paths:
- "{{ drupal_root }}/sites/default/files"
- '{{ drupal_root }}/sites/default/files'
```
---
@ -786,15 +780,16 @@ vault_database_user: user
vault_database_password: secret
vault_hash_salt: dfgiy$fd2!34gsf2*34g74
```
---
```yaml
# vars/vars.yml
---
database_name: "{{ vault_database_name }}"
database_password: "{{ vault_database_password }}"
database_user: "{{ vault_database_user }}"
hash_salt: "{{ vault_hash_salt }}"
database_name: '{{ vault_database_name }}'
database_password: '{{ vault_database_password }}'
database_user: '{{ vault_database_user }}'
hash_salt: '{{ vault_hash_salt }}'
```
---
@ -864,7 +859,9 @@ $base_url = '{{ item.1.settings.base_url }}';
- name: Create settings files
template:
src: settings.php.j2
dest: '{{ item.0.drupal_root }}/sites/{{ item.1.name|default("default") }}/{{ item.1.filename|default("settings.php") }}'
dest:
'{{ item.0.drupal_root }}/sites/{{ item.1.name|default("default") }}/{{
item.1.filename|default("settings.php") }}'
with_subelements:
- '{{ drupal_settings }}'
- sites
@ -874,6 +871,7 @@ $base_url = '{{ item.1.settings.base_url }}';
---
# **Multiple environments**
## Dev, test, production
---
@ -907,7 +905,7 @@ all:
project_deploy_path: /app
git_branch: master
drupal_hash_salt: "{{ vault_drupal_hash_salt }}"
drupal_hash_salt: '{{ vault_drupal_hash_salt }}'
drupal_install: true
drupal_settings:
@ -928,7 +926,7 @@ all:
project_deploy_path: /app-test
git_branch: develop
drupal_hash_salt: "{{ vault_drupal_hash_salt }}"
drupal_hash_salt: '{{ vault_drupal_hash_salt }}'
drupal_install: true
drupal_settings:

View file

@ -1,10 +1,5 @@
autoscale: true
build-lists: true
header-emphasis: #3D85C6
header: alignment(left)
text: alignment(left)
text-emphasis: #3D85C6
theme: poster, 8
autoscale: true build-lists: true header-emphasis: #3D85C6 header:
alignment(left) text: alignment(left) text-emphasis: #3D85C6 theme: poster, 8
code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5)
[.header: alignment(center)]
@ -12,6 +7,7 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5)
![](../images/title.png)
# [fit] Drupal Testing Workshop
### _September 2018_
---
@ -32,15 +28,16 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5)
- Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_
- More important with regular D8 releases
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst developing rather than after it's been released)
Refer to tests when writing implementation code
ONO merge conflict
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst
developing rather than after it's been released) Refer to tests when writing
implementation code ONO merge conflict
---
[.header: alignment(center)]
## [fit] _Having tests does not mean_
## [fit] there will be no bugs
---
@ -48,6 +45,7 @@ ONO merge conflict
[.header: alignment(center)]
## [fit] _Testing may add time now_
## [fit] but save more time in the future
---
@ -68,7 +66,7 @@ ONO merge conflict
- PHP class with _.php_ extension
- _tests/src_ directory within each module
- Within the *Drupal\Tests\module_name* namespace
- Within the _Drupal\Tests\module_name_ namespace
- Class name must match the filename
- Namespace must match the directory structure
- One test class per feature
@ -79,6 +77,7 @@ ONO merge conflict
---
### _Exercise 1_
## Local site setup
---
@ -109,11 +108,13 @@ ONO merge conflict
---
### _Exercise 2_
## Running Tests
---
### _Option 1_
## Simpletest module (UI)
---
@ -147,6 +148,7 @@ ONO merge conflict
---
### _Option 2_
## Command line
---
@ -181,7 +183,7 @@ cd web/core
---
## Pro-tip: Add paths to _$PATH_
## Pro-tip: Add paths to _\$PATH_
```bash
# ~/.zshrc
@ -196,6 +198,7 @@ export PATH=node_modules/.bin:$PATH
---
### _Option 2_
## CLI with Docksal
---
@ -223,6 +226,7 @@ cd web/core
---
### _Option 3_
## Docksal PHPUnit addon
---
@ -234,8 +238,7 @@ cd web/core
- Copies a stub phpunit.xml file if exists, or duplicates phpunit.xml.dist
- Shorter command, combines two actions
^ Checks for core/phpunit.xml on each test run
Will create one if is not present
^ Checks for core/phpunit.xml on each test run Will create one if is not present
---
@ -271,6 +274,7 @@ fin phpunit web/modules/contrib/examples/phpunit_example
Copying /var/www/web/core/phpunit.xml.dist to /var/www/web/core/phpunit.xml.
Please edit it's values as needed and re-run 'fin phpunit'.
```
---
```
@ -290,6 +294,7 @@ OK (34 tests, 41 assertions)
---
### _Option 4_
## IDE/text editor integration
---
@ -317,8 +322,6 @@ OK (34 tests, 41 assertions)
---
[.header: #3D85C6]
## Functional tests
@ -327,12 +330,12 @@ OK (34 tests, 41 assertions)
- Easiest to start with
- Provide most value
^ Less setup steps
No mocking etc.
^ Less setup steps No mocking etc.
---
### _Exercise_
## Let's write a <br>functional test
---
@ -357,7 +360,6 @@ type: module
---
```php
// ExampleFunctionalTest.php
@ -393,10 +395,8 @@ public function test_example_page_exists() {
}
```
^ Snake case test method names
Still works because it has the 'test' prefix
More readable than camel case?
Works with Simpletest/D7
^ Snake case test method names Still works because it has the 'test' prefix More
readable than camel case? Works with Simpletest/D7
---
@ -410,8 +410,7 @@ public function example_page_exists() {
}
```
^ Remove the prefix, use annotation
PHPUnit only
^ Remove the prefix, use annotation PHPUnit only
---
@ -541,6 +540,7 @@ OK (1 test, 3 assertions)
---
### _Exercise_
## Let's write a <br>kernel test
---
@ -692,6 +692,7 @@ OK (1 test, 5 assertions)
---
### _Exercise_
## Let's write a <br>unit test
---
@ -775,7 +776,6 @@ OK (1 test, 1 assertion)
---
## _Test Driven Development_
- Write a failing test
@ -785,8 +785,8 @@ OK (1 test, 1 assertion)
---
[.background-color: #FFFFFF]
[.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.background-color:
#FFFFFF][.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.footer-style: #2F2F2F]
![100%](../images/tdd-loop.png)
@ -804,8 +804,8 @@ OK (1 test, 1 assertion)
---
### _Exercise_
## Let's build a blog using test driven development
## Let's build a blog using test driven development
---
@ -828,12 +828,14 @@ OK (1 test, 1 assertion)
## _Implementation_
- Use views module
- Do the mininum amount at each step, make no assumptions, let the tests guide us
- Do the mininum amount at each step, make no assumptions, let the tests guide
us
- Start with functional test
---
### _Step 1_
## Create the module
---
@ -849,6 +851,7 @@ type: 'module'
---
### _Step 2_
## Ensure the blog page exists
---
@ -869,7 +872,6 @@ class BlogPageTest extends BrowserTestBase {
---
```php
public function testBlogPageExists() {
$this->drupalGet('/blog');
@ -880,7 +882,6 @@ public function testBlogPageExists() {
---
```
There was 1 error:
@ -937,7 +938,7 @@ id: blog
```
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided
by <em class="placeholder">tdd_blog</em>
have unmet dependencies: <em class="placeholder">views.view.blog
(node.type.article, node, views)</em>
@ -945,7 +946,6 @@ have unmet dependencies: <em class="placeholder">views.view.blog
---
```yml,[.highlight: 1, 7-10]
# tdd_blog.info.yml
@ -961,10 +961,9 @@ dependencies:
---
```
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided
by <em class="placeholder">tdd_blog</em> have unmet dependencies:
<em class="placeholder">views.view.blog (node.type.article)</em>
```
@ -975,7 +974,6 @@ by <em class="placeholder">tdd_blog</em> have unmet dependencies:
---
```
OK (1 test, 3 assertions)
```
@ -993,11 +991,11 @@ OK (1 test, 3 assertions)
---
### _Step 3_
## Ensure only published articles are shown
---
```php
public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles,
@ -1012,11 +1010,11 @@ public function testOnlyPublishedArticlesAreShown() {
---
### _Option 1_
## Functional tests
---
```php
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1043,11 +1041,11 @@ public function testOnlyPublishedArticlesAreShown() {
---
### _Option 2_
## Kernel tests
---
```php
namespace Drupal\Tests\tdd_blog\Kernel;
@ -1074,10 +1072,8 @@ public function testOnlyPublishedArticlesAreShown() {
}
```
^ Kernel test approach
Dropping down a level
No need for the brower, not asserting against HTML
Faster to run
^ Kernel test approach Dropping down a level No need for the brower, not
asserting against HTML Faster to run
---
@ -1156,7 +1152,8 @@ Failed asserting that actual size 2 matches expected size 1.
---
>- _There is no content type filter on the view_
> - _There is no content type filter on the view_
- Add the filter
- Re-export and save the view
@ -1183,11 +1180,11 @@ OK (1 test, 6 assertions)
---
### _Step 4_
## Ensure the articles are ordered by date
---
```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1202,7 +1199,6 @@ public function testArticlesAreOrderedByDate() {
---
```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1232,7 +1228,6 @@ $this->createNode([
---
```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1267,7 +1262,6 @@ public function testArticlesAreOrderedByDate() {
---
```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1281,7 +1275,6 @@ public function testArticlesAreOrderedByDate() {
---
```
There was 1 failure:
@ -1346,14 +1339,14 @@ OK (1 test, 5 assertions)
- Writing tests is an _investment_
- OK to _start small_, introduce tests gradually
- Easier to _refactor_
- Tests can pass, but things can _still be broken_. Tests only report on what they cover.
- Tests can pass, but things can _still be broken_. Tests only report on what
they cover.
^ Made me think about how I'm going to do something more starting to do it
Less cruft, only write code that serves a purpose
Spending time writing tests pays dividends later on
Start by introducing tests for new features or regression tests when fixing bugs
If you know things pass, then you can refactor code knowing if something is broken
Manual testing is still important
^ Made me think about how I'm going to do something more starting to do it Less
cruft, only write code that serves a purpose Spending time writing tests pays
dividends later on Start by introducing tests for new features or regression
tests when fixing bugs If you know things pass, then you can refactor code
knowing if something is broken Manual testing is still important
---

View file

@ -1,10 +1,10 @@
# Having fun with Drupal 8, PHP libraries Drupal.org API
# Having fun with Drupal 8, PHP libraries Drupal.org API
- Open slides
- Open Chrome tabs
- Open PhpStorm for all projects
- Open Sequel Pro for both DBs
+ Clear cache tables
- Clear cache tables
- Start PHP server for each site
- Start recording
@ -12,13 +12,13 @@
- Show in PhpStorm
- Show readme with examples
+ Run test.php
- Run test.php
- Show query classes
+ Not drupal coding standards (PSR-2)
+ Explain laravel collections
- Not drupal coding standards (PSR-2)
- Explain laravel collections
- Show entity classes
- Show tests
+ Show fake query classes
- Show fake query classes
- Run tests
## Project statistics
@ -26,18 +26,18 @@
- Show /projects page
- Show routing
- Show ProjectController
+ Using PHP 7 return types
+ Explain dependency injection
+ Explain about collection
+ Explain render array
+ Show how to change ordering
- Using PHP 7 return types
- Explain dependency injection
- Explain about collection
- Explain render array
- Show how to change ordering
- Show ProjectRetriever
+ More dependency injection
+ Show services file
- More dependency injection
- Show services file
- Show settings form
- Add another module (Sophie's simple integrations?)
+ See it loading on projects page
+ See it cached
- See it loading on projects page
- See it cached
## Drupalversary
@ -45,18 +45,18 @@
- Show block
- Show block form
- Show accountretriever
+ Highlight caching
+ Services file
+ Show cached items in the DB
- Highlight caching
- Services file
- Show cached items in the DB
- Show routing
- Show UserController
+ More dependency injection
+ Services file
- More dependency injection
- Services file
- Show date parser
+ Show drupalversary model
- Show drupalversary model
- Show adding own username via form
+ See it cached
+ Show adding uid via form
+ See it cached
- See it cached
- Show adding uid via form
- See it cached
- Show Dries' because this year drupalversary has passed
- Try with attendee ID
- Try with attendee ID

View file

@ -1,5 +1,4 @@
autoscale: true
theme: Plain Jane, 1
autoscale: true theme: Plain Jane, 1
# **Taking Flight with <br>Tailwind CSS**
@ -36,10 +35,8 @@ Going to be using Tailwind 1.0 which was released recently (May 13th)
# A **utility-first** CSS framework for rapidly building **custom designs**.
^ CSS utility class generator
PostCSS
Make different looking sites using the same class names
No "Tailwind looking site" like there is with Bootstrap
^ CSS utility class generator PostCSS Make different looking sites using the
same class names No "Tailwind looking site" like there is with Bootstrap
---
@ -47,11 +44,9 @@ No "Tailwind looking site" like there is with Bootstrap
# Tailwind CSS is a **highly customizable**, **low-level** CSS framework
^ No components like Bootstrap or Bulma
Configure it per project
Extendable if needed via additional plugins
Avoids the need to name things prematurely
Can extract components if needed (reusability)
^ No components like Bootstrap or Bulma Configure it per project Extendable if
needed via additional plugins Avoids the need to name things prematurely Can
extract components if needed (reusability)
---
@ -59,8 +54,10 @@ Can extract components if needed (reusability)
# Tailwind is more than a CSS framework, it's an engine for <br>**creating design systems**.
^ Good default values provided - colours, fonts, padding, widths
Designing with constraints. Using inline styles, every value is a magic number. With utilities, you're choosing styles from a predefined design system, which makes it much easier to build visually consistent UIs.
^ Good default values provided - colours, fonts, padding, widths Designing with
constraints. Using inline styles, every value is a magic number. With utilities,
you're choosing styles from a predefined design system, which makes it much
easier to build visually consistent UIs.
---
@ -106,15 +103,22 @@ Designing with constraints. Using inline styles, every value is a magic number.
---
## **Benefits**
- You aren't wasting time and energy inventing class names
- Your CSS stops growing
- Making changes feels safer
^ No more adding silly class names like sidebar-inner-wrapper just to be able to style something, and no more agonizing over the perfect abstract name for something that's really just a flex container.
^ No more adding silly class names like sidebar-inner-wrapper just to be able to
style something, and no more agonizing over the perfect abstract name for
something that's really just a flex container.
^ Using a traditional approach, your CSS files get bigger every time you add a new feature. With utilities, everything is reusable so you rarely need to write new CSS.
^ Using a traditional approach, your CSS files get bigger every time you add a
new feature. With utilities, everything is reusable so you rarely need to write
new CSS.
^ CSS is global and you never know what you're breaking when you make a change. Classes in your HTML are local, so you can change them without worrying about something else breaking.
^ CSS is global and you never know what you're breaking when you make a change.
Classes in your HTML are local, so you can change them without worrying about
something else breaking.
---
@ -219,8 +223,9 @@ Designing with constraints. Using inline styles, every value is a magic number.
## **To get the most out of Tailwind, <br>you really should install it via npm.**
^ - You can't customize Tailwind's default theme
- You can't use any directives like *@apply*, *@variants*, etc.
- You can't enable features like *group-hover*
- You can't use any directives like _@apply_, _@variants_, etc.
- You can't enable features like _group-hover_
- You can't install third-party plugins
---
@ -244,9 +249,7 @@ Designing with constraints. Using inline styles, every value is a magic number.
[.code-highlight: 2-7]
```css
# src/css/style.css
@tailwind base;
#src/css/style.css @tailwind base;
@tailwind components;
@ -277,8 +280,7 @@ Designing with constraints. Using inline styles, every value is a magic number.
## **Processing your CSS with Tailwind <br>with the build command**
^ Compile the generated CSS
Pass through PostCSS and Tailwind
^ Compile the generated CSS Pass through PostCSS and Tailwind
---
@ -288,19 +290,19 @@ Pass through PostCSS and Tailwind
```css
.text-left {
text-align: left;
text-align: left;
}
.text-center {
text-align: center;
text-align: center;
}
.text-right {
text-align: right;
text-align: right;
}
.text-justify {
text-align: justify;
text-align: justify;
}
```
@ -317,9 +319,7 @@ Pass through PostCSS and Tailwind
```js
const mix = require('laravel-mix')
mix.postCss('src/css/app.css', 'dist/css', [
require('tailwindcss')()
])
mix.postCss('src/css/app.css', 'dist/css', [require('tailwindcss')()])
```
^ PostCSS - useful if you're including other PostCSS plugins like PostCSS Nested
@ -331,8 +331,7 @@ const mix = require('laravel-mix')
require('laravel-mix-tailwind')
mix.postCss('src/css/app.css', 'dist/css')
.tailwind()
mix.postCss('src/css/app.css', 'dist/css').tailwind()
```
---
@ -341,13 +340,11 @@ mix.postCss('src/css/app.css', 'dist/css')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta charset="UTF-8" />
<title>My new website</title>
<link rel="stylesheet" href="/dist/css/app.css">
<link rel="stylesheet" href="/dist/css/app.css" />
</head>
<body>
</body>
<body></body>
</html>
```
@ -359,10 +356,10 @@ mix.postCss('src/css/app.css', 'dist/css')
# `npm run prod`
---
# **Interaction states**
## hover, focus, group-hover, focus-within
^ Start to differ from inline styles
@ -371,9 +368,9 @@ mix.postCss('src/css/app.css', 'dist/css')
# `.[state][separator][class]`
^ State = hover, focus, group focus, focus within
Separator = configurable, colon by default
Class = the same utility class that you would have used normally
^ State = hover, focus, group focus, focus within Separator = configurable,
colon by default Class = the same utility class that you would have used
normally
---
@ -594,11 +591,10 @@ colors: {
```js
const mix = require('laravel-mix')
mix.postCss('src/css/site.css', 'dist/css')
.purgeCss({
folders: ['templates'],
extensions: ['html', 'php', 'twig']
})
mix.postCss('src/css/site.css', 'dist/css').purgeCss({
folders: ['templates'],
extensions: ['html', 'php', 'twig'],
})
```
---
@ -610,14 +606,14 @@ const mix = require('laravel-mix')
require('laravel-mix-purgecss')
mix.postCss('src/css/site.css', 'dist/css')
.purgeCss({
folders: ['templates'],
extensions: ['html', 'php', 'twig']
})
mix.postCss('src/css/site.css', 'dist/css').purgeCss({
folders: ['templates'],
extensions: ['html', 'php', 'twig'],
})
```
^ Can be tricky using Drupal/WordPress as you don't know where the classes could be coming from, no generated output directory
^ Can be tricky using Drupal/WordPress as you don't know where the classes could
be coming from, no generated output directory
---
@ -631,9 +627,7 @@ mix.postCss('src/css/site.css', 'dist/css')
# Could the duplication <br>**be moved elsewhere**?
^ Twig partials
Vue components
WordPress template parts
^ Twig partials Vue components WordPress template parts
---
@ -672,8 +666,8 @@ WordPress template parts
} %}
```
^ Move the duplicate markup into a partial, so there's only one version
Pass data in.
^ Move the duplicate markup into a partial, so there's only one version Pass
data in.
---
@ -689,9 +683,8 @@ a.btn:hover {
}
```
^ Use utilities as mixins
Copy classes from markup
Still re-using the same design system and constraints as before
^ Use utilities as mixins Copy classes from markup Still re-using the same
design system and constraints as before
---
@ -730,12 +723,13 @@ a.btn:hover {
module.exports = {
theme: {
extend: {}
extend: {},
},
plugins: [],
variants: {}
variants: {},
}
```
---
[.code-highlight: 5-7]
@ -746,12 +740,12 @@ module.exports = {
module.exports = {
theme: {
colors: {
inherit: 'inherit'
inherit: 'inherit',
},
extend: {}
extend: {},
},
plugins: [],
variants: {}
variants: {},
}
```
@ -768,12 +762,12 @@ module.exports = {
theme: {
extend: {
colors: {
inherit: 'inherit'
}
}
inherit: 'inherit',
},
},
},
plugins: [],
variants: {}
variants: {},
}
```
@ -790,10 +784,10 @@ module.exports = {
prefix: '',
important: false,
theme: {
extend: {}
extend: {},
},
plugins: [],
variants: {}
variants: {},
}
```
@ -818,12 +812,10 @@ module.exports = {
module.exports = {
theme: {
extend: {}
extend: {},
},
plugins: [
require('tailwindcss-list-reset')()
],
variants: {}
plugins: [require('tailwindcss-list-reset')()],
variants: {},
}
```
@ -841,13 +833,16 @@ module.exports = {
```js
// index.js
module.exports = (variants) => ({ addUtilities }) => {
addUtilities({
'.list-reset': {
listStyle: 'none',
padding: 0
}
}, variants)
module.exports = variants => ({addUtilities}) => {
addUtilities(
{
'.list-reset': {
listStyle: 'none',
padding: 0,
},
},
variants,
)
}
```
@ -874,10 +869,11 @@ module.exports = (variants) => ({ addUtilities }) => {
---
# **Thanks!**
# opdavi.es/talks/tailwind
## _@opdavies_ <br>_oliverdavies.uk_
^ Find this talk at opdavi.es/talks/tailwind
Follow me on Twitter
oliverdavies.uk where I blog about PHP, Drupal, Symfony, automated testing, Tailwind etc.
Subscribe to the RSS feed
^ Find this talk at opdavi.es/talks/tailwind Follow me on Twitter
oliverdavies.uk where I blog about PHP, Drupal, Symfony, automated testing,
Tailwind etc. Subscribe to the RSS feed

View file

@ -1,11 +1,6 @@
theme: poster, 8
autoscale: true
build-lists: true
header-emphasis: #53B0EB
header: alignment(left)
text: alignment(left)
text-emphasis: #53B0EB
code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
theme: poster, 8 autoscale: true build-lists: true header-emphasis: #53B0EB
header: alignment(left) text: alignment(left) text-emphasis: #53B0EB code:
Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
[.header: alignment(center)]
@ -41,10 +36,8 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
---
[.background-color: #FFFFFF]
[.build-lists: false]
[.header: #111111]
[.text: #111111, alignment(left)]
[.background-color: #FFFFFF][.build-lists: false] [.header:
#111111][.text: #111111, alignment(left)]
![right 800%](../images/me-phpnw.png)
@ -57,9 +50,8 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
- @opdavies
- www.oliverdavies.uk
^ Work at Microserve.
Maintain Drupal modules, PHP CLI tools and libraries
Blog on my website
^ Work at Microserve. Maintain Drupal modules, PHP CLI tools and libraries Blog
on my website
---
@ -74,8 +66,7 @@ Blog on my website
---
[.background-color: #FFFFFF]
[.text: #111111, alignment(left)]
[.background-color: #FFFFFF][.text: #111111, alignment(left)]
![right 100%](../images/microserve-light.png)
@ -89,10 +80,9 @@ Blog on my website
[.header: alignment(center)]
## test_driven_drupal_.com_
## test*driven_drupal*.com\_
^ Book on automated testing in Drupal 8
Building a conference website
^ Book on automated testing in Drupal 8 Building a conference website
---
@ -129,12 +119,13 @@ Building a conference website
- Become maintainer in 2012
- Had some existing tests
- Used on _11,046 sites_ in October 2012 (_84_ D5, _7,094_ D6, _3,868_ D7)
- Used on _30,572 sites_ in March 2019 (_10_ D5, _1,180_ D6, _24,057_ D7, _5,335_ D8)
- Used on _30,572 sites_ in March 2019 (_10_ D5, _1,180_ D6, _24,057_ D7,
_5,335_ D8)
- _#230_ most used module on Drupal.org
- Crucial to preventing regressions
^ Preventing regressions when adding new features or fixing bugs, but also user submitted patches
First module I ported to Drupal 8, aided by tests
^ Preventing regressions when adding new features or fixing bugs, but also user
submitted patches First module I ported to Drupal 8, aided by tests
---
@ -154,9 +145,9 @@ First module I ported to Drupal 8, aided by tests
- Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_
- More important with regular D8 releases
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst developing rather than after it's been released)
Refer to tests when writing implementation code
ONO merge conflict
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst
developing rather than after it's been released) Refer to tests when writing
implementation code ONO merge conflict
---
@ -164,7 +155,8 @@ ONO merge conflict
- New features should be accompanied by automated tests.
- If the feature does not have an implementation, provide a test implementation.
- Bug fixes should be accompanied by changes to a test (either modifying an existing test case or adding a new one) that demonstrate the bug.
- Bug fixes should be accompanied by changes to a test (either modifying an
existing test case or adding a new one) that demonstrate the bug.
[.footer: https://opdavi.es/drupal-core-testing-gate]
@ -194,7 +186,7 @@ ONO merge conflict
- PHP class with _.php_ extension
- _tests/src_ directory within each module
- Within the *Drupal\Tests\module_name* namespace
- Within the _Drupal\Tests\module_name_ namespace
- Class name must match the filename
- Namespace must match the directory structure
- One test class per feature
@ -206,7 +198,9 @@ ONO merge conflict
[.header: alignment(center)]
## _1._ Arrange
## _2._ Act
## _3._ Assert
---
@ -214,7 +208,9 @@ ONO merge conflict
[.header: alignment(center)]
## _3._ Assert
## _2._ Act
## _1._ Arrange
---
@ -239,11 +235,8 @@ class ExampleTest extends BrowserTestBase {
}
```
^ PHP class
Filename matches class name
Namespace matches directory structure
Extend BrowserTestBase
Add test method
^ PHP class Filename matches class name Namespace matches directory structure
Extend BrowserTestBase Add test method
---
@ -282,8 +275,8 @@ public function it_does_something() {}
- What provides the most value to the client?
- What would you not like to be fixing on a Friday afternoon or after hours?
^ Payments! Anything related to money.
What would provide the largest negative impact to the client if it were to fail?
^ Payments! Anything related to money. What would provide the largest negative
impact to the client if it were to fail?
---
@ -293,7 +286,6 @@ What would provide the largest negative impact to the client if it were to fail?
---
[.header: #53B0EB]
## What to test first?
@ -301,10 +293,9 @@ What would provide the largest negative impact to the client if it were to fail?
- Write a _new test_ when adding any _new functionality_
- Write a _regression test_ when _fixing a bug_
^ Use tests to replicate the bug
Could be a new test, or adding to an existing test
Test passes when the bug is fixed
That issue cannot be re-added without the test failing again
^ Use tests to replicate the bug Could be a new test, or adding to an existing
test Test passes when the bug is fixed That issue cannot be re-added without the
test failing again
---
@ -352,9 +343,8 @@ class JobTest extends UnitTestCase {
}
```
^ Within a Unit directory and namespace
Called JobTest because it's testing the Job class
Called testCreate because it's testing the create method
^ Within a Unit directory and namespace Called JobTest because it's testing the
Job class Called testCreate because it's testing the create method
---
@ -404,8 +394,7 @@ class JobTest extends UnitTestCase {
}
```
^ Retrieve data from the object with getters
Asssert that the data is correct.
^ Retrieve data from the object with getters Asssert that the data is correct.
---
@ -539,8 +528,8 @@ protected function setUp() {
}
```
^ Because it's a kernel test, we have access to the container
to get the AdvancedQueue processor service.
^ Because it's a kernel test, we have access to the container to get the
AdvancedQueue processor service.
---
@ -627,9 +616,7 @@ public function testProcessor() {
- Slower to run
- With/without JavaScript
^ testing profile
Functional/FunctionalJavascript
Nightwatch
^ testing profile Functional/FunctionalJavascript Nightwatch
---
@ -666,8 +653,8 @@ protected function setUp() {
}
```
^ We have the ability to place blocks
And create users with permissions and log them in
^ We have the ability to place blocks And create users with permissions and log
them in
---
@ -710,6 +697,7 @@ public function testQueueDeletion() {
```
---
```php, [.highlight: 12-14]
// tests/src/Functional/QueueTest.php
@ -761,21 +749,25 @@ public function testQueueDeletion() {
[.header: #FFFFFF, alignment(left)]
### _How do I know_
## Which type of test to use?
---
### _Need a browser?_
## Use a functional test
---
### _Interact with other services?_
## Use a kernel test
---
### _Isolated PHP code?_
## Use a unit test
---
@ -786,9 +778,9 @@ public function testQueueDeletion() {
## _Or should you test_ <br>your render array to generate the block?
^ The answer might be 'both'.
The right type of test to use might not be that obvious.
You may be able to use a different type of test if you take a different approach.
^ The answer might be 'both'. The right type of test to use might not be that
obvious. You may be able to use a different type of test if you take a different
approach.
---
@ -876,8 +868,7 @@ statusCodeNotEquals()
---
[.background-color: #FFFFFF]
[.footer-style: #2F2F2F]
[.background-color: #FFFFFF][.footer-style: #2f2f2f]
![inline 150%](images/broadbean.png)
@ -892,7 +883,8 @@ statusCodeNotEquals()
- Jobs need to be linked to offices
- Job length specified in number of days
- Path is specified as a field in the API
- Application URL constructed from domain, includes role ID as a GET parameter and optionally UTM parameters
- Application URL constructed from domain, includes role ID as a GET parameter
and optionally UTM parameters
---
@ -941,9 +933,10 @@ $data = [
- Added route to accept data from API as XML
- Added system user with API role to authenticate
- *active_for* converted from number of days to UNIX timestamp
- *branch_name* and *locations* converted from plain text to entity reference (job node to office node)
- *url_alias* property mapped to *path*
- _active_for_ converted from number of days to UNIX timestamp
- _branch_name_ and _locations_ converted from plain text to entity reference
(job node to office node)
- _url_alias_ property mapped to _path_
---
@ -954,8 +947,7 @@ $data = [
- If no error, create the job node, return OK response to Broadbean
- If an Exception is thrown, return an error code and message
^ Required field missing
Incorrect branch name
^ Required field missing Incorrect branch name
---
@ -975,9 +967,12 @@ Incorrect branch name
## Types of tests
- _Unit:_ ensure number of days are converted to timestamps correctly
- _Kernel:_ job nodes can be added and deleted, expired job nodes are deleted, application URL is generated correctly
- _Functional:_ job nodes are created with the correct URL and the correct response code is returned
- _FunctionalJavaScript:_ application URL is updated with JavaScript based on UTM parameters (hosting)
- _Kernel:_ job nodes can be added and deleted, expired job nodes are deleted,
application URL is generated correctly
- _Functional:_ job nodes are created with the correct URL and the correct
response code is returned
- _FunctionalJavaScript:_ application URL is updated with JavaScript based on
UTM parameters (hosting)
---
@ -998,6 +993,7 @@ Incorrect branch name
---
### _Option 1_
## SimpleTest module (UI)
---
@ -1031,6 +1027,7 @@ Incorrect branch name
---
### _Option 2_
## Core script
---
@ -1046,6 +1043,7 @@ $ php core/scripts/run-tests.sh --class ExampleTest
---
### _Option 3_
## PHPUnit
---
@ -1103,8 +1101,8 @@ fin addon install phpunit
fin phpunit modules/custom
```
^ Copies a stub phpunit.xml file or copies phpunit.xml.dist
Runs the phpunit command within the correct directory
^ Copies a stub phpunit.xml file or copies phpunit.xml.dist Runs the phpunit
command within the correct directory
---
@ -1133,8 +1131,8 @@ Runs the phpunit command within the correct directory
---
[.background-color: #FFFFFF]
[.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.background-color:
#FFFFFF][.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.footer-style: #2F2F2F]
![100%](images/tdd-loop.png)
@ -1174,6 +1172,7 @@ Runs the phpunit command within the correct directory
[.header: alignment(center)]
## [fit] _Building a new Drupal 8 Module with_
## [fit] test driven development
---
@ -1203,12 +1202,14 @@ Runs the phpunit command within the correct directory
## Implementation
- Use views module
- Do the mininum amount at each step, make no assumptions, let the tests guide us
- Do the mininum amount at each step, make no assumptions, let the tests guide
us
- Start with functional test
---
### _Step 1_
## Create the module
---
@ -1224,6 +1225,7 @@ type: 'module'
---
### _Step 2_
## Ensure the blog page exists
---
@ -1250,7 +1252,6 @@ class BlogPageTest extends BrowserTestBase {
---
```php, [.highlight: 3]
// tests/src/Functional/BlogPageTest.php
@ -1273,7 +1274,6 @@ class BlogPageTest extends BrowserTestBase {
---
```php, [.highlight: 5-7]
// tests/src/Functional/BlogPageTest.php
@ -1296,7 +1296,6 @@ class BlogPageTest extends BrowserTestBase {
---
```php, [.highlight: 9]
// tests/src/Functional/BlogPageTest.php
@ -1319,7 +1318,6 @@ class BlogPageTest extends BrowserTestBase {
---
```php, [.highlight: 11-15]
// tests/src/Functional/BlogPageTest.php
@ -1342,7 +1340,6 @@ class BlogPageTest extends BrowserTestBase {
---
```bash, [.highlight: 1]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1367,7 +1364,6 @@ Tests: 1, Assertions: 3, Errors: 1.
---
```bash, [.highlight: 4]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1392,7 +1388,6 @@ Tests: 1, Assertions: 3, Errors: 1.
---
```bash, [.highlight: 5-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1417,7 +1412,6 @@ Tests: 1, Assertions: 3, Errors: 1.
---
```bash, [.highlight: 14-16]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1442,7 +1436,6 @@ Tests: 1, Assertions: 3, Errors: 1.
---
```bash, [.highlight: 18-19]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1542,7 +1535,6 @@ Tests: 1, Assertions: 0, Errors: 1.
---
```yml,[.highlight: 1, 7-10]
# tdd_blog.info.yml
@ -1558,7 +1550,6 @@ dependencies:
---
```[.highlight: 10-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1593,7 +1584,6 @@ Tests: 1, Assertions: 0, Errors: 1.
---
```[.highlight: 5, 9]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1619,11 +1609,11 @@ OK (1 test, 3 assertions)
---
### _Step 3_
## Ensure only published articles are shown
---
```php
public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles,
@ -1638,11 +1628,11 @@ public function testOnlyPublishedArticlesAreShown() {
---
### _Option 1_
## Functional tests
---
```php,[.highlight: 1, 4-8]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1668,7 +1658,6 @@ public function testOnlyPublishedArticlesAreShown() {
---
```php,[.highlight: 10-12]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1692,7 +1681,6 @@ public function testOnlyPublishedArticlesAreShown() {
---
```php, [.highlight: 13-17]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1717,11 +1705,11 @@ public function testOnlyPublishedArticlesAreShown() {
---
### _Option 2_
## Kernel tests
---
```php
namespace Drupal\Tests\tdd_blog\Kernel;
@ -1743,10 +1731,8 @@ class BlogPageTest extends EntityKernelTestBase {
}
```
^ Kernel test approach
Dropping down a level
No need for the brower, not asserting against HTML
Faster to run
^ Kernel test approach Dropping down a level No need for the brower, not
asserting against HTML Faster to run
---
@ -1819,7 +1805,6 @@ class BlogPageTest extends EntityKernelTestBase {
---
```[.highlight: 9-16]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog/tests/src/Kernel/
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1844,7 +1829,6 @@ Tests: 1, Assertions: 2, Errors: 1.
---
```php, [.highlight: 2]
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter']);
@ -1857,7 +1841,6 @@ public function testOnlyPublishedArticlesAreShown() {
---
```php, [.highlight: 8]
public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter']);
@ -1872,7 +1855,6 @@ public function testOnlyPublishedArticlesAreShown() {
---
```php, [.highlight: 3]
...
@ -1894,7 +1876,6 @@ public function testOnlyPublishedArticlesAreShown() {
---
```php, [.highlight: 6]
...
@ -1916,7 +1897,6 @@ public function testOnlyPublishedArticlesAreShown() {
---
```php, [.highlight: 8-15]
...
@ -1936,13 +1916,11 @@ public function testOnlyPublishedArticlesAreShown() {
}
```
^ Assert
Should only be one result, should be node 2
Node IDs are reset on each test method
^ Assert Should only be one result, should be node 2 Node IDs are reset on each
test method
---
```
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1964,7 +1942,6 @@ Tests: 1, Assertions: 4, Failures: 1.
---
```[.highlight: 8-13]
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1990,7 +1967,8 @@ Tests: 1, Assertions: 4, Failures: 1.
---
>- _There is no content type filter on the view_
> - _There is no content type filter on the view_
- Add the filter
- Re-export and save the view
@ -2024,11 +2002,11 @@ OK (1 test, 6 assertions)
---
### _Step 4_
## Ensure the articles are ordered by date
---
```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2043,7 +2021,6 @@ public function testArticlesAreOrderedByDate() {
---
```php, [.highlight: 4-9]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2073,7 +2050,6 @@ $this->createNode([
---
```php, [.highlight: 10-11]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2116,7 +2092,6 @@ public function testArticlesAreOrderedByDate() {
---
```php, [.highlight: 5-9, 17-18]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2141,7 +2116,6 @@ public function testArticlesAreOrderedByDate() {
---
```
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -2255,8 +2229,7 @@ OK (1 test, 5 assertions)
![fit](images/tdd-blog-installed.png)
^ Using the minimal installation profile
Post 3 is unpublished
^ Using the minimal installation profile Post 3 is unpublished
---
@ -2277,45 +2250,49 @@ Post 3 is unpublished
- Writing tests is an _investment_
- OK to _start small_, introduce tests gradually
- Easier to _refactor_
- Tests can pass, but things can _still be broken_. Tests only report on what they cover.
- Tests can pass, but things can _still be broken_. Tests only report on what
they cover.
^ Made me think about how I'm going to do something more starting to do it
Less cruft, only write code that serves a purpose
Spending time writing tests pays dividends later on
Start by introducing tests for new features or regression tests when fixing bugs
If you know things pass, then you can refactor code knowing if something is broken
Manual testing is still important
^ Made me think about how I'm going to do something more starting to do it Less
cruft, only write code that serves a purpose Spending time writing tests pays
dividends later on Start by introducing tests for new features or regression
tests when fixing bugs If you know things pass, then you can refactor code
knowing if something is broken Manual testing is still important
---
[.header: alignment(center)]
## [fit] _Having tests does not mean_
## [fit] there will be no bugs
^ Only means that the tests you wrote are passing
You may not have included a certain use case
Be sure to test in the UI!
We can test what happens in a test when a user has a permission, but in our site we still need to assign the permission to a role and the role to a user.
^ Only means that the tests you wrote are passing You may not have included a
certain use case Be sure to test in the UI! We can test what happens in a test
when a user has a permission, but in our site we still need to assign the
permission to a role and the role to a user.
---
### _You might be testing the wrong thing_
## Maybe it doesn't work the way you think it does
---
### _Have you written enough assertions?_
## Have you only covered the 'happy path' scenarios?
^ If your tests are passing but there is an issue, maybe you haven't written enough assertions
Be sure to check for the negative use cases too
Check that something is not included as well as what should be included
What if you pass in an incorrect value?
^ If your tests are passing but there is an issue, maybe you haven't written
enough assertions Be sure to check for the negative use cases too Check that
something is not included as well as what should be included What if you pass in
an incorrect value?
---
### _Other modules can affect things_
## Tests may pass, but fail when other modules are enabled
---
@ -2323,6 +2300,7 @@ What if you pass in an incorrect value?
[.header: alignment(center)]
## [fit] _Testing may add time now_
## [fit] but save more time in the future
---
@ -2330,20 +2308,21 @@ What if you pass in an incorrect value?
[.header: alignment(center)]
## [fit] _How do you get quicker at writing tests?_
# [fit] By writing more tests
^ Practice makes perfect
Become more familar with and knowledge of recurring errors
Find better practices and approaches. Different base classes? Less setup steps. Less time, more productive.
^ Practice makes perfect Become more familar with and knowledge of recurring
errors Find better practices and approaches. Different base classes? Less setup
steps. Less time, more productive.
---
## _Start small_
## Some tests are better than no tests
---
[.background-color: #FFFFFF]
![140%](images/tawny-tweet-1.png)
@ -2371,5 +2350,7 @@ Find better practices and approaches. Different base classes? Less setup steps.
[.header: alignment(center)]
# Thanks
### _@opdavies_
### _oliverdavies.uk_

View file

@ -1,3 +1,2 @@
- Show composer.json setup
- Add "things you can test" and "things you shouldn't test"

View file

@ -1,15 +1,8 @@
theme: poster, 8
autoscale: true
build-lists: true
header-emphasis: #53B0EB
header: alignment(left)
text: alignment(left)
text-emphasis: #53B0EB
code: Operator Mono, line-height(1.5)
theme: poster, 8 autoscale: true build-lists: true header-emphasis: #53B0EB
header: alignment(left) text: alignment(left) text-emphasis: #53B0EB code:
Operator Mono, line-height(1.5)
[.background-color: #FFFFFF]
[.hide-footer]
[.header: #111111, alignment(center)]
[.background-color: #FFFFFF][.hide-footer] [.header: #111111, alignment(center)]
## Using Laravel Collections... <br>Outside Laravel
@ -21,12 +14,11 @@ code: Operator Mono, line-height(1.5)
## Collections :thumbsup:
^ Became a fan of Collections whilst learning Laravel
Powerful object orientated way to interact with arrays
Store items within the collection, run methods, chainable
More readable, less temporary variables
Video on Laracasts, Adam Wathan's refactoring to Collections
Wanted to use them with different PHP projects e.g. Drupal
^ Became a fan of Collections whilst learning Laravel Powerful object orientated
way to interact with arrays Store items within the collection, run methods,
chainable More readable, less temporary variables Video on Laracasts, Adam
Wathan's refactoring to Collections Wanted to use them with different PHP
projects e.g. Drupal
---
@ -36,15 +28,13 @@ collect(['foo', 'bar']); // ['foo', 'bar']
collect('foobar'); // ['foobar']
$object = new stdClass();
$object->foo = 'bar';
$object->foo = 'bar';
collect($object); // ['foo' => 'bar']
collect($object)->get('foo'); // bar
```
^ How do you make a collection?
collect function is provided
String, array or object
Stored as items within the Collection object
^ How do you make a collection? collect function is provided String, array or
object Stored as items within the Collection object
---
@ -68,10 +58,9 @@ $collection->filter(function ($item) {
}); // [3, 4]
```
^ Once you have a collection, what can you do with it?
"contains" - no more needle/haystack, haystack/needle
"filter" - filters false, null values
Can pass callbacks to `first` and `filter`, return true or false as needed.
^ Once you have a collection, what can you do with it? "contains" - no more
needle/haystack, haystack/needle "filter" - filters false, null values Can pass
callbacks to `first` and `filter`, return true or false as needed.
---
@ -96,12 +85,12 @@ $collection->filter(function ($person) {
![100%](images/druplicon.png)
^ This is great, but how can I do that in my Drupal code?
How can I do that?
^ This is great, but how can I do that in my Drupal code? How can I do that?
---
## Theres a module for that!
### _- Drupalers_
---
@ -109,6 +98,7 @@ How can I do that?
[.text: alignment(center)]
## [fit] There's not a module for that. :disappointed:
### _- Me_
---
@ -119,12 +109,11 @@ How can I do that?
---
### _Version 1.0_
## Write my own Collection class
^ Wrote my own Collection class
Wrote my own tests
^ Wrote my own Collection class Wrote my own tests
---
@ -140,13 +129,14 @@ Wrote my own tests
---
### Collect - Illuminate Collections as a separate package.
#### _https://packagist.org/packages/tightenco/collect_
---
### Import Laravel's Collections into non-Laravel packages easily, without needing to require the entire Illuminate\Support package.
#### _https://packagist.org/packages/tightenco/collect_
---
@ -162,6 +152,7 @@ Wrote my own tests
## _composer require_<br>tightenco/collect
---
![](images/drupal-issue-2.png)
---
@ -171,6 +162,7 @@ Wrote my own tests
---
### _Version 2.0_
## Use someone elses Collection class
^ More fully featured, less code to maintain
@ -215,9 +207,8 @@ $collection->each(function ($item) {
});
```
^ Require/include autoload.php
Start using Collections!
`collect` function is autoloaded
^ Require/include autoload.php Start using Collections! `collect` function is
autoloaded
---
@ -242,5 +233,7 @@ Start using Collections!
[.header: alignment(center)]
# Thanks!
### _@opdavies_
### _oliverdavies.uk_