Laravel/Vue.js勉強会#9 開催しました!

こんにちは、株式会社SCOUTERの佐藤( @r_sato1201 )です。

先日、Laravue勉強会#9を開催いたしました。 はやいもので、今回で第9回目。今回もたくさんの方に参加していただき、とても有意義な勉強会になりました。 今回はその模様を報告させて頂きたいと思います。

laravue.connpass.com

会場

今回は、カオナビさんのオフィスをお借りしました。 f:id:ryonnsui1201:20190523111947j:plain

写真が少なく、内観が伝わらないかもしれませんが非常に綺麗で、素敵なオフィスでした。 今回のLaraVue勉強会以外でも、勉強会などをカオナビさんのオフィスで実施するようなので、是非行って確認してみてください!

発表内容

スポンサー枠も含め、7人のかたに発表していただきました。 発表資料が公開されている中で、特に印象に残った発表を抜粋して報告したいと思います。

SSRの話(@kahirokunnさん)

f:id:ryonnsui1201:20190523113242j:plain

トップバッターは @kahirokunnさん。 SSRまわりの話をしていただきました。

サーバーサイドで描画した後、その結果をjsonとしてhtmlに埋め込み、クライアントサイドではその結果を流用してすばやくDOMを再現することができるハイドレーションという機能は恥ずかしながら初めて知りました。とてもおもしろい内容で、SSRまわりに関してもっと理解を深めなくてはいけないと感じました。

slides.com

Optional Chaining + Laravel FormRequestでバリデメッセージを表示する (@kotamat)

 f:id:ryonnsui1201:20190523113327j:plain

弊社CTO、松本の発表です。

LaravelのFormRequestは非常に便利だが、ネストしたエラーメッセージはハンドリングが辛いためOptional Chainingを使うと非常にハンドリングしやすいという内容でした。
冗長なコードを避ける、ベストなプラクティスだと思います。 ただし、Optional ChainingはBabel7から入ってきたもので、Vue2系だとテンプレートにBabelは入っていません。その際の回避策として、optional-valueを使うといいようです。

slides.com  

Laravel+Dockerを本番でも使いたい!(@moyashidaisukeさん)

f:id:ryonnsui1201:20190523113438j:plain

LaravelでDockerを本番でも使う際の知見を発表していただきました。
LaraDockとAWS Fargateは相性が悪く、LaraDockはVolumeを使ってホストのディレクトリをマウントすることが前提になっているが、fargateはホストという概念がないためそれができないそうです。 自分でDockerfileを書くときの設定など、とてもわかり易くまとまった内容でした。

docs.google.com 

Laravel 初めての業務で遭遇したハマりポイント×2(furuichiさん)

f:id:ryonnsui1201:20190524045933j:plain

業務上で遭遇したハマりポイントを発表していただきました。
Eloquentは主キーのカラム名idを想定しており、それ以外の名前を主キーに設定したい場合は、モデルの中に明示的に追加しなくてはならない、というのは初めて知りました。 さらに調べたところ、デフォルト状態で主キーは自動的にintへキャストされるので、自動増分、整数値でない主キーを使う場合、モデルにpublicの$incrementingプロパティを用意し、falseをセットする必要があるようです。とても勉強になりました。

speakerdeck.com

懇親会

f:id:ryonnsui1201:20190523104416j:plain f:id:ryonnsui1201:20190523112423j:plain

発表後は、カオナビさんが提供してくれた飲食を囲み懇親会をしました! 多くの方に残っていただき、懇親会で親交を深めていただきました。

まとめ

初学者からエンジニア歴が長い人まで、各々の知見を共有できた素晴らしい勉強会になったと思います。 スポンサーして頂いた、カオナビさんありがとうございました!

詳細な日程は未定ですが、次回は7月頃にheyさんの会場をお借りして開催いたします!

最後に

SCOUTER社では一緒に頑張ってくれる方を募集しております。 デザイン、エンジニアの皆さん興味のある方はご応募お願いします!

www.wantedly.com

www.wantedly.com

 

Vue Devtools で快適なデバッグ

こんにちは、 SCOUTER エンジニアの匠平@show60です。

SCOUTER のフロントエンドの開発は Nuxt.js を使用しており、デバッグの際に Vue Devtools というツールを使っています。

