1.简介

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

2.问题

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

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

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

3.想法

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

  1. String js = "document.getElementById('createTime').removeAttribute('readonly')"; // 原生js,移除属性
  2.  
  3. ((JavascriptExecutor)driver).executeScript(js); //将driver强制转换为JavascriptExecutor类型
  4.  
  5. driver.findElement(By.id("createTime")).sendKeys("2016-08-24"); //输入日期

4.注意

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

  1. import org.openqa.selenium.JavascriptExecutor;

5.项目实战

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

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

5.1代码准备

5.1.1前端HTML代码

前端HTML代码如下:

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

HTML滑块CSS样式代码如下:

  1. * {
  2. margin: 0;
  3. padding: 0;
  4. }
  5.  
  6. body {
  7. font-size: 13px;
  8. }
  9.  
  10. .calendar {
  11. width: 330px;
  12. }
  13.  
  14. .calendar .title {
  15. position: relative;
  16. width: 100%;
  17. height: 30px;
  18. line-height: 30px;
  19. background: #17a4eb;
  20. }
  21.  
  22. .title div {
  23. position: absolute;
  24. }
  25.  
  26. .prev {
  27. left: 10px;
  28. }
  29.  
  30. .now {
  31. left: 40%;
  32. }
  33.  
  34. .next {
  35. right: 10px;
  36. }
  37.  
  38. input {
  39. height: 30px;
  40. width: 326px;
  41. }
  42.  
  43. table {
  44. width: 100%;
  45. border-collapse: collapse;
  46. }
  47.  
  48. table th {
  49. border: 1px solid #ccc;
  50. }
  51.  
  52. table td {
  53. text-align: center;
  54. border: 1px solid #ccc;
  55. }
  56.  
  57. .red {
  58. background-color: #a1cbdb;
  59. }
  60.  
  61. .blue {
  62. background-color: #e4e3e3;
  63. }
  64.  
  65. .button1 {
  66. background-color: #f44336;
  67. border: none;
  68. color: white;
  69. padding: 15px 32px;
  70. text-align: center;
  71. text-decoration: none;
  72. display: inline-block;
  73. font-size: 28px;
  74. margin-bottom: 100px;
  75. text-decoration: none;
  76. color: white;
  77. }
  78.  
  79. #myAnchor {
  80. text-decoration: none;
  81. color: white;
  82. }
5.1.3日历JS

