1.简介

  理想很丰满现实很骨感,在应用selenium实现web自动化时,经常会遇到处理日期控件点击问题,手工很简单,可以一个个点击日期控件选择需要的日期,但自动化执行过程中,完全复制手工这样的操作就有点难了。宏哥上一篇已经讲解了如何处理日历时间控件,但是对于第一种方法可能会遇到输入框是readonly的情况,那么第一种方法就不适用了,但是只要我们稍微的变通地处理一下,就又可以使用了。

2.问题

宏哥第一种方法地思路就是把它当做输入框,直接输入日期即可,想法是很美好的,但是有时候实行起来却不执行,这个时候我们就要仔细去看看前端的代码了,代码如下:

<div class="col-lg-3 form-input">
  <input id="createTime" class="form-control" type="text" readonly="readonly" name="tatsudoDate" onclick="WdatePicker()" aria-required="true">
</div>

从上边的代码可以看出属性readonly人家根本不允许你输入,你就行不通了。

3.想法

既然这样了,我们就稍微变通一下,不要一条道走到黑。这个时候我们可以移除readonly的属性,问题就轻轻松松解决了,代码如下:

String js = "document.getElementById('createTime').removeAttribute('readonly')"; // 原生js,移除属性

((JavascriptExecutor)driver).executeScript(js); //将driver强制转换为JavascriptExecutor类型

driver.findElement(By.id("createTime")).sendKeys("2016-08-24"); //输入日期

4.注意

代码里面一定要记得导入这个方法(一般代码编辑器eclipse都会报错提示)虽然有提示,但是宏哥在这里还是提示一下,不要导错包了。:

import org.openqa.selenium.JavascriptExecutor;

5.项目实战

网上找了半天也没有找到这样的例子,以前12306的日历是这种。最近升级了,已经不是这种了。不找了索性宏哥自己在本地做一个这样的小demo给小伙伴或者童鞋们来演示一下。

注:本文演示的数据大家可以在公众号后台回复 宏哥38,在java+selenium->38 文件夹领取。

5.1代码准备

5.1.1前端HTML代码

前端HTML代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script src="dateJs.js"></script>
<link rel="stylesheet" type="text/css" href="date.css">
</head>
<body>
<div id="wrapper" style="position: relative;top: 100px;left:600px;">
<button class="button1"><a id="myAnchor" href="https://www.cnblogs.com/du-hong/">北京-宏哥</a></button></br>
<input type="text" id="Dateinput" readonly=""/>
<div class="calendar" id="calender" style="display: none;">
</div>
</div>
</body>
</html>
5.1.2CSS样式

HTML滑块CSS样式代码如下:

* {
margin: 0;
padding: 0;
} body {
font-size: 13px;
} .calendar {
width: 330px;
} .calendar .title {
position: relative;
width: 100%;
height: 30px;
line-height: 30px;
background: #17a4eb;
} .title div {
position: absolute;
} .prev {
left: 10px;
} .now {
left: 40%;
} .next {
right: 10px;
} input {
height: 30px;
width: 326px;
} table {
width: 100%;
border-collapse: collapse;
} table th {
border: 1px solid #ccc;
} table td {
text-align: center;
border: 1px solid #ccc;
} .red {
background-color: #a1cbdb;
} .blue {
background-color: #e4e3e3;
} .button1 {
background-color: #f44336;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 28px;
margin-bottom: 100px;
text-decoration: none;
color: white;
} #myAnchor {
text-decoration: none;
color: white;
}
5.1.3日历JS

日历JS代码如下:

