20200721のNode.jsに関する記事は7件です。

[Node.js] 一時的ファイル(temp file)を使ってFirebase Storageへファイルをアップロードする

環境・バージョン

  • node version v14.4.0
  • "firebase-admin": "^8.7.0"
  • "tmp": "^0.2.1"

実装

Firebase Admin SDKの初期化

firebase-admin.js
var admin = require('firebase-admin')

// Retrieve environment variables
const ServiceAccountFilePath = process.env.FIREBASE_SERVICEACCOUNT_FILEPATH
const StorageURL = process.env.FIREBASE_STORAGE_URL // xxxxx.appspot.com

const serviceAccount = require(ServiceAccountFilePath)

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  storageBucket: StorageURL,
})

module.exports = admin

temp fileを使ってアップロード

Firebase Storageに対してファイルをアップロードするために、GCP Node.jsライブラリのBucket.uploadメソッドを利用しました。

一時的ファイル作成と削除にはtmpというサードパッケージを利用しました。

firebase-storage.js
const fs = require('fs')
const tmp = require('tmp')
const admin = require('./firebase-admin') // 上記の初期化コードをインポート

const requestToStorageService = (cloudFilePath, fileContent) => {
  var promise

  tmp.file(function _tempFileCreated(err, path, fd, cleanupCallback) {
    if (err) throw err

    try {
      const bucket = admin.storage().bucket()

      fs.writeFile(path, JSON.stringify(fileContent), err => { // 一時ファイルに書き込み
        if (err) throw err
      })

      promise = bucket.upload(path, { // ファイルをFirebase Storageへアップロード
        destination: cloudFilePath,
        metadata: { contentType: 'application/json' },
      })
    } finally {
      cleanupCallback() // ファイル削除
    }
  })

  return promise
}

