JQuery セレクター指定ミスの検出

# はじめに

JQuery セレクターを多用するシステムがある。
多用するが故にセレクターミスが多い。
他システムからの流用を前提としている。
画面レイアウト（DOM要素構成）が流用元と多少異なるところがある。
JSソースをそのまま流用すると、多少異なるところにセレクターミスが多発する。
セレクターミスを人間の目で（ソースチェックで）検出するのは量的に至難の業である。

なんとかしたい！という要望を受けて、少し考えてみました。

```:セレクターミスの例
HTML部)

   <input id='jyuchuId' type='text' value='' />

JS部)

   var elem = $('#jyucyuId');
   // id=jyucyuId なる要素は存在しない。つまり JS 側のミス。
   // タイプミスを探したい。

   var main = $('div#main');
   // div#main は流用元画面にはあるが、流用先システムでは削除されている。
   // JS部を流用して未使用ロジックを消すのだが、消し忘れがよく起こる！
   
```


# JQuery 拡張版（デバック版）

セレクターを使って要素を取るFunctionの中で、該当する要素がないと検出される場合はログを出してみたらよいのか？の発想で JQueryを拡張してみます。

```:つまりこうゆうこと
var __$2 = $;
$ = jQuery = function (selector, context) {
    // 下記実装で同じことをしていることになる。
    var _jj = new __$2.fn.init(selector, context);
    return _jj;

    // あとは求める要素を取れていないときに
    // テキトーにログを出せばよいですね。
}

```


```:拡張前
  <script type='text/javascript' src='/js/jquery-2.1.1.js'></script>

```
```:拡張後(jqueryを引いている箇所の下にデバッグ用JSを追加)
  <script type='text/javascript' src='/js/jquery-2.1.1.js'></script>
  <script type='text/javascript' src='/js/_DEBUG_jQueryDebugChecker.js'></script>

```
```:_DEBUG_jQueryDebugChecker.js
// 全部を退避(__$2 は nullクリアしてはダメ！)
var __$2 = $;

// 除外キーワード(文字列)配列  【お好みで追加削除してください】
var excludeSelectorsKeywords = [ // ログに出したくない selector のキーワード
    '.ySpinner',
    '.tmSpinner',
    '.todayDefault',
    '.img-upload',
    '.fileUpload',
    '#hSlist',
    '#hdnArea',
     // \\s のみは正規表現でかく
    '#main\\s+input[\\s*type\\s*=\\s*radio\\s*]',
];

// 除外キーワードRegExp配列
var excludeSelectorsRegExp = [];
for (var idx = 0; idx < excludeSelectorsKeywords.length;idx++) {
    // キーワードがあるか否かをチェックするためのRegExp
    var _word = excludeSelectorsKeywords[idx];
    if (_word && "string" == typeof _word) { 
        var word = _word
            .replace(/\[/g, '\\[')	// [ 対応
            .replace(/\]/g, '\\]')	// ] 対応
            .replace(/\(/g, '\\(')	// ( 対応
            .replace(/\)/g, '\\)')	// ) 対応
            .replace(/\./g, '\\.');	// ピリオド対応
        var regexp = new RegExp(word, 'g');
        excludeSelectorsRegExp.push(regexp); // 要素追加
    }
}

// $,JQueryをオーバーライド( function(selector,context) を置換 )
$ = jQuery = function (selector, context) {

    // ログメッセージを組み立てておく。
    var msg = "CHECK!!. selector=[" + selector + "]";
    if (context != undefined) {
        msg += ",context=[" + context + "]";
    }
    //------------------------------------------------
    // 元の fn.init を呼び出して要素を取り出す
    var _jj = new __$2.fn.init(selector, context);
    if (_jj && _jj.length > 0) {
        // 要素が存在するとき
        return _jj; // init(selector, context)の結果。
    } else {
        // 要素が存在しないとき
        for (var idx = 0; idx < excludeSelectorsRegExp.length;idx++) {
            var regexp = excludeSelectorsRegExp[idx];
            // ログ除外するとき
            var match = selector.match(regexp);
            //console.log("selector=" + selector + ",match=" + match+",source="+regexp.source);
            if (match && match.length > 0) {
               // ループ抜ける
               return _jj; // init(selector, context)の結果
            }
        }
        console.info(msg);
        console.trace(); // 検出した場所を知らせるために traceを出す
        return _jj; // init(selector, context)の結果 
    }
}

// 仕上げ：その他のプロパティを再度格納し直す
for (var item in __$2) {
    $[item] = __$2[item];
}

```

上記の拡張版の $ を使って、下記が実現できます。
・JQueryの全てのメソッドをそのまま使える
・かつ、セレクター異常の場合は console ログを出す。
・ログ出力時には、スタックトレースを出してどの行で検出したか知らせる。


# 実行例

Infoレベルで CHECK!!～　というメッセージとともに、
selector の指定内容、$( ) が呼び出された場所の情報を表示します！
【開発者ツールのコンソール】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/6103637c-f732-ab22-506d-5c3381831638.png)


# 制約事項

確認は jQuery 2.1.1 でとりました。
多少のバージョン相違は支障ないはずです。


_DEBUG_jQueryDebugChecker.js　の仕組みを組み込んだまま「ひととおりのJQueryメソッド」を実行できますが、組み込んだ状態で本番にＵＰしてはダメですよ！

それから、jQueryセレクターミスを検出する用途の局面だけで使ってくださいね。

単体テストといえども、デバッグＪＳを組み込んだままではよろしくない。


# まとめ

## よいこと
共通的に書いておくことで、いろんな画面の無効セレクターを検出できる。

## わるいこと
共通処理に書いてあるのを忘れて、正式テスト時に取り忘れてしまうこと！
↑  正式テスト時には、必ず点検する観点にあげておくこと