Zoho CRMのWidget(ウィジェット)の異常系テストとは、CRMの中に自作した入力画面に、わざと間違った値や操作を与えて、おかしなデータが保存されないかを確かめる作業です。ここでいうウィジェットは、CRMの画面の中で動く自作の小さなWebアプリのことです(仕組みは公式のWidgets Overviewにあります)。標準の入力画面では足りない業務に合わせて、紙の伝票に近い画面を作るときなどに使います。

この記事では、九州の小売店向けに作った「受注書入力画面」で、異常系21ケースを試した記録を紹介します。初回は5件が不合格でした。どこで落ちたか、どう直したか、テストの進め方で何を変えたかをまとめます。

対象にした画面と、合格の基準

対象は次の3つです。

  1. 受注書作成ウィジェット:顧客を選び、商品の明細(最大30行)を入れ、領収額から残額を出して保存し、B5の控えを印刷する画面
  2. 商品情報一括編集ウィジェット:商品グループと、その下のサイズ別の商品(SKU)の価格をまとめて編集する画面
  3. 顧客関係名の自動生成:家族などの関係を登録したとき、Deluge関数で「起点の人・対象の人(種別)」という名前を自動で付ける仕組み

合格の基準は1つに絞りました。

不正な入力は、エラーメッセージで止めるか、安全な値に自動で直す。どちらの場合も、不整合なデータをCRMに保存しない。

「エラーで止める」と「自動で直す」のどちらにするかは、ケースごとに決めました。たとえば顧客が未選択なら止めます。数量に0を入れたら1に直します。現場の人が入力を何度もやり直さずに済むよう、直せるものは直す方針です。

ウィジェットのテストケースは何を用意するか:異常系21ケースの一覧

実際に使ったケースです。項目名は一般的な名前にしています。

受注書作成ウィジェット(14ケース)

# ケース 期待する動き 初回
1 顧客を選ばずに保存 「顧客を選択してください」で止める 合格
2 明細なしで保存 「商品を1件以上選択してください」で止める 合格
3 数量に0・マイナス 1に直す 合格
4 数量を空にする 1に直す 合格
5 単価に文字 0円として扱う 合格
6 単価にマイナス 0に直す 不合格
7 領収額にマイナス 0に直す(残額が合計を超えない) 不合格
8 領収額が合計より多い 残額を0にする(マイナスにしない) 合格
9 新規顧客の名前が空 止める。顧客も受注も作らない 合格
10 存在しない商品名を入れたまま保存 確定していない行は保存しない 合格
11 商品を選んだ後でグループを変える 商品欄を空に戻す 合格
12 明細を31行目まで足す 「明細は最大30行です」で止める 合格
13 保存ボタンの連打 保存中はボタンを押せなくする 合格
14 保存が終わった後、同じ内容で再保存 二重登録しない 不合格

商品情報一括編集ウィジェット(4ケース)

# ケース 期待する動き 初回
15 グループ名を空で保存 止める 合格
16 商品名が空のSKUを保存 止める。SKUを作らない 合格
17 価格に文字 0として保存する(NaNを送らない) 合格
18 価格にマイナス 0に直す 不合格

顧客関係名の自動生成(3ケース・APIで確認)

# ケース 期待する動き 初回
19 関係の種別が空 種別なしの名前で作る 合格
20 極端に長い氏名どうし 上限の文字数で切って保存する 不合格
21 起点と対象が同じ人 名前は作る(エラーにしない) 合格

ケースを考えるときは、入力欄ごとに「空」「0」「マイナス」「文字」「上限超え」を当てはめました。そこに操作の誤りとして「連打」「保存後の再保存」「選び直し」を足しています。

初回に落ちた5件と直し方

1. 単価にマイナスを入れると、マイナス金額の伝票が作れた

単価に -1,000 と入れると、そのまま金額に反映され、保存できました。集計や帳票の金額が合わなくなります。行の値が変わったときの処理で、0を下限にしました。

// 明細の値が変わったとき
if (field === "unitPrice") {
  row.unitPrice = Math.max(0, toNumber(input.value));
}

2. 領収額にマイナスを入れると、残額が合計を超えた

残額は「合計 − 領収額」です。領収額がマイナスだと、残額が合計より大きくなります。合計の計算で、領収額と残額の両方に0の下限をかけました。

function calculateTotals() {
  const total = rows.reduce((sum, row) => sum + rowAmount(row), 0);
  const receipt = Math.max(0, toNumber(receiptInput.value));
  const balance = Math.max(total - receipt, 0);
  return { total, receipt, balance };
}