tmp.file(function _tempFileCreated(err, path, fd, cleanupCallback)によって一時的ファイルのパス(path)とファイルディスクリプタ(fd)が渡されます。

そのファイルに書き込みし、Firebase Storageへアップロードします。

また、bucket.uploadはPromiseを返します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

簡単レシート印刷 receiptline の API を調べてみた

日本発のオープンソース receiptline でレシート印刷に少しずつトライしています。
何と超速でマクドナルドのレシートを再現している方を発見!びっくりこ!

落札したレシートプリンターは無事届きました。
しかしまだ準備ができていないので、前回利用した開発ツールを引き続き使います。
今回は receiptline の API です。

01.png

開発ツールは何をしている?

開発ツールの左側の編集エリアに文字を入力すると、右側のレシート用紙にプレビューが表示されます。
Web ブラウザーのデベロッパーツールを使って、開発ツールの内部を解析してみました。

02.png

入力データ

ReceiptLine
^^領収書|
2019/07/20 01:23|
#NGC17TH|

缶ビール | ¥211~
シュークリーム | ¥129*

出力データ

見やすいように整形して、   に置換しておきました。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="576px" height="168px" viewBox="0 0 576 168" preserveAspectRatio="xMinYMin meet" version="1.1">
    <defs>
        <filter id="receiptlineinvert" x="0" y="0" width="100%" height="100%">
            <feFlood flood-color="#000"></feFlood>
            <feComposite in="SourceGraphic" operator="xor"></feComposite>
        </filter>
    </defs>
    <g font-family="'MS Gothic', 'San Francisco', 'Osaka-Mono', 'Courier New', 'Courier', monospace" fill="#000" font-size="24" dominant-baseline="text-after-edge">
        <g transform="translate(0,48)">
            <text transform="scale(1,2)" x="504,528,552">領収書</text>
        </g>
        <g transform="translate(0,72)">
            <text x="384,396,408,420,432,444,456,468,480,492,504,516,528,540,552,564">2019/07/20&#xa0;01:23</text>
        </g>
        <g transform="translate(0,96)">
            <text x="480,492,504,516,528,540,552,564">#NGC17TH</text>
        </g>
        <g transform="translate(0,120)">
            <text x="0">&#xa0;</text>
        </g>
        <g transform="translate(0,144)">
            <text x="0,24,48,72">缶ビール</text>
            <text x="516,528,540,552,564">¥211&#xa0;</text>
        </g>
        <g transform="translate(0,168)">
            <text x="0,24,48,72,96,120,144">シュークリーム</text>
            <text x="516,528,540,552,564">¥129*</text>
        </g>
    </g>
</svg>

ソースコード

開発ツールの内部で、入力データを出力データに変換しているはずです。
ソースコードを解読して、該当部分を探し出しました。

designer/script/receiptline-designer.js
const printer = {
    cpl: Number(cpl.textContent),
    encoding: /^ja/.test(window.navigator.language) ? 'cp932' : 'cp437'
};
const svg = receiptline.transform(edit.value, printer);

ありました。transform メソッドです。
引数は、編集エリアの文字列と、オプション (レシート用紙の桁数、日本語 or 英語)。
戻り値は SVG の文字列です。これを DOM に変換して表示しています。

アプリ開発では、このメソッドに渡す文字列の組み立て処理がメインになりますね。

サンプルプログラム

receiptline パッケージには、コピーして使えるサンプルプログラムが添付されています。
・・・はじめからこちらをチェックすべきでしたね。

Web ブラウザー用

example/js/ja.html
// for SVG output
const printer = {
    // cpl: characters per line (required)
    cpl: 48,
    // font: Japanese, encoding: utf-8 (required)
    encoding: 'cp932',
    // upsideDown: ignored (optional)
    upsideDown: false,
    // gamma: ignored (optional)
    gamma: 1.0,
    // command: SVG (optional)
    command: 'svg'
};
const svg = receiptline.transform(reader.result, printer);

テキストファイルを読み込んで、変換して、表示しています。
中身は開発ツールのソースコードとほとんど一緒です。

Node.js 用

example/nodejs/start.js
sock.on('connect', () => {
    const command = receiptline.transform(text, printer);
    sock.write(command, /^<svg/.test(command) ? 'utf8' : 'binary');
});

テキストデータを HTTP で受信して、変換して、仮想プリンターへ送信しています。
開発ツールを起動する designer.js のソースコードと全く同じでした。

変換 API を使ったプログラミングは後日トライすることにします。
次回は仮想プリンターを試してみようと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ESLint 7.5.0

v7.4.0 | 次 (2020-08-01 JST)

ESLint 7.5.0 がリリースされました。小さな機能追加とバグ修正が含まれています。

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

? 日本語 Issue 管理リポジトリ
? 日本語サポート チャット (招待リンク)
? 本家リポジトリ
? 本家サポート チャット (招待リンク)


[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。


✨ 本体への機能追加

Optional Chaining 構文をサポートしました

? #13416

Optional Chaining 構文をサポートしました。新しい構文を利用するには、parserOptions.ecmaVersion2020に設定する必要があります。

.eslintrc.json (例)
{
    "parserOptions": {
        "ecmaVersion": 2020
    }
}

id-blacklist ルールが非推奨になりました

? #13465

前回のリリースで id-blacklist ルールは id-denylist に名称変更され、既存の id-blacklistid-denylist の別名になりました。

しかし、同じルールが複数の名称で存在するのは関連ツールにとって不便だったため、id-blacklist は非推奨としてマークされることになりました。今後は id-denylist をご利用ください。

? 新しいルール

特になし

? オプションが追加されたルール

sort-imports allowSeparatedGroups

? #13455

他の文、または空行やコメントによって分離されたimport文について、それぞれ別個に並び順を矯正するためのオプションが追加されました。

/*eslint sort-imports: [error, { allowSeparatedGroups: true }]*/

//✔ GOOD
import b from 'b.js';
import c from 'c.js';
// 空行やコメント行などで分離されているので、`import a` は `import b` より下にあっても良い
import a from 'a.js';

//✘ BAD
import b2 from 'b.js';
import c2 from 'c.js';
import a2 from 'a.js'; // 空行やコメント行などで分離されていないので、`import a2` は `import b2` より上にないとダメ

Open Online Demo

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

error TS1192: Module '"fs"' has no default export.

モジュール '"fs"' に既定エクスポートがありません
error TS1192: Module '"fs"' has no default export.

のようなエラーが出た時の対処法メモ

はじめに

これはnode.jsのデフォルトモジュールのfsが原因で起こるエラーでは有りません。
TypeScriptの仕様によるものです。
tsconfig.jsonのオプションでこのエラーを解決する方法があります。

結論

tsconfig.json"allowSyntheticDefaultImports": trueを追記する

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true
  }
}