今回はこの Vue Devtools で、開発に普段使いしてもらいたい機能をいくつかご紹介したいと思います。

Vue Devtools の導入

最も人気がありシンプルなのは、Chrome 向け および Firefox 向け の優れた Vue.js devtools を使用することです。

VS Code によるデバッグ — Vue.js

Vue Devtools の導入には、拡張機能とデスクトップアプリケーションの2つの方法があります。

Chrome と Firefox は拡張機能が提供されており、普段の Devtools と同じように開けるのでこちらが便利でしょう。

他のブラウザをお使いの方は、デスクトップアプリで使用することになります。

ここでは Chrome 拡張機能を用いて、以下のとおりシンプルな Nuxt.js アプリケーションを例にしたいと思います。

f:id:show-hei:20190514212914p:plain

Vue Devtools の基本機能

Devtools とは、ブラウザで使用できるデバッグツールで、主にフロントエンド開発に使用します。

3月末に Vue Devtools が ver 5 にアップデートされ、新しい機能が追加されました。

基本機能に大きな変更はありませんが、新たに追加された機能、強化された機能を織り交ぜて紹介します。

  • イベントの動作をレコーディング
  • パフォーマンスタブでレンダリング時間を計測
  • Vuex 内のデータを編集
  • 試してほしい便利機能

イベントの動作をレコーディング

このタブでは、アプリ内で行われたイベントをレコーディングし、それらの動作によって正しくデータが渡されているかを確認することができます。

以下のサンプルの input は、 AppInput.vue というコンポーネントとそのラッパーである InputWrapper.vue で構成されています。

f:id:show-hei:20190514214644g:plain

input タグにテキストを入力すると、中央にそのタグ名や時刻などが表示され、右側は event info 、つまりイベントの詳細が書かれています。記録されるイベントは $emit が対象となるようです。

event info の項目

  • name
    • イベント修飾子の名称
  • type
    • イベントの種類 (Vue Devtools の Github を見る限り、表示されるテキストは $emit しかないよう)
  • source
    • イベントを含んでいるコンポーネント名
  • payload
    • 受け渡されたデータ

このサンプルでは単純な構成ですが、複数のコンポーネントを経由してデータを受け渡すことも多いでしょう。

目的のページやコンポーネントまでデータが渡らないというときに、どのコンポーネントまで渡ってきているのかが視覚的に分かりやすくなります。

1動作ごとに記録ができるので、ほしいデータが膨大な記録に埋もれてしまうといった心配もないですね。

パフォーマンスタブでレンダリング時間を計測

パフォーマンスタブ内では2つの方法でパフォーマンスを計測することができます。

Frames per second

Vuex やルーティングなどの動作のパフォーマンスを計測することができます。 レコーディングを Start し、ブラウザ操作を行った後に Stop するとその間のパフォーマンスを秒単位計測することができます。

f:id:show-hei:20190514225955p:plain

アルファベットが書かれた丸いアイコンが、その動作を示しています。

  • E: Events
  • R: Routes
  • M: Mutations

Vuex の Mutations の動作が記録されるため、動作のタイミングを確認したり、重複している動作を見つけるのにも役立ちそうです。

f:id:show-hei:20190514230409p:plain

計測したパフォーマンスは自動的に保存されるため、複数回の計測で比較することもできますが、表示が秒単位なので細かな分析には向いていないかもしれません。

Component render

こちらもレコーディングを Start してから Stop するまでの時間を計測することができますが、コンポーネント単位でのレンダリングを表しています。

f:id:show-hei:20190515034044p:plain

右側には Vue.js の Lifecycle hooks の関数と同名の項目が並んでおり、各項目ごとの処理時間がミリ秒単位で記されています。

手元のコードで動かしてみる限り、 mountRenderupdateRender あたりのレンダリング処理は他の処理と比べて時間がかかるようです。

ページやコンポーネントの処理に時間がかかるなどといった場合のデバッグに利用できそうです。

Vuex 内のデータを編集

以前のバージョンより、 Vuex の state, mutation, getters を確認することができていましたが、 Ver 5 のアップデートからは新たに Devtools 上で Vuex を編集できるようになりました。

f:id:show-hei:20190515044042g:plain

ブラウザ上に表示されるテキストであればブラウザの Devtools で編集してしまうと思います。

