【React,Jest, testing library】ReferenceError: fetch is not definedエラーの解消方法【vite,webpack】

今回はReactアプリを作成する際にReferenceError: fetch is not definedエラーが出た際の解消方法をエントリーします。

ケースとしてはcreate react appではなくwebpackviteでアプリを作成しアプリ内でfetchを使いAPIなどを利用したケースをJest + Testing libraryでテストを行った際にReferenceError: fetch is not definedが発生しました。

エラー概要

コンポーネントで呼び出しているfetchでエラーとなっています。

ReferenceError: fetch is not defined

      26 |   const handleClick = async (user: User) => {
      27 |     
    > 28 |     const response = await fetch('http://localhost:8080/xxxx', {
         |                      ^
      29 |       method: 'POST',
      30 |       mode: 'cors',
      31 |       cache: 'no-cache',

解消方法

cross-fetch/polyfillを用いて解消します。

npm install --save-dev cross-fetch

テストコードサンプル

import 'cross-fetch/polyfill'でポリフィルをimport

<Sample />コンポーネントが今回fetchを利用しているコンポーネントです。

import { render, screen } from '@testing-library/react'
import 'cross-fetch/polyfill'

describe('Sample', () => {
  it('test', async () => {
    render(
      <Sample />
    )
    expect(screen.getByText('テストコード')).toBeInTheDocument()
  }
}

SMARTフレームワークとは

SMARTフレームワークとは5つの要素「具体的」「測定可能」「行動指向」「関連がある」「時間制約」を含んだ問いかけや目標設定です。

5つの要素

具体的

その問いかけ(目標設定)は具体的か?

測定可能

その問いかけ(目標設定)は測定可能か?

行動指向

その問いかけ(目標設定)の答えは何かしらの行動計画を立てるのに意味があるか?

関連がある

その問いかけ(目標設定)は解決しようとしている特定の課題に関連しているか?

時間制約

その問いかけ(目標設定)の答え(達成条件)は調査対象(達成対象)となる特定の期間のものであるか?

避けた方が良い問いかけ

SMARTフレームワークにて問いかける際に避けた方が良い代表的な問いかけ例

誘導尋問

質問の中に回答を示唆している。

「このサービスは高いと思いますよね?」

選択式(クローズドエンド)

回答から一言しか得られず有益な情報になりえない。

「このサービスに満足していただけましたか?」

漠然、曖昧

具体的ではないケースやコンテキストがあってないケース

「このサービスはあなたにあってますか?」

Node.js Express QueryString(クエリストリング)の取得方法

今回はNode.js Express QueryString(クエリストリング)の取得方法についてエントリーします。

req.query.xxx(xxxはリクエスト時に指定したパラメータ名)で取得できます。

コード例

http://localhost:xxxx/sample?num=10とした場合res.json(req.query.num);eq.query.numには文字列の10が渡ってきます。

const express = require("express");
const app = express();
const PORT = process.env.PORT || 5000;

app.get("/sample", (req, res) => {
  res.json(req.query.num);
});

app.listen(PORT, () => {
  console.log(`Listening *: ${PORT}`);
});

Node.js Expressでパスパラメータの取得方法

Node.js Expressでパスパラメータの取得方法

http://localhost:5000/sample/123でパスパラメータの123を取得したい場合"/sample/:id"でエンドポイントを定義しreq.params.idで取得できる。また123は文字列なのでabc,1b3なども取得できる。ただし/sample/123/abcのように更に追加された場合はエラーとなる。

コード例

const express = require("express");
const app = express();
const PORT = process.env.PORT || 5000;

app.get("/sample/:id", (req, res) => {
  res.json(req.params.id);
});

app.listen(PORT, () => {
  console.log(`Listening *: ${PORT}`);
});

id?

/sample/:idと違い名前付きオプションとなりhttp://localhost:5000/sample,http://localhost:5000/sample/も追加でundefinedで取得できる。

const express = require("express");
const app = express();
const PORT = process.env.PORT || 5000;

app.get("/sample/:id?", (req, res) => {
  res.json(req.params.id);
});

app.listen(PORT, () => {
  console.log(`Listening *: ${PORT}`);
});

id*

"/sample/:id"に加えて/sample/123/abcのように更に追加されたケースでも取得できる(この場合は123が取得される)

const express = require("express");
const app = express();
const PORT = process.env.PORT || 5000;

app.get("/sample/:id*", (req, res) => {
  res.json(req.params.id);
});

app.listen(PORT, () => {
  console.log(`Listening *: ${PORT}`);
});

正規表現

"/sample/:id(\\d+)"で数字のみ許可できる

const express = require("express");
const app = express();
const PORT = process.env.PORT || 5000;

app.get("/sample/:id(\\d+)", (req, res) => {
  res.json(req.params.id);
});

app.listen(PORT, () => {
  console.log(`Listening *: ${PORT}`);
});

TypeScript + Express + ESLintの導入

今回はTypeScript + Express + ESLintの導入をしたので備忘録としてエントリーしたいと思います。

インストール

開発環境のみで利用するためnpmの場合は--save-dev、yarnの場合は-Dのオプションをつけます

npmの場合

npm install --save-dev eslint

yarnの場合

yarn add -D eslint

初期化

npx eslint --init

以下で設定しました

You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · syntax
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · none
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser, node
✔ What format do you want your config file to be in? · JavaScript
The config that you've selected requires the following dependencies:

@typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm
Installing @typescript-eslint/eslint-plugin@latest, @typescript-eslint/parser@latest

カレントディレクトリに.eslintrc.jsが作成されていれば成功です。以下は作成されたものです。

module.exports = {
    "env": {
        "browser": true,
        "es2021": true,
        "node": true
    },
    "overrides": [
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint"
    ],
    "rules": {
    }
}

ルールの設定

ESLint公式のルールを的時追記していきます。

package.jsonスクリプトの追加

自分の環境では./src配下に./src/apiなど複数のディレクトリでアプリを配置しているためpackage.jsonscript内に以下で設定しました。

"scripts": {
    他の設定,
    "lint": "eslint src/**/**/*"
  },

APIを使わずにHTML「aタグ」で作成したリンクでGoogleカレンダーに予定を入れる方法

APIを使わずにHTML「aタグ」で作成したリンクでGoogleカレンダーに予定を入れる方法

イベントページを作成した際にAPIを使わずにHTML「aタグ」のリンクで予定を入れれるのは便利なので是非マスターしましょう。

正月の予定を登録

上の例をクリックすると以下のように自分のGoogleカレンダーの予定の登録画面になると思います

Googleカレンダー
Googleカレンダー

コード

<a href="http://www.google.com/calendar/event?action=TEMPLATE&text=title-text&dates=20220101/20220102"target="_blank">正月の予定を登録</a>

解説

http://www.google.com/calendar/event?action=TEMPLATE&text=title-text&dates=20220101/20220102を分解して解説していきます。

URL

http://www.google.com/calendar/eventまず最初にこちらを指定します。このURLは固定です。このURLにクエリストリングでパラメータを追加していきます。

パラメータ

パラメータは以下になります。

パラメーター 必須 / オプション 説明
action 必須 TEMPLATE
text 必須 予定の件名
dates オプション 予定の日時
location オプション 予定の場所
trp オプション 外部向け表示
add オプション 予定に招待するゲストのメールアドレス。複数指定する場合は、カンマ(,)で連結して指定します。
src オプション カレンダーを指定する
details オプション 予定の詳細

「Rust」cargo watchで変更を自動検知しホットリロード

今回はRustで開発する際に便利なツールcargo watchを紹介したいと思います。

cargo-watch GitHubリポジトリ

インストール

cargo install cargo-watch

watch

cargo watch -x run

実際に試す

簡単なWebアプリのサンプルコードで試してみました

main.rs

use actix_web::{get, App, HttpResponse, HttpServer, ResponseError};
use thiserror::Error;

#[derive(Debug, Error)]
enum MyError {}

impl ResponseError for MyError {}

#[get("/")]
async fn index() -> Result<HttpResponse, MyError> {
    let response_body = "Hello";

    Ok(HttpResponse::Ok().body(response_body))
}
#[actix_web::main]
async fn main() -> Result<(), actix_web::Error> {
    HttpServer::new(move || App::new().service(index))
        .bind("0.0.0.0:8484")?
        .run()
        .await?;
    Ok(())
}

let response_body = "Hello";let response_body = "Hello World!";に書き換えセーブすると[Running 'cargo run']が出力され更新されます。更新後ブラウザをリロードすると変更された内容が出力されます。