※スマホ対応はしてません。

タグ: 試験

Cannot find module ‘firebase-admin’ from ‘index.cjs.js’と言われたらそのfirebase-adminをインストールする

カテゴリー: JavaScript

Firebase Firestore の試験書くのに @firebase/testing という npm パッケージがあるんだけど、どうやら先月2020年8月に deprecated になり新しい @firebase/rules-unit-testing というものに置き換えられたようです。

エラー

さっそく手元のコードを置き換えたところ、同じコードでエラーになってしまいました。

こちらがコード。かつて @firebase/testing 利用の頃はそのまま動いてました。

import { initializeAdminApp } from "@firebase/rules-unit-testing";
import "babel-polyfill";

it("is ok", async () => {
  const admin = initializeAdminApp({ projectId: "my-project" });

  try {
    const doc = admin.firestore().collection("items").doc("item-1");
    await doc.set({ name: "Item 1" });
    const ss = await doc.get();
    expect(ss.data()?.name).toBe("Item 1");
  } finally {
    await admin.delete();
  }
});

で、エラーです。

Cannot find module 'firebase-admin' from 'index.cjs.js'

      3 |
      4 | it("is ok", async () => {
    > 5 |   const admin = initializeAdminApp({ projectId: "my-project" });
        |                 ^

firebase-admin って何だよ index.cjs.js ってどこだよ。

解決策

勘で試したところ firebase-admin は npm パッケージで、それをインストールすれば解決しました。そっか。

$ npm install -D firebase-admin

クライアント側で使わないので dependencies じゃなくて devDependencies へインストールしておきます。

コードは変更なし

特に変えてないけどちゃんと動いてるっぽいです。

おしまい

node_modules/@firebase/rules-unit-testing/package.json を開くと件の firebase-admin は案の定 peerDependencies に含まれていました。

ずっとクライアント側の実装でばかり使っていたので firebase-admin は使ったことがなく気付かなかったけど、思いついて良かった。

問題を整理すると解決に繋がることが多いですね。勘も必要だけども。

参考

Module xxx in the setupFilesAfterEnv option was not foundと言われたら<rootDir>を足す。

カテゴリー: JavaScript

ここまでのあらすじ

Jest で試験前に import "@testing-library/jest-dom/extend-expect"; とかそういう準備をするじゃないですか、そういうのをやるために準備用ファイルを読み込むため setupFilesAfterEnv オプション使ったらエラーになりました。

エラー

package.json で setupFilesAfterEnv オプション付けました。

{
  "jest": {
    "setupFilesAfterEnv": [
      "src/setupTests.ts"
    ]
  }

そしたらこんなエラーに。

● Validation Error:

  Module src/setupTests.ts in the setupFilesAfterEnv option was not found.
         <rootDir> is: /mnt/c/Users/ginpei/projects/my-project

  Configuration Documentation:
  https://jestjs.io/docs/configuration.html

解決策:<rootDir> を足す

ファイルパスの最初に <rootDir> を足します。

{
  "jest": {
    "setupFilesAfterEnv": [
      "<rootDir>/src/setupTests.ts"
    ]
  }

これで動くようになりました。

ドキュメント

を読んだらまさにそう書いてありました。(翻訳されてないや。)


If you want a path to be relative to the root directory of your project, please include <rootDir> inside a path’s string, like "<rootDir>/a-configs-folder".

もしパスをあなたのプロジェクトのルートディレクトリーに対し相対的なものにしたい場合、パス文字列の中に <rootDir> を含めてください。例:"<rootDir>/a-configs-folder"

おしまい

ドキュメント読もうね案件でした。

こういう、一度設定したらもう触らない系の話はすぐ忘れちゃう。

参考

JSDomのlocalStorageでSecurityErrorが出たら、URL指定で解決するかも。

カテゴリー: JavaScript

した。

エラーになるコード

const { JSDOM } = require('jsdom');
const sinon = require('sinon');

const dom = new JSDOM();
dom.window.localStorage.setItem('foo', 'bar');
// SecurityError: localStorage is not available for opaque origins

解決

new JSDOM() のところで、 url を適当に設定してやれば解決します。

const dom = new JSDOM('', { url: 'https://localhost' });

原因

件の url の初期値が about:blank で、URLがそれだと localStorage が駄目なので。

試しにブラウザーで about:blank を開いてコンソールから localStorage を触ろうとしても同じようなエラーが出ます。

MDNに説明があります。

例外

SecurityError
リクエストがポリシーの決定に反している、またはオリジンが妥当な scheme/host/port tupleでない (これは例えば、オリジンが file: や data: スキームを使うときに起こります)。例えば、ユーザーがブラウザー設定で特定オリジンへのデータ永続化のパーミッションを拒否していることもあります。

参考

JSDomでclientWidthやgetBoundingClientRect()は動かないので上書きして試験する。

カテゴリー: JavaScript

正直これで良いのかわからないけど、とりえあえず手元の clientWidth の値を使う処理の試験は走るようになった。

メソッド系

しれっとstub的な関数で上書きする。

const { JSDOM } = require('jsdom');

const dom = new JSDOM();
const el = dom.window.document.createElement('div');

console.log(el.getBoundingClientRect()); // => { width: 0, top: 0, ... }

// こうする
el.getBoundingClientRect = () => ({
  width: 200,
});
console.log(el.getBoundingClientRect()); // => { width: 200 }

試験を通すだけなので不要な値まで全部書く必要はない。

本当なら sinon.stub() ↓の方が丁寧な感じがするけど、まあ使い捨てるインスタンスだし、良いでしょ。

sinon.stub(el, 'getBoundingClientRect").returns({ width: 200 });

プロパティ系

clientWidth や clientHeight は単純に代入してもだめなので、 Object.defineProerty() で上書きする。

const { JSDOM } = require("jsdom");

const dom = new JSDOM();
const el = dom.window.document.createElement("div");

console.log(el.clientWidth); // => 0

// こうする
Object.defineProperty(el, 'clientWidth', { value: 100 });
console.log(el.clientWidth); // => 100

JSDomはレイアウト計算をサポートしない

とREADMEにあるので、バグじゃないです。

Beyond just features that we haven’t gotten to yet, there are two major features that are currently outside the scope of jsdom. These are:

  • Navigation: the ability to change the global object, and all other objects, when clicking a link or assigning location.href or similar.
  • Layout: the ability to calculate where elements will be visually laid out as a result of CSS, which impacts methods like getBoundingClientRects() or properties like offsetTop.

まだやっていないだけの機能もありますが、今のところjsdomのスコープ外である主要な機能が2つあります。

  • ナビゲーション: リンクをクリックしたり location.href を設定する等した際に、 グローバルオブジェクト他を変更する機能
  • レイアウト: CSSの結果として要素が視覚的に配置された結果を計算する機能。 getBoundingClientRects() のようなメソッドや、 offsetTop といったプロパティへ影響するもの

その他

ちなみに本物のDOMでも視覚的に配置されるまで、例えば document.body.appendChild(el) とかするまでは値が 0 だったりします。

参考

既存のRailsアプリにRSpecを導入してテストしてみるテスト。

カテゴリー: Ruby on Rails

めもめも。先日の続きです。

最初からRSpec使ってれば良かったんですが、後から知ったもので、既にアプリを作っちゃってる場合を考えます。ここに後からRSpecを導入して、テストする、というのを試してみました。

環境

$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [i686-linux]
$ rails -v
Rails 3.2.1

準備

とりあえずこんなプロジェクトを準備。

rails new my_shop
cd my_shop
rails g scaffold item name:string description:text price:integer on_sale:boolean
rake db:migrate

(さらに…)