3. 保存した後に、同じ内容でもう一度保存すると二重登録になった

保存中にボタンを押せなくする対策は入れていたので、連打(13)は合格でした。しかし保存が終わるとボタンは押せる状態に戻ります。そこで同じ内容のまま押すと、別の受注書がもう1件できました。現場では「保存できたか不安でもう一度押す」ことが起きやすく、実運用で二重伝票になる危険が高い不具合です。

保存に成功したときの入力内容を文字列にして控えておき、次に保存するときに比べるようにしました。

function orderSignature(rows, totals) {
  return JSON.stringify({
    contact: selectedContactId,
    orderDate: orderDateInput.value,
    receipt: totals.receipt,
    rows: rows.map((r) => [r.productId, r.quantity, r.unitPrice])
  });
}

// 保存の直前
const signature = orderSignature(rows, totals);
if (signature === state.lastSavedSignature) {
  throw new Error("この内容は保存済みです。内容を変えてから保存してください");
}
// 保存に成功したら
state.lastSavedSignature = signature;

内容を1か所でも変えれば保存できることも、あわせて確かめました。

4. 商品の価格にマイナスが保存できた

商品編集の画面でも、希望小売価格・仕入価格・販売価格にマイナスが入りました。受注書と同じく、保存する前に0を下限にそろえました。

5. 氏名が長すぎると、関係名の自動生成が黙って失敗した

関係名は「起点の氏名・対象の氏名(種別)」をつなげて作ります。両方の氏名が長いと、名前の項目の文字数上限(120字)を超えて更新が失敗しました。画面にはエラーが出ず、関数のログにだけ残るため、気付きにくい不具合です。Deluge関数で、保存の前に上限で切るようにしました。

// Deluge(顧客関係名の生成)
if(newName.length() > 120)
{
    newName = newName.subString(0,120);
}

直した後、以前に失敗していたレコードも編集し直して名前を作り直しました。

5件を直してウィジェットを入れ替え、21件すべてを試し直して合格になりました。

画面操作の確認で見つかったこと

異常系とは別に、CRMの画面を実際に操作して22項目を確かめました。22項目のうち19項目は合格でした。残りで見つかったことのうち、ほかの案件でも起きそうなものを3つ挙げます。

項目のAPI名が食い違い、専用の項目に保存されていなかった

受注書を保存すると、画面上は問題なく見えました。ところがAPIで保存された値を読むと、領収額と受渡方法が専用の項目に入らず、説明欄にだけ残っていました。ウィジェットが送る項目のAPI名と、CRMで作った項目のAPI名が食い違っていたのが原因です(綴りの違い、単数形と複数形の違いなど)。CRM側のAPI名をウィジェットにそろえて直し、保存し直した値が専用の項目に入ることをAPIで確かめました。

当社の案件では、CRMにない項目名で送っても保存全体はエラーにならず、値は説明欄にだけ残っていました。そのため画面で見るだけでは気付けません。保存した後に、APIでレコードを読み、値が狙った項目に入っているかを照合する手順を、テストに必ず入れるようにしました。項目をAPIで作ってAPI名を最初からそろえておく方法は、Zoho CRMのカスタム項目をAPIで作成するで紹介しています。

選択肢に誤った値が残っていた

顧客の区分の選択リストに、作成途中の誤った値が残っていました。ウィジェットではなくCRMの設定の問題ですが、入力画面から選べてしまうため、テストの対象に入れて当日中に直しました。

「+SKUを追加」が反応しなかった

自動操作での確認中、商品編集の画面で行を足すボタンが反応しませんでした。最初は操作の環境のせいだと考えましたが、調べると実際の不具合でした。既存のグループで行を足すと、その行にグループが設定されず、表示の絞り込みで行が隠れていました。行を足すときに、選んでいるグループを設定するよう直しています。

実環境に上げる前にどうテストするか:モックと実環境の二段構え

ウィジェットの改修を、まずモックで画面の入力チェックや計算を確かめ、次に実環境で保存した値が狙った項目に入っているかを確かめる二段階で示した図

ウィジェットの改修は、2段階で確かめるようにしました。

  1. モックで画面だけ確かめる ローカルのWebサーバーでウィジェットを開き、URLに ?mock=1 を付けると、CRMにつながず用意したデータで動くようにしてあります。入力のチェック、計算、帳票の表示などは、ここで先に確かめます。商品が大量にある場合の表示を見るために、データを水増しする切り替えも用意しました。
  2. 実環境で保存結果を確かめる CRMにウィジェットを入れ、詳細画面のボタンなどを作った後で、実際に保存します。保存した値はAPIで読み、狙った項目に入っているかを照合します。ワークフローやDeluge関数との連動は、ここでしか確かめられません。