window.onload = function () {
//获取日期 输入框
var oInput = document.getElementById('Dateinput');
//获取日历
var oCalender = document.getElementById('calender');
//获取当前日期
var oDate = new Date();
//获取当年 年
var year = oDate.getFullYear();
//获取当前 月
var month = oDate.getMonth() + 1; //日历框不能重复创建
var flag = false;
//日期输入框 获取焦点时 加载日历
oInput.onfocus = function () {
showDate(year, month);
} //显示日历
function showDate(year, month) {
if (false == flag) {
//1.日历标题
var oTitle = document.createElement('div');
oTitle.className = 'title'; //1.1日历标题文本
var prevM = 0;
var nextM = 0; prevM = month - 1;
nextM = month + 1; //当月份为1时 上一个月为12
if (month == 1) {
prevM = 12;
}//当月份为12时 下一个月为1
else if (month == 12) {
nextM = 1;
} var titleHtml = "";
titleHtml += '<div class="prev" id="prev"><span>';
titleHtml += prevM + '</span>月</div>';
titleHtml += '<div class="now">';
titleHtml += '<span class="span">';
titleHtml += year;
titleHtml += '</span>年';
titleHtml += '<span class="span">' + month;
titleHtml += '</span>月</div>';
titleHtml += '<div class="next" id="next"><span>';
titleHtml += nextM + '</span>月</div>'; oTitle.innerHTML = titleHtml;
//将日历标题 拼接到日历
oCalender.appendChild(oTitle); //1.2获取日历 表头元素(以便添加事件)
var oSpans = oCalender.getElementsByTagName('span');
var prevMonth = oSpans[0];
var nextMonth = oSpans[3];
var nowMonth = oSpans[2];
var nowYear = oSpans[1]; //2.创建星期 表头
var otable = document.createElement('table');
var othead = document.createElement('thead');
var otr = document.createElement('tr'); //2.1表头内容填充
var arr = ['日', '一', '二', '三', '四', '五', '六'];
for (var i = 0; i < arr.length; i++) {
//创建th
var oth = document.createElement('th');
oth.innerHTML = arr[i];
otr.appendChild(oth);
} //2.2将表头加入到日历
othead.appendChild(otr);
otable.appendChild(othead);
oCalender.appendChild(otable); //3.添加 当前日历 全部日期
//3.1.先获得当期月 有多少天
var dayNum = 0;
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
dayNum = 31;
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
dayNum = 30;
} else if (month == 2 && isLeapYear(year)) {
dayNum = 29;
} else {
dayNum = 28;
} //3.2.创建 6行7列 日期容器
var otbody = document.createElement('tbody');
for (var i = 0; i < 6; i++) {
var otr = document.createElement('tr');
for (var j = 0; j < 7; j++) {
var otd = document.createElement('td');
otr.appendChild(otd);
}
otbody.appendChild(otr);
}
otable.appendChild(otbody); //3.3获得 1号对应的是星期几
//3.3.1.将当月1号赋值给日期变量
oDate.setFullYear(year);
//注意 js日期的月份是从0 开始计算
oDate.setMonth(month - 1);
oDate.setDate(1); //3.3.2.计算1号在第一行日期容器中的位置,依次给日期容器填充内容
//注意 js中 getDay方法是获取当前日期是星期几
var week = oDate.getDay();
var otds = oCalender.getElementsByTagName('td');
for (var i = 0; i < dayNum; i++) {
otds[i + week].innerHTML = i + 1;
} //让当前日期显示红色、后面的显示蓝色
showColor(otds);
//给左右月份绑定点击事件
monthEvent();
//判断最后一行是否全为空
lastTr(otds);
flag = true;
document.getElementById('calender').style.display = "block";
}
} //判断是否是闰年
function isLeapYear(year) {
if (year % 100 == 0 && year % 400 == 0) {
return true;
} else if (year % 100 != 0 && year % 4 == 0) {
return true;
} else {
return false;
}
} //判断日期容器最后一行是否有值
function lastTr(otds) {
var flag = true;
for (var i = 35; i < 42; i++) {
if (otds[i].innerHTML != '') {
flag = false;
}
}
//全是空的
if (flag) {
for (var i = 35; i < 42; i++) {
otds[i].style.display = 'none';
}
}
} //当前日期显示红色、前面的显示灰色
function showColor(otds) {
//当前日期
var nowday = new Date().getDate();
var nowyear = new Date().getFullYear();
var nowmonth = new Date().getMonth(); var oCalendar = document.getElementById("calender");
ospans = oCalendar.getElementsByTagName('span');
var contralYear = ospans[1].innerHTML;
var contralMonth = ospans[2].innerHTML; var oindex = 0;
for (var i = 0; i < otds.length; i++) {
if (nowday == otds[i].innerHTML && nowyear == contralYear && nowmonth + 1 == contralMonth) {
otds[i].className = 'red';
oindex = i;
}
}
} //给左右月份绑定点击事件
function monthEvent() {
var oCalendar = document.getElementById("calender");
var prevDiv = document.getElementById("prev");
var nextDiv = document.getElementById("next"); var prevMonth = prevDiv.getElementsByTagName("span");
var nextMonth = nextDiv.getElementsByTagName("span"); prevDiv.onclick = function () {
flag = false;
oCalendar.innerHTML = '';
showDate(year, parseInt(prevMonth[0].innerHTML));
} nextDiv.onclick = function () {
flag = false;
oCalendar.innerHTML = '';
showDate(year, parseInt(nextMonth[0].innerHTML));
} }
}

