http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/0e704f9b/mustella/src/main/java/marmotinni/SetProperty.java ---------------------------------------------------------------------- diff --git a/mustella/src/main/java/marmotinni/SetProperty.java b/mustella/src/main/java/marmotinni/SetProperty.java new file mode 100644 index 0000000..b05c419 --- /dev/null +++ b/mustella/src/main/java/marmotinni/SetProperty.java @@ -0,0 +1,119 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package marmotinni; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import org.xml.sax.Attributes; + +/** + * SetProperty + * + * Set a property + */ +public class SetProperty extends TestStep { + + public SetProperty () { + } + + /** + * Set the target's property to the specified value + */ + @Override + protected void doStep() + { + String valueString = null; + if (valueExpression != null) + valueString = ((JavascriptExecutor)webDriver).executeScript(valueExpression).toString(); + else if (value != null) + { + if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("true")) + valueString = value; + else { + try { + Double.parseDouble(value); + valueString = value; + } + catch (Exception e) { + valueString = "'" + value + "'"; + } + } + } + else + valueString = "null"; + + StringBuilder setScript = new StringBuilder(); + insertTargetScript(setScript, target); + setScript.append("if (typeof(target['set_' + '" + propertyName + "']) == 'function') target['set_' + '" + propertyName + "'](" + valueString + ");"); + setScript.append(" else target['" + propertyName + "']=" + valueString + ";"); + if (TestStep.showScripts) + System.out.println(setScript.toString()); + ((JavascriptExecutor)webDriver).executeScript(setScript.toString()); + } + + /** + * The object to set a property on + */ + public String target; + + /** + * The name of the property to set + */ + public String propertyName; + + /** + * The value to set + */ + public String value; + + /** + * The value to set + */ + public String valueExpression; + + /** + * customize string representation + */ + @Override + public String toString() + { + String s = "SetProperty"; + if (target != null) + s += ": target = " + target.toString(); + if (propertyName != null) + s += ": propertyName = " + propertyName.toString(); + if (value != null) + s += ": value = " + value; + return s; + } + + @Override + public void populateFromAttributes(Attributes attributes) + { + target = attributes.getValue("target"); + propertyName = attributes.getValue("propertyName"); + value = attributes.getValue("value"); + valueExpression = attributes.getValue("valueExpression"); + } + +}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/0e704f9b/mustella/src/main/java/marmotinni/TestCase.java ---------------------------------------------------------------------- diff --git a/mustella/src/main/java/marmotinni/TestCase.java b/mustella/src/main/java/marmotinni/TestCase.java new file mode 100644 index 0000000..06e0e80 --- /dev/null +++ b/mustella/src/main/java/marmotinni/TestCase.java @@ -0,0 +1,293 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package marmotinni; + +import java.util.List; +import java.util.ArrayList; +import java.util.Date; + +import org.openqa.selenium.WebDriver; + +import org.xml.sax.Attributes; + +/** + * TestCase + * + * A set of TestSteps. + */ +public class TestCase { + + public static boolean showSteps = false; + + /** + * The history of bugs that this test case has encountered + */ + public List<String> bugs; + + /** + * The sequence of TestSteps that comprise the test setup + */ + public List<TestStep> setup; + + /** + * The sequence of TestSteps that comprise the test + */ + public List<TestStep> body; + + /** + * The sequence of TestSteps that restore the test environment + */ + public List<TestStep> cleanup; + + /** + * An identifier for the test + */ + public String testID; + + /** + * A description of the test + */ + public String description; + + /** + * keywords, summarizing the tests + */ + public String keywords; + + /** + * frequency, an estimate of the tests's intersection with real-world + * usage. 1 = most frequent usage; 2 somewhat common; 3 = unusual + */ + public String frequency; + + /** + * The current set of steps (setup, body, cleanup) we are executing + */ + private List<TestStep> currentSteps; + + /** + * Which step we're currently executing (or waiting on an event for) + */ + private int currentIndex = 0; + + /** + * Number of steps in currentSteps + */ + private int numSteps = 0; + + /** + * Storage for the cleanupAsserts + */ + private List<AssertStep> cleanupAsserts; + + /** + * Steps we have to review at the end of the body to see if + * they failed or not. These steps monitor activity like + * checking for duplicate events or making sure unwanted events + * don't fire. + */ + public List<AssertStep> getCleanupAsserts() + { + return cleanupAsserts; + } + + /** + * Storage for this tests's result + */ + private TestResult testResult; + + /** + * This tests's result + */ + public TestResult getTestResult() + { + testResult.testID = testID; + return testResult; + } + + /** + * Constructor. Create the TestResult associated with this TestCase + */ + public TestCase() { + + testResult = new TestResult(); + testResult.testID = testID; + + cleanupAsserts = new ArrayList<AssertStep>(); + } + + /** + * Called when it is time to execute + * this test case. + * + */ + public boolean runTest(WebDriver webDriver) + { + testResult.beginTime = new Date().getTime(); + + return runSetup(webDriver); + } + + /** + * Execute the setup portion of the test + */ + private boolean runSetup(WebDriver webDriver) + { + if (!testResult.hasStatus()) + { + if (setup != null) + { + testResult.phase = TestResult.SETUP; + currentIndex = 0; + currentSteps = setup; + numSteps = setup.size(); + // return if we need to wait for something + if (!runSteps(webDriver)) + return false; + + } + } + return runBody(webDriver); + } + + /** + * Execute the body portion of the test + */ + private boolean runBody(WebDriver webDriver) + { + if (!testResult.hasStatus()) + { + if (body != null) + { + testResult.phase = TestResult.BODY; + currentIndex = 0; + currentSteps = body; + numSteps = body.size(); + // return if we need to wait for something + if (!runSteps(webDriver)) + return false; + + } + } + return runCleanup(webDriver); + } + + /** + * Execute the cleanup portion of the test + */ + private boolean runCleanup(WebDriver webDriver) + { + if (!testResult.hasStatus()) + { + if (cleanup != null) + { + testResult.phase = TestResult.CLEANUP; + currentIndex = 0; + currentSteps = cleanup; + numSteps = cleanup.size(); + // return if we need to wait for something + if (!runSteps(webDriver)) + return false; + + } + } + return runComplete(); + } + + /** + * Clean up when all three phases are done. Sends an event + * to the UnitTester harness to tell it that it can run + * the next test case. + */ + private boolean runComplete() + { + int n = cleanupAsserts.size(); + for (int i = 0; i < n; i++) + { + AssertStep asrt = cleanupAsserts.get(i); + asrt.cleanup(); + } + testResult.endTime = new Date().getTime(); + return true; + } + + /** + * Go through the currentSteps, executing each one. + * Returns true if no test steps required waiting. + * Returns false if we have to wait for an event before + * continuing. + */ + private boolean runSteps(WebDriver webDriver) + { + while (currentIndex < numSteps) + { + // return if a step failed + if (testResult.hasStatus()) + return true; + + TestStep step = currentSteps.get(currentIndex); + if (!(step instanceof AssertStep)) + { + // look at subsequent steps for Asserts and set them up early + for (int j = currentIndex + 1; j < numSteps; j++) + { + // scan following asserts for AssertEvents and set them up early + TestStep nextStep = currentSteps.get(j); + if (nextStep instanceof AssertStep) + { + ((AssertStep)nextStep).preview(webDriver, this, testResult); + /* TODO: (aharui) re-enable when we need these asserts + // do a check to be sure folks are using AssertEventPropertyValue correctly + if (nextStep instanceof AssertEventPropertyValue) + { + // AEPV must follow an AssertEvent or another AEPV + if (j == 0 || !(currentSteps[j-1] instanceof AssertEvent || currentSteps[j-1] instanceof AssertEventPropertyValue)) + TestOutput.logResult("WARNING: AssertEventPropertyValue may be missing preceding AssertEvent"); + } + else if (nextStep instanceof AssertError) + { + if (step instanceof SetProperty) + SetProperty(step).expectError = true; + } + */ + } + else + break; + } + } + if (TestCase.showSteps) + System.out.println(step.toString()); + step.execute(webDriver, this, testResult); + currentIndex++; + } + return true; + } + + public void populateFromAttributes(Attributes attributes) + { + description = attributes.getValue("description"); + testID = attributes.getValue("testID"); + keywords = attributes.getValue("keywords"); + frequency = attributes.getValue("frequency"); + + } + +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/0e704f9b/mustella/src/main/java/marmotinni/TestOutput.java ---------------------------------------------------------------------- diff --git a/mustella/src/main/java/marmotinni/TestOutput.java b/mustella/src/main/java/marmotinni/TestOutput.java new file mode 100644 index 0000000..4b63f10 --- /dev/null +++ b/mustella/src/main/java/marmotinni/TestOutput.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package marmotinni; + +/** + * The class that collects TestResults for a TestCase + */ +public class TestOutput +{ + + /** + * get printable version of phase + */ + public static void logResult(String message) { + System.out.println(message); + } + +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/0e704f9b/mustella/src/main/java/marmotinni/TestResult.java ---------------------------------------------------------------------- diff --git a/mustella/src/main/java/marmotinni/TestResult.java b/mustella/src/main/java/marmotinni/TestResult.java new file mode 100644 index 0000000..1d64bae --- /dev/null +++ b/mustella/src/main/java/marmotinni/TestResult.java @@ -0,0 +1,151 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package marmotinni; + +import java.util.Date; + +/** + * The class that collects TestResults for a TestCase + */ +public class TestResult +{ + + public static final int PASS = 0; + public static final int FAIL = 1; + public static final int ERROR = 2; + + public static final int SETUP = 0; + public static final int BODY = 1; + public static final int CLEANUP = 2; + + /** + * testID + */ + public String testID; + + /** + * begin time + */ + public long beginTime; + + /** + * end time + */ + public long endTime; + + /** + * result + */ + public int result = -1; // "pass", "fail", "error" + + /** + * message. Failures often have messages + */ + public String message = ""; + + /** + * extraInfo: failures may have a file associated + */ + public String extraInfo = ""; + + /** + * Name of the Script associated with this result + */ + public String scriptName = ""; + + /** + * phase. how far the test finished. setup, body, cleanup + */ + public int phase = -1; + + /** + * get printable version of phase + */ + public static String getPhaseString(int val) { + if (val == CLEANUP) { + return "cleanup"; + }else if (val == BODY) { + return "body"; + }else if (val == SETUP) { + return "setup"; + + } + return "no phase set"; + } + + /** + * get printable version of result + */ + public static String getResultString(int val) { + if (val == PASS) { + return "pass"; + }else if (val == FAIL) { + return "fail"; + }else if (val == ERROR) { + return "error"; + } + return null; + } + + + /** + * default output look + */ + public String toString() + { + return "RESULT: scriptName=" + scriptName + " id=" + testID + " result=" + getResultString(result) + " elapsed=" + (endTime-beginTime) + " phase=" + getPhaseString(phase) + " started=" + beginTime + " extraInfo=" + extraInfo + " msg=" + message ; + } + + + public boolean hasStatus() { + return (result != -1); + } + + + public void doFail (String msg) { + doFail(msg, null, null, 0); + } + + public void doFail (String msg, String extraInfo) { + doFail(msg, extraInfo, null, 0); + } + + public void doFail (String msg, String extraInfo, TestStep lastStep, int lastStepLine) { + // first failure is the one we keep + if (this.result != FAIL) + { + this.result = FAIL; + // this.message = msg; + if (lastStep != null) + { + String tmp = lastStep.toString().substring(0, lastStep.toString().indexOf (":")) + "(" + getPhaseString(phase) + ":step " + (lastStepLine + 1) + ") "; + this.message = tmp + " " + msg; + } + else + { + this.message = msg; + } + this.extraInfo = extraInfo; + } + } + + +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/0e704f9b/mustella/src/main/java/marmotinni/TestStep.java ---------------------------------------------------------------------- diff --git a/mustella/src/main/java/marmotinni/TestStep.java b/mustella/src/main/java/marmotinni/TestStep.java new file mode 100644 index 0000000..23eb1b3 --- /dev/null +++ b/mustella/src/main/java/marmotinni/TestStep.java @@ -0,0 +1,124 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package marmotinni; + +import org.openqa.selenium.WebDriver; + +import org.xml.sax.Attributes; + +/** + * TestStep + * + * Base class for test steps like DispatchMouseEvent and AssertPropertyValue, etc. + */ +public class TestStep { + + public static boolean showScripts = false; + + public TestStep () { + } + + public boolean execute(WebDriver webDriver, TestCase testCase, TestResult testResult) + { + this.webDriver = webDriver; + this.testCase = testCase; + this.testResult = testResult; + + doStep(); + + // if test failed, don't bother waiting, just bail + if (testResult.hasStatus()) + { + if (waitEvent != null) + { + /* TODO: figure out how to wait */ + } + } + + return true; + } + + /** + * The name of the object to listen for an event we're waiting on + */ + public String waitTarget; + + /** + * The name of the event to listen for on the waitTarget + */ + public String waitEvent; + + /** + * The number of milliseconds to wait before giving up + */ + public int timeout = 3000; + + /** + * The TestResult for this TestCase + */ + protected TestResult testResult; + + /** + * The TestCase that this step belongs to + */ + protected TestCase testCase; + + /** + * The WebDriver for this session + */ + protected WebDriver webDriver; + + /** + * The method that gets called when it is time to perform the work in the step. + */ + protected void doStep() + { + } + + public void populateFromAttributes(Attributes attributes) throws Exception + { + waitTarget = attributes.getValue("waitTarget"); + waitEvent = attributes.getValue("waitEvent"); + } + + protected void insertTargetScript(StringBuilder sb, String target) + { + sb.append("var target = document.getElementsByTagName('body')[0];"); + sb.append("target = target.flexjs_wrapper;"); + sb.append("target = target.initialView;"); + if (target == null || target.length() == 0) + { + return; + } + String parts[] = target.split("\\."); + int n = parts.length; + for (int i = 0; i < n; i++) + { + sb.append("target = target['" + parts[i] + "'];"); + } + + } + + public String toString() + { + return ""; + } +}