そうでない裏側で動いている Vuex のデータで、ちょっと値を変更して確認したいだけなんだよなーってときにはとても便利です。

数値であれば + - で簡単に増減できますし、配列の要素も同様に増やすことができます。

試してほしい便利機能

Vue Devtools の隅っこの見逃しそうな場所に inspect DOMOpen in editor があります。

f:id:show-hei:20190515111448p:plain

ブラウザの横幅を縮めると見えなくなっちゃうのですが、もっと自信を持って表に出てきてもいいくらいの便利機能です。

ブラウザの Devtools にジャンプ

inspect DOM は、今開いているコンポーネント (ここでは <logo>) を通常のブラウザの Devtools の Elements で開いてくれます。

f:id:show-hei:20190515111609p:plain

わざわざ同じ箇所を再度探す必要がないので二度手間が省けてちょっとだけ嬉しくなれます。

見ているコンポーネントをエディタで自動的に開く

Open in editor をクリックすると、今開いているコンポーネントファイルをデフォルトエディタとして登録しているエディタで開いて表示してくれます。

f:id:show-hei:20190516110834g:plain

デバッグで当たりをつけたらこの Open in editor をクリックするだけですぐに修正を書き始めることができます。

これもコンポーネントを探す手間がいらないのでめちゃめちゃ便利です!

さいごに

基本機能を直感で簡単に使えるようになっている分、他の機能に触れることが少ないかもしれません。 かゆいところに手が届く仕様になっていると思うので、ぜひお試しください!

私達 back check チームは、日本の採用文化を変えるために、共にプロダクト開発をしていただけるエンジニアの募集をしております。

興味をお持ちいただいた方はぜひご連絡ください。

www.wantedly.com

www.wantedly.com

NuxtMeetUp#8 を開催しました

こんにちはみなさん niisan-tokyoです。

弊社ではアプリケーションの開発にLaravel + Vue.js を採用しておりますが、バックエンドとフロントエンドの分離を促進するために、最近ではバックエンドをLaravel、フロントエンドをNuxt.js で実装することが多くなっています。
そんななかで、過去最大規模である180人定員のNuxtMeetupを、令和初営業日の5/7に開催しまして、その開催報告を書いていこうかと思います。
nuxt-meetup.connpass.com

また、今回はスポンサーに株式会社ガイアックス様をお迎えし、イベントスペースを提供していただきました!

会場

会場は永田町にあるNagatacho GRiDさんのイベントスペースを使用させていただきました。 grid.tokyo.jp 設営のために到着した直後はこんな感じでした。

f:id:niikura23:20190509101052j:plain
会場
いい感じですね。
その後、人数規模に合わせて椅子を増設した結果、開催時にはこんな感じになりました。
f:id:niikura23:20190509101259j:plain
開催時の様子
改めて見てもすごい人数です。
それだけNuxt界隈が盛り上がっていることなのでしょう!

懇親会

ミートアップですので、セッションと同じくらい大事なのが懇親会です。
今回もたくさんの方に懇親会に参加していただきました。
その様子がこちらです。

f:id:niikura23:20190509101118j:plain
フード
f:id:niikura23:20190509104754j:plain
懇親会の様子

セッション

ミートアップといえばやはり濃密なセッションです。 すべて紹介するのは冗長なので、いくつかピックアップしていこうかと思います。

スタートアップがNuxtを採用するメリット

slides.com

株式会社テックピットの前山さんによるスポンサーセッションですが、Nuxtを採用する場面がどこなのか、実用に即して発表しておられました。
スポンサーはガイアックスさんではなかったのか、って思ったのですが、「Gaiax STARTUP STUDIO」という、スタートアップを同時多発的に生み出す組織にて立ち上がったスタートアップであるとのことでした。

axios-moduleをやめてaxiosを使う

slides.com

ピクセルグリッド所属で、副業で弊社のプロダクトにジョインしているじまぐさんによる発表です。
「プロダクトの成長を阻害する仕組みを排除する」という至言が飛び出す、個人的にとても感銘を受けた発表でした。

新規に参画したプロジェクトでNuxtに移植しようとした話

speakerdeck.com