または

// error TS1192: Module '"fs"' has no default export.
import fs from 'fs'

// no error
import * as fs from 'fs'

解説(tsconfigのオプション追加は省略)

TypeScriptでES6のデフォルト構文を使うとエラーでコンパイルエラーが起きます。

そういう時は下記の様な構文で指定ファイルの全てをインポートしてあげましょう。

import * as fs from 'fs'

エラーが出ないもの

また、下記の様に個別にexportされたものをimportする場合はエラーが出ません。

// hogeModuleファイル
export const hoge = () => {}
import { hoge } from 'hogeModule'

上記と同様にexport defaultが指定されているものもエラーになりません。

// hogeModule
export default class hoge {}
import hoge from 'hogeModule'

記事のもと

https://github.com/microsoft/TypeScript/issues/3337
https://qiita.com/bouzuya/items/edf5274241b50f32c621
https://qiita.com/alfas/items/539ade65926deb530e0e

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nodebrew使ってColorfulbox(レンタルサーバー)にNode.jsをインストールする

参考記事
https://qiita.com/yni17196791/items/f49b3e2f683cd06b3120

やってみる

$ wget git.io/nodebrew
$ perl nodebrew setup
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bashrc
$ source ~/.bashrc

確認

$ nodebrew -v
$ nodebrew install-binary stable
$ nodebrew ls
$ nodebrew use v8.7.0
$ node -v
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeのRemote-ContainerでReact(Node.js+TypeScript)環境をサクッと構築する。

環境構築はDockerで作りたい。

Dockerに慣れてくると何でもDockerを使いたくなりませか?
僕はそんな人間の一人で、パソコンを買い換えてDockerを本格的に使い始めてから、手元の環境が汚れるのが嫌で環境構築は全てDockerを使っています。潔癖症かな?

今回は、VSCodeでDockerを使い倒すための神拡張機能のRemote-Containersを使って、JavaScriptのライブラリのReactの開発環境を作っていきます。

事前に準備が必要なもの
  • Docker
  • VSCode

Remote-Containersを使って環境を作る

事前にDockerがインストールされているものとします。

拡張機能のDockerとRemote-Containers をインストールします。
スクリーンショット 2020-07-21 11.16.39.png

スクリーンショット 2020-07-21 9.59.15.png

適当なフォルダを開いて、コマンドパレットから
Remote-Containers:Add Development Containers Configuration Files
を選択。
スクリーンショット 2020-07-21 10.05.24.png

インストールしたい環境のサンプルが表示されるので、Show All Definitionsを選択し、
スクリーンショット 2020-07-21 10.07.31.png

最新版であるNode.js 14 & TypeScriptを選択。
スクリーンショット 2020-07-21 10.07.50.png

そうすると.devcontainerフォルダが生成され、中にはMS社が用意してくれた指定した環境のDockerFileと追加設定を行うdevcontainer.jsonが保存されています。
スクリーンショット 2020-07-21 10.12.05.png

スクリーンショット 2020-07-21 10.11.39.png

Reactを利用するにはコマンドラインツールのcreate-react-appを使うのがラクチンなので、これをnpmでインストールする設定をDockerFileに追記しておきます。
スクリーンショット 2020-07-21 10.15.47.png

また、コンテナ側の3000番ポートを使用することになるので、devcontinaer.jsonファイルにフォワードポートの設定を追記します。
スクリーンショット 2020-07-21 10.17.23.png

最後にこれらのファイルを元にDockerイメージとコンテナを生成します。拡張機能からRemote-Containers:Rebuild and Reopen in Container 実行。
(または右下に出てるであろうポップアップをクリック)
スクリーンショット 2020-07-21 10.20.25.png

スクリーンショット 2020-07-21 10.23.37.png

画面が一度閉じ、再び開いたあと少し待つと、VScodeの左下がコンテナの中に入っていることを示す状態に変わっていると思います。
スクリーンショット 2020-07-21 10.37.11.png

これでReactの環境は完成です。簡単!

実際に動かしてみる

create-react-appを実際に使って、サンプルアプリを動かしてみます。

ターミナルを開いて、
# npx create-react-app test

を実行。必要なライブラリ一式がダウンロードされていきます。
スクリーンショット 2020-07-21 10.51.35.png