6.自动化代码实现

6.1代码设计

6.2参考代码

package lessons;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;//注意不要倒错包
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver; /**
* @author 北京-宏哥
*
* 《手把手教你》系列技巧篇(三十八)-java+ selenium自动化测试-日历时间控件-下篇(详解教程)
*
* 2021年10月31日
*/
public class calendar { public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", ".\\Tools\\chromedriver.exe");
WebDriver driver =new ChromeDriver();
driver.manage().window().maximize();
try {
driver.get("file:///C:/Users/DELL/Desktop/test/Calendar/Calendar.html");
Thread.sleep(5000);
//执行方式
JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
String js = "document.getElementById('Dateinput').removeAttribute('readonly')";
jsExecutor.executeScript(js);//执行js,将readonly属性去掉后就可以写入日期
driver.findElement(By.id("Dateinput")).clear();//写入前清除数据
driver.findElement(By.id("Dateinput")).sendKeys("2021-11-11");//写入期望日期
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("执行结束,关闭浏览器!提前祝大家光棍节快乐!!!");
driver.quit();
}
}
}

6.3运行代码

1.运行代码,右键Run AS->Java Appliance,控制台输出,如下图所示:

2.运行代码后电脑端的浏览器的动作,如下小视频所示:

7.小结

好了,时间不早了,今天就分享到这里,感谢大家耐心的阅读,这两篇其实是为后边文章的JavaScript的调用做一下铺垫和入门。

《手把手教你》系列技巧篇(三十八)-java+ selenium自动化测试-日历时间控件-下篇(详解教程)的更多相关文章

  1. 《手把手教你》系列技巧篇(三十七)-java+ selenium自动化测试-日历时间控件-上篇(详解教程)

    1.简介 我们在实际工作中,有可能遇到有些web产品,网页上有一些时间选择,然后支持按照不同时间段范围去筛选数据.网页上日历控件一般,是一个文本输入框,鼠标点击,就会弹出日历界面,可以选择具体日期.这 ...

  2. 《手把手教你》系列技巧篇(十)-java+ selenium自动化测试-元素定位大法之By class name(详细教程)

    1.简介 按宏哥计划,本文继续介绍WebDriver关于元素定位大法,这篇介绍By ClassName.看到ID,NAME这些方法的讲解,小伙伴们和童鞋们应该知道,要做好Web自动化测试,最好是需要了 ...

  3. 《手把手教你》系列技巧篇(三十)-java+ selenium自动化测试- Actions的相关操作下篇(详解教程)

    1.简介 本文主要介绍两个在测试过程中可能会用到的功能:Actions类中的拖拽操作和Actions类中的划取字段操作.例如:需要在一堆log字符中随机划取一段文字,然后右键选择摘取功能. 2.拖拽操 ...

  4. 《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)

    1.简介 在实际自动化测试过程中,我们也避免不了会遇到下拉选择的测试,因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助. 2.select 下拉框 2.1Select ...

  5. 《手把手教你》系列技巧篇(二十八)-java+ selenium自动化测试-处理模态对话框弹窗(详解教程)

    1.简介 在前边的文章中窗口句柄切换宏哥介绍了switchTo方法,这篇继续介绍switchTo中关于处理alert弹窗的问题.很多时候,我们进入一个网站,就会弹窗一个alert框,有些我们直接关闭, ...

  6. 《手把手教你》系列技巧篇(四十八)-java+ selenium自动化测试-判断元素是否可操作(详解教程)

    1.简介 webdriver有三种判断元素状态的方法,分别是isEnabled,isSelected 和 isDisplayed,其中isSelected在前面的内容中已经简单的介绍了,isSelec ...

  7. 《手把手教你》系列技巧篇(十七)-java+ selenium自动化测试-元素定位大法之By css上卷(详细教程)

    1.简介 CSS定位方式和xpath定位方式基本相同,只是CSS定位表达式有其自己的格式.CSS定位方式拥有比xpath定位速度快,且比CSS稳定的特性.下面详细介绍CSS定位方式的使用方法.xpat ...

  8. 《手把手教你》系列技巧篇(四十七)-java+ selenium自动化测试-判断元素是否显示(详解教程)

    1.简介 webdriver有三种判断元素状态的方法,分别是isEnabled,isSelected 和 isDisplayed,其中isSelected在前面的内容中已经简单的介绍了,isSelec ...

  9. 《手把手教你》系列技巧篇(六)-java+ selenium自动化测试-阅读selenium源码(详细教程)

    1.简介 前面几篇基础系列文章,足够你迈进了Selenium门槛,再不济你也至少知道如何写你第一个基于Java的Selenium自动化测试脚本.接下来宏哥介绍Selenium技巧篇,主要是介绍一些常用 ...

