🛵

ZephyrというテストマネジメントツールのAPIクライアントが見つからなかったので作って公開してみた

に公開

こんにちは。ダイの大冒険エンジョイ勢のbun913と申します。

みなさんはテストマネジメントツールを使ったことがありますか?以前私はTestRailというツールについて、MCPサーバーなどのツールを作成してみました。

https://zenn.dev/moneyforward/articles/6c439bab3cb0f4

今回事情があり、JIRAのプラグインとして提供されているZephyrというテストマネジメントツールを試してみることにしました。

https://marketplace.atlassian.com/apps/1213259/zephyr-test-management-and-automation-for-jira

調べている中で Zephyr には REST API が提供されていることがわかり、今後MCPサーバーを自作したり、データの移行などでAPIを利用したい時には何かと便利そうだと思いました。

https://support.smartbear.com/zephyr-scale-cloud/api-docs/

しかし、 npm で検索してもそれっぽいクライアントライブラリが見つからなかったので、今回最小労力でAPIクライアントを作成してみました。

https://www.npmjs.com/package/zephyr-api-client

https://github.com/bun913/zephyr-api-client

特にZephyrのようなツールはQAエンジニアのようなあまりコードを書かない方が利用することも多いため、それぞれのプロジェクトでクライアントを生成するのは大変です。そこで、できるだけ簡単に型が効くツールを少ない労力で作成してみました。

Zephyr API クライアントの作成

今回ありがたいことに、ZephyrのAPIドキュメントがOpenAPI形式で提供されていました。

そこで今回は、クライアントの多くのコードを swagger-typescript-api で生成しつつ、いざ型定義の更新やなんらかの理由でコードに手を入れたい時にも、このクライアントに手を加えれば済むようにしてみました。

型定義の自動・定期生成

APIドキュメントが作成されていれば、swagger-typescript-api などのツールで簡単に型ファイルやクライアントコードを生成できます。

https://github.com/acacode/swagger-typescript-api

仕組みは簡単で、公開されている OpenAPI ドキュメントに直接アクセスして、型定義を特定のディレクトリに生成するスクリプトを用意しました。

tools/generate-types.ts
import { generateApi } from "swagger-typescript-api";
import * as path from "node:path";
import * as fs from "node:fs/promises";
import axios from "axios";

const OPENAPI_SPEC_URL =
	"https://support.smartbear.com/zephyr-scale-cloud/api-docs/api.cloud.expanded.yml";
const OUTPUT_DIR = path.resolve(process.cwd(), "src/v2/resources");
const TEMP_SPEC_FILE = path.resolve(process.cwd(), ".tmp-api-spec.yml");

async function downloadSpec(): Promise<void> {
	console.log("Downloading OpenAPI spec...");
	const response = await axios.get(OPENAPI_SPEC_URL, { responseType: "text" });
	await fs.writeFile(TEMP_SPEC_FILE, response.data, "utf-8");
}

async function cleanupTempFile(): Promise<void> {
	try {
		await fs.unlink(TEMP_SPEC_FILE);
	} catch {
		// Ignore if file doesn't exist
	}
}

async function generateTypes() {
	console.log("Starting type generation...");

	try {
		await downloadSpec();

		await generateApi({
			input: TEMP_SPEC_FILE,
			output: OUTPUT_DIR,
			httpClientType: "axios",
			modular: true,
			silent: false,
		});

		await cleanupTempFile();
		console.log("Type generation completed successfully");
	} catch (error) {
		await cleanupTempFile();
		console.error("Type generation failed:", error);
		process.exit(1);
	}
}

generateTypes();

また、 GitHub Actions でこのスクリプトを定期的に実行するようにして、diffが見つかり次第私が手を加える必要があるか確認するようにしています。

TypeScript で生成された型をほぼラップしている形なので、当然利用時には型安全に使えます。

type

以下のようなコードで簡単にAPIを呼び出せます。

example.ts
import { ZephyrV2Client } from "zephyr-api-client";