株式会社オクトの藤井さんによる発表です。
現行システムをNuxtに移行している最中という、実例に即した現在進行形の話であり、今後Nuxt移行を進めたい方々にとっては貴重なセッションだったのではと思います。
「ブログで経過報告しているよ!」とのことなので、今後の推移が気になるところです。

まとめ

今回、NuxtMeetUpには初参加かつ開催側での参加ということもあり、いろいろ右往左往した部分もありましたが、参加者の方々のおかげで無事に終えることができました。

最後に

現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

www.wantedly.com

www.wantedly.com

LaravelにおけるMVCの基本

こんにちは!
株式会社SCOUTER開発部フロントエンドエンジニアの佐藤(@r_sato1201)です

弊社では、Laravel+Vue(nuxt)で開発をしています。 私は普段、フロントエンドの開発を担当していますが、サーバーサイドでの開発もできるようにしたいと思いLaravelの学習を始めました。

学習を進めていても、初めはどのような処理の流れなのか、MVCって何?といった感じで全くどのような動きをしているのかが掴めませんでした。

今回はLaravel初学者の方向けに、MVCにそって
シンプルなTODOアプリの「ユーザーのブラウザにサイト画面が表示されるまで」を例に、自分が理解した基本的なLaravelの処理の流れを説明したいと思います。

DBは下記のような想定です。

tasks

カラム名 内容
title タスク名
content タスクの内容

MVCとは

MVCとはアプリケーションを実装するためのデザインパターンです。 複雑なアプリケーションの処理を3つの役割に分割することで、実装の見通しもよくなるというメリットがあります。

それぞれの役割は、

Model データ処理全般。DBへのアクセスに関する処理を行う
View 画面表示を担当。ユーザーに表示する情報を出力する
Controller 全体の制御を担当。ユーザーからの入力をモデルに渡したり、モデルから渡されたデータをビューに渡し画面に表示する役割を担う

となっています。

ルーティングの設定

まずはルーティングです。 ルーティングとは、アクセスしたアドレスをもとに処理を割り振るための機能です。

routes/web.php

Route::get('tasks', 'TasksController@index');

例えば、上記のように書くとGETでルートパスにアクセスした際に
TasksControllerというコントローラのindexメソッドが実行されることを表しています。

モデル

モデルは、DBからデータを取得する処理が書かれています。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    //
}

中身は空ですが、これでDBのtasksテーブルと紐付けることができます。

createやupdateなどの処理を実装した際は、 初期設定のままだとテーブルのどのカラムにも値を挿入することが出来てしまいますが、
fillableguardedを使うことで、こちらが意図していないカラムへの挿入を防ぐことが出来ます。
fillableプロパティには、挿入したいカラムを
guardedプロパティには、挿入したくないカラムを
指定することができます。

class Task extends Model
{
    protected $fillable = ['title', 'content'];
}

今回の例だと、title,contentはユーザーが値を自由に挿入するカラムなので、fillableを使っています。

コントローラ

コントローラとは、モデルとビューの橋渡しをする役割をしています。

app/Http/Controllers/TasksController.php

class TasksController extends Controller
{
    public function index()
    {
        $tasks = Task::all();
        return view('tasks.index', compact('tasks'));
    }
}

これはTaskモデルを使って、DBからデータを取得しビューに渡す処理をしています。

ビュー

ビューは画面表示を担当する箇所です。 コントローラーで運んできたデータを使って画面を完成させます。 ビューには、bladeというLaravelのテンプレートエンジンを使用します。 bladeはビューのなかに直接PHPを記述することもできます。 基本的にはresources/viewsディレクトリの中に設置します。

resources/views/task/index.blade.php

<html>
<head>
  <title>タスク一覧画面</title>
</head>
<body>
<h1>タスク一覧</h1>
<table>
  <tr>
    <th>タスク名</th>
    <th>内容</th>
  </tr>
  @foreach ($tasks as $task)
  <tr>
    <td>{{$task->title}}</td>
    <td>{{$task->content}}</td>
  </tr>
  @endforeach
</table>
</body>
</html>

まとめ

以上で、ユーザーのブラウザにサイト画面が表示されるまでの流れを追うことができました。 まとめると、

  1. ブラウザのURLによってルーティング処理を行う
  2. 該当のコントローラでDBからの情報を取得するようモデルに指示
  3. モデルでDBからデータを取得
  4. コントローラがモデルで取得したデータをビューに渡す
  5. ビューでユーザーの画面に表示