Happy hacking!の文字が出たら完了です。
testディレクトリが作成されており、中にはReactを動かすためのテンプレート になるファイルが生成されています。
スクリーンショット 2020-07-21 10.59.05.png

こいつを動かしてみます。

# cd/test     //カレントディレクトリを移動
# npm start   //アプリを起動

アプリを起動したらlocalhost:3000にアクセス。下記のような画面が表示されていたら成功です!
スクリーンショット 2020-07-21 11.03.06.png

コンテナから抜けるには、VSCodeの画面を閉じるだけでコンテナOKです。
再びコンテナに入るには、VSCodeのDockerのオプションからお目当てのコンテナを右クリックして、Startをクリック。
スクリーンショット 2020-07-21 11.21.44.png

そうするとコンテナが立ち上がるので、もう一度右クリックしてAttach Visual Studio Codeをクリックして完了です。
スクリーンショット 2020-07-21 11.21.57.png

それでは、良いDocker & Reactライフを!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodeceptJS (+ Puppeteer) を触ってみた

きっかけ

今までSelenium WebDriverでE2Eテストを書いてきました。
が、開発チームから「もっと楽に書こうよ」という話が出て調べてみたところ、CodeceptJSが良さそうなので触ってみた話。
CodeceptJS + WebDriverも出来るようですが、Puppeteerの方が手軽で実行速度も速いようなのでPuppeteerを選択。
ただクロスブラウザやBrowserStackでテストをしたいので将来的にはWebDriverに移行予定。けど今じゃない。

CodeceptJSの何が良かったのか

  • テストコードが自然言語っぽく書けて誰でも読みやすい
  • 要素指定が簡単で分かりやすい(良い意味で雑に書ける)
  • プラグインが充実してる
  • WebDriverとかPuppeteerとか複数のヘルパーに対応してる

インストール + 初期設定

