Help us understand the problem. What is going on with this article?

[Selenium] WebDriverでaddCookieするとき単位はミリ秒にしないといけない

More than 3 years have passed since last update.

躓きポイント

取ってきたCookieを削除してもう1回すぐセットするだけのコードを書いたつもりが、何故か2回目のセットで失敗してしまう。ところがexpiryだけ無視すると正常にセットされた。Cookieオブジェクトでは秒単位なのに、addCookieの引数はミリ秒単位になっているという意味不明な実装が原因だった。

Cookieをオブジェクトとして取得

var cookie = await driver.manage().getCookie('PHPSESSID');

Cookieの削除

await driver.manage().deleteCookie('PHPSESSID');

Cookieの再セット

BAD
await driver.manage().addCookie(
    cookie.name,
    cookie.value,
    cookie.path,
    cookie.domain,
    cookie.secure,
    cookie.expiry
);
GOOD
await driver.manage().addCookie(
    cookie.name,
    cookie.value,
    cookie.path,
    cookie.domain,
    cookie.secure,
    cookie.expiry * 1000
);

当該ソースを読んでみる

ググっても全然同様の質問が見当たらなかったので自分でソース読んで見るまで気づきませんでした。何でこうなってるんだろう…

webdriver.WebDriver.Options.prototype.addCookie = function(
    name, value, opt_path, opt_domain, opt_isSecure, opt_expiry) {
  // We do not allow '=' or ';' in the name.
  if (/[;=]/.test(name)) {
    throw Error('Invalid cookie name "' + name + '"');
  }

  // We do not allow ';' in value.
  if (/;/.test(value)) {
    throw Error('Invalid cookie value "' + value + '"');
  }

  var cookieString = name + '=' + value +
      (opt_domain ? ';domain=' + opt_domain : '') +
      (opt_path ? ';path=' + opt_path : '') +
      (opt_isSecure ? ';secure' : '');

  var expiry;
  if (goog.isDef(opt_expiry)) {
    var expiryDate;
    if (goog.isNumber(opt_expiry)) {
      expiryDate = new Date(opt_expiry);
    } else {
      expiryDate = /** @type {!Date} */ (opt_expiry);
      opt_expiry = expiryDate.getTime();
    }
    cookieString += ';expires=' + expiryDate.toUTCString();
    // Convert from milliseconds to seconds.
    expiry = Math.floor(/** @type {number} */ (opt_expiry) / 1000);
  }

  return this.driver_.schedule(
      new webdriver.Command(webdriver.CommandName.ADD_COOKIE).
          setParameter('cookie', {
            'name': name,
            'value': value,
            'path': opt_path,
            'domain': opt_domain,
            'secure': !!opt_isSecure,
            'expiry': expiry
          }),
      'WebDriver.manage().addCookie(' + cookieString + ')');
};

Node.jsだけでなく、Java本家もそうなってました。うーん…

public class AddCookie extends WebDriverHandler<Void> implements JsonParametersAware {

  private volatile Map<String, Object> rawCookie;

  public AddCookie(Session session) {
    super(session);
  }

  @Override
  public Void call() throws Exception {
    Cookie cookie = createCookie();

    getDriver().manage().addCookie(cookie);

    return null;
  }

  @SuppressWarnings({"unchecked"})
  public void setJsonParameters(Map<String, Object> allParameters) throws Exception {
    if (allParameters == null) {
      return;
    }
    rawCookie = Maps.newHashMap((Map<String, Object>) allParameters.get("cookie"));
  }

  protected Cookie createCookie() {
    if (rawCookie == null) {
      return null;
    }

    String name = (String) rawCookie.get("name");
    String value = (String) rawCookie.get("value");
    String path = (String) rawCookie.get("path");
    String domain = (String) rawCookie.get("domain");
    Boolean secure = (Boolean) rawCookie.get("secure");
    if (secure == null) {
        secure = false;
    }

    Number expiryNum = (Number) rawCookie.get("expiry");
    Date expiry = expiryNum == null ? null : new Date(
        TimeUnit.SECONDS.toMillis(expiryNum.longValue()));

    return new Cookie.Builder(name, value)
        .path(path)
        .domain(domain)
        .isSecure(secure)
        .expiresOn(expiry)
        .build();
  }

  @Override
  public String toString() {
    return "[add cookie: " + createCookie() + "]";
  }
}
mpyw
PHP(Laravel) / JavaScript(React/Redux/ReactNative/Vue) / MySQL あたりが得意分野なWeb系エンジニア。最近マンネリ化がひどいので Go / Kotlin / Rust / Swift あたりから何か掘り下げたいと思っている。Go は 2.x 出てから書きます。古い記事はそのまま参考にしないようにご注意ください
http://gravatar.com/mpyw
synapse
Synapseは、オンラインサロンサービスにおけるパイオニアとして、かつて存在していたスタートアップです。
https://synapseam.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした