Skip to content

Commit

Permalink
SimonStewart: Checking in patch from AlexisVuillemin that adds the ab…
Browse files Browse the repository at this point in the history
…ility to find elements by class name

r5241
  • Loading branch information
shs96c committed May 28, 2008
1 parent c319015 commit 4846167
Show file tree
Hide file tree
Showing 15 changed files with 220 additions and 15 deletions.
2 changes: 2 additions & 0 deletions CREDITS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ James Cooper
Malcolm Rowe
Mirko Nasato
Marc Guillemot
Alexis Vuillemin

44 changes: 42 additions & 2 deletions common/src/java/com/googlecode/webdriver/By.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package com.googlecode.webdriver;

import java.util.List;

import com.googlecode.webdriver.internal.FindsByClassName;
import com.googlecode.webdriver.internal.FindsById;
import com.googlecode.webdriver.internal.FindsByLinkText;
import com.googlecode.webdriver.internal.FindsByName;
import com.googlecode.webdriver.internal.FindsByXPath;

import java.util.List;

/**
* Mechanism used to locate elements within a document. In order to create
* your own locating mechanisms, it is possible to subclass this class and
Expand Down Expand Up @@ -115,6 +116,45 @@ public String toString() {
};
}

public static By className(final String className) {
if (className == null)
throw new IllegalArgumentException("Cannot find elements when the class name expression is null.");

return new By() {
@Override
public List<WebElement> findElements(SearchContext context) {
if (context instanceof FindsByClassName)
return ((FindsByClassName) context).findElementsByClassName(className);
return ((FindsByXPath) context).findElementsByXPath("//*[" + containingWord("class", className) + "]");
}

@Override
public WebElement findElement(SearchContext context) {
if (context instanceof FindsByClassName)
return ((FindsByClassName) context).findElementByClassName(className);
return ((FindsByXPath) context).findElementByXPath("//*[" + containingWord("class", className) + "]");
}

/**
* Generates a partial xpath expression that matches an element whose specified attribute
* contains the given CSS word. So to match &lt;div class='foo bar'&gt; you would
* say "//div[" + containingWord("class", "foo") + "]".
*
* @param attribute name
* @param word name
* @return XPath fragment
*/
private String containingWord(String attribute, String word) {
return "contains(concat(' ',normalize-space(@" + attribute + "),' '),' " + word + " ')";
}

@Override
public String toString() {
return "By.className: " + className;
}
};
}