$ npm init -y
$ npm install codeceptjs puppeteer --save-dev
$ npx codeceptjs init                                 # ここから対話形式
? Where are your tests located? (./*_test.js)      # 指定のファイル名を自動でテストファイルと認識してくれる
? What helpers do you want to use? (Use arrow keys)   # Puppeteerを選択
  WebDriver 
❯ Puppeteer 
  TestCafe 
  Protractor 
  Nightmare 
  Appium 
  Playwright
? Where should logs, screenshots, and reports to be stored? (./output)  # スクリーンショット等の出力先
? Do you want localization for tests? (See https://codecept.io/translation/) (Use arrow keys)  # 日本語を選択
  pl-PL 
  zh-CN 
  zh-TW 
❯ ja-JP 
  de-DE 
  English (no localization) 
  pt-BR 
(Move up and down to reveal more choices)
? [Puppeteer] Base url of site to be tested (http://localhost)  # ドメイン以降が同じ構成で、ドメインでテスト環境や本番環境を分けている場合はBase URLを指定すると便利
? [Puppeteer] Show browser window (Y/n)          # テスト時にブラウザを表示するかどうか
? [Puppeteer] Browser viewport size (1200x900)   # ブラウザサイズ

一旦ここで初期設定は終了です。初期設定が終わると必要なファイルやフォルダが作成されます。
npx codeceptjs initがうまく行かない場合があるようなので、その場合は代わりにnode node_modules/.bin/codeceptjsを実行します。
作成されたファイルの中のcodecept.conf.jsに上記で設定した内容が書かれています。もちろん後からも内容変更可能です。
続いてテストケースファイルの作成が対話形式で行われます。

 Almost ready... Next step:
Creating a new test...
----------------------
? Feature which is being tested (ex: account, login, etc)  # テストケースファイル毎に付けられる名前
? Filename of a test (『上で付けたFeature名』_test.js)          # ファイル名

なお、この対話形式のテストケースファイル作成は、初期設定後に以下のコマンドでも呼び出せます。

$ npx codeceptjs gt

以下が作成されたテストケースファイルの中身です。
(ここではFeatureをQiita Testとし、ファイル名をQiita_Test_test.jsとしています)

Feature('Qiita Test');    // ? Feature which is being tested で指定した名前

Scenario('test something', (I) => {

});

作成されたファイル・フォルダは以下になります。

.
├── codecept.conf.js
├── jsconfig.json
├── node_modules
├── output
├── package-lock.json
├── package.json
├── Qiita_Test_test.js
├── steps.d.ts
└── steps_file.js

テストケースの書き方

最初にも上げましたが、CodeceptJSは自然言語っぽく書くので、テスト内容が分かりやすいです。
また要素指定もボタン名とかを書くと、いい感じに要素特定してくれて素敵です。具体的にはこんな感じになります。

Feature('Qiita Test');

Scenario('test something', (I) => {
    I.amOnPage('https://qiita.com/');       // 指定URLにアクセスして
    I.seeInTitle('Qiita');                  // ページタイトルが「Qiita」になっていることを確認して
    I.see('How developers code is here.');  // 画面上に「How developers code is here.」と表示されていることを確認して
    I.click('マイルストーン');                  // 「マイルストーン」と書かれているところをクリックして
    I.wait(1);                              // 1秒待って
    I.seeCurrentUrlEquals('https://qiita.com/milestones');  // URLが期待値通りか確認して
    I.saveScreenshot('Qiita01.png', true);  // スクリーンショットを撮る(撮ったファイルはoutputフォルダの中に入る)
});

詳しくはTesting with Puppeteer | CodeceptJSを参照してみてください。

テスト実施

テスト実施方法は複数あります。
まずは基本パターンです。
最初の初期設定? Where are your tests located? (./*_test.js)で設定したファイル形式のファイルをすべて実行します。

$ npx codeceptjs run
#### 以下結果 ####
CodeceptJS v2.6.6
Using test root "xxxxxxxxxxxxxxxx"

Qiita Test --test something in 6668ms

  OK  | 1 passed   // 9s

指定のファイルのみ実施したい場合はファイル名を指定します。

$ npx codeceptjs run [ファイル名]

上記のやり方だとテスト成功した場合、詳しい結果が分かりません。
なので詳しく知りたい場合は以下の3つの方法で実施します。

--stepsをつけるとテストケースっぽく出力されます。

$ npx codeceptjs run --steps
#### 以下結果 ####
CodeceptJS v2.6.6
Using test root "xxxxxxxxxxxxxxxx"

Qiita Test --
  test something
    私は ページを移動する "https://qiita.com/"
    私は タイトルに文字が含まれるか確認する "Qiita"
    私は テキストがあるか確認する "How developers code is here."
    私は クリックする "マイルストーン"
    私は 待つ 1
    私は  U r lが等しいか確認する "https://qiita.com/milestones"
    私は スクリーンショットを保存する "Qiita01.png", true
  ✔ OK in 7568ms


  OK  | 1 passed   // 11s

もっと詳しく実施。

$ npx codeceptjs run --debug

さらに詳しく実施。

$ npx codeceptjs run --verbose

詳しい使い方はReporters | CodeceptJSを参照してみてください。

レポート

プラグインを導入するとかっこいいレポートを出力できます。

インストール

$ npm install -g allure-commandline --save-dev

codecept.conf.jspluginsにallureを追加します。

// 編集前
  plugins: {
    retryFailedStep: {
      enabled: true
    },
    screenshotOnFail: {
      enabled: true
    }
  }
// 編集後
  plugins: {
    retryFailedStep: {
      enabled: true
    },
    screenshotOnFail: {
      enabled: true
    },
    allure: {
      enabled: true
    }
  }

起動

レポート出力するには以下のようにallureを有効にしてテストを実施します。

$ npx codeceptjs run --plugins allure

outputフォルダがある場所(=codecept.conf.jsがある場所)で以下のコマンドを実行してレポートサーバを立ち上げます。

$ allure serve output

するとブラウザが自動で立ち上がり、レポートが表示されます。
スクリーンショット 2020-07-21 7.34.15.png
レポートサーバーはCtrl+cで終了です。(macの場合)

まとめ

Puppeteerはどの文字が2つ続くのか毎回分からなくなる :worried:

We're hiring!

AIチャットボットを開発しています。
ご興味ある方は Wantedlyページ からお気軽にご連絡ください!

参考

Testing with Puppeteer | CodeceptJS
Reporters | CodeceptJS
Plugins | CodeceptJS
E2Eテストの面倒くさいことはCodeceptJSにお願いしよう - Qiita
E2EテストでWEBサイトをチェック(CodeceptJS × Puppeteer) | HAFILOG

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む