前回の記事でclientScripts
メソッドについて説明したので具体的な実装方法について書いていきます。
(一緒にE2E実装を進めてくれた@rainymoment0616さんThanksです)
##大まかな実装の流れ
①チェックしたい箇所が視覚的に分かるようにテスト用CSSファイルを作成する
②TestcafeのclientScripts
メソッドを利用して作成したCSSを挿入し、チェックしたい要素にスタイルが当たった状態のスクリーンショットを撮影
かなりざっくりですが、流れはこんな感じです。
それでは、いきます!
##CSSを用意する
まずはテスト用のCSSを作成します。
- 任意の場所にファイルを置きます。
e2e/stylus/e2e-markup.styl
:リスト系の子要素に誤った要素が入ってないか/h1があるかどうかチェックする用
e2e/stylus/e2e-img.styl
:alt属性・width属性・height属性が含まれているかチェックする用
e2e/stylus/e2e-link.styl
:blankにrel="noopener"が付与されてるか/javascript:void(0)が使われてないかチェックする用
今回は用途に合わせて3種類のCSSを作成しました。
チェック項目がたくさんあると見た目が煩雑になって確認しづらくなったり、imgだけ〜linkだけ〜チェックしたい時のために分けています。
CSSはこんな感じ↓
// variables
// ------------------------- //
$testcafe-error=#dc143c
$testcafe-error_=rgba(220, 20, 60, .3)
$testcafe-warn=#ffd700
$testcafe-warn_=rgba(255, 215, 0, .3)
// mixins
// ------------------------- //
$grad(color, deg)
background-size: 20px 20px
background-image: linear-gradient(deg, transparent, transparent 25%, color 25%, color 50%, transparent 50%, transparent 75%, color 75%,color)
background-repeat: initial
h1
outline: 2px solid #66cdaa
background: rgba(102, 205, 170, .3)
// 子要素で利用されているもののチェック
ol
& > *:not(li)
$grad($testcafe-error, 45deg)
&:before
display: block
content: '【NG】olタグの子要素はliのみだよ!'
background-color: $testcafe-error
color: #fff
ul
& > *:not(li)
$grad($testcafe-error, 45deg)
&:before
display: block
content: '【NG】ulタグの子要素はliのみだよ!'
background-color: $testcafe-error
color: #fff
dl
& > *:not(dt):not(dd):not(div)
$grad($testcafe-error, 45deg)
&:before
display: block
content: '【NG】dlタグの子要素はdt, dd, divのみだよ!'
background-color: $testcafe-error
color: #fff
// TODO: あるorなしチェック
// 「存在してたら」はできるけど、「なかったら」は厳しそう
hgroup
outline: 2px solid $testcafe-warn
background-color: $testcafe-warn_
&:before
display: block
content: '【注意】一部廃止されてるのでhgroupの使用は非推奨'
background-color: $testcafe-warn
font,
[size]
[color]
outline: 2px solid $testcafe-error
background: $testcafe-error_
&:before
display: block
content: '【非推奨】font要素、size属性/color属性は、HTML5で廃止されたよ'
background-color: $testcafe-error
color: #fff
time:not([datetime])
outline: 2px solid $testcafe-warn
background: $testcafe-warn_
&:before
display: block
content: '【注意】datetime属性ついてないけど大丈夫?'
background-color: $testcafe-warn
stylusやSassなどで書いていく場合はgulpやwebpackでcssにコンパイルしてください。
【gulpを使う場合の例】↓
const stylusTask = () => {
return gulp
.src('e2e/stylus/e2e-*.styl')
.pipe(stylus())
.pipe(pleeease({
stylus: true,
minifier: true,
autoprefixer: {
"browsers": ["last 4 versions"]
},
mqpacker: true
}))
.pipe(csscomb()).on('error', console.error.bind(console))
.pipe(cssmin())
.pipe(gulp.dest('static/testcafe'));
}
exports.stylusTask = stylusTask
Nuxt.js環境で実装しているのでCSSの生成先はstatic
にしています
##処理を書いていく
cssが用意できたら実行するための処理をJavascriptでザクザク書いていきます。
e2e/detail/markup.js
import { Selector, ClientFunction } from 'testcafe'
const config = require('../config')
const { testUrl } = config;
let scriptContent = `
var headEls = document.getElementsByTagName("head");
var headEl = headEls.item(0);
var styleSheetEl = document.createElement('link');
var cssType = document.createAttribute('rel');
var cssHref = document.createAttribute('href');
cssType.nodeValue = 'stylesheet';
cssHref.nodeValue = '/testcafe/e2e-markup.css';
styleSheetEl.setAttributeNode(cssType);
styleSheetEl.setAttributeNode(cssHref);
headEl.appendChild(styleSheetEl);
`;
// TODO: 読み込むCSSの制御
switch (process.argv[3]) {
default:
case 'markup':
break
case 'img':
scriptContent = `
var headEls = document.getElementsByTagName("head");
var headEl = headEls.item(0);
var styleSheetEl = document.createElement('link');
var cssType = document.createAttribute('rel');
var cssHref = document.createAttribute('href');
cssType.nodeValue = 'stylesheet';
cssHref.nodeValue = '/testcafe/e2e-img.css';
styleSheetEl.setAttributeNode(cssType);
styleSheetEl.setAttributeNode(cssHref);
headEl.appendChild(styleSheetEl);
`
break
case 'link':
scriptContent = `
var headEls = document.getElementsByTagName("head");
var headEl = headEls.item(0);
var styleSheetEl = document.createElement('link');
var cssType = document.createAttribute('rel');
var cssHref = document.createAttribute('href');
cssType.nodeValue = 'stylesheet';
cssHref.nodeValue = '/testcafe/e2e-link.css';
styleSheetEl.setAttributeNode(cssType);
styleSheetEl.setAttributeNode(cssHref);
headEl.appendChild(styleSheetEl);
`
break
}
const takeCapture = (testName, testUrl, time) => {
fixture(testName)
.page(testUrl)
.clientScripts({
content: scriptContent
});
test
('マークアップチェックスクショ', async t => {
// ↓デバッグモードにする時
// await t.debug()
await t.wait(time * 4)
const type = !!process.argv[3] ? process.argv[3] : 'basic'
await t
.takeScreenshot({
path: `markup/${type}/${testName}.png`,
fullPage: true,
})
})
}
const urlList = [
{
'testName': 'top',
'url': `${testUrl}`
},
{
'testName': 'about',
'url': `${testUrl}/about`
}
]
urlList.forEach(obj => {
const delay = !!obj.time ? obj.time : 1000
takeCapture(obj.testName, obj.url, delay)
})
####process.argv[i]
チェック項目ごとにcssを分けているので、コマンドライン引数を取得し、読み込むcssを制御しています。
"scripts": {
"markup": "testcafe e2e/detail/markup.js",
"markup_img": "testcafe e2e/detail/markup.js 'img'",
"markup_link": "testcafe e2e/detail/markup.js 'link'"
}
package.jsonのscriptsにこのように記述しているため、imgとlinkのコマンドを実行する時の引数は3
になります。
コマンドライン引数を取得するには
for (var i = 0; i <= process.argv.length; i++) {
console.log("argv[" + i + "] = " + process.argv[i]);
}
これで引数を調べることができるので環境に合わせて変更してください。
チェック用CSSを読み込んでみるとこのようになります。
左から
- マークアップチェック用CSS
- imgチェック用CSS
- linkチェック用CSS
赤や黄色、ボーダーで目立つような色使いと:before/:after擬似要素で注意書きテキストが表示されるようになっているので分かりやすくなっていると思います!
###おまけ
Nuxtで、サンプル用ページpages/ignore/markup.vue
を作成しました。
このままだとルーティング生成されてしまうのでignoreでルーティング除外してください。
# ignoreフォルダにあるページを無視する
pages/ignore/*.vue
その他のignoreプロパティは公式をご確認ください。
以上、E2Eテスト -マークアップチェック編- でした!