となります。

次回以降の投稿では、

  • ビューの部分をLaravelに置き換える
  • 生成、更新処理の流れ
  • ユーザー認証

などの内容をアウトプットできればなと思います。

さいごに

現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

www.wantedly.com

www.wantedly.com

参考資料

Vue.jsを1年触ったのでオススメパッケージを紹介

はじめに

こんにちは株式会社SCOUTERでエンジニアをしているhirokinishizawaです。 業務では、SARDINEという人材紹介会社向けの業務管理システムを開発しています。

前回プログラミングを初めてから1年が経ったので「1年間のプログラミングを通して得た3つの教訓」というブログを書きました。

1年間実務だけやってきて自分が得た教訓をプログラミングを始めたばかりの方や、これから始めてみたいと思っている方に共有できればという思いで書いた記事になっています。

techblog.scouter.co.jp

今回は1年間Vue.jsを触ってきて自分がおすすめだなと思ったパッケージについて紹介していきたいと思います。

紹介するパッケージ一覧

  • Vue.Draggable

github.com

  • vue-social-sharing

github.com

  • vue-carousel

github.com

  • vue-star

github.com

こちらの4つについて話していこうかと思います。

導入方法はすべて定番のyarn add [package-name]npm install [package-name]で導入できます。

Vue.Draggable

以前Vue.Draggableを業務で扱う機会があったのでその時にブログを書きました。ドラッグ&ドロップでリストを並び替えすることをお手軽に実装できるパッケージになっています。

techblog.scouter.co.jp

業務で扱った時は横の移動だけではなく縦の移動もあるため縦の順番もデータとして持っておく必要がありデータベースの設計を慎重に行わなければいけませんでした。Vue.Draggableでドラッグ&ドロップをした時にどのようなデータを受け取ることができるのか把握してから設計を行えば横移動も縦移動も問題なく動かすことが出来るかと思います。

vue-social-sharing

vue-social-sharingとfont-awesomeを導入することでソーシャルボタンを簡単に設置できます。

<template>
  <social-sharing
    url="https://twitter.com/hiroki_2438"
    title=" タイトル記載"
    description="説明文を記載してください"
    hashtags="Vue.js"
    twitter-user="hiroki_2438"
    inline-template
  >
    <div>
      <network network="facebook">
        <i class="fa fa-facebook-official"></i>
      </network>
      <network network="twitter">
        <i class="fa fa-twitter"></i>
      </network>
    </div>
  </social-sharing>
</template>

<script>
import SocialSharing from "vue-social-sharing";

export default {
  components: {
    SocialSharing
  }
}
</script>

f:id:hiroki-nishizawa:20190419033835p:plain

networkタグのnetwork属性を変更することよりソーシャルメディアを変更をすることができます。

今回facebooktwitterだけしか実装していませんが他にも

など。上記以外にもありますが、メインどころはこんなところでしょうか。

次にSocialSharingコンポーネントにpropsでtitleなどを渡していますが実際にコンポーネントで何を受け取っているのか調べてみました。

渡しているもの 説明 補足
url シェアしたいurlになります 何も指定しなければでソーシャルボタンが設置されているurlが指定されます
title タイトルになります 利用可能なのはemail,twitterになります
description 説明文です 利用可能なのはemail,LINE,SMS
quote facebook用のquoteになります facebookのみ使用可能
hashtags ハッシュタグです facebooktwitterのみ使用可能でfacebookは1つ目のみ使われます
twitter-user twitterのアカウントIDをいれてください twitterのみ使用可能

自分がよく使うのは基本的にfacebooktwitterなので十分だったのと、導入するだけで簡単に実装できるし以前aタグでやっていたときより簡潔で読みやすくなるのでおすすめです。

以前aタグでやっていた時

#facebook
<a class="fb btn" :href="`http://www.facebook.com/share.php?url=urlを記載`"
             onclick="window.open(this.href, 'FBwindow', 'width=650, height=450, menubar=no, toolbar=no, scrollbars=yes'); return false;">
    <img src="facebookのicon画像">
</a>

#twitter
<a :href="`https://twitter.com/intent/tweet?text=タイトル&url=urlを記載`" target="_blank">
    <img src="twitterのicon画像">