日历JS代码如下:

  1. window.onload = function () {
  2. //获取日期 输入框
  3. var oInput = document.getElementById('Dateinput');
  4. //获取日历
  5. var oCalender = document.getElementById('calender');
  6. //获取当前日期
  7. var oDate = new Date();
  8. //获取当年 年
  9. var year = oDate.getFullYear();
  10. //获取当前 月
  11. var month = oDate.getMonth() + 1;
  12.  
  13. //日历框不能重复创建
  14. var flag = false;
  15. //日期输入框 获取焦点时 加载日历
  16. oInput.onfocus = function () {
  17. showDate(year, month);
  18. }
  19.  
  20. //显示日历
  21. function showDate(year, month) {
  22. if (false == flag) {
  23. //1.日历标题
  24. var oTitle = document.createElement('div');
  25. oTitle.className = 'title';
  26.  
  27. //1.1日历标题文本
  28. var prevM = 0;
  29. var nextM = 0;
  30.  
  31. prevM = month - 1;
  32. nextM = month + 1;
  33.  
  34. //当月份为1时 上一个月为12
  35. if (month == 1) {
  36. prevM = 12;
  37. }//当月份为12时 下一个月为1
  38. else if (month == 12) {
  39. nextM = 1;
  40. }
  41.  
  42. var titleHtml = "";
  43. titleHtml += '<div class="prev" id="prev"><span>';
  44. titleHtml += prevM + '</span>月</div>';
  45. titleHtml += '<div class="now">';
  46. titleHtml += '<span class="span">';
  47. titleHtml += year;
  48. titleHtml += '</span>年';
  49. titleHtml += '<span class="span">' + month;
  50. titleHtml += '</span>月</div>';
  51. titleHtml += '<div class="next" id="next"><span>';
  52. titleHtml += nextM + '</span>月</div>';
  53.  
  54. oTitle.innerHTML = titleHtml;
  55. //将日历标题 拼接到日历
  56. oCalender.appendChild(oTitle);
  57.  
  58. //1.2获取日历 表头元素(以便添加事件)
  59. var oSpans = oCalender.getElementsByTagName('span');
  60. var prevMonth = oSpans[0];
  61. var nextMonth = oSpans[3];
  62. var nowMonth = oSpans[2];
  63. var nowYear = oSpans[1];
  64.  
  65. //2.创建星期 表头
  66. var otable = document.createElement('table');
  67. var othead = document.createElement('thead');
  68. var otr = document.createElement('tr');
  69.  
  70. //2.1表头内容填充
  71. var arr = ['日', '一', '二', '三', '四', '五', '六'];
  72. for (var i = 0; i < arr.length; i++) {
  73. //创建th
  74. var oth = document.createElement('th');
  75. oth.innerHTML = arr[i];
  76. otr.appendChild(oth);
  77. }
  78.  
  79. //2.2将表头加入到日历
  80. othead.appendChild(otr);
  81. otable.appendChild(othead);
  82. oCalender.appendChild(otable);
  83.  
  84. //3.添加 当前日历 全部日期
  85. //3.1.先获得当期月 有多少天
  86. var dayNum = 0;
  87. if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
  88. dayNum = 31;
  89. } else if (month == 4 || month == 6 || month == 9 || month == 11) {
  90. dayNum = 30;
  91. } else if (month == 2 && isLeapYear(year)) {
  92. dayNum = 29;
  93. } else {
  94. dayNum = 28;
  95. }
  96.  
  97. //3.2.创建 6行7列 日期容器
  98. var otbody = document.createElement('tbody');
  99. for (var i = 0; i < 6; i++) {
  100. var otr = document.createElement('tr');
  101. for (var j = 0; j < 7; j++) {
  102. var otd = document.createElement('td');
  103. otr.appendChild(otd);
  104. }
  105. otbody.appendChild(otr);
  106. }
  107. otable.appendChild(otbody);
  108.  
  109. //3.3获得 1号对应的是星期几
  110. //3.3.1.将当月1号赋值给日期变量
  111. oDate.setFullYear(year);
  112. //注意 js日期的月份是从0 开始计算
  113. oDate.setMonth(month - 1);
  114. oDate.setDate(1);
  115.  
  116. //3.3.2.计算1号在第一行日期容器中的位置,依次给日期容器填充内容
  117. //注意 js中 getDay方法是获取当前日期是星期几
  118. var week = oDate.getDay();
  119. var otds = oCalender.getElementsByTagName('td');
  120. for (var i = 0; i < dayNum; i++) {
  121. otds[i + week].innerHTML = i + 1;
  122. }
  123.  
  124. //让当前日期显示红色、后面的显示蓝色
  125. showColor(otds);
  126. //给左右月份绑定点击事件
  127. monthEvent();
  128. //判断最后一行是否全为空
  129. lastTr(otds);
  130. flag = true;
  131. document.getElementById('calender').style.display = "block";
  132. }
  133. }
  134.  
  135. //判断是否是闰年
  136. function isLeapYear(year) {
  137. if (year % 100 == 0 && year % 400 == 0) {
  138. return true;
  139. } else if (year % 100 != 0 && year % 4 == 0) {
  140. return true;
  141. } else {
  142. return false;
  143. }
  144. }
  145.  
  146. //判断日期容器最后一行是否有值
  147. function lastTr(otds) {
  148. var flag = true;
  149. for (var i = 35; i < 42; i++) {
  150. if (otds[i].innerHTML != '') {
  151. flag = false;
  152. }
  153. }
  154. //全是空的
  155. if (flag) {
  156. for (var i = 35; i < 42; i++) {
  157. otds[i].style.display = 'none';
  158. }
  159. }
  160. }
  161.  
  162. //当前日期显示红色、前面的显示灰色
  163. function showColor(otds) {
  164. //当前日期
  165. var nowday = new Date().getDate();
  166. var nowyear = new Date().getFullYear();
  167. var nowmonth = new Date().getMonth();
  168.  
  169. var oCalendar = document.getElementById("calender");
  170. ospans = oCalendar.getElementsByTagName('span');
  171. var contralYear = ospans[1].innerHTML;
  172. var contralMonth = ospans[2].innerHTML;
  173.  
  174. var oindex = 0;
  175. for (var i = 0; i < otds.length; i++) {
  176. if (nowday == otds[i].innerHTML && nowyear == contralYear && nowmonth + 1 == contralMonth) {
  177. otds[i].className = 'red';
  178. oindex = i;
  179. }
  180. }
  181. }
  182.  
  183. //给左右月份绑定点击事件
  184. function monthEvent() {
  185. var oCalendar = document.getElementById("calender");
  186. var prevDiv = document.getElementById("prev");
  187. var nextDiv = document.getElementById("next");
  188.  
  189. var prevMonth = prevDiv.getElementsByTagName("span");
  190. var nextMonth = nextDiv.getElementsByTagName("span");
  191.  
  192. prevDiv.onclick = function () {
  193. flag = false;
  194. oCalendar.innerHTML = '';
  195. showDate(year, parseInt(prevMonth[0].innerHTML));
  196. }
  197.  
  198. nextDiv.onclick = function () {
  199. flag = false;
  200. oCalendar.innerHTML = '';
  201. showDate(year, parseInt(nextMonth[0].innerHTML));
  202. }
  203.  
  204. }
  205. }

