Skip to content

Commit b1d30a5

Browse files
committed
Wrap each Core test step with a decorator
1 parent 0982021 commit b1d30a5

File tree

6 files changed

+193
-65
lines changed

6 files changed

+193
-65
lines changed

java/server/src/org/openqa/selenium/server/htmlrunner/CoreStep.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
import com.thoughtworks.selenium.Selenium;
2121

2222
public interface CoreStep {
23-
Object execute(Selenium selenium);
23+
NextStepDecorator execute(Selenium selenium);
2424
}

java/server/src/org/openqa/selenium/server/htmlrunner/CoreStepFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
import java.util.List;
2222

2323
interface CoreStepFactory {
24-
CoreStep create(Iterator<List<String>> remainingSteps, String locator, String value);
24+
CoreStep create(String locator, String value);
2525
}

java/server/src/org/openqa/selenium/server/htmlrunner/CoreTestCase.java

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@
2828
import org.openqa.selenium.JavascriptExecutor;
2929
import org.openqa.selenium.WebDriver;
3030

31+
import java.util.ArrayList;
3132
import java.util.Iterator;
3233
import java.util.List;
34+
import java.util.logging.Logger;
3335

3436
public class CoreTestCase {
3537

38+
private static final Logger LOG = Logger.getLogger(CoreTestCase.class.getName());
39+
3640
private static final ImmutableMap<String, CoreStepFactory> STEP_FACTORY =
3741
ImmutableMap.<String, CoreStepFactory>builder()
3842
.putAll(new ReflectivelyDiscoveredSteps().get())
@@ -50,18 +54,20 @@ public void run(Results results, WebDriver driver, Selenium selenium) {
5054
driver.get(url);
5155
}
5256

53-
List<CoreStep> steps = findCommands(driver);
54-
for (CoreStep step : steps) {
55-
try {
56-
step.execute(selenium);
57-
} catch (SeleniumException e) {
58-
results.addTestFailure();
59-
return;
57+
List<LoggableStep> steps = findCommands(driver);
58+
List<StepResult> testResults = new ArrayList<>(steps.size());
59+
NextStepDecorator decorator = NextStepDecorator.IDENTITY;
60+
for (LoggableStep step : steps) {
61+
LOG.info(step.toString());
62+
decorator = Preconditions.checkNotNull(decorator.evaluate(step, selenium), step);
63+
testResults.add(new StepResult(step, null));
64+
if (!decorator.isOkayToContinueTest()) {
65+
break;
6066
}
6167
}
6268
}
6369

64-
private List<CoreStep> findCommands(WebDriver driver) {
70+
private List<LoggableStep> findCommands(WebDriver driver) {
6571
// Let's just run and hide in the horror that is JS for the sake of speed.
6672
List<List<String>> rawSteps = (List<List<String>>) ((JavascriptExecutor) driver).executeScript(
6773
"var toReturn = [];\n" +
@@ -77,15 +83,65 @@ private List<CoreStep> findCommands(WebDriver driver) {
7783
"}\n" +
7884
"return toReturn;");
7985

80-
ImmutableList.Builder<CoreStep> steps = ImmutableList.builder();
86+
ImmutableList.Builder<LoggableStep> steps = ImmutableList.builder();
8187
Iterator<List<String>> stepIterator = rawSteps.iterator();
8288
while (stepIterator.hasNext()) {
8389
List<String> step = stepIterator.next();
8490
if (!STEP_FACTORY.containsKey(step.get(0))) {
8591
throw new SeleniumException("Unknown command: " + step.get(0));
8692
}
87-
steps.add(STEP_FACTORY.get(step.get(0)).create(stepIterator, step.get(1), step.get(2)));
93+
steps.add(new LoggableStep(
94+
STEP_FACTORY.get(step.get(0)).create(step.get(1), step.get(2)),
95+
step.get(0),
96+
step.get(1),
97+
step.get(2)));
8898
}
8999
return steps.build();
90100
}
101+
102+
private static class LoggableStep implements CoreStep {
103+
private final CoreStep actualStep;
104+
private final String command;
105+
private final String locator;
106+
private final String value;
107+
108+
public LoggableStep(CoreStep toWrap, String command, String locator, String value) {
109+
this.actualStep = toWrap;
110+
this.command = command;
111+
this.locator = locator;
112+
this.value = value;
113+
}
114+
115+
@Override
116+
public NextStepDecorator execute(Selenium selenium) {
117+
return actualStep.execute(selenium);
118+
}
119+
120+
@Override
121+
public String toString() {
122+
return String.format("|%s | %s | %s |", command, locator, value);
123+
}
124+
}
125+
126+
private static class StepResult {
127+
private final LoggableStep step;
128+
private final Throwable cause;
129+
130+
public StepResult(LoggableStep step, Throwable cause) {
131+
this.step = Preconditions.checkNotNull(step);
132+
this.cause = cause;
133+
}
134+
135+
public boolean isSuccessful() {
136+
return cause == null;
137+
}
138+
139+
public boolean isError() {
140+
return cause instanceof SeleniumException;
141+
}
142+
143+
public boolean isFailure() {
144+
return !isSuccessful() && !isError();
145+
}
146+
}
91147
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.server.htmlrunner;
19+
20+
21+
import com.thoughtworks.selenium.Selenium;
22+
23+
abstract class NextStepDecorator {
24+
25+
static NextStepDecorator IDENTITY = new NextStepDecorator() {
26+
27+
@Override
28+
public boolean isOkayToContinueTest() {
29+
return true;
30+
}
31+
};
32+
33+
static NextStepDecorator ASSERTION_FAILED = new NextStepDecorator() {
34+
35+
@Override
36+
public boolean isOkayToContinueTest() {
37+
return false;
38+
}
39+
};
40+
41+
static NextStepDecorator VERIFICATION_FAILED = new NextStepDecorator() {
42+
43+
@Override
44+
public boolean isOkayToContinueTest() {
45+
return true;
46+
}
47+
};
48+
49+
public abstract boolean isOkayToContinueTest();
50+
51+
public NextStepDecorator evaluate(CoreStep nextStep, Selenium selenium) {
52+
return nextStep.execute(selenium);
53+
}
54+
55+
public static NextStepDecorator ERROR(Throwable cause) {
56+
return new NextStepDecorator() {
57+
@Override
58+
public boolean isOkayToContinueTest() {
59+
return false;
60+
}
61+
};
62+
}
63+
}

java/server/src/org/openqa/selenium/server/htmlrunner/NonReflectiveSteps.java

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,14 @@
2121
import com.google.common.base.Supplier;
2222
import com.google.common.base.Suppliers;
2323
import com.google.common.collect.ImmutableMap;
24-
import com.google.common.primitives.Booleans;
2524

26-
import com.thoughtworks.selenium.SeleneseTestBase;
25+
import com.thoughtworks.selenium.Selenium;
2726
import com.thoughtworks.selenium.SeleniumException;
2827

29-
import java.util.List;
3028
import java.util.logging.Logger;
3129

3230
class NonReflectiveSteps {
3331
private static final Logger LOG = Logger.getLogger("Selenium Core Step");
34-
private static final ImmutableMap<String, CoreStepFactory> wrappableSteps =
35-
new ReflectivelyDiscoveredSteps().get();
3632

3733
private static Supplier<ImmutableMap<String, CoreStepFactory>> STEPS =
3834
Suppliers.memoize(() -> build());
@@ -44,49 +40,47 @@ public ImmutableMap<String, CoreStepFactory> get() {
4440
private static ImmutableMap<String, CoreStepFactory> build() {
4541
ImmutableMap.Builder<String, CoreStepFactory> steps = ImmutableMap.builder();
4642

47-
CoreStepFactory nextCommandFails = (remainingSteps, locator, value) -> {
48-
if (!remainingSteps.hasNext()) {
49-
throw new SeleniumException("Next command not present. Unable to assert failure");
50-
}
51-
List<String> toWrap = remainingSteps.next();
52-
if (!wrappableSteps.containsKey(toWrap.get(0))) {
53-
throw new SeleniumException("Unable to wrap: " + toWrap.get(0));
54-
}
55-
56-
return (selenium -> {
57-
Object result;
58-
59-
try {
60-
result = wrappableSteps.get(toWrap.get(0)).create(null, locator, value).execute(selenium);
61-
} catch (SeleniumException e) {
62-
result = e.getMessage();
63-
}
64-
65-
SeleneseTestBase.assertEquals(value, String.valueOf(result));
66-
return null;
67-
});
68-
};
69-
// Not ideal, but it'll help us move things forward
43+
CoreStepFactory nextCommandFails = (locator, value) -> (selenium) -> new NextCommandFails();
7044
steps.put("assertErrorOnNext", nextCommandFails);
7145
steps.put("assertFailureOnNext", nextCommandFails);
7246

73-
steps.put("echo", ((remainingSteps, locator, value) -> (selenium) -> {
47+
steps.put("echo", ((locator, value) -> (selenium) -> {
7448
LOG.info(locator);
75-
return null;
49+
return NextStepDecorator.IDENTITY;
7650
}));
7751

78-
steps.put("pause", ((remainingSteps, locator, value) -> (selenium) -> {
52+
steps.put("pause", ((locator, value) -> (selenium) -> {
7953
try {
8054
long timeout = Long.parseLong(locator);
8155
Thread.sleep(timeout);
82-
return null;
56+
return NextStepDecorator.IDENTITY;
8357
} catch (NumberFormatException e) {
84-
throw new SeleniumException("Unable to parse timeout: " + locator);
58+
return NextStepDecorator.ERROR(
59+
new SeleniumException("Unable to parse timeout: " + locator));
8560
} catch (InterruptedException e) {
8661
System.exit(255);
8762
throw new CoreRunnerError("We never get this far");
8863
}
8964
}));
9065
return steps.build();
9166
}
67+
68+
private static class NextCommandFails extends NextStepDecorator {
69+
70+
@Override
71+
public NextStepDecorator evaluate(CoreStep nextStep, Selenium selenium) {
72+
NextStepDecorator actualResult = nextStep.execute(selenium);
73+
74+
// This is kind of fragile. Oh well.
75+
if (actualResult.equals(NextStepDecorator.IDENTITY)) {
76+
return NextStepDecorator.ASSERTION_FAILED;
77+
}
78+
return NextStepDecorator.IDENTITY;
79+
}
80+
81+
@Override
82+
public boolean isOkayToContinueTest() {
83+
return true;
84+
}
85+
}
9286
}

java/server/src/org/openqa/selenium/server/htmlrunner/ReflectivelyDiscoveredSteps.java

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ private static ImmutableMap<String, CoreStepFactory> discover() {
6868
continue;
6969
}
7070

71-
CoreStepFactory factory = ((remainingSteps, locator, value) -> (selenium) ->
71+
CoreStepFactory factory = ((locator, value) -> (selenium) ->
7272
invokeMethod(method, selenium, buildArgs(method, locator, value)));
7373

7474
factories.put(method.getName(), factory);
@@ -88,48 +88,62 @@ private static ImmutableMap<String, CoreStepFactory> discover() {
8888
if (shortName != null && method.getParameterCount() < 2) {
8989
String negatedName = negateName(shortName);
9090

91-
factories.put("assert" + shortName, ((remainingSteps, locator, value) -> (selenium) -> {
91+
factories.put("assert" + shortName, ((locator, value) -> (selenium) -> {
9292
Object seen = invokeMethod(method, selenium, buildArgs(method, locator, value));
9393
String expected = getExpectedValue(method, locator, value);
9494

95-
SeleneseTestBase.assertEquals(expected, seen);
96-
return null;
95+
try {
96+
SeleneseTestBase.assertEquals(expected, seen);
97+
return NextStepDecorator.IDENTITY;
98+
} catch (AssertionError e) {
99+
return NextStepDecorator.ASSERTION_FAILED;
100+
}
97101
}));
98102

99-
factories.put("assert" + negatedName, ((remainingSteps, locator, value) -> (selenium) -> {
103+
factories.put("assert" + negatedName, ((locator, value) -> (selenium) -> {
100104
Object seen = invokeMethod(method, selenium, buildArgs(method, locator, value));
101105
String expected = getExpectedValue(method, locator, value);
102106

103-
SeleneseTestBase.assertNotEquals(expected, seen);
104-
return null;
107+
try {
108+
SeleneseTestBase.assertNotEquals(expected, seen);
109+
return NextStepDecorator.IDENTITY;
110+
} catch (AssertionError e) {
111+
return NextStepDecorator.ASSERTION_FAILED;
112+
}
105113
}));
106114

107-
factories.put("verify" + shortName, ((remainingSteps, locator, value) -> (selenium) -> {
115+
factories.put("verify" + shortName, ((locator, value) -> (selenium) -> {
108116
Object seen = invokeMethod(method, selenium, buildArgs(method, locator, value));
109117
String expected = getExpectedValue(method, locator, value);
110118

111-
// TODO: Not this. Actual verification.
112-
SeleneseTestBase.assertEquals(expected, seen);
113-
return null;
119+
try {
120+
SeleneseTestBase.assertEquals(expected, seen);
121+
return NextStepDecorator.IDENTITY;
122+
} catch (AssertionError e) {
123+
return NextStepDecorator.VERIFICATION_FAILED;
124+
}
114125
}));
115126

116-
factories.put("verify" + negatedName, ((remainingSteps, locator, value) -> (selenium) -> {
127+
factories.put("verify" + negatedName, ((locator, value) -> (selenium) -> {
117128
Object seen = invokeMethod(method, selenium, buildArgs(method, locator, value));
118129
String expected = getExpectedValue(method, locator, value);
119130

120-
// TODO: Not this. Actual verification.
121-
SeleneseTestBase.assertNotEquals(expected, seen);
122-
return null;
131+
try {
132+
SeleneseTestBase.assertNotEquals(expected, seen);
133+
return NextStepDecorator.IDENTITY;
134+
} catch (AssertionError e) {
135+
return NextStepDecorator.VERIFICATION_FAILED;
136+
}
123137
}));
124138
}
125139

126140
factories.put(
127141
method.getName() + "AndWait",
128-
((remainingSteps, locator, value) -> (selenium -> {
142+
((locator, value) -> (selenium -> {
129143
Object result = invokeMethod(method, selenium, buildArgs(method, locator, value));
130144
// TODO: Hard coding this is obviously bogus
131145
selenium.waitForPageToLoad("30000");
132-
return result;
146+
return NextStepDecorator.IDENTITY;
133147
})));
134148
}
135149

@@ -176,13 +190,14 @@ private static String getExpectedValue(Method method, String locator, String val
176190
}
177191
}
178192

179-
private static Object invokeMethod(Method method, Selenium selenium, String[] args) {
193+
private static NextStepDecorator invokeMethod(Method method, Selenium selenium, String[] args) {
180194
try {
181-
return method.invoke(selenium, args);
195+
method.invoke(selenium, args);
196+
return NextStepDecorator.IDENTITY;
182197
} catch (ReflectiveOperationException e) {
183198
for (Throwable cause = e; cause != null; cause = cause.getCause()) {
184199
if (cause instanceof SeleniumException) {
185-
throw (SeleniumException) cause;
200+
return NextStepDecorator.ERROR(cause);
186201
}
187202
}
188203
throw new CoreRunnerError(

0 commit comments

Comments
 (0)