</a>

vue-carousel

vue-carouselはカルーセルを簡単に実装できレスポンシブにも対応していてとても使いやすいUIコンポーネントです。

<template>
  <Carousel
    :per-page="1"
    loop=true
    :navigation-enabled="true"
    navigation-prev-label="〈"
    navigation-next-label="〉"
    touchDrag=true
    :speed="1000"
  >
    <Slide v-for="(slide, key) in slides" :key="key">
      <span>{{slide}}</span>
    </Slide>
  </Carousel>
</template>

<script>
import { Carousel, Slide } from "vue-carousel";

export default {
  components: {
    Carousel,
    Slide
  },
  data() {
    return {
      slides: ["slide1", "slide2", "slide3", "slide4", "slide5", "slide6"]
    };
  }
};
</script>


f:id:hiroki-nishizawa:20190419053208p:plain

上記のCarouselコンポーネントにpropsで渡してしているのは

  • per-page
    • 各ページに表示されるスライドの最大数
  • loop
    • 最後に到達したときにカルーセルをループさせるためのもの
  • navigation-enabled
    • navigation-prev-labelとnavigation-next-labelを使用できるようにするもの
  • navigation-prev-label
    • ナビゲーションの前に戻るボタンのテキスト
  • navigation-next-label
    • ナビゲーションの次に進むボタンのテキスト
  • touchDrag
    • タッチドラッグを出来るようにするもの
  • speed
    • スライドする時のスピードを調節するもの

それぞれこのような設定になっています。

今回使っているものの他に autoplay autoplayDirection autoplayHoverPause autoplayTimeoutのように時間で自動的にスライドを出来るようにするための設定だったり、スマホ用にスワイプで切り替わるようにするための設定だったりとカルーセルの実装をするために必要なものを簡単に実装できるのがとてもおすすめできるポイントだなと思います。

vue-star

twitterのいいねみたいなアニメーションを簡単に実装できるUIコンポーネントになっています。

<template>
  <vue-star color="#F05654">
    <i slot="icon" class="fa fa-heart"></i>
  </vue-star>
</template>

<script>
import VueStar from "vue-star";
export default {
  components: {
    VueStar
  }
};
</script>

f:id:hiroki-nishizawa:20190419195526g:plain

他にもcolorのカラーコードを変えて色を変更したり、animateという属性を使ってanimationのクラスを入れることによって違う動きができたりします。 自分は使っているのですがanimate.cssを入れることでより簡単にanimationの幅を広げることができます。

<template>
  <div class="vue-stars">
    <vue-star animate="animated wobble" color="#0000ff">
      <i slot="icon" class="fa fa-heart"></i>
    </vue-star>
  </div>
</template>

f:id:hiroki-nishizawa:20190419195233g:plain 自分がプログラミングを初めて半年とかの時に業務でお気に入り機能を実装することになったのですが、当時デザイナーの意向でやりたいという話になりcssで出来るっぽいってとこまでわかったのですが工数的にやらないという意思決定になりました。そのときにこれを知っていたら実装できたのではないか。と思っております。。。

このようなアニメーションが必要な時にほんと簡単に実装できるのでとてもおすすめです。

まとめ

今回は数あるパッケージの中から自分が実際に使い個人的にいいなと思ったパッケージを紹介しました。もちろん他にもたくさんのパッケージがあります。今回紹介したものと似たようなパッケージ、自分が知らない便利なパッケージ、絶対業務では扱わないけど面白そうなパッケージ。たくさんのVue.jsのパッケージがあり、パッケージをまとめてくれている方も多いので試しに使ってみてはいかがでしょうか。

自分の場合はドラッグ&ドロップをしたいだったり、カルーセルを実装したいだったりしたときにVue.jsを冒頭に付けて検索をした結果触ることになったり、まとめてくれているサイトで面白そうってだけで触ったりしました。

最後に

弊社では事業・サービスが成長していくにあたってメンバーを増やしていきたいと思っています。

興味のある方は下記からご応募いただくか、@hirokiにご連絡ください!!

www.wantedly.com

www.wantedly.com

www.wantedly.com

E2Eテストを導入して自分を救う (TestCafe編)

こんにちは、自意識過剰な正義のヒーローでお馴染みの株式会社SCOUTERの石岡 将明( @masaakikunsan )です。