interface ZephyrError {
  response?: {
    status: number;
    data: unknown;
  };
  message: string;
}

async function testAPI(): Promise<void> {
  const apiToken = process.env.ZEPHYR_API_TOKEN || "";
  const projectKey = process.env.PROJECT_KEY || "test";

  const client = new ZephyrV2Client({ apiToken });

  try {
    const response = await client.testcases.listTestCases({
      projectKey,
      maxResults: 5,
    });

    if (response.data.values && response.data.values.length > 0) {
      console.log("\nTest Cases:");
      for (const testCase of response.data.values) {
        console.log(`- [${testCase.key}] ${testCase.name}`);
      }
    }

    console.log("\nAPI call successful!");
  } catch (error) {
    console.error("\nAPI call failed:");
    const err = error as ZephyrError;
    if (err.response) {
      console.error(`Status: ${err.response.status}`);
      console.error(`Message: ${JSON.stringify(err.response.data, null, 2)}`);
    } else {
      console.error(err.message);
    }
    process.exit(1);
  }
}

testAPI();

ユニットテストの追加

ただ単にツールをラップするだけではなく、ユニットテストを追加しています。

特に自動生成された型定義を使ったAPIの呼び出し部分については、「ちゃんと意図するURLで呼び出されているか」「Swaggerに書かれたリクエスト通りのパラメーターが渡せるようになっているか」などを中心にテストを追加しました。

本当はE2Eテストにあたる本物のAPI呼び出しを追加したかったのですが、有償のツールであるため今回は手が出ませんでした。

--------------------|---------|----------|---------|---------|-----------------------------------------------
File                | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                             
--------------------|---------|----------|---------|---------|-----------------------------------------------
All files           |   98.35 |     86.2 |   98.86 |   98.35 |                                               
 src                |       0 |      100 |     100 |       0 |                                               
  index.ts          |       0 |      100 |     100 |       0 | 8-28                                          
 src/v2             |     100 |      100 |     100 |     100 |                                               
  client.ts         |     100 |      100 |     100 |     100 |                                               
 src/v2/resources   |   98.48 |    85.71 |    98.8 |   98.48 |                                               
  Automations.ts    |     100 |      100 |     100 |     100 |                                               
  Environments.ts   |     100 |      100 |     100 |     100 |                                               
  Folders.ts        |     100 |      100 |     100 |     100 |                                               
  Healthcheck.ts    |     100 |      100 |     100 |     100 |                                               
  Issuelinks.ts     |     100 |      100 |     100 |     100 |                                               
  Links.ts          |     100 |      100 |     100 |     100 |                                               
  Priorities.ts     |     100 |      100 |     100 |     100 |                                               
  Projects.ts       |     100 |      100 |     100 |     100 |                                               
  Statuses.ts       |     100 |      100 |     100 |     100 |                                               
  Testcases.ts      |     100 |      100 |     100 |     100 |                                               
  Testcycles.ts     |     100 |      100 |     100 |     100 |                                               
  Testexecutions.ts |     100 |      100 |     100 |     100 |                                               
  Testplans.ts      |     100 |      100 |     100 |     100 |                                               
  http-client.ts    |   89.25 |    54.28 |   85.71 |   89.25 | 86-87,104,115-116,121-122,153,168-170,172-173 
--------------------|---------|----------|---------|---------|-----------------------------------------------

まとめ

  • Zephyr というテストマネジメントツールにREST API が提供されていた
  • 今後 MCPサーバーや色々なツールを作成する上で、APIクライアントがあったほうが便利そう
    • また、QAエンジニアの方などコードを書かない方も利用することが多いので、できるだけ簡単に型が効くツールを少ない労力で作成してみた
  • swagger-typescript-api で型定義を自動生成し、ユニットテストを充実化させてクライアントを作成しました

以上、少し短いですが、Zephyr API クライアントの紹介でした。もし興味があればぜひ使ってみてください。

最後までお読みいただきありがとうございました。

GitHubで編集を提案
Money Forward Developers

Discussion