お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。

確認環境

Env Ver Misc
golang 1.16.4-alpine3.13 DockerImage
VSCode 1.56.0
golang.go 0.24.2 VSCode 拡張

サンプルコード

Dockerfile

シェルが貧弱なので、ついでに好きなシェルも入れておくのが無難

FROM golang:1.16.4-alpine3.13
RUN apk add git gcc libc-dev
RUN go get golang.org/x/tools/gopls \
    && go get -u github.com/go-delve/delve/cmd/dlv

.vscode/settings.json

  • あとはF5を押せば起動する
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch file",
            "type": "go",
            "request": "launch",
            "mode": "debug",
            "program": "${workspaceFolder}/"
        },
    ]
}

トラブルシュート

デバッグしようとして起きるエラーとか
上のサンプルコードを使っている限り起きないはず

exec: "gcc": executable file not found in $PATH

gccを入れれば解決する

_cgo_export.c:3:10: fatal error: stdlib.h: No such file or directory

libc-devを入れれば解決する

投稿日:
言語::Markdownソフトウェア

確認環境

Windows 10

Env Ver
Pandoc 2.11.4
Java 1.8.0_291
PlantUML 1.2021.3

やり方

パス書式はMSYS2で流す前提

  1. https://github.com/pandoc/lua-filters/tree/master/diagram-generator からdiagram-generator.luaを落としてくる
  2. https://gist.github.com/andyferra/2554919 を拾ってくる
  3. pandoc Foo.md --self-contained -s -c /c/pandoc/github.css --lua-filter=/c/pandoc/diagram-generator.lua --metadata=plantumlPath:"C:\pandoc\plantuml.jar" --metadata=javaPath:"C:\Program Files\Java\jre1.8.0_291\bin\java.exe" -o Foo.html
    1. --self-contained
      1. バイナリを全部Base64で出力(1ファイルに封じ込める)
    2. -s
      1. 完全なHTMLを出力
    3. -c
      1. CSS
    4. --lua-filter
      1. Luaフィルタ
    5. --metadata=
      1. フィルタに食べさせる引数
  • global.navigatorをモックにする方法
    • モックというか書き換えてるだけ
  • jestのモック機能はプロパティのモックが出来ないので、実オブジェクトを強制的に書き換えて実施する

サンプルコード

  • Object.defineProperty() を利用して実装
    • value, プロパティが返す値
    • configurable, 再定義可能かどうか、設定しないと再実行でコケる
  • 実際の使用ではユーティリティ関数を作っておき、 afterAll()navigator.userAgentを初期値に戻すのが望ましい
Object.defineProperty(global.navigator, 'userAgent', {
  value:
      'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
  configurable: true,
});
  • 理論上可能そうだったので、ひたすら試行錯誤してたらできたのでメモがてら
  • axiosそのものをモックして、その結果に応じた処理が想定通り走っているかどうかを確認したい
  • create-react-appで作成したTypeScript Reactのプロジェクトにnpm tを掛けてテストすることを想定
  • 但し検証用のプロジェクトは@lycolia/ts-boilerplate-generator-cliで作成

確認環境

Env Ver
react 17.0.1
react-scripts 4.0.2
typescript 4.1.3

確認内容

検証対象

  • ページ読み込み時に一回だけAPIを蹴ってなんかすることを想定
import axios from 'axios';
import { useEffect } from 'react';

export const AsyncHookExample = () => {
  useEffect(() => {
    axios
      .get('https://localhost/')
      .then((res) => console.log(res))
      .catch((err) => console.error(err));
  }, []);

  return <p />;
};

検証方法

  • axiosをモックした上で、モック関数のPromiseの解決を待ち、 PromiseのコールバックをspyOnして検査する内容
  • モック関数のPromiseの解決法を求めるのにハマりましたが、これはfoo.mock.results[0].valueに対してawait expect(foo.mock.results[0].value).resolvesとしてやればいける
  • 細かいことはソースコードのコメント参照
import { render } from '@testing-library/react';
import axios from 'axios';
import { AsyncHookExample } from './AsyncHookExample';

// `axios` をモックにする
jest.mock('axios');
// `axios` のモックを取得
const mockedAxios = axios as jest.Mocked<typeof axios>;
// `console.log()` を `spyOn'
const spiedConsoleLog = jest.spyOn(console, 'log');
// `console.error()` を `spyOn'
const spiedConsoleError = jest.spyOn(console, 'error');

describe('AsyncHookExample', () => {
  it('resolve promise in Hook', async () => {
    // テストに期待する結果
    // `axios` はモックなので値は適当
    const beResult = {
      status: 200,
      data: null,
    };
    // `axios` のモックが `resolve` する値を設定
    mockedAxios.get.mockResolvedValue(beResult);
    // コンポーネントを `render` して `useEffect` を走らせる
    render(<AsyncHookExample />);
    // `axios.get()` が呼ばれたことを確認
    expect(mockedAxios.get).toBeCalled();
    // モックの結果を取得
    const testResult = mockedAxios.get.mock.results[0].value;
    // `reject` された値が期待通りであることを確認
    await expect(testResult).resolves.toEqual(beResult);
    // `useEffect` の中の `Promise` の中にある `console.log()` が呼ばれたことを確認
    expect(spiedConsoleLog).toBeCalled();
  });

  it('reject promise in Hook', async () => {
    // テストに期待する結果
    // `axios` はモックなので値は適当
    const beResult = {
      status: 400,
      data: null,
    };
    // `axios` のモックが `reject` する値を設定
    mockedAxios.get.mockRejectedValue(beResult);
    // コンポーネントを `render` して `useEffect` を走らせる
    render(<AsyncHookExample />);
    // `axios.get()` が呼ばれたことを確認
    expect(mockedAxios.get).toBeCalled();
    // モックの結果を取得
    const testResult = mockedAxios.get.mock.results[0].value;
    // `reject` された値が期待通りであることを確認
    await expect(testResult).rejects.toEqual(beResult);
    // `useEffect` の中の `Promise` の中にある `console.error()` が呼ばれたことを確認
    expect(spiedConsoleError).toBeCalled();
  });
});

あとがき

  • mockResolvedValueのスコープやらモックのPromiseを解決させるマッチャやら調べるのに手間取った
    • あとはそもそもPromiseが解決した結果がどこに入るのかとか、兎に角あれこれ
  • expect(mockedAxios.get).toBeCalled()が通るのはすぐに気づいたので、なら出来るだろうとひたすら調べてた
    • とりあえず言えることはJestの公式ドキュメントが大正義なので、ここを穴が開くまで読めば大抵のことは解決する