先月のブログで、フロントにおける unit test についてブログを書いている人がいたので、今回は E2E テストについて書いていこうかなと思います。

E2E テストとは

E2E (End to End)テストとは Web ブラウザを通して一通りの処理をテストすることです。

今回のデモで作成するものを例として挙げます。

  1. ユーザー登録画面を表示
  2. 名前を入力
  3. bioを入力
  4. 送信ボタンをクリック
  5. ユーザー一覧ページに遷移
  6. ユーザー一覧に追加したユーザーが追加されている

なぜ E2E テストが必要なのか

みなさんはリリース前にテストをして最終確認をすると思います。 その際に全ページの UI の確認と挙動が想定どおりになるかどうかのテストを毎回していたらかなり時間の無駄です。

そこで、 E2E テストをすることで手を動かさずに全ページの UI と挙動のテストをすることができ、時間もコストもかなり下がり生産性があがるでしょう。

また、このような経験はありませんか?

実装した箇所以外のテストが漏れていてリリースしたらバグがあった。みたいな E2E テストを実行すれば基本的にこれは防げます。

全画面のテストを自動でやることで、影響範囲の漏れもなくなり品質担保にも繋がります。

つまり、 E2E テストはコストを下げる為だけでなく自分を救うことにも繋がります。

Nuxt.js に E2E テストを導入しよう

json-server を追加する

今回はテストに使う mock サーバーとして json-server を利用します。

さっそく導入していきます。

$ yarn add -D json-server

次に json を追加していきます。

db/db.json を追加して以下を記載します。

{
  "user": [
    {
      "id": 1,
      "name": "masaakikunsan",
      "bio": "自意識過剰な正義のヒーロー"
    }
  ]
}

最後に json-server を実行するために package.json に scripts を追加しましょう。

"server": "json-server --watch db/db.json --port 4000"

これで、 $ yarn server を実行し、 localhost:4000/user にアクセスすると db.json に記載したデータが表示されるでしょう。

f:id:masaakikunsan:20190416172936p:plain

次に、ユーザー一覧ページとユーザー作成ページを作っていきます。

ユーザー一覧とユーザー作成ページ

下記のようなページを作成しました。

f:id:masaakikunsan:20190416185539p:plain

f:id:masaakikunsan:20190416185657p:plain

コードはURLを載せて置くのでみてください。 github.com

TestCafe の導入

E2E テストですと、Puppeteer がかなり主流になってきていますが今回は TestCafe を使います。 理由としては、ブラウザを指定することでそのブラウザでのテストが可能だからです。

あと Puppeteer よりドキュメントが読みやすくて個人的に好きというのもありますw

まぁ他にも理由はあるので自分で調べてみてください。

devexpress.github.io

それではさっそく導入していきましょう。

$ yarn add -D testcafe

次に TestCafe を実行するために package.json に scripts を追加しましょう。

"e2e": "testcafe chrome test/e2e/*.js --speed 0.5"

speed を指定することで E2E の実行スピードを指定できます。

それでは、テストコードを書いていきましょう。

test/e2e/test.js を作成し下記コードを記載していきます。

import { Selector } from 'testcafe'

fixture('ユーザー追加').page('http://localhost:3000/create')

const customDataAttribute = name => `[data-test='${name}']`

test('必要項目を入力後、送信して遷移先を確認', async t => {
  const userName = await Selector(customDataAttribute('name'))
  const userBio = await Selector(customDataAttribute('bio'))
  const submitButton = await Selector(customDataAttribute('submit-button'))

  await t
    .setNativeDialogHandler(() => true)
    .typeText(userName, 'test')
    .typeText(userBio, 'bioだよ〜')
    .click(submitButton)

  const tableUserName = await Selector(customDataAttribute('user-name')).nth(-1)
    .innerText

  await t.expect(tableUserName).eql('test')
})

Selector は、テスト内の要素を識別するものです。 ここでは、data属性を定義しそれを元に要素を識別しテストを実装していきます。

それでは実行していきましょう。

テストで正しく挙動していることが確認できました。

scripts の testcafe の横の chromesafari にすれば safari が起動しますし、 firefox にしたら firefox が起動します。 これでブラウザテストの時間もかなり削減できます。

