diff --git a/apps/.vscode/launch.json b/apps/.vscode/launch.json index a04635572..5faa59444 100644 --- a/apps/.vscode/launch.json +++ b/apps/.vscode/launch.json @@ -30,6 +30,7 @@ "appRoot": "${workspaceRoot}", "sourceMaps": true, "watch": true, + "stopOnEntry": true, "tnsArgs": [ "--sync-all-files" ] diff --git a/tests/app/TKUnit.ts b/tests/app/TKUnit.ts index 46057b5f9..b8787c275 100644 --- a/tests/app/TKUnit.ts +++ b/tests/app/TKUnit.ts @@ -15,6 +15,7 @@ import * as timer from "tns-core-modules/timer"; import * as trace from "tns-core-modules/trace"; import * as types from "tns-core-modules/utils/types"; import * as platform from "tns-core-modules/platform"; +import { topmost } from "tns-core-modules/ui/frame"; import * as utils from "tns-core-modules/utils/utils"; @@ -42,12 +43,12 @@ export function time(): number { } } -export var write = function write(message: string, type?: number) { +export function write(message: string, type?: number) { //console.log(message); trace.write(message, trace.categories.Test, type); } -var runTest = function (testInfo: TestInfoEntry) { +function runTest(testInfo: TestInfoEntry) { let start = time(); let duration; try { @@ -74,7 +75,7 @@ var runTest = function (testInfo: TestInfoEntry) { testInfo.errorMessage = e.message; } } -}; +} export interface TestFailure { moduleName: string; @@ -89,55 +90,45 @@ export interface TestModuleRunResult { failed: Array; } -var testsQueue: Array; -var defaultTimeout = 5000; +let testsQueue: Array; +const defaultTimeout = 5000; -// testInfo : {testFunc: func, testName: string, isTest: boolean, isPassed: boolean, errorMessage: string} function runAsync(testInfo: TestInfoEntry, recursiveIndex: number, testTimeout?: number) { - var error; - var isDone = false; - var handle; - var testStartTime = time(); + let error; + let isDone = false; + let handle; + const testStartTime = time(); //write("--- [" + testInfo.testName + "] Started at: " + testStartTime, trace.messageType.info); - var doneCallback = function (e: Error) { + const doneCallback = (e: Error) => { if (e) { error = e; - } - else { + } else { isDone = true; } } - var testTimeout = testInfo.testTimeout; - if (!testTimeout) { - testTimeout = defaultTimeout; - } + + const timeout = testTimeout || testInfo.testTimeout || defaultTimeout; let duration; - var checkFinished = function () { + const checkFinished = () => { duration = time() - testStartTime; testInfo.duration = duration; if (isDone) { - write("--- [" + testInfo.testName + "] OK, duration: " + duration, trace.messageType.info); - //write("--- [" + testInfo.testName + "] took: " + (new Date().getTime() - testStartTime), trace.messageType.info); + write(`--- [${testInfo.testName}] OK, duration: ${duration}`, trace.messageType.info); testInfo.isPassed = true; runTests(testsQueue, recursiveIndex + 1); - } - else if (error) { - write("--- [" + testInfo.testName + "] FAILED: " + error.message + ", duration: " + duration, trace.messageType.error); - //write("--- [" + testInfo.testName + "] took: " + (new Date().getTime() - testStartTime), trace.messageType.info); + } else if (error) { + write(`--- ["${testInfo.testName}"] FAILED: ${error.message}, duration: ${duration}`, trace.messageType.error); testInfo.errorMessage = error.message; runTests(testsQueue, recursiveIndex + 1); - } - else { - var testEndTime = time(); - if (testEndTime - testStartTime > testTimeout) { - write("--- [" + testInfo.testName + "] TIMEOUT, duration: " + duration, trace.messageType.error); - //write("--- [" + testInfo.testName + "] took: " + (testEndTime - testStartTime), trace.messageType.info); + } else { + const testEndTime = time(); + if (testEndTime - testStartTime > timeout) { + write(`--- ["${testInfo.testName}"] TIMEOUT, duration: ${duration}`, trace.messageType.error); testInfo.errorMessage = "Test timeout."; runTests(testsQueue, recursiveIndex + 1); - } - else { - setTimeout(checkFinished, 10); + } else { + setTimeout(checkFinished, 0); } } } @@ -146,7 +137,7 @@ function runAsync(testInfo: TestInfoEntry, recursiveIndex: number, testTimeout?: if (testInfo.instance) { testInfo.testFunc.apply(testInfo.instance, [doneCallback]); } else { - var func: any = testInfo.testFunc; + const func: any = testInfo.testFunc; func(doneCallback); } } catch (e) { @@ -156,17 +147,15 @@ function runAsync(testInfo: TestInfoEntry, recursiveIndex: number, testTimeout?: setTimeout(checkFinished, 0); } -// tests : Array<{testFunc: func, testName: string, isTest: boolean, isPassed: boolean, errorMessage: string}> -export var runTests = function (tests: Array, recursiveIndex) { +export function runTests(tests: Array, recursiveIndex) { testsQueue = tests; + + for (let i = recursiveIndex; i < testsQueue.length; i++) { + const testEntry = testsQueue[i]; - var i; - for (i = recursiveIndex; i < testsQueue.length; i++) { - var testEntry = testsQueue[i]; if (testEntry.testFunc.length > 0) { return runAsync(testEntry, i); - } - else { + } else { runTest(testEntry); } } @@ -176,35 +165,31 @@ export function assert(test: any, message?: string) { if (!test) { throw new Error(message); } -}; +} export function assertTrue(test: boolean, message?: string) { if (test !== true) { throw new Error(message); } -}; +} export function assertFalse(test: boolean, message?: string) { if (test !== false) { throw new Error(message); } -}; +} export function assertNotEqual(actual: any, expected: any, message?: string) { - - var equals = false; + let equals = false; if (types.isUndefined(actual) && types.isUndefined(expected)) { equals = true; - } - else if (!types.isNullOrUndefined(actual) && !types.isNullOrUndefined(expected)) { + } else if (!types.isNullOrUndefined(actual) && !types.isNullOrUndefined(expected)) { if (types.isFunction(actual.equals)) { - // Use the equals method if (actual.equals(expected)) { equals = true; } - } - else { + } else { equals = actual === expected; } } @@ -228,7 +213,7 @@ export function assertEqual(actual else if (actual !== expected) { throw new Error(`${message} Actual: <${actual}>(${typeof (actual)}). Expected: <${expected}>(${typeof (expected)})`); } -}; +} /** * Assert two json like objects are deep equal. @@ -310,13 +295,13 @@ export function assertNull(actual: any, message?: string) { if (actual !== null && actual !== undefined) { throw new Error(message + " Actual: " + actual + " is not null/undefined"); } -}; +} export function assertNotNull(actual: any, message?: string) { if (actual === null || actual === undefined) { throw new Error(message + " Actual: " + actual + " is null/undefined"); } -}; +} export function areClose(actual: number, expected: number, delta: number): boolean { if (isNaN(actual) || Math.abs(actual - expected) > delta) { @@ -325,18 +310,19 @@ export function areClose(actual: number, expected: number, delta: number): boole return true; } + export function assertAreClose(actual: number, expected: number, delta: number, message?: string) { if (!areClose(actual, expected, delta)) { throw new Error(message + " Numbers are not close enough. Actual: " + actual + " Expected: " + expected + " Delta: " + delta); } -}; +} export function arrayAssert(actual: Array, expected: Array, message?: string) { if (actual.length !== expected.length) { throw new Error(message + " Actual array length: " + actual.length + " Expected array length: " + expected.length); } - var i; - for (i = 0; i < actual.length; i++) { + + for (let i = 0; i < actual.length; i++) { if (actual[i] !== expected[i]) { throw new Error(message + " Actual element at " + i + " is: " + actual[i] + " Expected element is: " + expected[i]); } @@ -344,7 +330,7 @@ export function arrayAssert(actual: Array, expected: Array, message?: } export function assertThrows(testFunc: () => void, assertMessage?: string, expectedMessage?: string) { - var actualError: Error; + let actualError: Error; try { testFunc(); } catch (e) { @@ -360,29 +346,30 @@ export function assertThrows(testFunc: () => void, assertMessage?: string, expec } } -export var wait = function (seconds: number) { - waitUntilReady(function () { - return false; - }, seconds, false); -}; +export function wait(seconds: number): void { + waitUntilReady(() => false, seconds, false); +} -export var waitUntilReady = function (isReady: () => boolean, timeoutSec: number = 3, shouldThrow: boolean = true) { +export function waitUntilReady(isReady: () => boolean, timeoutSec: number = 300, shouldThrow: boolean = true) { if (!isReady) { return; } if (Application.ios) { - const waitTime = 20 / 1000; - var totalWaitTime = 0; + // const waitTime = 1 / 10000; + const timeoutMs = timeoutSec * 1000; + let totalWaitTime = 0; while (true) { - utils.ios.getter(NSRunLoop, NSRunLoop.currentRunLoop).runUntilDate(NSDate.dateWithTimeIntervalSinceNow(waitTime)); - + // const nsDate = NSDate.dateWithTimeIntervalSinceNow(waitTime); + const begin = time(); + const currentRunLoop = utils.ios.getter(NSRunLoop, NSRunLoop.currentRunLoop); + currentRunLoop.limitDateForMode(currentRunLoop.currentMode); if (isReady()) { break; } - totalWaitTime += waitTime; - if (timeoutSec && totalWaitTime >= timeoutSec) { + totalWaitTime += (time() - begin); + if (totalWaitTime >= timeoutMs) { if (shouldThrow) { throw new Error("waitUntilReady Timeout."); } else { @@ -393,26 +380,23 @@ export var waitUntilReady = function (isReady: () => boolean, timeoutSec: number } else if (Application.android) { doModalAndroid(isReady, timeoutSec, shouldThrow); } -}; +} // Setup for the Android modal loop implementation // TODO: If these platform-specific implementations continue to grow, think of per-platform separation (TKUnit.android) -var nextMethod; -var targetField; -var prepared; +let nextMethod; +let targetField; +let prepared; -var prepareModal = function () { +function prepareModal() { if (prepared) { return; } - var clsMsgQueue = java.lang.Class.forName("android.os.MessageQueue"); - var clsMsg = java.lang.Class.forName("android.os.Message"); - - nextMethod; - var methods = clsMsgQueue.getDeclaredMethods(); - var i; - for (i = 0; i < methods.length; i++) { + const clsMsgQueue = java.lang.Class.forName("android.os.MessageQueue"); + const clsMsg = java.lang.Class.forName("android.os.Message"); + const methods = clsMsgQueue.getDeclaredMethods(); + for (let i = 0; i < methods.length; i++) { if (methods[i].getName() === "next") { nextMethod = methods[i]; nextMethod.setAccessible(true); @@ -420,9 +404,8 @@ var prepareModal = function () { } } - targetField; - var fields = clsMsg.getDeclaredFields(); - for (i = 0; i < fields.length; i++) { + const fields = clsMsg.getDeclaredFields(); + for (let i = 0; i < fields.length; i++) { if (fields[i].getName() === "target") { targetField = fields[i]; targetField.setAccessible(true); @@ -433,28 +416,28 @@ var prepareModal = function () { prepared = true; } -var doModalAndroid = function (quitLoop: () => boolean, timeoutSec: number, shouldThrow: boolean = true) { +function doModalAndroid(quitLoop: () => boolean, timeoutSec: number, shouldThrow: boolean = true) { if (!quitLoop) { return; } prepareModal(); - var queue = android.os.Looper.myQueue(); + const queue = android.os.Looper.myQueue(); let quit = false; let timeout = false; - timer.setTimeout(function () { + timer.setTimeout(() => { quit = true; timeout = true; }, timeoutSec * 1000); - var msg; + let msg; while (!quit) { msg = nextMethod.invoke(queue, null); if (msg) { - var target = targetField.get(msg); + const target = targetField.get(msg); if (!target) { quit = true; } else { @@ -474,4 +457,4 @@ var doModalAndroid = function (quitLoop: () => boolean, timeoutSec: number, shou quit = true; } } -}; +} \ No newline at end of file diff --git a/tests/app/app/mainPage.ts b/tests/app/app/mainPage.ts index 7b21f6028..049b79ac1 100644 --- a/tests/app/app/mainPage.ts +++ b/tests/app/app/mainPage.ts @@ -9,14 +9,14 @@ trace.enable(); trace.addCategories(trace.categories.Test + "," + trace.categories.Error); // When debugging -//trace.setCategories(trace.categories.concat( +// trace.setCategories(trace.categories.concat( // trace.categories.Test, // trace.categories.Navigation, // trace.categories.Transition, // trace.categories.NativeLifecycle, // trace.categories.ViewHierarchy, // trace.categories.VisualTreeEvents -//)); +// )); let page = new Page(); page.id = "mainPage"; @@ -57,6 +57,7 @@ function onNavigatedTo(args) { runTests(); } + export function createPage() { return page; -} +} \ No newline at end of file diff --git a/tests/app/http/http-tests.ts b/tests/app/http/http-tests.ts index 98e4a71a2..891feea5e 100644 --- a/tests/app/http/http-tests.ts +++ b/tests/app/http/http-tests.ts @@ -223,7 +223,7 @@ export var test_getFile = function (done) { var result; // >> http-get-urlfile - http.getFile("https://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/tests/logo.png").then(function (r) { + http.getFile("https://raw.githubusercontent.com/NativeScript/NativeScript/master/tests/app/logo.png").then(function (r) { //// Argument (r) is File! // >> (hide) result = r; @@ -273,7 +273,7 @@ export var test_getContentAsFile = function (done) { export var test_getFile_fail = function (done) { var result; - http.getImage({ url: "hgfttp://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/tests/logo.png", method: "GET", timeout: 2000 }).catch(function (e) { + http.getImage({ url: "hgfttp://raw.githubusercontent.com/NativeScript/NativeScript/master/tests/app/logo.png", method: "GET", timeout: 2000 }).catch(function (e) { result = e; try { TKUnit.assert(result instanceof Error, "Result from getFile().catch() should be Error! Current type is " + typeof result); @@ -457,7 +457,7 @@ export var test_request_responseContentToImageShouldReturnCorrectImage = functio export var test_request_responseContentToFileFromUrlShouldReturnCorrectFile = function (done) { var result; - http.request({ url: "https://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/app/ui-tests-app/image-view/red.png", method: "GET" }).then(function (response) { + http.request({ url: "https://raw.githubusercontent.com/NativeScript/NativeScript/master/tests/app/logo.png", method: "GET" }).then(function (response) { result = response.content.toFile(); try { TKUnit.assert(result instanceof fs.File, "Result from toFile() should be valid File object!"); diff --git a/tests/app/navigation/custom-transition.d.ts b/tests/app/navigation/custom-transition.d.ts new file mode 100644 index 000000000..4b14ce81a --- /dev/null +++ b/tests/app/navigation/custom-transition.d.ts @@ -0,0 +1,6 @@ +import { Transition } from "tns-core-modules/ui/transition"; + +export class CustomTransition extends Transition { + constructor(); + constructor(duration: number, curve: any); +} \ No newline at end of file diff --git a/tests/app/navigation/navigation-tests.ts b/tests/app/navigation/navigation-tests.ts index 05cfaf93c..98bb264a5 100644 --- a/tests/app/navigation/navigation-tests.ts +++ b/tests/app/navigation/navigation-tests.ts @@ -1,7 +1,7 @@ import * as TKUnit from "../TKUnit"; -import {Page, NavigatedData} from "tns-core-modules/ui/page"; -import {topmost as topmostFrame, NavigationTransition} from "tns-core-modules/ui/frame"; -import {Color} from "tns-core-modules/color"; +import { Page, NavigatedData } from "tns-core-modules/ui/page"; +import { topmost as topmostFrame, NavigationTransition } from "tns-core-modules/ui/frame"; +import { Color } from "tns-core-modules/color"; import * as helper from "../ui/helper"; // Creates a random colorful page full of meaningless stuff. @@ -14,14 +14,6 @@ let pageFactory = function (): Page { return page; }; -function androidGC() { - let topmost = topmostFrame(); - if (topmost.android) { - gc(); - java.lang.System.gc(); - } -} - function attachEventListeners(page: Page, events: Array) { let argsToString = (args: NavigatedData) => { return `${(args.object).id} ${args.eventName} ${(args.isBackNavigation ? "back" : "forward")}`; @@ -36,36 +28,32 @@ function attachEventListeners(page: Page, events: Array) { function _test_backstackVisible(transition?: NavigationTransition) { let topmost = topmostFrame(); let mainTestPage = topmost.currentPage; - helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: true }); - + topmost.navigate({ create: pageFactory, transition: transition, animated: !!transition }); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); // page1 should not be added to the backstack let page0 = topmost.currentPage; - helper.navigateWithEntry({ create: pageFactory, backstackVisible: false, transition: transition, animated: true }); - - helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: true }); - - helper.goBack(); - + topmost.navigate({ create: pageFactory, backstackVisible: false, transition: transition, animated: !!transition }); + topmost.navigate({ create: pageFactory, transition: transition, animated: !!transition }); + topmost.goBack(); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); // From page2 we have to go directly to page0, skipping page1. - TKUnit.assert(topmost.currentPage === page0, "Page 1 should be skipped when going back."); + TKUnit.assertEqual(topmost.currentPage, page0, "Page 1 should be skipped when going back."); helper.goBack(); TKUnit.assertEqual(topmost.currentPage, mainTestPage, "We should be on the main test page at the end of the test."); } export function test_backstackVisible() { - androidGC(); _test_backstackVisible(); } export function test_backstackVisible_WithTransition() { - androidGC(); - _test_backstackVisible({ name: "fade" }); + _test_backstackVisible({ name: "fade", duration: 10 }); } function _test_backToEntry(transition?: NavigationTransition) { - let topmost = topmostFrame(); - let page = (tag) => () => { + const topmost = topmostFrame(); + const page = (tag) => () => { const p = new Page(); p.actionBarHidden = true; p.id = `NavTestPage${id++}`; @@ -73,114 +61,90 @@ function _test_backToEntry(transition?: NavigationTransition) { return p; }; - let mainTestPage = topmost.currentPage; - let waitFunc = tag => TKUnit.waitUntilReady(() => topmost.currentPage["tag"] === tag, 1); - let navigate = tag => { - topmost.navigate({ create: page(tag), transition: transition, animated: true }); - waitFunc(tag); + const mainTestPage = topmost.currentPage; - }; - - let back = pages => { - topmost.goBack(topmost.backStack[topmost.backStack.length - pages]); - }; - - let currentPageMustBe = tag => { - waitFunc(tag); // TODO: Add a timeout... - TKUnit.assert(topmost.currentPage["tag"] === tag, "Expected current page to be " + tag + " it was " + topmost.currentPage["tag"] + " instead."); - }; + const navigate = tag => topmost.navigate({ create: page(tag), transition: transition, animated: !!transition }); + const back = pages => topmost.goBack(topmost.backStack[topmost.backStack.length - pages]); + const currentPageMustBe = tag => TKUnit.assertEqual(topmost.currentPage["tag"], tag, "Expected current page to be " + tag + " it was " + topmost.currentPage["tag"] + " instead."); navigate("page1"); navigate("page2"); navigate("page3"); navigate("page4"); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); currentPageMustBe("page4"); + back(2); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); + currentPageMustBe("page2"); + back(1); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); + currentPageMustBe("page1"); + navigate("page1.1"); navigate("page1.2"); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); + currentPageMustBe("page1.2"); + back(1); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); + currentPageMustBe("page1.1"); + back(1); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); + currentPageMustBe("page1"); - let page1 = topmost.currentPage; + back(1); - helper.waitUntilNavigatedFrom(page1); + TKUnit.waitUntilReady(() => topmost.navigationQueueIsEmpty()); + TKUnit.assertEqual(topmost.currentPage, mainTestPage, "We should be on the main test page at the end of the test."); } export function test_backToEntry() { - androidGC(); _test_backToEntry(); } export function test_backToEntry_WithTransition() { - androidGC(); - _test_backToEntry({ name: "flip" }); + _test_backToEntry({ name: "fade", duration: 10 }); } function _test_ClearHistory(transition?: NavigationTransition) { let topmost = topmostFrame(); - let mainTestPage = topmost.currentPage; - let mainPageFactory = function (): Page { - return mainTestPage; - }; - - helper.navigateWithEntry({ create: pageFactory, clearHistory: true, transition: transition, animated: true }); + let x = 0; + helper.navigateWithEntry({ create: pageFactory, clearHistory: true, transition: transition, animated: !!transition }); TKUnit.assertEqual(topmost.backStack.length, 0, "1.topmost.backStack.length"); TKUnit.assertEqual(topmost.canGoBack(), false, "1.topmost.canGoBack()."); - helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: true }); + helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: !!transition }); TKUnit.assertEqual(topmost.backStack.length, 1, "2.topmost.backStack.length"); TKUnit.assertEqual(topmost.canGoBack(), true, "2.topmost.canGoBack()."); - helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: true }); + helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: !!transition }); TKUnit.assertEqual(topmost.backStack.length, 2, "3.topmost.backStack.length"); TKUnit.assertEqual(topmost.canGoBack(), true, "3.topmost.canGoBack()."); - helper.navigateWithEntry({ create: pageFactory, clearHistory: true, transition: transition, animated: true }); + helper.navigateWithEntry({ create: pageFactory, clearHistory: true, transition: transition, animated: !!transition }); TKUnit.assertEqual(topmost.backStack.length, 0, "4.topmost.backStack.length"); TKUnit.assertEqual(topmost.canGoBack(), false, "4.topmost.canGoBack()."); - - helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, animated: false }); - TKUnit.assertEqual(topmost.backStack.length, 0, "5.topmost.backStack.length"); - TKUnit.assertEqual(topmost.canGoBack(), false, "5.topmost.canGoBack()."); - - TKUnit.assertEqual(topmost.currentPage, mainTestPage, "We should be on the main test page at the end of the test."); - TKUnit.assertEqual(topmost.backStack.length, 0, "Back stack should be empty at the end of the test."); } -// Clearing the history messes up the tests app. export function test_ClearHistory() { - androidGC(); _test_ClearHistory(); } export function test_ClearHistory_WithTransition() { - androidGC(); - _test_ClearHistory({ name: "fade" }); -} - -export function test_ClearHistory_WithTransition_WithCachePagesOnNavigate() { - androidGC(); - let topmost = topmostFrame(); - if (!topmost.android) { - return; - } - - let originalCachePagesOnNavigate = topmost.android.cachePagesOnNavigate; - topmostFrame().android.cachePagesOnNavigate = true; - _test_ClearHistory({ name: "fade" }); - topmostFrame().android.cachePagesOnNavigate = originalCachePagesOnNavigate; + _test_ClearHistory({ name: "fade", duration: 10 }); } // Test case for https://github.com/NativeScript/NativeScript/issues/1948 export function test_ClearHistoryWithTransitionDoesNotBreakNavigation() { - androidGC(); let topmost = topmostFrame(); let mainTestPage = topmost.currentPage; let mainPageFactory = function (): Page { @@ -191,14 +155,14 @@ export function test_ClearHistoryWithTransitionDoesNotBreakNavigation() { helper.navigateWithEntry({ create: pageFactory, clearHistory: false, animated: true }); // Go back to main-page with clearHistory - topmost.transition = { name: "fade" }; + topmost.transition = { name: "fade", duration: 10 }; helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, animated: true }); // Go to details-page AGAIN helper.navigateWithEntry({ create: pageFactory, clearHistory: false, animated: true }); // Go back to main-page with clearHistory - topmost.transition = { name: "fade" }; + topmost.transition = { name: "fade", duration: 10 }; helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, animated: true }); // Clean up @@ -209,7 +173,6 @@ export function test_ClearHistoryWithTransitionDoesNotBreakNavigation() { } export function test_ClearHistoryWithTransitionDoesNotBreakNavigation_WithLocalTransition() { - androidGC(); const topmost = topmostFrame(); let originalCachePagesOnNavigate: boolean; @@ -224,16 +187,16 @@ export function test_ClearHistoryWithTransitionDoesNotBreakNavigation_WithLocalT }; // Go to 1st page - helper.navigateWithEntry({ create: pageFactory, clearHistory: false, transition: { name: "fade" }, animated: true }); + helper.navigateWithEntry({ create: pageFactory, clearHistory: false, transition: { name: "fade", duration: 10 }, animated: true }); // Go to 2nd page - helper.navigateWithEntry({ create: pageFactory, clearHistory: false, transition: { name: "fade" }, animated: true }); + helper.navigateWithEntry({ create: pageFactory, clearHistory: false, transition: { name: "fade", duration: 10 }, animated: true }); // Go to 3rd page with clearHistory - helper.navigateWithEntry({ create: pageFactory, clearHistory: true, transition: { name: "fade" }, animated: true }); + helper.navigateWithEntry({ create: pageFactory, clearHistory: true, transition: { name: "fade", duration: 10 }, animated: true }); // Go back to main - helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, transition: { name: "fade" }, animated: true }); + helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, transition: { name: "fade", duration: 10 }, animated: true }); if (topmost.android) { topmostFrame().android.cachePagesOnNavigate = originalCachePagesOnNavigate; @@ -263,7 +226,7 @@ function _test_NavigationEvents(transition?: NavigationTransition) { }; // Go to other page - helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: true }); + helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: !!transition }); // Go back to main helper.goBack(); @@ -290,13 +253,11 @@ function _test_NavigationEvents(transition?: NavigationTransition) { } export function test_NavigationEvents() { - androidGC(); _test_NavigationEvents(); } export function test_NavigationEvents_WithTransition() { - androidGC(); - _test_NavigationEvents({ name: "fade" }); + _test_NavigationEvents({ name: "fade", duration: 10 }); } function _test_NavigationEvents_WithBackstackVisibile_False_Forward_Back(transition?: NavigationTransition) { @@ -314,7 +275,7 @@ function _test_NavigationEvents_WithBackstackVisibile_False_Forward_Back(transit }; // Go to other page - helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: true, backstackVisible: false }); + helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: !!transition, backstackVisible: false }); // Go back to main helper.goBack(); @@ -331,13 +292,11 @@ function _test_NavigationEvents_WithBackstackVisibile_False_Forward_Back(transit } export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Back() { - androidGC(); _test_NavigationEvents_WithBackstackVisibile_False_Forward_Back(); } export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Back_WithTransition() { - androidGC(); - _test_NavigationEvents_WithBackstackVisibile_False_Forward_Back({ name: "fade" }); + _test_NavigationEvents_WithBackstackVisibile_False_Forward_Back({ name: "fade", duration: 10 }); } function _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward(transition?: NavigationTransition) { @@ -355,10 +314,10 @@ function _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward(tran }; // Go to other page - helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: true, backstackVisible: false }); + helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: !!transition, backstackVisible: false }); // Go forward to third page - helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: true }); + helper.navigateWithEntry({ create: pageFactory, transition: transition, animated: !!transition }); // Go back to main helper.goBack(); @@ -375,13 +334,11 @@ function _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward(tran } export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward() { - androidGC(); _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward(); } export function test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward_WithTransition() { - androidGC(); - _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward({ name: "fade" }); + _test_NavigationEvents_WithBackstackVisibile_False_Forward_Forward({ name: "fade", duration: 10 }); } function _test_NavigationEvents_WithClearHistory(transition?: NavigationTransition) { @@ -389,12 +346,12 @@ function _test_NavigationEvents_WithClearHistory(transition?: NavigationTransiti const mainTestPage = topmost.currentPage; mainTestPage.id = "main-page"; - let actualMainPageEvents = new Array(); + const actualMainPageEvents = new Array(); attachEventListeners(mainTestPage, actualMainPageEvents); - let actualSecondPageEvents = new Array(); + const actualSecondPageEvents = new Array(); const secondPage = new Page(); - let secondPageFactory = function (): Page { + const secondPageFactory = function (): Page { secondPage.actionBarHidden = true; secondPage.id = "second-page"; attachEventListeners(secondPage, actualSecondPageEvents); @@ -403,29 +360,21 @@ function _test_NavigationEvents_WithClearHistory(transition?: NavigationTransiti }; // Go to second page - helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: true, clearHistory: true }); + helper.navigateWithEntry({ create: secondPageFactory, transition: transition, animated: !!transition, clearHistory: true }); - let expectedMainPageEvents = [ - "main-page navigatingFrom forward", - "main-page navigatedFrom forward" - ]; + const expectedMainPageEvents = [ "main-page navigatingFrom forward", "main-page navigatedFrom forward" ]; TKUnit.arrayAssert(actualMainPageEvents, expectedMainPageEvents, "Actual main-page events are different from expected."); - let expectedSecondPageEvents = [ - "second-page navigatingTo forward", - "second-page navigatedTo forward", - ]; + const expectedSecondPageEvents = [ "second-page navigatingTo forward", "second-page navigatedTo forward" ]; TKUnit.arrayAssert(actualSecondPageEvents, expectedSecondPageEvents, "Actual main-page events are different from expected."); TKUnit.assertEqual(topmost.currentPage, secondPage, "We should be on the second page at the end of the test."); } export function test_NavigationEvents_WithClearHistory() { - androidGC(); _test_NavigationEvents_WithClearHistory(); } export function test_NavigationEvents_WithClearHistory_WithTransition() { - androidGC(); - _test_NavigationEvents_WithClearHistory({ name: "fade" }); -} + _test_NavigationEvents_WithClearHistory({ name: "fade", duration: 10 }); +} \ No newline at end of file diff --git a/tests/app/navigation/transition-tests.ts b/tests/app/navigation/transition-tests.ts index db630af26..cdf9b0e37 100644 --- a/tests/app/navigation/transition-tests.ts +++ b/tests/app/navigation/transition-tests.ts @@ -6,6 +6,7 @@ import { Color } from "tns-core-modules/color"; import { NavigationEntry, NavigationTransition, topmost as topmostFrame } from "tns-core-modules/ui/frame"; import { Page } from "tns-core-modules/ui/page"; import { AnimationCurve } from "tns-core-modules/ui/enums" +import { CustomTransition } from "./custom-transition"; function _testTransition(navigationTransition: NavigationTransition) { var testId = `Transition[${JSON.stringify(navigationTransition)}]`; @@ -24,57 +25,39 @@ function _testTransition(navigationTransition: NavigationTransition) { } helper.navigateWithEntry(navigationEntry); - TKUnit.wait(0.100); } -// Extremely slow. Run only if needed. -export var test_Transitions = function () { - let topmost = topmostFrame(); - let mainTestPage = topmost.currentPage; - let mainPageFactory = function (): Page { +export function test_Transitions() { + const topmost = topmostFrame(); + const mainTestPage = topmost.currentPage; + const mainPageFactory = function (): Page { return mainTestPage; }; helper.navigate(() => { - var page = new Page(); + const page = new Page(); page.id = "TransitionsTestPage_MAIN" page.style.backgroundColor = new Color(255, Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)); return page; }); var transitions; - var testCustomTransition = true; if (platform.device.os === platform.platformNames.ios) { transitions = ["curl"]; - } - else { - var _sdkVersion = parseInt(platform.device.sdkVersion); + } else { + const _sdkVersion = parseInt(platform.device.sdkVersion); transitions = _sdkVersion >= 21 ? ["explode"] : []; - if (_sdkVersion === 23) { - // Apparently, there is some kind of Android 6.0 (API 23) bug when using ObjectAnimators - // http://stackoverflow.com/questions/33188485/resultindex-is-1-the-polygon-must-be-invalid-adter-addview - testCustomTransition = false; - } } - transitions = transitions.concat(["fade", "flip", "slide"]); - var durations = [undefined, 10]; - var curves = [undefined, AnimationCurve.easeIn]; + + transitions = transitions.concat(["fade", "slide"]); + + // Custom transition + _testTransition({ instance: new CustomTransition(), duration: 10 }); // Built-in transitions transitions.forEach(name => { - durations.forEach(duration => { - curves.forEach(curve => { - _testTransition({ name, duration, curve }); - }); - }); + _testTransition({ name, duration: 20, curve: AnimationCurve.easeIn }); }); - // Custom transition - if (testCustomTransition) { - var customTransitionModule = require("./custom-transition"); - var customTransition = new customTransitionModule.CustomTransition(); - _testTransition({ instance: customTransition }); - } - - helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, animated: false }); -} + // helper.navigateWithEntry({ create: mainPageFactory, clearHistory: true, animated: false }); +} \ No newline at end of file diff --git a/tests/app/testRunner.ts b/tests/app/testRunner.ts index cfbedf229..f98947464 100644 --- a/tests/app/testRunner.ts +++ b/tests/app/testRunner.ts @@ -29,7 +29,7 @@ export function isRunningOnEmulator(): boolean { } } -export var allTests = {}; +export const allTests = {}; import * as domNodeTest from "./debugger/dom-node-tests"; allTests["DOM-NODE"] = domNodeTest; @@ -226,23 +226,19 @@ allTests["ANIMATION"] = animationTests; import * as lifecycle from "./ui/lifecycle/lifecycle-tests"; allTests["LIFECYCLE"] = lifecycle; + import * as cssAnimationTests from "./ui/animation/css-animation-tests"; allTests["CSS-ANIMATION"] = cssAnimationTests; import * as transitionTests from "./navigation/transition-tests"; -// Skip transitions on android emulators with API 23 -if (!(platform.device.os === platform.platformNames.android && parseInt(platform.device.sdkVersion) === 23 && isRunningOnEmulator())) { - allTests["TANSITIONS"] = transitionTests; -} - +allTests["TANSITIONS"] = transitionTests; import * as searchBarTests from "./ui/search-bar/search-bar-tests"; allTests["SEARCH-BAR"] = searchBarTests; import * as navigationTests from "./navigation/navigation-tests"; allTests["NAVIGATION"] = navigationTests; -var testsWithLongDelay = { - test_Transitions: 3 * 60 * 1000, +const testsWithLongDelay = { testLocation: 10000, testLocationOnce: 10000, testLocationOnceMaximumAge: 10000, @@ -257,14 +253,14 @@ var testsWithLongDelay = { test_AnimateBackgroundColor_FromString: 10 * 1000 } -var startTime; -var running = false; -var testsQueue = new Array(); +let startTime; +let running = false; +let testsQueue = new Array(); function printRunTestStats() { const testCases = new Array(); - var failedTestCount = 0; + let failedTestCount = 0; const failedTestInfo = []; const slowTests = new Array(); @@ -285,7 +281,7 @@ function printRunTestStats() { const totalTime = (TKUnit.time() - startTime).toFixed(2); - let finalMessage = `\n`+ + let finalMessage = `\n` + `=== ALL TESTS COMPLETE ===\n` + `${(allTests.length - failedTestCount)} OK, ${failedTestCount} failed\n` + `DURATION: ${totalTime} ms\n`; @@ -335,14 +331,13 @@ function generateTestFile(allTests: TestInfo[]) { } function showReportPage(finalMessage: string) { - let stack = new StackLayout(); - - let btn = new Button(); + const stack = new StackLayout(); + const btn = new Button(); btn.text = "Rerun tests"; btn.on("tap", () => runAll(testsSelector)); stack.addChild(btn); - let messageContainer = new TextView(); + const messageContainer = new TextView(); messageContainer.editable = messageContainer.autocorrect = false; messageContainer.text = finalMessage; stack.addChild(messageContainer); @@ -378,16 +373,16 @@ function log(): void { } let testsSelector: string -export var runAll = function (testSelector?: string) { +export function runAll(testSelector?: string) { testsSelector = testSelector; if (running) { // TODO: We may schedule pending run requests return; } - var singleModuleName, singleTestName; + let singleModuleName, singleTestName; if (testSelector) { - var pair = testSelector.split("."); + const pair = testSelector.split("."); singleModuleName = pair[0]; if (singleModuleName) { if (singleModuleName.length === 0) { @@ -409,17 +404,17 @@ export var runAll = function (testSelector?: string) { console.log("TESTS: " + singleModuleName ? singleModuleName : "" + " " + singleTestName ? singleTestName : ""); - var totalSuccess = 0; - var totalFailed: Array = []; + const totalSuccess = 0; + const totalFailed: Array = []; testsQueue.push(new TestInfo(() => { running = true; startTime = TKUnit.time(); })); - for (var name in allTests) { + for (const name in allTests) { if (singleModuleName && (singleModuleName !== name.toLowerCase())) { continue; } - var testModule = allTests[name]; + const testModule = allTests[name]; - var test = testModule.createTestCase ? testModule.createTestCase() : testModule; + const test = testModule.createTestCase ? testModule.createTestCase() : testModule; test.name = name; testsQueue.push(new TestInfo(startLog, test)); @@ -428,17 +423,17 @@ export var runAll = function (testSelector?: string) { testsQueue.push(new TestInfo(test.setUpModule, test)); } - for (var testName in test) { + for (const testName in test) { if (singleTestName && (singleTestName !== testName.toLowerCase())) { continue; } - var testFunction = test[testName]; + const testFunction = test[testName]; if ((typeof (testFunction) === "function") && (testName.substring(0, 4) == "test")) { if (test.setUp) { testsQueue.push(new TestInfo(test.setUp, test)); } - var testTimeout = testsWithLongDelay[testName]; + const testTimeout = testsWithLongDelay[testName]; testsQueue.push(new TestInfo(testFunction, test, true, name + "." + testName, false, null, testTimeout)); if (test.tearDown) { testsQueue.push(new TestInfo(test.tearDown, test)); @@ -457,8 +452,6 @@ export var runAll = function (testSelector?: string) { TKUnit.runTests(testsQueue, 0); } - - class TestInfo implements TKUnit.TestInfoEntry { testFunc: () => void; instance: any; @@ -479,4 +472,4 @@ class TestInfo implements TKUnit.TestInfoEntry { this.testTimeout = testTimeout; this.duration = duration; } -} +} \ No newline at end of file diff --git a/tests/app/timer/timer-tests.ts b/tests/app/timer/timer-tests.ts index 94c62f2ec..6b1d98fd3 100644 --- a/tests/app/timer/timer-tests.ts +++ b/tests/app/timer/timer-tests.ts @@ -110,51 +110,55 @@ export function test_setTimeout_callbackShouldBeCleared() { TKUnit.assert(!completed, "Callback should be cleared when clearTimeout() is executed for specified id!"); }; -export function test_setInterval_callbackCalledDuringPeriod() { +export function test_setInterval_callbackCalledDuringPeriod(done) { let counter = 0; - let expected = 4; + const expected = 4; + const start = TKUnit.time(); // >> timer-set-expression const id = timer.setInterval(() => { // >> (hide) counter++; + if (counter === 4) { + const end = TKUnit.time(); + timer.clearInterval(id); + done(end - start > 250 ? new Error('setInterval too slow.') : null); + } // << (hide) }, 50); // << timer-set-expression - - TKUnit.waitUntilReady(() => counter >= expected, 0.25, false); - timer.clearInterval(id); - TKUnit.assert(counter >= expected, "Callback should be raised at least" + expected + "times! Callback raised " + counter + " times."); }; -export function test_setInterval_callbackCalledWithExtraArgs() { +export function test_setInterval_callbackCalledWithExtraArgs(done) { let counter: number = 0; - let expected: number = 4; - let rnd: number = Math.random(); + const expected: number = 4; + const rnd: number = Math.random(); + const start = TKUnit.time(); const id = timer.setInterval((arg) => { counter += arg === rnd ? 1 : -1; + if (counter === 4) { + const end = TKUnit.time(); + timer.clearInterval(id); + done(end - start > 250 ? new Error('setInterval too slow.') : null); + } }, 50, rnd); - - TKUnit.waitUntilReady(() => counter >= expected, 0.25, false); - timer.clearInterval(id); - TKUnit.assert(counter >= expected, "Callback raised " + counter + " times with arguments."); }; -export function test_setInterval_callbackShouldBeCleared() { +export function test_setInterval_callbackShouldBeCleared(done) { let counter = 0; + const start = TKUnit.time(); // >> timer-set-interval const id = timer.setInterval(() => { // >> (hide) - counter++; + const end = TKUnit.time(); + timer.clearInterval(id); + done(end - start > 150 ? new Error('setInterval too slow.') : null); // << (hide) timer.clearInterval(id); }, 50); // << timer-set-interval - - TKUnit.wait(0.15); - TKUnit.assertEqual(counter, 1, "Callback should be raised only once!"); }; export function test_clearTimeout_multipleTimes_afterTick() { @@ -205,4 +209,4 @@ export function test_clearTimeout_insideCallback() { TKUnit.waitUntilReady(() => completed, 0.5); TKUnit.assert(completed, "Callback should be called"); -} +} \ No newline at end of file diff --git a/tests/app/ui-test.ts b/tests/app/ui-test.ts index 5d615f34c..b0108ebcb 100644 --- a/tests/app/ui-test.ts +++ b/tests/app/ui-test.ts @@ -22,16 +22,12 @@ export class UITest implements trace.TraceWriter { return this._testView; } - public waitUntilTestElementIsLoaded(timeoutSec?: number): void { - TKUnit.waitUntilReady(() => { - return this.testView.isLoaded; - }, timeoutSec || 1); + public waitUntilTestElementIsLoaded(timeoutSec: number = 1): void { + TKUnit.waitUntilReady(() => this.testView.isLoaded, timeoutSec); } - public waitUntilTestElementLayoutIsValid(timeoutSec?: number): void { - TKUnit.waitUntilReady(() => { - return this.testView.isLayoutValid; - }, timeoutSec || 1); + public waitUntilTestElementLayoutIsValid(timeoutSec: number = 1): void { + TKUnit.waitUntilReady(() => this.testView.isLayoutValid, timeoutSec); } public create(): T { @@ -77,4 +73,4 @@ export class UITest implements trace.TraceWriter { export function createTestCase(): UITest { return null; -} +} \ No newline at end of file diff --git a/tests/app/ui/animation/animation-tests.ts b/tests/app/ui/animation/animation-tests.ts index 235114943..7b4c7af3f 100644 --- a/tests/app/ui/animation/animation-tests.ts +++ b/tests/app/ui/animation/animation-tests.ts @@ -33,8 +33,8 @@ export function test_AnimatingProperties(done) { translate: { x: 100, y: 100 }, scale: { x: 2, y: 2 }, rotate: 180, - duration: 10, - delay: 100, + duration: 5, + delay: 10, iterations: 3, curve: enums.AnimationCurve.easeIn }) @@ -58,7 +58,7 @@ export function test_CancellingAnimation(done) { let label = prepareTest(); // >> animation-cancel - var animation1 = label.createAnimation({ translate: { x: 100, y: 100 }, duration: 20 }); + var animation1 = label.createAnimation({ translate: { x: 100, y: 100 }, duration: 5 }); animation1.play() .then(() => { @@ -87,7 +87,7 @@ export function test_CancellingAnimate(done) { let label = prepareTest(); // >> animation-cancel2 - var animation1 = label.animate({ translate: { x: 100, y: 100 }, duration: 20 }) + var animation1 = label.animate({ translate: { x: 100, y: 100 }, duration: 5 }) .then(() => { //console.log("Animation finished"); // >> (hide) @@ -188,9 +188,9 @@ export function test_AnimatingMultipleViews(done) { // >> animation-multiple-views var animations: Array = [ - { target: label1, translate: { x: 200, y: 200 }, duration: 20, delay: 0 }, - { target: label2, translate: { x: 200, y: 200 }, duration: 20, delay: 7 }, - { target: label3, translate: { x: 200, y: 200 }, duration: 20, delay: 14 }, + { target: label1, translate: { x: 200, y: 200 }, duration: 5, delay: 0 }, + { target: label2, translate: { x: 200, y: 200 }, duration: 5, delay: 2 }, + { target: label3, translate: { x: 200, y: 200 }, duration: 5, delay: 4 }, ]; var a = new animation.Animation(animations); a.play() @@ -215,7 +215,7 @@ export function test_AnimatingMultipleViews(done) { export function test_AnimateOpacity(done) { let label = prepareTest(); - label.animate({ opacity: 0.75, duration: 20 }) + label.animate({ opacity: 0.75, duration: 5 }) .then(() => { TKUnit.assertEqual(label.opacity, 0.75, "label.opacity"); done(); @@ -301,7 +301,7 @@ export function test_AnimateBackgroundColor(done) { let label = prepareTest(); var red = new colorModule.Color("Red"); - label.animate({ backgroundColor: red, duration: 20 }) + label.animate({ backgroundColor: red, duration: 5 }) .then(() => { TKUnit.assert((label.backgroundColor).equals(red)); done(); @@ -316,7 +316,7 @@ export function test_AnimateBackgroundColor_FromString(done) { var expected = "Red"; var clr = new colorModule.Color(expected); - label.animate({ backgroundColor: expected, duration: 20 }) + label.animate({ backgroundColor: expected, duration: 5 }) .then(() => { TKUnit.assert((label.backgroundColor).equals(clr)); done(); @@ -329,7 +329,7 @@ export function test_AnimateBackgroundColor_FromString(done) { export function test_AnimateTranslate(done) { let label = prepareTest(); - label.animate({ translate: { x: 100, y: 200 }, duration: 20 }) + label.animate({ translate: { x: 100, y: 200 }, duration: 5 }) .then(() => { TKUnit.assertEqual(label.translateX, 100, "label.translateX"); TKUnit.assertEqual(label.translateY, 200, "label.translateY"); @@ -344,7 +344,7 @@ export function test_AnimateTranslate(done) { export function test_AnimateScale(done) { let label = prepareTest(); - label.animate({ scale: { x: 2, y: 3 }, duration: 20 }) + label.animate({ scale: { x: 2, y: 3 }, duration: 5 }) .then(() => { TKUnit.assertEqual(label.scaleX, 2, "label.scaleX"); TKUnit.assertEqual(label.scaleY, 3, "label.scaleY"); @@ -359,7 +359,7 @@ export function test_AnimateScale(done) { export function test_AnimateRotate(done) { let label = prepareTest(); - label.animate({ rotate: 123, duration: 20 }) + label.animate({ rotate: 123, duration: 5 }) .then(() => { TKUnit.assertEqual(label.rotate, 123, "label.rotate"); assertIOSNativeTransformIsCorrect(label); @@ -377,7 +377,7 @@ export function test_AnimateTranslateScaleAndRotateSimultaneously(done) { translate: { x: 100, y: 200 }, scale: { x: 2, y: 3 }, rotate: 123, - duration: 20 + duration: 5 }) .then(() => { TKUnit.assertEqual(label.translateX, 100, "label.translateX"); @@ -396,12 +396,12 @@ export function test_AnimateTranslateScaleAndRotateSimultaneously(done) { export function test_AnimateTranslateScaleAndRotateSequentially(done) { let label = prepareTest(); - label.animate({ translate: { x: 100, y: 200 }, duration: 20 }) + label.animate({ translate: { x: 100, y: 200 }, duration: 5 }) .then(() => { TKUnit.assertEqual(label.translateX, 100, "label.translateX"); TKUnit.assertEqual(label.translateY, 200, "label.translateY"); assertIOSNativeTransformIsCorrect(label); - return label.animate({ scale: { x: 2, y: 3 }, duration: 20 }); + return label.animate({ scale: { x: 2, y: 3 }, duration: 5 }); }) .then(() => { TKUnit.assertEqual(label.translateX, 100, "label.translateX"); @@ -409,7 +409,7 @@ export function test_AnimateTranslateScaleAndRotateSequentially(done) { TKUnit.assertEqual(label.scaleX, 2, "label.scaleX"); TKUnit.assertEqual(label.scaleY, 3, "label.scaleY"); assertIOSNativeTransformIsCorrect(label); - return label.animate({ rotate: 123, duration: 20 }); + return label.animate({ rotate: 123, duration: 5 }); }) .then(() => { TKUnit.assertEqual(label.translateX, 100, "label.translateX"); @@ -428,8 +428,8 @@ export function test_AnimateTranslateScaleAndRotateSequentially(done) { export function test_AnimationsAreAlwaysPlayed(done) { let label = prepareTest(); - var animation1 = label.createAnimation({ opacity: 0, duration: 20 }); - var animation2 = label.createAnimation({ opacity: 1, duration: 20 }); + var animation1 = label.createAnimation({ opacity: 0, duration: 5 }); + var animation2 = label.createAnimation({ opacity: 1, duration: 5 }); animation1.play() .then(() => { @@ -449,7 +449,7 @@ export function test_AnimationsAreAlwaysPlayed(done) { export function test_PlayPromiseIsResolvedWhenAnimationFinishes(done) { let label = prepareTest(); - var animation = label.createAnimation({ opacity: 0, duration: 20 }); + var animation = label.createAnimation({ opacity: 0, duration: 5 }); animation.play() .then(function onResolved() { @@ -464,7 +464,7 @@ export function test_PlayPromiseIsResolvedWhenAnimationFinishes(done) { export function test_PlayPromiseIsRejectedWhenAnimationIsCancelled(done) { let label = prepareTest(); - var animation = label.createAnimation({ opacity: 0, duration: 20 }); + var animation = label.createAnimation({ opacity: 0, duration: 5 }); animation.play() .then(function onResolved() { diff --git a/tests/app/ui/helper.ts b/tests/app/ui/helper.ts index 1046e6774..36ff92310 100644 --- a/tests/app/ui/helper.ts +++ b/tests/app/ui/helper.ts @@ -153,7 +153,14 @@ export function getClearCurrentPage(): Page { } export function waitUntilNavigatedFrom(oldPage: Page) { - TKUnit.waitUntilReady(() => getCurrentPage() && getCurrentPage() !== oldPage); + let completed = false; + function navigatedFrom(args) { + args.object.page.off("navigatedFrom", navigatedFrom); + completed = true; + } + + oldPage.on("navigatedFrom", navigatedFrom); + TKUnit.waitUntilReady(() => completed); } export function waitUntilLayoutReady(view: View): void { diff --git a/tests/app/ui/lifecycle/lifecycle-tests.ts b/tests/app/ui/lifecycle/lifecycle-tests.ts index 9dd91855f..c3346c8b0 100644 --- a/tests/app/ui/lifecycle/lifecycle-tests.ts +++ b/tests/app/ui/lifecycle/lifecycle-tests.ts @@ -111,7 +111,9 @@ export function test_navigating_away_does_not_excessively_reset() { const page2 = helper.navigateToModule("ui/lifecycle/pages/page-one"); - helper.waitUntilLayoutReady(page2); + if (!page2.isLayoutValid) { + helper.waitUntilLayoutReady(page2); + } // NOTE: Recycling may mess this up so feel free to change the test, // but ensure a reasonable amount of native setters were called when the views navigate away diff --git a/tests/app/ui/list-view/list-view-tests.ts b/tests/app/ui/list-view/list-view-tests.ts index 23fd0e23f..b6a671841 100644 --- a/tests/app/ui/list-view/list-view-tests.ts +++ b/tests/app/ui/list-view/list-view-tests.ts @@ -639,9 +639,8 @@ export class ListViewTest extends testModule.UITest { } public test_LoadedUnloaded() { - let listView = this.testView; - let count = 10; - let modifier = listView.ios ? 1 : 0; // iOS has one fake measure cell that raises loaded. + const listView = this.testView; + const count = 10; let items = new observableArray.ObservableArray(); for (let i = 0; i < count; i++) { @@ -664,10 +663,15 @@ export class ListViewTest extends testModule.UITest { this.waitUntilListViewReady(); helper.navigateWithHistory(() => new Page()); + for (let i = 0; i < count; i++) { + TKUnit.assertEqual(items.getItem(i).loadedCount, 1, "Loaded Count"); + TKUnit.assertEqual(items.getItem(i).unloadedCount, 1, "Unloaded Count"); + } + helper.goBack(); for (let i = 0; i < count; i++) { - TKUnit.assertEqual(items.getItem(i).loadedCount, 1 + modifier, "Loaded Count"); + TKUnit.assertEqual(items.getItem(i).loadedCount, 2, "Loaded Count"); TKUnit.assertEqual(items.getItem(i).unloadedCount, 1, "Unloaded Count"); } } diff --git a/tests/app/ui/page/page-tests-common.ts b/tests/app/ui/page/page-tests-common.ts index 5ccc57385..9a243003e 100644 --- a/tests/app/ui/page/page-tests-common.ts +++ b/tests/app/ui/page/page-tests-common.ts @@ -1,32 +1,27 @@ // >> article-require-page-module -import * as pageModule from "tns-core-modules/ui/page"; +import { Page, ShownModallyData, NavigatedData } from "tns-core-modules/ui/page"; // FrameModule is needed in order to have an option to navigate to the new page. -import * as frameModule from "tns-core-modules/ui/frame"; +import { topmost, NavigationEntry } from "tns-core-modules/ui/frame"; // << article-require-page-module +import { resolvePageFromEntry } from "tns-core-modules/ui/frame"; + // >> article-set-bindingcontext function pageLoaded(args) { - let page = args.object; + const page = args.object; page.bindingContext = { name: "Some name" }; } exports.pageLoaded = pageLoaded; // << article-set-bindingcontext import * as TKUnit from "../../TKUnit"; -import * as labelModule from "tns-core-modules/ui/label"; -import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout"; import * as helper from "../helper"; -import * as view from "tns-core-modules/ui/core/view"; -import * as observable from "tns-core-modules/data/observable"; -import { Page, ShownModallyData, NavigatedData } from "tns-core-modules/ui/page"; +import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout"; +import { View, PercentLength, Observable, unsetValue, EventData, isIOS } from "tns-core-modules/ui/core/view"; import { Label } from "tns-core-modules/ui/label"; -import { EventData } from "tns-core-modules/data/observable"; -import { PercentLength } from "tns-core-modules/ui/core/view"; -import * as platform from "tns-core-modules/platform"; -import { unsetValue } from "tns-core-modules/ui/core/view"; import { Color } from "tns-core-modules/color"; export function addLabelToPage(page: Page, text?: string) { - let label = new Label(); + const label = new Label(); label.text = text || "The quick brown fox jumps over the lazy dog."; page.content = label; } @@ -40,16 +35,11 @@ export function test_AfterPageLoaded_is_called_NativeInstance_is_created() { let label: Label; let nativeInstanceCreated = false; - let handler = function (data) { - if (label.ios || label.android) { - nativeInstanceCreated = true; - } - } - - let pageFactory = function (): Page { + const handler = (data) => nativeInstanceCreated = !!label.nativeViewProtected; + const pageFactory = () => { page = new Page(); page.id = `page_test_AfterPageLoaded_is_called_NativeInstance_is_created`; - page.on(view.View.loadedEvent, handler); + page.on(Label.loadedEvent, handler); label = new Label(); label.text = "Text"; @@ -60,7 +50,7 @@ export function test_AfterPageLoaded_is_called_NativeInstance_is_created() { helper.navigate(pageFactory); TKUnit.assertTrue(nativeInstanceCreated, "nativeInstanceCreated"); - page.off(view.View.loadedEvent, handler); + page.off(Label.loadedEvent, handler); } export function test_PageLoaded_is_called_once() { @@ -69,11 +59,11 @@ export function test_PageLoaded_is_called_once() { let page2: Page; let loaded = 0; - let handler = function (data) { + const handler = function (data) { loaded++; } - let pageFactory = function (): Page { + const pageFactory = function (): Page { page1 = new Page(); page1.id = `page1_test_PageLoaded_is_called_once`; addLabelToPage(page1, "Page 1"); @@ -83,49 +73,49 @@ export function test_PageLoaded_is_called_once() { helper.navigate(pageFactory); TKUnit.assertEqual(loaded, 0); - let pageFactory2 = function (): Page { + const pageFactory2 = function (): Page { page2 = new Page(); page2.id = `page2_test_PageLoaded_is_called_once`; addLabelToPage(page2, "Page 2"); - page2.on(view.View.loadedEvent, handler); + page2.on(Label.loadedEvent, handler); return page2; }; helper.navigate(pageFactory2); TKUnit.assertEqual(loaded, 1); - page2.off(view.View.loadedEvent, handler); + page2.off(Label.loadedEvent, handler); } export function test_NavigateToNewPage() { - // >> artivle-create-navigate-to-page - let currentPage; - let topFrame = frameModule.topmost(); - currentPage = topFrame.currentPage; + // >> article-create-navigate-to-page + + const topFrame = topmost(); + const currentPage = topFrame.currentPage; let testPage: Page; - let pageFactory = function (): Page { - testPage = new pageModule.Page(); - let label = new labelModule.Label(); + const pageFactory = function (): Page { + testPage = new Page(); + const label = new Label(); label.text = "The quick brown fox jumps over the lazy dog."; testPage.content = label; return testPage; }; - let navEntry = { + const navEntry = { create: pageFactory, animated: false }; topFrame.navigate(navEntry); - // << artivle-create-navigate-to-page + // << article-create-navigate-to-page - TKUnit.waitUntilReady(() => { return testPage.isLayoutValid }); + TKUnit.waitUntilReady(() => testPage.isLayoutValid); // >> article-navigating-backward topFrame.goBack(); // << article-navigating-backward - TKUnit.waitUntilReady(() => { return topFrame.currentPage !== null && topFrame.currentPage === currentPage }); + TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty()); TKUnit.assertNull(testPage.parent, "Page.parent should become undefined after navigating back"); TKUnit.assertNull(testPage._context, "Page._context should become undefined after navigating back"); TKUnit.assertFalse(testPage.isLoaded, "Page.isLoaded should become false after navigating back"); @@ -142,10 +132,11 @@ export function test_PageNavigation_EventSequence_WithoutTransition() { } function _test_PageNavigation_EventSequence(withTransition: boolean) { + const context = { property: "this is the context" }; + const eventSequence = []; + let testPage: Page; - let context = { property: "this is the context" }; - let eventSequence = []; - let pageFactory = function () { + const pageFactory = () => { testPage = new Page(); testPage.id = "testPage_test_PageNavigation_EventSequence"; addLabelToPage(testPage); @@ -155,15 +146,15 @@ function _test_PageNavigation_EventSequence(withTransition: boolean) { TKUnit.assertEqual(data.context, context, "navigatingTo: navigationContext"); }); - testPage.on(Page.loadedEvent, function (data: observable.EventData) { + testPage.on(Page.loadedEvent, function (data: EventData) { eventSequence.push("loaded"); - TKUnit.assertNotEqual(frameModule.topmost().currentPage, data.object); + TKUnit.assertNotEqual(topmost().currentPage, data.object); }); testPage.on(Page.navigatedToEvent, function (data: NavigatedData) { eventSequence.push("navigatedTo"); TKUnit.assertEqual(data.context, context, "navigatedTo : navigationContext"); - TKUnit.assertEqual(frameModule.topmost().currentPage, data.object); + TKUnit.assertEqual(topmost().currentPage, data.object); }); testPage.on(Page.navigatingFromEvent, function (data: NavigatedData) { @@ -183,54 +174,47 @@ function _test_PageNavigation_EventSequence(withTransition: boolean) { return testPage; }; - let navigationEntry: frameModule.NavigationEntry; - if (withTransition) { - navigationEntry = { - create: pageFactory, - context: context, - animated: true, - transition: { - name: "slide", - duration: 100, - } - } - } - else { - navigationEntry = { - create: pageFactory, - context: context, - animated: false - } + const navigationEntry: NavigationEntry = { + create: pageFactory, + context: context, + animated: withTransition, + transition: withTransition ? { + name: "slide", + duration: 10, + } : undefined } + helper.navigateWithEntry(navigationEntry); helper.goBack(); - let expectedEventSequence = ["navigatingTo", "loaded", "navigatedTo", "navigatingFrom", "unloaded", "navigatedFrom"]; + const expectedEventSequence = ["navigatingTo", "loaded", "navigatedTo", "navigatingFrom", "unloaded", "navigatedFrom"]; TKUnit.arrayAssert(eventSequence, expectedEventSequence, "Actual event sequence is not equal to expected. Actual: " + eventSequence + "; Expected: " + expectedEventSequence); } export function test_NavigateTo_WithContext() { - let currentPage = frameModule.topmost().currentPage; + const currentPage = topmost().currentPage; // >> article-pass-data - let testPage: pageModule.Page; - let pageFactory = function (): pageModule.Page { - testPage = new pageModule.Page(); - testPage.on(pageModule.Page.navigatedToEvent, function () { + let testPage: Page; + const pageFactory = function (): Page { + testPage = new Page(); + testPage.on(Page.navigatedToEvent, function () { //console.log(JSON.stringify(context)); }); return testPage; }; - let navEntry = { + + const navEntry = { create: pageFactory, context: "myContext", animated: false }; - let topFrame = frameModule.topmost(); + + const topFrame = topmost(); topFrame.navigate(navEntry); // << article-pass-data - TKUnit.waitUntilReady(() => topFrame.currentPage !== null && topFrame.currentPage !== currentPage && testPage.isLayoutValid); + TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty()); - let actualContextValue = testPage.navigationContext; + const actualContextValue = testPage.navigationContext; TKUnit.assertEqual(actualContextValue, "myContext"); helper.goBack(); @@ -239,34 +223,35 @@ export function test_NavigateTo_WithContext() { //https://github.com/NativeScript/NativeScript/issues/731 export function test_NavigateTo_WithBindingContext() { - let currentPage = frameModule.topmost().currentPage; + const currentPage = topmost().currentPage; let testPage: Page; let bindingContext; - let pageFactory = function (): Page { + const pageFactory = function (): Page { testPage = new Page(); - testPage.on(pageModule.Page.navigatingToEvent, function (args: NavigatedData) { + testPage.on(Page.navigatingToEvent, function (args: NavigatedData) { bindingContext = (args.object).bindingContext; }); return testPage; }; - let navEntry = { + + const navEntry = { create: pageFactory, bindingContext: "bindng context", animated: false }; - let topFrame = frameModule.topmost(); + + const topFrame = topmost(); topFrame.navigate(navEntry); - TKUnit.waitUntilReady(() => topFrame.currentPage !== null && topFrame.currentPage !== currentPage && testPage.isLayoutValid); + TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty()); helper.goBack(); TKUnit.assertEqual(bindingContext, navEntry.bindingContext, "The Page's bindingContext should be equal to the NavigationEntry.bindingContext property when navigating to."); } export function test_FrameBackStack_WhenNavigatingForwardAndBack() { - helper.navigate(() => new Page()); let testPage: Page; - let pageFactory = function () { + const pageFactory = function () { testPage = new Page(); testPage.id = "testPage_test_FrameBackStack_WhenNavigatingForwardAndBack"; addLabelToPage(testPage); @@ -275,7 +260,7 @@ export function test_FrameBackStack_WhenNavigatingForwardAndBack() { helper.navigateWithHistory(pageFactory); - let topFrame = frameModule.topmost(); + const topFrame = topmost(); TKUnit.assertEqual(topFrame.backStack.length, 1); TKUnit.assertTrue(topFrame.canGoBack(), "topFrame.canGoBack() should be true"); @@ -286,38 +271,38 @@ export function test_FrameBackStack_WhenNavigatingForwardAndBack() { } export function test_LoadPageFromModule() { - let topFrame = frameModule.topmost(); + const topFrame = topmost(); helper.navigateToModule("ui/page/test-page-module"); TKUnit.assert(topFrame.currentPage.content instanceof Label, "Content of the test page should be a Label created within test-page-module."); - let testLabel =