モックかどうかの判定は次のようにしています。ZohoのSDKが読み込まれていないときも、モックで動くようにしました。

function useMock() {
  return new URLSearchParams(location.search).get("mock") === "1"
    || typeof window.ZOHO === "undefined";
}

その後の改修では、テストケース17件のうち、モックで確かめられる8件を先に合格させました。ボタンからの起動、関数による連動、二重保存の確認などは「実環境待ち」として分けて記録し、実環境に入れた後に確かめる段取りにしています。モックでの合格を、実環境での合格と混同しないためです。

テストケースは仕様と一緒に書き換える

テストに合格した後も、仕様は変わります。この案件では後から次の変更がありました。

  • マイナスの単価は「値引きの行」として扱うことになりました。そのため「単価のマイナスを0に直す」確認は、「値引きが商品の合計を超えたら保存させない」確認に置き換えました。
  • 二重登録の対策は、「同じ内容なら止める」から、「別の受注書として保存」を明示的に選んだ場合は保存し、注意を出す形に変わりました。同じ内容の受注が実際に2件ある場合に対応するためです。

当社が確認した範囲では、Zohoのウィジェットは別ドメインの枠(iframe)の中で動くため、Chromeでは window.confirm の確認ダイアログが表示されませんでした。確認を求める処理は、ダイアログではなく画面内の表示やボタンで作っています。

仕様が変わったら、テストケースの表と結果の記録も同じ日に直します。古いケースのまま「合格」と記録すると、次に改修した人が誤った前提で確かめてしまうからです。

まとめ:異常系テストのチェックリスト

ウィジェットで入力画面を作ったら、少なくとも次を試してください。

  1. 必須の欄を空にして保存する
  2. 数値の欄に 0・マイナス・文字・空を入れる
  3. 合計や残額が、マイナスや合計超えにならないか見る
  4. 明細の行数の上限を超えて足す
  5. 選んだ後に、上位の選択(グループなど)を変える
  6. 保存ボタンを連打する
  7. 保存が終わった後に、同じ内容でもう一度保存する
  8. 文字数の上限を超える値を入れ、自動処理が黙って失敗しないか見る
  9. 保存した値をAPIで読み、狙った項目に入っているか照合する
  10. 仕様が変わったら、テストケースと結果の記録を同じ日に直す

ウィジェットそのものの作り方は、Zoho CRMに「類似案件レコメンド」を自作するで、ウィジェットからCOQLで既存の取引先を検索するときの件数制限と0件時の扱いは、Zoho CRMウィジェットで取引先を名寄せ取込するで紹介しています。標準の入力画面のままで入力を補助したい場合は、クライアントスクリプトで氏名を自動入力する構成案も参考になります。業務に合わせた入力画面の作り込みを相談したい場合は、Zoho CRMカスタマイズ・設定代行サービスのページをご覧ください。

よくある質問

Zoho CRMのウィジェットは、実環境に上げないとテストできませんか?

画面の動きだけなら、ローカルで動かすモックモードを作っておくと先に確かめられます。当社はURLに ?mock=1 を付けたときと、ZohoのSDKが読み込まれていないときにモックのデータで動くようにしました。ただしワークフローやDeluge関数との連動、保存した値の確認は、実環境でしか確かめられません。

二重登録を防ぐには、保存ボタンを押せなくするだけで十分ですか?

十分ではありませんでした。保存中にボタンを押せなくする対策は、連打には効きます。しかし保存が終わってボタンが戻った後に、同じ内容でもう一度押すと二重登録になりました。保存した内容の控えを持っておき、次の保存時に比べる仕組みを足して防ぎました。

異常系のテストケースは、いくつくらい用意すればよいですか?

件数より、入力欄ごとに「空」「0」「マイナス」「文字」「上限超え」を当てはめ、操作として「連打」「保存後の再保存」「選んだ後の選び直し」を足すと、抜けが少なくなります。当社の受注書と商品編集の2画面、自動命名の関数で21ケースになりました。

テストに合格した後で仕様が変わったら、テストケースはどうしますか?

テストケースも一緒に書き換えます。当社の例では、後から「マイナスの単価は値引きの行として扱う」と仕様が変わり、単価のマイナスを0にする確認は「値引きが合計を超えたら保存させない」確認に置き換えました。