随机推荐

  1. Java面向对象系列(14)- 接口的定义与实现

    接口 普通类:只有具体实现 抽象类:具体实现和规范(抽象方法)都有 接口:只有规范!约束和实现分离 接口就是规范,定义的是一组规则,体现了现实世界中"如果你是-则必须能-"的思想. ...

  2. 接口测试checklist

    静态测试 接口文档与设计文档对应 接口定义 接口定义与数据库定义 业务功能测试 系统全流程验证 逆向全流程验证 事务性测试 边界值测试 业务规则边界值 场景分析合理长度 场景分析合理数据量 输入.输出 ...

  3. centos实现免密登陆及远程操作

    ----------------------------**********------------------------------------------------- 免密码登陆 第一步: 执 ...

  4. 鸿蒙内核源码分析(fork篇) | 一次调用,两次返回 | 百篇博客分析OpenHarmony源码 | v45.03

    百篇博客系列篇.本篇为: v45.xx 鸿蒙内核源码分析(Fork篇) | 一次调用,两次返回 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内 ...

  5. Spirit带你彻底搞懂JS的6种继承方案

    JavaScript中实现继承的6种方案 01-原型链的继承方案 function Person(){ this.name="czx"; } function Student(){ ...

  6. spring-data-redis 上百万的 QPS 压力太大连接失败,我 TM 人傻了

    大家好,我们最近业务量暴涨,导致我最近一直 TM 人傻了.前几天晚上,发现由于业务压力激增,某个核心微服务新扩容起来的几个实例,在不同程度上,出现了 Redis 连接失败的异常: org.spring ...

  7. Radius协议-学习

    目录 RFC Radius 协议 Radius-学习 RADIUS协议的主要特征 客户端/服务器模式 安全的消息交互机制 良好的扩展性 AAA介绍 C/S结构 RADIUS在协议栈中的位置 RADIU ...

  8. Java集合——List,Set,Map总结笔记

    1. 集合 Collection 1.1 Java 集合框架 ​ ​ ​ ​ ​ ​ ​ ​ Java 集合框架位于 java.util 包中.Java 集合框架主要包括两种类型的容器,一种是集合(C ...

  9. asp.net core使用identity+jwt保护你的webapi(二)——获取jwt token

    前言 上一篇已经介绍了identity在web api中的基本配置,本篇来完成用户的注册,登录,获取jwt token. 开始 开始之前先配置一下jwt相关服务. 配置JWT 首先NuGet安装包: ...

  10. Dapr + .NET Core实战(十四)虚拟机集群部署 mDNS + Consul

    前面我们说了在单机模式下和K8S集群下的Dapr实战,这次我们来看看如何在不使用K8S的情况下,在一个传统的虚拟机集群里来部署Dapr. 1.环境准备 我们准备两台centos7虚拟机 Dapr1:1 ...