/**
* Find a single element. Override this method if necessary.
* @param context A context to use to find the element
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.googlecode.webdriver.internal;

import java.util.List;

import com.googlecode.webdriver.WebElement;

public interface FindsByClassName {
WebElement findElementByClassName(String using);
List<WebElement> findElementsByClassName(String using);
}
6 changes: 5 additions & 1 deletion common/src/web/xhtmlTest.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ <h1 class="header">XHTML Might Be The Future</h1>
</form>
</div>

<div class="extraDiv">Another div starts here.<p/>
<h2 class="nameA nameBnoise nameC">An H2 title</h2>
</div>

<div>
<a id="id1" href="#">Foo</a>
<ul id="id2" />
Expand All @@ -34,4 +38,4 @@ <h1 class="header">XHTML Might Be The Future</h1>
<p id="empty"></p>
<p id="self-closed" />
</body>
</html>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,4 @@ public void testfindElementsByLinkText() {
By.linkText("hello world"));
assertThat(children.size(), is(2));
}

}
39 changes: 39 additions & 0 deletions common/test/java/com/googlecode/webdriver/ElementFindingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,45 @@ public void testShouldFindElementsByName() {
assertThat(element.getValue(), is("furrfu"));
}

public void testShouldFindElementsByClass() {
driver.get(xhtmlTestPage);

WebElement element = driver.findElement(By.className("extraDiv"));
assertTrue(element.getText().startsWith("Another div starts here."));
}

public void testShouldFindElementsByClassWhenItIsTheFirstNameAmongMany() {
driver.get(xhtmlTestPage);

WebElement element = driver.findElement(By.className("nameA"));
assertThat(element.getText(), equalTo("An H2 title"));
}

public void testShouldFindElementsByClassWhenItIsTheLastNameAmongMany() {
driver.get(xhtmlTestPage);

WebElement element = driver.findElement(By.className("nameC"));
assertThat(element.getText(), equalTo("An H2 title"));
}

public void testShouldFindElementsByClassWhenItIsInTheMiddleAmongMany() {
driver.get(xhtmlTestPage);

WebElement element = driver.findElement(By.className("nameBnoise"));
assertThat(element.getText(), equalTo("An H2 title"));
}

public void testShouldNotFindElementsByClassWhenTheNameQueriedIsShorterThanCandidateName() {
driver.get(xhtmlTestPage);

try {
driver.findElement(By.className("nameB"));
fail("Should not have succeeded");
} catch (NoSuchElementException e) {
// this is expected
}
}

// You don't want to ask why this is here
public void testWhenFindingByNameShouldNotReturnById() {
driver.get(formPage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ public static Test suite() {
.usingDriver(IE)
.keepDriverInstance()
.includeJavascriptTests()
.onlyRun("RenderedWebElementTest")
// .method("testShouldReturnTheValueOfTheDisabledAttrbuteEvenIfItIsMissing")
// .leaveRunningAfterTest()
.onlyRun("ElementAttributeTest")
.method("testShouldReturnValueOfClassAttributeOfAnElement")
// .method("testShouldFindElementsByClass")
// .leaveRunningAfterTest()
.create();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void testShouldFindSingleElementByXPath() {
public void testShouldFindElementsByXPath() {
driver.get(xhtmlTestPage);
List<WebElement> divs = driver.findElements(By.xpath("//div"));
assertThat(divs.size(), equalTo(3));
assertThat(divs.size(), equalTo(4));
}

@Ignore(value = "safari", reason = "Test fails")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ public List<WebElement> findElementsByXPath(String using) {
return elements;
}

public List<WebElement> findElementsByClassName(String using) {
throw new UnsupportedOperationException("findElementsByClassName");
}

public WebElement findElementByLinkText(String using) {
return findElement("selectElementUsingLink", using);
}
Expand All @@ -203,6 +207,10 @@ public WebElement findElementByXPath(String using) {
return findElement("selectElementUsingXPath", using);
}

public WebElement findElementByClassName(String using) {
throw new UnsupportedOperationException("findElementByClassName");
}

private WebElement findElement(String commandName, String argument) {
String elementId = sendMessage(NoSuchElementException.class, commandName, argument);

Expand Down
46 changes: 46 additions & 0 deletions jobbie/src/cpp/InternetExplorerDriver/InternetExplorerDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,52 @@ ElementWrapper* InternetExplorerDriver::selectElementByName(const wchar_t *eleme
throw "Cannot find element";
}

ElementWrapper* InternetExplorerDriver::selectElementByClassName(const wchar_t *elementClassName)
{
CComPtr<IHTMLDocument2> doc2;
getDocument(&doc2);

CComPtr<IHTMLElementCollection> allNodes;
doc2->get_all(&allNodes);

CComPtr<IUnknown> unknown;
allNodes->get__newEnum(&unknown);
CComQIPtr<IEnumVARIANT> enumerator(unknown);

CComVariant var;
CComBSTR nameRead;
enumerator->Next(1, &var, NULL);

const int exactLength = (int) wcslen(elementClassName);
wchar_t *next_token, seps[] = L" ";

for (CComPtr<IDispatch> disp;
disp = V_DISPATCH(&var);
enumerator->Next(1, &var, NULL))
{ // We are iterating through all the DOM elements
CComQIPtr<IHTMLElement> curr(disp);
if (!curr) continue;

curr->get_className(&nameRead);
if(!nameRead) continue;

for ( wchar_t *token = wcstok_s(nameRead, seps, &next_token);
token;
token = wcstok_s( NULL, seps, &next_token) )
{
int lengthRead = next_token - token;
if(*next_token!=NULL) lengthRead--;
if(exactLength != lengthRead) continue;
if(0!=wcscmp(elementClassName, token)) continue;
// Woohoo, we found it
CComQIPtr<IHTMLDOMNode> node(curr);
return new ElementWrapper(this, node);
}
}

throw "Cannot find element by ClassName";
}

void InternetExplorerDriver::waitForNavigateToFinish()
{
VARIANT_BOOL busy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class InternetExplorerDriver
ElementWrapper* selectElementById(const wchar_t *elementId);
ElementWrapper* selectElementByLink(const wchar_t *elementLink);
ElementWrapper* selectElementByName(const wchar_t *elementName);
ElementWrapper* selectElementByClassName(const wchar_t *elementClassName);
void getDocument(IHTMLDocument2 **pdoc);

void waitForNavigateToFinish();
Expand Down Expand Up @@ -77,4 +78,4 @@ class IeEventSink : public IDispatch
DWORD eventSinkCookie;
};

#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@ JNIEXPORT jobject JNICALL Java_com_googlecode_webdriver_ie_InternetExplorerDrive
}
}

JNIEXPORT jobject JNICALL Java_com_googlecode_webdriver_ie_InternetExplorerDriver_selectElementByClassName
(JNIEnv *env, jobject obj, jstring name)
{
InternetExplorerDriver* ie = getIe(env, obj);
const wchar_t* converted = (const wchar_t*)env->GetStringChars(name, 0);

try {
ElementWrapper* wrapper = ie->selectElementByClassName(converted);
env->ReleaseStringChars(name, (jchar*) converted);

jclass clazz = env->FindClass("com/googlecode/webdriver/ie/InternetExplorerElement");
jmethodID cId = env->GetMethodID(clazz, "<init>", "(J)V");

return env->NewObject(clazz, cId, (jlong) wrapper);
} catch (const char *message) {
env->ReleaseStringChars(name, (jchar*) converted);
throwNoSuchElementException(env, message);
return NULL;
}
}

JNIEXPORT jobject JNICALL Java_com_googlecode_webdriver_ie_InternetExplorerDriver_getDocument
(JNIEnv *env, jobject obj)
Expand Down Expand Up @@ -216,4 +236,4 @@ JNIEXPORT jstring JNICALL Java_com_googlecode_webdriver_ie_InternetExplorerDrive

#ifdef __cplusplus
}
#endif
#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@
import com.googlecode.webdriver.Speed;
import com.googlecode.webdriver.WebDriver;
import com.googlecode.webdriver.WebElement;
import com.googlecode.webdriver.internal.FindsByClassName;
import com.googlecode.webdriver.internal.FindsById;
import com.googlecode.webdriver.internal.FindsByLinkText;
import com.googlecode.webdriver.internal.FindsByName;
import com.googlecode.webdriver.internal.FindsByXPath;
import com.googlecode.webdriver.internal.ReturnedCookie;

public class InternetExplorerDriver implements WebDriver, FindsById,
FindsByLinkText, FindsByName, FindsByXPath, SearchContext {
public class InternetExplorerDriver implements WebDriver, SearchContext,
FindsById, FindsByClassName, FindsByLinkText, FindsByName, FindsByXPath {
private long iePointer; // Used by the native code to keep track of the IE instance
private static boolean comStarted;

Expand Down Expand Up @@ -101,6 +102,16 @@ public WebElement findElementByName(String using) {
public List<WebElement> findElementsByName(String using) {
return selectElementsByName(using);
}

public WebElement findElementByClassName(String using) {
return selectElementByClassName(using);
}
private native WebElement selectElementByClassName(String using);

public List<WebElement> findElementsByClassName(String using) {
return selectElementsByClassName(using);
}
private native List<WebElement> selectElementsByClassName(String using);

public WebElement findElementByXPath(String using) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ public List<WebElement> findElementsByXPath(String using) {
return toReturn;
}

public List<WebElement> findElementsByClassName(String using) {
throw new UnsupportedOperationException("findElementsByClassName");
}

public WebElement findElementByClassName(String using) {
throw new UnsupportedOperationException("findElementByClassName");
}

private String addToElements() {
return "if (element) { " +
" if (!" + ELEMENTS + ")\r" +
Expand Down

0 comments on commit 4846167

Please sign in to comment.