Vue.jsで作成している画面をSelenideでテストしていたら、テキストフィールドをクリアしてもバインドした変数が変わらなくて困った


答えを先に書くと

Selenideでクリア処理をした直後に下記メソッドを実行して対応できました。

import static com.codeborne.selenide.impl.Events.events;
 events.fireEvent(WebDriverRunner.driver(), $("xxxxx"), "keydown", "keypress", "input", "keyup", "change");

各バージョン情報

  • Vue.js:2.6.12
  • Selenide:5.16.2
    • Selenium:3.141.59

サンプル画面

Herokuにサンプル画面を置いています。

単純にinputを配置してv-modelでバインドさせています。バインド変数の動作が見えるように変数を表示しています。
こんな感じのソースです。

Sample.vue
<template>
    <div class="container sample-container">
        <div class="row">
            <div class="col">
                <input id="input" class="form-control" v-model="inputText">
            </div>
        </div>
        <div class="row">
            <div class="col label-col">
                <span id="label">{{ inputText }}</span>
            </div>
        </div>
    </div>
</template>

<script>
export default {
  name: 'Sample',
  data () {
    return {
      inputText: ''
    }
  }
}
</script>
<style>
  .sample-container {
    padding: 3rem 1.5rem;
    text-align: center;
  }
  .label-col {
    text-align: left;
  }
</style>

テストコードからのクリア時の挙動

このサンプル画面に対して、単純にテキストを入力して、クリアしてみると・・・

テキストフィールドの内容は消えるのですが、変数を表示している方が消えません。
つまり、v-modelを記載しているのに変数が書き換わりません。
ちなみに、clear() を setValue("") に置き換えても挙動は変わりません。

参考までにテストコードはこのような感じです。

ClearTest.java

    @Test
    public void clearError() throws Exception {

        open("https://clear-test-sample.herokuapp.com/");

        // input
        $("#input").setValue("abcdef123456");
        sleep(2000);

        // clear
        $("#input").clear();
        sleep(2000);

        // assert
        $("#input").should(Condition.empty);
        $("#label").should(Condition.empty);    // fail

    }

なぜ変数が書き換わらないのか?

いろいろ試してみたところ、どうもSelenideの(Seleniumの)テキストへのクリアは処理が特別らしく(?)テキストの内容をクリアしてもoninputなどのイベントが発生しないようで、Vue.js側がテキストの変更を検知することができずに変数を書き換えることができていないようです。

ChromeFireFoxともに同じ動作をするので、もしかしたらイベントが発生しないことを仕様としているのかもしれないですね。。。自然じゃないと思いますが。

対処方法

イベントが発生していないのであれば、イベントを発生させればいいよね!ということで、Selenideの中に実装のあるEventsというクラスのfireEventというメソッドを使わせてもらいます。
さっきのテストコードでクリアメソッドを呼んでいる直後にfireEventを入れます。

ClearTest.java
    @Test
    public void fireEvent() throws Exception {

        open("https://clear-test-sample.herokuapp.com/");

        // input
        $("#input").setValue("abcdef123456");
        sleep(2000);

        // clear
        $("#input").clear();
        events.fireEvent(WebDriverRunner.driver(), $("#input"), "keydown", "keypress", "input", "keyup", "change");
        sleep(2000);

        // assert
        $("#input").should(Condition.empty);
        $("#label").should(Condition.empty);

    }

消えるようになりましたね!

サンプルコード

大したコードではないのですが、テストコードは github にあげてあります。
https://github.com/rh-dyamada/cleartestsample