wip
diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/test/JSTestGenerator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/test/JSTestGenerator.kt index 6e3002a..7ef3cfa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/test/JSTestGenerator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/test/JSTestGenerator.kt
@@ -42,25 +42,39 @@ return JsNameRef(name, JsNameRef("Kotlin")) } - fun generateTestCalls(moduleDescriptor: ModuleDescriptor) = generateTestCalls(moduleDescriptor, FqName.ROOT) + fun generateTestCalls(moduleDescriptor: ModuleDescriptor) { + val rootFunction = JsFunction(context.scope(), JsBlock(), "root suite function") - private fun generateTestCalls(moduleDescriptor: ModuleDescriptor, packageName: FqName) { + generateTestCalls(moduleDescriptor, FqName.ROOT, rootFunction) + + if (!rootFunction.body.isEmpty) { + context.addTopLevelStatement(JsInvocation(suiteRef, JsStringLiteral(""), rootFunction).makeStmt()) + } + } + + private fun generateTestCalls(moduleDescriptor: ModuleDescriptor, packageName: FqName, parentFun: JsFunction) { for (packageDescriptor in moduleDescriptor.getPackage(packageName).fragments) { if (DescriptorUtils.getContainingModule(packageDescriptor) !== moduleDescriptor) continue packageDescriptor.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS, MemberScope.ALL_NAME_FILTER).forEach { if (it is ClassDescriptor) { - generateTestFunctions(it) + generateTestFunctions(it, parentFun) } } } for (subpackageName in moduleDescriptor.getSubPackagesOf(packageName, MemberScope.ALL_NAME_FILTER)) { - generateTestCalls(moduleDescriptor, subpackageName) + val subPackageFunction = JsFunction(context.scope(), JsBlock(), "${subpackageName.asString()} package suite function") + + generateTestCalls(moduleDescriptor, subpackageName, subPackageFunction) + + if (!subPackageFunction.body.isEmpty) { + parentFun.body.statements += JsInvocation(suiteRef, JsStringLiteral(subpackageName.shortName().asString()), subPackageFunction).makeStmt() + } } } - private fun generateTestFunctions(classDescriptor: ClassDescriptor) { + private fun generateTestFunctions(classDescriptor: ClassDescriptor, parentFun: JsFunction) { if (classDescriptor.modality === Modality.ABSTRACT) return val suiteFunction = JsFunction(context.scope(), JsBlock(), "suite function") @@ -74,7 +88,7 @@ if (!suiteFunction.body.isEmpty) { val suiteName = JsStringLiteral(classDescriptor.name.toString()) - context.addTopLevelStatement(JsInvocation(classDescriptor.ref, suiteName, suiteFunction).makeStmt()) + parentFun.body.statements += JsInvocation(classDescriptor.ref, suiteName, suiteFunction).makeStmt() } } @@ -124,7 +138,7 @@ * } */ private val FunctionDescriptor.isTest - get() = annotationFinder("Test", "kotlin.test", "org.junit") + get() = annotationFinder("Test", "kotlin.test", "org.junit") // Support both ways for now. private val DeclarationDescriptor.isIgnored get() = annotationFinder("Ignore", "kotlin.test") @@ -132,10 +146,7 @@ private val DeclarationDescriptor.isFocused get() = annotationFinder("Only", "kotlin.test") - private fun DeclarationDescriptor.annotationFinder(shortName: String, vararg packages: String) = this.annotations.any { annotation: AnnotationDescriptor -> - annotation.type.toString() == shortName && packages.any { packageName -> - val descriptor = annotation.type.constructor.declarationDescriptor - descriptor != null && FqNameUnsafe("$packageName.$shortName") == DescriptorUtils.getFqName(descriptor) - } + private fun DeclarationDescriptor.annotationFinder(shortName: String, vararg packages: String) = packages.any { packageName -> + annotations.hasAnnotation(FqName("$packageName.$shortName")) } }
diff --git a/libraries/kotlin.test/js/it/build.gradle b/libraries/kotlin.test/js/it/build.gradle index ab9a954..406bd50 100644 --- a/libraries/kotlin.test/js/it/build.gradle +++ b/libraries/kotlin.test/js/it/build.gradle
@@ -49,27 +49,27 @@ download = true } -task testJest( type: NpmTask, dependsOn: [compileTestKotlin2Js, compileTestKotlin2Js, 'npmInstall']) { +task testJest(type: NpmTask, dependsOn: [compileTestKotlin2Js, npmInstall]) { args = ['run', 'test-jest'] } check.dependsOn testJest -task testJasmine( type: NpmTask, dependsOn: [compileTestKotlin2Js, compileTestKotlin2Js, 'npmInstall']) { +task testJasmine(type: NpmTask, dependsOn: [compileTestKotlin2Js, npmInstall]) { args = ['run', 'test-jasmine'] } check.dependsOn testJasmine -task testMocha( type: NpmTask, dependsOn: [compileTestKotlin2Js, compileTestKotlin2Js, 'npmInstall']) { +task testMocha(type: NpmTask, dependsOn: [compileTestKotlin2Js, npmInstall]) { args = ['run', 'test-mocha'] } check.dependsOn testMocha -task testQunit( type: NpmTask, dependsOn: [compileTestKotlin2Js, compileTestKotlin2Js, 'npmInstall']) { +task testQunit(type: NpmTask, dependsOn: [compileTestKotlin2Js, npmInstall]) { args = ['run', 'test-qunit'] } check.dependsOn testQunit -task testTape( type: NpmTask, dependsOn: [compileTestKotlin2Js, compileTestKotlin2Js, 'npmInstall']) { +task testTape(type: NpmTask, dependsOn: [compileTestKotlin2Js, npmInstall]) { args = ['run', 'test-tape'] } check.dependsOn testTape
diff --git a/libraries/kotlin.test/js/it/js/expected-outcomes.js b/libraries/kotlin.test/js/it/js/expected-outcomes.js index fbb7ede..3c6f31e 100644 --- a/libraries/kotlin.test/js/it/js/expected-outcomes.js +++ b/libraries/kotlin.test/js/it/js/expected-outcomes.js
@@ -1,11 +1,22 @@ -module.exports.full = { - 'SimpleTest testFoo': 'fail', - 'SimpleTest testBar': 'pass', - 'SimpleTest testFooWrong': 'pending', - 'TestTest emptyTest': 'pending' +var full = { + ' SimpleTest testFoo': 'fail', + ' SimpleTest testBar': 'pass', + ' SimpleTest testFooWrong': 'pending', + ' TestTest emptyTest': 'pending', + ' org OrgTest test': 'pass', + ' org some SomeTest test': 'pass', + ' org some name NameTest test': 'pass', + ' org other name NameTest test': 'pass' }; -module.exports.noPending = { - 'SimpleTest testFoo': 'fail', - 'SimpleTest testBar': 'pass' -}; \ No newline at end of file +// Filter out pending tests for Tape +var noPending = {}; +for (var name in full) { + var result = full[name]; + if (result !== 'pending') { + noPending[name] = result; + } +} + +module.exports.full = full; +module.exports.noPending = noPending; \ No newline at end of file
diff --git a/libraries/kotlin.test/js/it/package.json b/libraries/kotlin.test/js/it/package.json index 59e2ed6..f98b126 100644 --- a/libraries/kotlin.test/js/it/package.json +++ b/libraries/kotlin.test/js/it/package.json
@@ -7,7 +7,7 @@ "test-jasmine": "jasmine js/paths.js js/jasmine-reporter.js build/classes/test/it_test.js", "test-jest": "jest", "test-mocha": "mocha -r js/paths.js --reporter js/mocha-reporter.js build/classes/test/it_test.js", - "test-qunit": "qunit -c js/paths.js -d js/qunit-reporter.js -t build/classes/test/it_test.js", + "test-qunit": "qunit -d js/paths.js -c js/qunit-reporter.js -t build/classes/test/it_test.js", "test-tape": "tape js/paths.js js/tape-reporter.js js/tape-plugin.js build/classes/test/it_test.js" }, "author": "",
diff --git a/libraries/kotlin.test/js/it/test/org/OrgTest.kt b/libraries/kotlin.test/js/it/test/org/OrgTest.kt new file mode 100644 index 0000000..84c114f --- /dev/null +++ b/libraries/kotlin.test/js/it/test/org/OrgTest.kt
@@ -0,0 +1,8 @@ +package org + +import kotlin.test.* + +class OrgTest { + @Test fun test() { + } +}
diff --git a/libraries/kotlin.test/js/it/test/org/other/name/NameTest.kt b/libraries/kotlin.test/js/it/test/org/other/name/NameTest.kt new file mode 100644 index 0000000..5f33526 --- /dev/null +++ b/libraries/kotlin.test/js/it/test/org/other/name/NameTest.kt
@@ -0,0 +1,8 @@ +package org.other.name + +import kotlin.test.* + +class NameTest { + @Test fun test() { + } +} \ No newline at end of file
diff --git a/libraries/kotlin.test/js/it/test/org/some/SomeTest.kt b/libraries/kotlin.test/js/it/test/org/some/SomeTest.kt new file mode 100644 index 0000000..5487e2b --- /dev/null +++ b/libraries/kotlin.test/js/it/test/org/some/SomeTest.kt
@@ -0,0 +1,8 @@ +package org.some + +import kotlin.test.* + +class SomeTest { + @Test fun test() { + } +}
diff --git a/libraries/kotlin.test/js/it/test/org/some/name/NameTest.kt b/libraries/kotlin.test/js/it/test/org/some/name/NameTest.kt new file mode 100644 index 0000000..de4a162 --- /dev/null +++ b/libraries/kotlin.test/js/it/test/org/some/name/NameTest.kt
@@ -0,0 +1,8 @@ +package org.some.name + +import kotlin.test.* + +class NameTest { + @Test fun test() { + } +}
diff --git a/libraries/kotlin.test/js/src/main/kotlin/FrameworkAdapter.kt b/libraries/kotlin.test/js/src/main/kotlin/FrameworkAdapter.kt index 83d17d50..4450c6d 100644 --- a/libraries/kotlin.test/js/src/main/kotlin/FrameworkAdapter.kt +++ b/libraries/kotlin.test/js/src/main/kotlin/FrameworkAdapter.kt
@@ -14,8 +14,6 @@ * limitations under the License. */ -import kotlin.test.assertHook - @JsName("suite") fun suite(name: String, suiteFn: () -> Unit) { currentAdapter.suite(name, suiteFn) @@ -53,12 +51,10 @@ if (js("typeof adapter === 'string'")) { if (adapter in DefaultAdapters.NAME_TO_ADAPTER) { setAdapter(DefaultAdapters.NAME_TO_ADAPTER[adapter]) - } - else { + } else { throw IllegalArgumentException("Unsupported test framework adapter: '$adapter'") } - } - else { + } else { currentAdapter = adapter } } @@ -86,36 +82,58 @@ enum class DefaultAdapters : FrameworkAdapter { QUNIT { - override fun suite(name: String, suiteFn: () -> Unit) { - QUnit.module(name, suiteFn) + var scopeStack = mutableListOf<String>() + + var shouldSkip = false + + val testName: String + get() = scopeStack.joinToString(separator = " ") + + private fun withName(name: String, block: () -> Unit) { + scopeStack.add(name) + block() + scopeStack.removeAt(scopeStack.size - 1) } + override fun suite(name: String, suiteFn: () -> Unit) = withName(name, suiteFn) + override fun xsuite(name: String, suiteFn: () -> Unit) { - // QUnit doesn't support ignoring modules, so just don't execute it + if (shouldSkip) { + suiteFn() + } + else { + shouldSkip = true + suiteFn() + shouldSkip = false + } } - override fun fsuite(name: String, suiteFn: () -> Unit) { - // QUnit doesn't support focusing on a single module - QUnit.module(name, suiteFn) - } + // QUnit doesn't support focusing on a single module + override fun fsuite(name: String, suiteFn: () -> Unit) = withName(name, suiteFn) override fun test(name: String, testFn: () -> Unit) { - QUnit.test(name, wrapTest(testFn)) + if (shouldSkip) { + xtest(name, testFn) + } + else { + withName(name) { + QUnit.test(testName, wrapTest(testFn)) + } + } } - override fun xtest(name: String, testFn: () -> Unit) { - QUnit.skip(name, wrapTest(testFn)) + override fun xtest(name: String, testFn: () -> Unit) = withName(name) { + QUnit.skip(testName, wrapTest(testFn)) } - override fun ftest(name: String, testFn: () -> Unit) { - QUnit.only(name, wrapTest(testFn)) + override fun ftest(name: String, testFn: () -> Unit) = withName(name) { + QUnit.only(testName, wrapTest(testFn)) } private fun wrapTest(testFn: () -> Unit): (dynamic) -> Unit = { assert -> if (js("typeof assert !== 'function'")) { assertHook = { result, _, _, msgFn -> assert.ok(result, msgFn()) } - } - else { + } else { assertHook = { result, expected, actual, msgFn -> val data = js("{}") data.result = result @@ -208,13 +226,14 @@ }; companion object { - val AUTO_DETECTED = when { - js("typeof QUnit !== 'undefined'") -> QUNIT - js("typeof describe === 'function' && typeof it === 'function'") -> { - if (js("typeof xit === 'function'")) JASMINE else MOCHA + val AUTO_DETECTED: FrameworkAdapter + get() = when { + js("typeof QUnit !== 'undefined'") -> QUNIT + js("typeof describe === 'function' && typeof it === 'function'") -> { + if (js("typeof xit === 'function'")) JASMINE else MOCHA + } + else -> BARE } - else -> BARE - } val NAME_TO_ADAPTER = mapOf( "qunit" to QUNIT, @@ -224,6 +243,12 @@ } } +internal var assertHook: (result: Boolean, expected: Any?, actual: Any?, () -> String?) -> Unit = { result, _, _, msgFun -> + if (js("typeof QUnit !== 'undefined'")) { + ok(result, msgFun()) + } +} + /** * The [QUnit](http://qunitjs.com/) API */ @@ -241,6 +266,7 @@ * Jasmine/Mocha API */ external fun describe(name: String, fn: () -> Unit) + external fun xdescribe(name: String, fn: () -> Unit) external fun fdescribe(name: String, fn: () -> Unit)
diff --git a/libraries/kotlin.test/js/src/main/kotlin/JsImpl.kt b/libraries/kotlin.test/js/src/main/kotlin/JsImpl.kt index bc44788..47856b5 100644 --- a/libraries/kotlin.test/js/src/main/kotlin/JsImpl.kt +++ b/libraries/kotlin.test/js/src/main/kotlin/JsImpl.kt
@@ -16,6 +16,7 @@ package kotlin.test +import assertHook import kotlin.reflect.KClass /** @@ -46,8 +47,6 @@ private val qunitAsserter = QUnitAsserter() -internal var assertHook: (result: Boolean, expected: Any?, actual: Any?, () -> String?) -> Unit = { _, _, _, _ -> } - // TODO: make object in 1.2 class QUnitAsserter : Asserter { private var e: Any? = undefined