我针对其运行的网站位于内部服务器上,因此无法提供链接,但是我可以发布一些单击“显示元素”时显示的相关代码。
有五个与此相关的元素:
此页面显示学生组,并允许用户在组之间拖动学生。每个组都有一个移动元素。棘手的部分是,仅当用户将学生元素拖到该组上时,任何给定组的“移动”按钮才会显示,而该学生并非来自该组。
目的是将学生转移到新的小组中,然后再移回原来的小组。
注意:学生XPath会在更改组时发生更改,我无法确认,但我相信移动按钮的XPath在隐藏和可见之间是不同的
我当前的代码:
IWebDriver driver = (IWebDriver)FeatureContext.Current["Driver"]; Actions builder = new Actions(driver); IWebElement originalstudent = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[3]/a[1]/div[1]/div")); IWebElement originalClass = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[1]")); IWebElement newClass = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[2]/div[2]/div[3]/div[1]/div[1]")); IWebElement originalMove = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[2]/div[2]/div[2]/div/div[2]/div[1]/div")); IWebElement newMove = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[2]/div[2]/div[3]/div[1]/div[2]/div[1]/div")); builder.ClickAndHold(originalstudent); builder.MoveToElement(newClass); builder.Release(newMove); builder.Build().Perform(); IWebElement save = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[1]/div/div/button[2]")); builder.Click(save); builder.Build().Perform(); //assert group2 has 1 student and group 1 has 3 students IWebElement newstudent = driver.FindElement(By.XPath("//*[@id=\"AMTeacherApp\"]/div/div/div[1]/div/div[3]/div/div/div[2]/div[2]/div[3]/div/div[3]/a/div[1]/div")); builder.ClickAndHold(newstudent); builder.MoveToElement(originalClass); builder.Release(originalMove); builder.Click(save); builder.Build().Perform();
此代码不会移动任何元素,并且在尝试查找保存时会失败,因为未进行任何更改(鉴于没有任何移动,这是预期的)。
页面中的相关代码:
<div class="column small-5 filter"> <div class="row groups-header"> <!-- ngIf: !model.configData.groupingMode.autoRegroup --> <div ng-if="!model.configData.groupingMode.autoRegroup" class="column small-8 ng-scope"> </div> <!-- end ngIf: !model.configData.groupingMode.autoRegroup --> <!-- ngIf: model.configData.groupingMode.autoRegroup --> <div class="column small-4 left-delimiter no-regroup" ng-class="{'no-regroup' : !model.configData.groupingMode.autoRegroup}"> <button type="button" class="light" ng-click="model.addGroup()" ng-disabled="!model.canAddGroup()">Add group </button> </div> </div> <!-- ngRepeat: group in model.groupingData --> <div class="group ng-scope" ng-repeat="group in model.groupingData"> ******<div index="1" class="drop-outer" ui-on-drop="model.onDrop(group)" ui-drag-enter="model.dragOver(group)" ui-drag-leave="model.dragLeave(group)"> <div class="button radius group-btn" ng-style="{'background-color': group.color}" ng-click="model.toggleState(group)" ui-on-drop="model.onMoveDrop(group)" ui-drag-enter="moveActive = true;model.autoScroll(el);" ui-drag-leave="moveActive = false;" style="background-color: rgb(0, 155, 159);"> <div class="left group-label ng-binding">Group 1 | 4 <span ng-show="group.students.length !== 1" class="">Students </span> <span ng-show="group.students.length === 1" class="ng-hide">Student </span> </div> <div class="right group-collapser" ng-hide="group.students.length == 0"> <!-- ngIf: group.collapsed --> <!-- ngIf: !group.collapsed --> <span class="glyph-chevron-collapsed ng-scope" ng-if="!group.collapsed"> </span> <!-- end ngIf: !group.collapsed --> </div> </div> <div ng-show="group.showAddContainers" class="row drop-container ng-hide"> <div ui-on-drop="model.onMoveDrop(group)" class="column" ng-class="{'active':moveActive}"> **********<div class="move">Move </div> </div> <div ui-on-drop="model.onCopyDrop(group)" class="column"> <div class="copy">Copy </div> </div> </div> <!-- ngIf: !group.collapsed --> ******<div class="row students slide-animation drag-elements ng-scope" ng-if="!group.collapsed"> <!-- ngRepeat: student in group.students --> <a no-chrome-href="" title="AM2Paper S" alt="AM2Paper S" class="student-btn-cont fade-animation ng-scope" ng-repeat="student in group.students" ui-draggable="true" on-drag-begin="model.dragStart(student, group)" drag="student" drag-class="student-btn-cont student-btn-cont-dragged" on-drop-success="model.dropSuccessHandler($index,group)" draggable="true" style=""> <div ng-style="{'background-color': group.color}" class="radius column student-btn" style="background-color: rgb(0, 155, 159);"> ************<div class="left student-label ng-isolate-scope" rl-display-name="" long-name="AM2Paper S" style="font-size: 9px;">AM2Paper S </div> </div> <div class="dots dots-line"> </div> </a> <!-- end ngRepeat: student in group.students --> <a no-chrome-href="" title="AMTest A" alt="AMTest A" class="student-btn-cont fade-animation ng-scope" ng-repeat="student in group.students" ui-draggable="true" on-drag-begin="model.dragStart(student, group)" drag="student" drag-class="student-btn-cont student-btn-cont-dragged" on-drop-success="model.dropSuccessHandler($index,group)" draggable="true" style=""> <div ng-style="{'background-color': group.color}" class="radius column student-btn" style="background-color: rgb(0, 155, 159);"> <div class="left student-label ng-isolate-scope" rl-display-name="" long-name="AMTest A" style="font-size: 11px;">AMTest A </div> </div> <div class="dots dots-line"> </div> </a> <!-- end ngRepeat: student in group.students --> <a no-chrome-href="" title="AMTestPaper A" alt="AMTestPaper A" class="student-btn-cont fade-animation ng-scope" ng-repeat="student in group.students" ui-draggable="true" on-drag-begin="model.dragStart(student, group)" drag="student" drag-class="student-btn-cont student-btn-cont-dragged" on-drop-success="model.dropSuccessHandler($index,group)" draggable="true" style=""> <div ng-style="{'background-color': group.color}" class="radius column student-btn" style="background-color: rgb(0, 155, 159);"> <div class="left student-label ng-isolate-scope" rl-display-name="" long-name="AMTestPaper A" style="font-size: 9px;">AMTestPaper... </div> </div> <div class="dots dots-line"> </div> </a> <!-- end ngRepeat: student in group.students --> <a no-chrome-href="" title="AM2Online S" alt="AM2Online S" class="student-btn-cont fade-animation ng-scope" ng-repeat="student in group.students" ui-draggable="true" on-drag-begin="model.dragStart(student, group)" drag="student" drag-class="student-btn-cont student-btn-cont-dragged" on-drop-success="model.dropSuccessHandler($index,group)" draggable="true" style=""> <div ng-style="{'background-color': group.color}" class="radius column student-btn" style="background-color: rgb(0, 155, 159);"> <div class="left student-label ng-isolate-scope" rl-display-name="" long-name="AM2Online S" style="font-size: 9px;">AM2Online S </div> </div> <div class="dots dots-line"> </div> </a> <!-- end ngRepeat: student in group.students --> </div> <!-- end ngIf: !group.collapsed --> <div ng-show="group.showRemoveContainers" class="row drop-container ng-hide"> <div class="column remove" ui-on-drop="model.onRemoveDrop(group)"> <div class="remove ng-binding">Remove from Group 1 </div> </div> </div> </div> <!-- ngIf: group.students.length == 0 --> </div> <!-- end ngRepeat: group in model.groupingData --> <div class="group ng-scope" ng-repeat="group in model.groupingData"> ******<div index="2" class="drop-outer" ui-on-drop="model.onDrop(group)" ui-drag-enter="model.dragOver(group)" ui-drag-leave="model.dragLeave(group)"> <div class="button radius group-btn" ng-style="{'background-color': group.color}" ng-click="model.toggleState(group)" ui-on-drop="model.onMoveDrop(group)" ui-drag-enter="moveActive = true;model.autoScroll(el);" ui-drag-leave="moveActive = false;" style="background-color: rgb(109, 48, 146);"> <div class="left group-label ng-binding">Group 2 | 0 <span ng-show="group.students.length !== 1" class="">Students </span> <span ng-show="group.students.length === 1" class="ng-hide">Student </span> </div> <div class="right group-collapser ng-hide" ng-hide="group.students.length == 0"> <!-- ngIf: group.collapsed --> <!-- ngIf: !group.collapsed --> <span class="glyph-chevron-collapsed ng-scope" ng-if="!group.collapsed"> </span> <!-- end ngIf: !group.collapsed --> </div> </div> <div ng-show="group.showAddContainers" class="row drop-container ng-hide"> <div ui-on-drop="model.onMoveDrop(group)" class="column" ng-class="{'active':moveActive}"> ************<div class="move">Move </div> </div> <div ui-on-drop="model.onCopyDrop(group)" class="column"> <div class="copy">Copy </div> </div> </div> <!-- ngIf: !group.collapsed --> <div class="row students slide-animation drag-elements ng-scope" ng-if="!group.collapsed" style=""> <!-- ngRepeat: student in group.students --> </div> <!-- end ngIf: !group.collapsed --> <div ng-show="group.showRemoveContainers" class="row drop-container ng-hide"> <div class="column remove" ui-on-drop="model.onRemoveDrop(group)"> <div class="remove ng-binding">Remove from Group 2 </div> </div> </div> </div> <!-- ngIf: group.students.length == 0 --> <div class="empty-group-label ng-scope" ng-if="group.students.length == 0"> <span class="left">Drag student icons into this Group </span> <a href="" class="right" ng-click="model.removeGroup($index)">Delete this group </a> </div> <!-- end ngIf: group.students.length == 0 --> </div> <!-- end ngRepeat: group in model.groupingData --> </div>
星号标记相关元素。让我知道您是否需要上下文相关的其他信息。
Selenium的拖放操作在HTML5中效果不佳,因此我求助于使用jquery拖动元素。
我将这些用作参考:https : //gist.github.com/rcorreia/2362544 http://elementalselenium.com/tips/39-drag- and-drop
结果如下:
public void WhenAStudentIsMovedToANewGroup(string action, string student, string group) { WaitForAngular(); IWebDriver driver = (IWebDriver)FeatureContext.Current["Driver"]; /* * Load a version of jQuery that we can access */ driver.Manage().Timeouts().SetScriptTimeout(TimeSpan.FromSeconds(10)); IJavaScriptExecutor js = (IJavaScriptExecutor)driver; js.ExecuteAsyncScript(loadJQuery, jQueryUrl); string dragEntity = string.Format("[title=\"{0}\"]", student); string target = string.Format("[ui-on-drop=\"model.onMoveDrop(group)\"]:contains({0}) ~ div > div .{1}", group, action); string javaScriptString = string.Format("{0}$('{1}').simulateDragDrop({{ dropTarget: '{2}'}});", dragAndDropHelper, dragEntity, target); //Execute the drag and drop against the HTML5 js.ExecuteScript(javaScriptString); } const string dragAndDropHelper = @"(function( $ ) { $.fn.simulateDragDrop = function(options) { return this.each(function() { new $.simulateDragDrop(this, options); }); }; $.simulateDragDrop = function(elem, options) { this.options = options; this.simulateEvent(elem, options); }; $.extend($.simulateDragDrop.prototype, { simulateEvent: function(elem, options) { /*Simulating drag start*/ var type = 'dragstart'; var event = this.createEvent(type); this.dispatchEvent(elem, type, event); /*Simulating drop*/ type = 'drop'; var dropEvent = this.createEvent(type, {}); dropEvent.dataTransfer = event.dataTransfer; this.dispatchEvent($(options.dropTarget)[0], type, dropEvent); /*Simulating drag end*/ type = 'dragend'; var dragEndEvent = this.createEvent(type, {}); dragEndEvent.dataTransfer = event.dataTransfer; this.dispatchEvent(elem, type, dragEndEvent); }, createEvent: function(type) { var event = document.createEvent(""CustomEvent""); event.initCustomEvent(type, true, true, null); event.dataTransfer = { data: { }, setData: function(type, val){ this.data[type] = val; }, getData: function(type){ return this.data[type]; } }; return event; }, dispatchEvent: function(elem, type, event) { if(elem.dispatchEvent) { elem.dispatchEvent(event); }else if( elem.fireEvent ) { elem.fireEvent(""on""+type, event); } } }); })(jQuery);"; const string loadJQuery = @"(function(jqueryUrl, callback) { if (typeof jqueryUrl != 'string') { jqueryUrl = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'; } if (typeof jQuery == 'undefined') { var script = document.createElement('script'); var head = document.getElementsByTagName('head')[0]; var done = false; script.onload = script.onreadystatechange = (function() { if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) { done = true; script.onload = script.onreadystatechange = null; head.removeChild(script); callback(); } }); script.src = jqueryUrl; head.appendChild(script); } else { callback(); } })(arguments[0], arguments[arguments.length - 1]);";