まとめ

E2E テストでの実装例を紹介していきました。いかがだったでしょうか?

E2E を実際のプロダクトにいきなり導入するのはコスト的にも難しいでしょう。 ただ、E2Eテストを絶対にバグっててはいけないところだけ導入するだけでもかなりテストの工数も下がり良いでしょう。

ずっと、言っていますが自分を助けることになります。

ちなみに、僕はフリーランスのときに実装した箇所がクレカ決済の箇所に影響が及んでいてクレカ決済が死ぬっていうバグを起こして以来テストはまじ大事自分を助けるって気持ちになっています。

現在、back check チームでは、エンジニアの募集をしております。 僕と一緒にフロントエンドを朝まで語り尽くしたいフロントエンドエンジニアやレベルの高いフロントエンドチームと最高のプロダクトを作って行きたいサーバーサイドエンジニアは是非ご応募お願いいたいします!

www.wantedly.com

www.wantedly.com

[Nuxt.js] middleware で外部リソース取得処理を共通化

こんにちは!

SCOUTER社でエンジニアをしている匠平@SCOUTER(@show60)です。

開発を進めるにつれ page component も増えていきますが、複数の page component で同じ外部リソースが必要なことがあります。

同じ処理を行っている場合は処理をまとめちゃいたいですね。

そんなときのために、 middleware を使った処理の共通化についてお話しします。

fetch で外部リソースからデータを取得する

page component 内で使われるデータを外部リソースから取得したいとき、 Nuxt.js では page component 内で fetch を使うことでこの処理を行うことができます。

また、この fetch は、取得したデータを Vuex store に格納することを前提としています。

これにより、その page component 配下にある component でも Vuex store に格納されたデータを扱うことができるようになります。

下図内で、 ...fetches data before rendering page と記述してあるとおり、 page component で記述した fetch はその page component が読み込まれる度、そのレンダリングの前に発動します。

複数の page で使われている処理を共通化

複数の page compoent において、fetch で同じデータを取得しているとき共通化を考えます。 どこからでも呼び出せる処理の実装を考えたときに、手段として mixins と middleware があります。 fetch は page component でしか動作しないため、 mixins と middleware 上では、他の方法を考える必要があります。

mixins

下記の mixins を page component で呼び出すと page component 内で sample という data を使用することができます。 created のタイミングでデータ取得処理を発動させ、それを data に挿入しています。

// mixins/sampleMixins.js
export default {
  data: () => {
    return {
      sample: []
    }
  },
  created() {
    this.getSamples()
  },
  methods: {
    async getSamples() {
      this.sample = await this.$axios.$get('/api/sample')
    }
  }
}

ただし、 page component 内ですでに sample という名前で data が定義されている場合、そちらが優先されてしまいますので注意してください。

参考: Option Merging

外部リソースからデータを取得する処理自体は共通化することができましたが、この page component 配下で使用するためには props でデータを渡していく必要があります。

middleware

middleware 内では下記のようにすることで、外部リソースへ接続し、 Vuex store に値を格納することができました。

// middleware/index.js
export default ({ store }) => {
  // すでに store にデータが格納されている場合は再取得を行わない
  if (store.state.sample) {
    return
  }
  store.dispatch('getSamples')
}

middleware はページ遷移する度に呼び出されるため、必要なデータがすでに Vuex store に存在しているのであれば再取得の処理を行わないよう記述してあげるといいですね。

middleware で共通化する上で注意すること

middleware を介して Vuex store にデータを格納できたのですが、適さないデータというのもあります。

Nuxt.js の SPA ではページ遷移しても Vuex store のデータをそのまま保持しています。そのため、利用中に書き換わる頻度が高いデータにおいては正しいデータを表示してくれない事態が起きます。

例えば頻繁な更新がないと思われるユーザー情報や、部署名と部署 ID の対応表といったようなデータの取得に使用するほうがいいでしょう。 ユーザー認証されているかを全 page に渡って確認したい場合もこのように処理します。

最後に

SCOUTER は先日、新サービス back check を正式リリースいたしました!

これからたくさんのお客様に最高のプロダクトを届けていくため、一緒に開発を進めていくエンジニアの募集をしております。

ぜひご興味を持ったかたはご連絡ください!

www.wantedly.com

www.wantedly.com