added tests so we can easily run QUnit tests in headless mode inside a stand alone JUnit test without Selenium; with just Rhino. JsArrayTest works great in Rhino stand alone and in a browser; but not Selenium; not sure why yet...

This commit is contained in:
James Strachan
2012-07-05 21:40:06 +01:00
parent 6e3346c019
commit 33ef414f01
16 changed files with 461 additions and 18 deletions
@@ -0,0 +1,38 @@
/**
*
* 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 org.jetbrains.k2js.test.rhino;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
/**
*/
public class CompositeRhinoResultsChecker implements RhinoResultChecker {
private final RhinoResultChecker[] children;
public CompositeRhinoResultsChecker(RhinoResultChecker... children) {
this.children = children;
}
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
for (RhinoResultChecker child : children) {
child.runChecks(context, scope);
}
}
}
@@ -30,11 +30,17 @@ import static org.junit.Assert.assertEquals;
*/
public class RhinoFunctionResultChecker implements RhinoResultChecker {
private final String moduleId;
private final String namespaceName;
private final String functionName;
private final Object expectedResult;
public RhinoFunctionResultChecker(@Nullable String namespaceName, String functionName, Object expectedResult) {
this(TestConfig.TEST_MODULE_NAME, namespaceName, functionName, expectedResult);
}
public RhinoFunctionResultChecker(@Nullable String moduleId, @Nullable String namespaceName, String functionName, Object expectedResult) {
this.moduleId = moduleId;
this.namespaceName = namespaceName;
this.functionName = functionName;
this.expectedResult = expectedResult;
@@ -62,10 +68,15 @@ public class RhinoFunctionResultChecker implements RhinoResultChecker {
return cx.evaluateString(scope, functionCallString(), "function call", 0, null);
}
private String functionCallString() {
protected String functionCallString() {
StringBuilder sb = new StringBuilder();
if (namespaceName != null) {
sb.append("Kotlin.modules." + TestConfig.TEST_MODULE_NAME);
sb.append("Kotlin.modules");
if (moduleId.contains(".")) {
sb.append("['").append(moduleId).append("']");
} else {
sb.append(".").append(moduleId);
}
if (namespaceName != Namer.getRootNamespaceName()) {
sb.append('.').append(namespaceName);
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed 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 org.jetbrains.k2js.test.rhino;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.k2js.test.config.TestConfig;
import org.jetbrains.k2js.translate.context.Namer;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.Scriptable;
import static org.jetbrains.k2js.test.rhino.RhinoUtils.flushSystemOut;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
* Runs the QUnit test cases in headless mode (without requiring a browser) and asserts they all PASS
*/
public class RhinoQUnitResultChecker implements RhinoResultChecker {
private final String moduleId;
public RhinoQUnitResultChecker(@Nullable String moduleId) {
this.moduleId = moduleId;
}
@Override
public void runChecks(Context context, Scriptable scope) throws Exception {
Object result = evaluateFunction(context, scope);
flushSystemOut(context, scope);
assertResultValid(result, context);
}
protected void assertResultValid(Object result, Context context) {
if (result instanceof NativeArray) {
NativeArray array = (NativeArray) result;
StringBuffer buffer = new StringBuffer();
for (int i = 0, size = array.size(); i < size; i++) {
Object value = array.get(i);
String text = value.toString();
System.out.println(text);
if (!text.startsWith("PASS")) {
if (buffer.length() > 0) {
buffer.append("\n");
}
buffer.append(text);
}
}
if (buffer.length() > 0) {
fail(buffer.toString());
}
} else {
fail("Uknown QUnit result: " + result);
}
}
private Object evaluateFunction(Context cx, Scriptable scope) {
return cx.evaluateString(scope, functionCallString(), "function call", 0, null);
}
protected String functionCallString() {
return "runQUnitSuite()";
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.k2js.test.rhino;
import closurecompiler.internal.com.google.common.collect.Maps;
import com.google.common.base.Supplier;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
@@ -30,6 +31,7 @@ import org.mozilla.javascript.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -102,9 +104,17 @@ public final class RhinoUtils {
@NotNull RhinoResultChecker checker,
@Nullable Map<String, Object> variables,
@NotNull EcmaVersion ecmaVersion) throws Exception {
runRhinoTest(fileNames, checker, variables, ecmaVersion, Collections.EMPTY_LIST);
}
public static void runRhinoTest(@NotNull List<String> fileNames,
@NotNull RhinoResultChecker checker,
@Nullable Map<String, Object> variables,
@NotNull EcmaVersion ecmaVersion,
@NotNull List<String> jsLibraries) throws Exception {
Context context = createContext(ecmaVersion);
try {
Scriptable scope = getScope(ecmaVersion, context);
Scriptable scope = getScope(ecmaVersion, context, jsLibraries);
putGlobalVariablesIntoScope(scope, variables);
for (String filename : fileNames) {
runFileWithRhino(filename, context, scope);
@@ -119,28 +129,34 @@ public final class RhinoUtils {
}
@NotNull
private static Scriptable getScope(@NotNull EcmaVersion version, @NotNull Context context) {
private static Scriptable getScope(@NotNull EcmaVersion version, @NotNull Context context,
@NotNull List<String> jsLibraries) {
ScriptableObject scope = context.initStandardObjects(null, false);
scope.setParentScope(getParentScope(version, context));
scope.setParentScope(getParentScope(version, context, jsLibraries));
return scope;
}
@NotNull
private static Scriptable getParentScope(@NotNull EcmaVersion version, @NotNull Context context) {
private static Scriptable getParentScope(@NotNull EcmaVersion version, @NotNull Context context,
@NotNull List<String> jsLibraries) {
Scriptable parentScope = versionToScope.get(version);
if (parentScope == null) {
parentScope = initScope(version, context);
parentScope = initScope(version, context, jsLibraries);
versionToScope.put(version, parentScope);
}
return parentScope;
}
@NotNull
private static Scriptable initScope(@NotNull EcmaVersion version, @NotNull Context context) {
ScriptableObject scope = context.initStandardObjects();
private static Scriptable initScope(@NotNull EcmaVersion version, @NotNull Context context,
@NotNull List<String> jsLibraries) {
ScriptableObject scope = context.initStandardObjects(null, false);
try {
runFileWithRhino(getKotlinLibFile(version), context, scope);
runFileWithRhino(KOTLIN_JS_LIB_COMMON, context, scope);
for (String jsLibrary : jsLibraries) {
runFileWithRhino(jsLibrary, context, scope);
}
}
catch (Exception e) {
throw rethrow(e);
@@ -41,9 +41,9 @@ import java.util.Set;
*/
public class CompileMavenGeneratedJSLibrary extends SingleFileTranslationTest {
private final String generatedJsDir = "libraries/tools/kotlin-js-library/target/";
private String generatedJsDefinitionsDir = generatedJsDir + "generated-js-definitions";
private File generatedJsLibraryDir = new File( generatedJsDir + "generated-js-library");
protected final String generatedJsDir = "libraries/tools/kotlin-js-library/target/";
protected String generatedJsDefinitionsDir = generatedJsDir + "generated-js-definitions";
protected File generatedJsLibraryDir = new File( generatedJsDir + "generated-js-library");
public CompileMavenGeneratedJSLibrary() {
super("kotlin-js-library/");
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed 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 org.jetbrains.k2js.test.semantics;
import closurecompiler.internal.com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.test.rhino.CompositeRhinoResultsChecker;
import org.jetbrains.k2js.test.rhino.RhinoFunctionResultChecker;
import org.jetbrains.k2js.test.rhino.RhinoQUnitResultChecker;
import org.jetbrains.k2js.test.rhino.RhinoResultChecker;
import java.io.File;
import java.util.EnumSet;
import java.util.Map;
import static org.jetbrains.k2js.test.rhino.RhinoUtils.runRhinoTest;
/**
*/
public class StdLibJsArrayQUnitTest extends StdLibQUnitTestSupport {
public void testDummy() {
}
// TODO for some reason this test fails when ran as part of all the js-backend tests, but works stand alone
// generates: ReferenceError: "QUnit" is not defined. (js/js.translator/testFiles/stdlib/out/ArrayQUnitTest.compiler_v3.js#3058)
// when ran in batch
public void DISABLED_testArrayQUnitTest() throws Exception {
//performStdLibTest(EcmaVersion.all(),
performStdLibTest(EnumSet.of(EcmaVersion.v3),
"libraries/stdlib/test",
"js/JsArrayTest.kt");
}
}
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed 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 org.jetbrains.k2js.test.semantics;
import closurecompiler.internal.com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.test.rhino.CompositeRhinoResultsChecker;
import org.jetbrains.k2js.test.rhino.RhinoFunctionResultChecker;
import org.jetbrains.k2js.test.rhino.RhinoResultChecker;
import java.io.File;
import java.util.EnumSet;
import java.util.Map;
import static org.jetbrains.k2js.test.rhino.RhinoUtils.runRhinoTest;
/**
*/
public class StdLibJsArrayScriptTest extends StdLibTestBase {
public void testArrayScriptTest() throws Exception {
//performStdLibTest(EcmaVersion.all(),
performStdLibTest(EnumSet.of(EcmaVersion.v3),
"libraries/stdlib/test",
"js/JsArrayScript.kt");
}
@Override
protected void performChecksOnGeneratedJavaScript(String path, EcmaVersion version) throws Exception {
Map<String, Object> variables = Maps.newHashMap();
String moduleId = moduleIdFromOutputFile(path);
RhinoResultChecker checker = new CompositeRhinoResultsChecker(
new RhinoFunctionResultChecker(moduleId, "jstest", "testSize", 3.0),
new RhinoFunctionResultChecker(moduleId, "jstest", "testToListToString", "[]-[foo]-[foo, bar]")
);
runRhinoTest(Lists.newArrayList(path), checker, variables, version);
/*
RhinoResultChecker checker = new RhinoFunctionResultChecker(moduleId, "jstest", "runTest", 2.0) {
@Override
protected String functionCallString() {
//return "QUnit.test('JsArrayTest.arraySizeAndToList', function(){ (new Kotlin.modules['" + moduleId + "'].jstest.JsArrayTest).arraySizeAndToList(); });";
return "(new Kotlin.modules['" + moduleId + "'].jstest.JsArrayTest).arraySizeAndToList();";
}
};
runRhinoTest(Lists.newArrayList(path),
checker, variables, version,
Lists.newArrayList("js/js.translator/qunit/qunit.js"));
*/
}
}
@@ -0,0 +1,54 @@
/**
*
* 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 org.jetbrains.k2js.test.semantics;
import closurecompiler.internal.com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.test.rhino.RhinoQUnitResultChecker;
import org.jetbrains.k2js.test.rhino.RhinoResultChecker;
import java.util.Map;
import static org.jetbrains.k2js.test.rhino.RhinoUtils.runRhinoTest;
/**
* A base class for any JS compile test cases which should run the generated JS file as a QUnit test case
*/
public abstract class StdLibQUnitTestSupport extends StdLibTestBase {
@Override
protected void performChecksOnGeneratedJavaScript(String path, EcmaVersion version) throws Exception {
runQUnitTestCase(path, version);
}
protected void runQUnitTestCase(String path, EcmaVersion version) throws Exception {
runQUnitTestCase(path, version, Maps.<String, Object>newHashMap());
}
protected void runQUnitTestCase(String path, EcmaVersion version, Map<String, Object> variables) throws Exception {
String moduleId = moduleIdFromOutputFile(path);
RhinoResultChecker checker = new RhinoQUnitResultChecker(moduleId);
runRhinoTest(Lists.newArrayList(path),
checker, variables, version,
Lists.newArrayList(
"js/js.translator/qunit/qunit.js",
"js/js.translator/qunit/headless.js"
));
}
}
@@ -46,14 +46,29 @@ abstract class StdLibTestBase extends SingleFileTranslationTest {
compileFiles(ecmaVersions, files);
}
private void compileFiles(@NotNull EnumSet<EcmaVersion> ecmaVersions, @NotNull List<String> files) {
private void compileFiles(@NotNull EnumSet<EcmaVersion> ecmaVersions, @NotNull List<String> files) throws Exception {
List<String> libFiles = createLibFilesList();
for (EcmaVersion version : ecmaVersions) {
String outputFilePath = getOutputFilePath(getTestName(false) + ".compiler.kt", version);
invokeCompiler(files, libFiles, version, outputFilePath);
performChecksOnGeneratedJavaScript(outputFilePath, version);
}
}
/**
* Strategy method allowing the generated JS file to be invoked
*/
protected void performChecksOnGeneratedJavaScript(String path, EcmaVersion version) throws Exception {
}
protected String moduleIdFromOutputFile(String path) {
String moduleId = new File(path).getName();
if (moduleId.endsWith(".js")) {
moduleId = moduleId.substring(0, moduleId.length() - 3);
}
return moduleId;
}
//TODO: reuse this in CompileMavenGeneratedJSLibrary
private static void invokeCompiler(@NotNull List<String> files, @NotNull List<String> libFiles,
@NotNull EcmaVersion version, @NotNull String outputFilePath) {
+28
View File
@@ -0,0 +1,28 @@
(function () {
QUnit.init();
QUnit.config.blocking = true;
QUnit.config.autorun = true;
QUnit.config.updateRate = 0;
QUnit.results = []
QUnit.log = function (log) {
var outcome = log.result ? "PASS" : "FAIL";
QUnit.results.push(outcome + log.message)
};
})();
function runQUnitSuite() {
QUnit.begin();
QUnit.start();
/*
var answer = ""
var results = QUnit.results;
for (var i = 0, size = results.length; i < size; i++) {
answer += results[i];
answer += "\n";
}
return answer
*/
return QUnit.results;
}
@@ -116,6 +116,9 @@ public abstract class Config {
"/kotlin/JLangIterables.kt",
"/kotlin/JLangIterablesLazy.kt",
"/kotlin/JLangIterablesSpecial.kt",
"/generated/ArraysFromJLangIterables.kt",
"/generated/ArraysFromJLangIterablesLazy.kt",
"/generated/ArraysFromJUtilCollections.kt",
"/generated/JUtilIteratorsFromJLangIterables.kt",
"/generated/JUtilIterablesFromJUtilCollections.kt",
"/kotlin/support/AbstractIterator.kt",
+17
View File
@@ -0,0 +1,17 @@
package jstest
fun testSize(): Int {
val a1 = array<String>()
val a2 = array("foo")
val a3 = array("foo", "bar")
return a1.size + a2.size + a3.size
}
fun testToListToString(): String {
val a1 = array<String>()
val a2 = array("foo")
val a3 = array("foo", "bar")
return a1.toList().toString() + "-" + a2.toList().toString() + "-" + a3.toList().toString()
}
+2 -2
View File
@@ -1,11 +1,11 @@
package testPackage
package jstest
import org.junit.Test as test
import kotlin.test.*
class JsArrayTest {
test fun arrays() {
test fun arraySizeAndToList() {
val a1 = array<String>()
val a2 = array("foo")
val a3 = array("foo", "bar")
@@ -0,0 +1,62 @@
/**
*
* 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 tests;
import org.jetbrains.kotlin.js.qunit.SeleniumQUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*/
@RunWith(Parameterized.class)
public class SeleniumFireFox extends SeleniumTest {
static {
driver = createFirefoxDriver();
tester = new SeleniumQUnit(driver);
}
public static FirefoxDriver createFirefoxDriver() {
FirefoxProfile profile = new FirefoxProfile();
FirefoxDriver answer = new FirefoxDriver(profile);
return answer;
}
public SeleniumFireFox(WebElement element) {
super(element);
}
/*
@Parameterized.Parameters
public static List<Object[]> findTestElements() throws IOException, InterruptedException {
return SeleniumTest.findTestElements();
}
*/
}
@@ -36,9 +36,12 @@ import java.util.List;
@RunWith(Parameterized.class)
public class SeleniumTest {
protected static String testQueryString = "";
//protected static String testQueryString = "?testNumber=6";
protected static WebDriver driver = createDriver();
public static HtmlUnitDriver createDriver() {
public static WebDriver createDriver() {
HtmlUnitDriver answer = new HtmlUnitDriver(true);
answer.setJavascriptEnabled(true);
return answer;
@@ -68,7 +71,8 @@ public class SeleniumTest {
@Parameterized.Parameters
public static List<Object[]> findTestElements() throws IOException, InterruptedException {
File file = new File("../kotlin-js-tests/src/test/web/index.html");
String uri = "../kotlin-js-tests/src/test/web/index.html" + testQueryString;
File file = new File(uri);
driver.get("file://" + file.getCanonicalPath());
Thread.sleep(500);
List<WebElement> tests = tester.findTests();
+1 -1
View File
@@ -43,7 +43,7 @@
<include name="**/*.kt"/>
<exclude name="**/*JVM.kt"/>
<!-- TODO FixME ASAP - works fine in JS, why doesn't it work in JUnit? -->
<!-- TODO FixME ASAP - works fine in JS, why doesn't it work in JUnit with Rhino and Selenium? -->
<exclude name="**/JsArrayTest.kt"/>
</fileset>
<fileset dir="${basedir}/../../stdlib/test/dom">