6.自动化代码实现

6.1代码设计

6.2参考代码

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

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. Jmeter线程组设置

    添加线程组:右键测试计划->添加->Threads->线程组 左侧树形标签栏中,显示标签信息. 选中线程组,右侧内容栏中显示线程组的相关信息. 名称:可以给线程组设置一个个性化的命名 ...

  2. Python调用函数带括号和不带括号的区别

    1.不带括号时,调用的是这个函数本身 ,是整个函数体,是一个函数对象,不需等该函数执行完成 2.带括号(此时必须传入需要的参数),调用的是函数的return结果,需要等待函数执行完成的结果 如果函数本 ...

  3. springboot 运行出现错误 Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.

    原因是我将springboot启动类换到了另外一个方法中 出现了一个异常 后来发现因为我换了类但是忘记了换类名所以才报错 @ComponentScan @EnableAutoConfiguration ...

  4. LR虚拟用户已设置集合点,但controller无法设置集合点策略的解决方案

    原文来自:https://blog.csdn.net/qq_34982914/article/details/90905030 学习loadrunner的过程中,肯定涉及集合点的添加,但是我们按照书上 ...

  5. P7046-「MCOI-03」诗韵【SAM,倍增,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P7046 题目大意 给出一个长度为 \(n\) 的字符串,然后 \(m\) 次把它的一个子串加入集合.如果一个字符串 ...

  6. CF25E-Test【AC自动机,bfs】

    正题 题目链接:https://www.luogu.com.cn/problem/CF25E 题目大意 给出三个串,然后求一个最短的串包含这三个串. \(1\leq |s_1|,|s_2|,|s_3| ...

  7. 使用jacob调用Windows的com对象,进行word、ppt等转换成ptf、html(二)

    富文本转pdf : 注意:simsun.ttc 可以百度下载:http://www.pc6.com/softview/SoftView_100415.html package com.orangecd ...

  8. Cnblogs 主题设置

    https://www.cnblogs.com/enjoy233/p/cnblogs-markdown-code-display-opt.html 复制: 右上角添加复制按钮:https://www. ...

  9. minikube addons enable ingress 启动错误

    minikube addons enable ingress 启动错误 开启 minkube ingress 时错误 minikube addons enable ingress --alsologt ...

  10. Edit Step Ladders - UVA 10029

    题意 题目链接(Virtual Judge):Edit Step Ladders - UVA 10029 题意: 如果单词 \(x\) 能通过添加.删除或修改一个字母变换为单词 \(y\),则称单词 ...