🙌

Capybaraでエレメントの絶対位置を取得する。

2024/04/30に公開

概要

Capybaraとrspecでテストを書いていて、エレメントが正しい位置にあるかチェックするためにdocumentの左上端からのピクセル数を取得しようと思いました。位置の取得自体はJavascriptでTipsがいっぱいあるので、それを落とし込めばいいのですが、ちょっとクセっぽいところがあったので記事にしました。

コード

def calc_document_offset_rect(element)
  rect = element.evaluate_script <<~JS
    (() => {
      let el = this;
      let top = 0, left = 0;
      const width = el.offsetWidth;
      const height = el.offsetHeight;
      while (el !== undefined && el !== null) {
          top += el.offsetTop;
          left += el.offsetLeft;
          el = el.offsetParent;
      }
      return {
        top,
        left,
        width,
        height,
        bottom: top + height,
        right: left + width
      };
    })();
  JS

  rect.symbolize_keys
end

解説

javascriptのコードはこの辺を参考にしました。

https://stackoverflow.com/questions/442404/retrieve-the-position-x-y-of-an-html-element

elelment.evaluate_script('this.getBoundingClientRect()')とやると動くのでevaluate_scriptに渡すスクリプトの中ではthisはエレメント自体を指すのですが、varletcontなどで変数を宣言するとうまく動かないようです。

変数を使うには示したコードのように関数を作って即時呼び出しする必要があるようです。(() => {})()のところですね。また即時関数ですが(function(){})()だとthisがundefinedになるので() => {}とアロー関数を使う必要があります。

rect.symbolize_keysはrails特有のメソッドですが、返り値のキーはシンボルの方が扱いやすいと思うので変換しました。rails無しなら

rect.map{|k,v| [k.to_sym, v] }.to_h

でイケるかと。

https://qiita.com/zakuroishikuro/items/5b08d65d4fef79982f19

Discussion