mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
app
This commit is contained in:
@ -1,2 +1 @@
|
|||||||
<Frame defaultPage="main-page">
|
<Frame defaultPage="home/home-page"></Frame>
|
||||||
</Frame>
|
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
/*
|
@import '~@nativescript/theme/css/core.css';
|
||||||
In NativeScript, the app.css file is where you place CSS rules that
|
@import '~@nativescript/theme/css/default.css';
|
||||||
you would like to apply to your entire application. Check out
|
|
||||||
http://docs.nativescript.org/ui/styling for a full list of the CSS
|
|
||||||
selectors and properties you can use to style UI components.
|
|
||||||
|
|
||||||
/*
|
.btn {
|
||||||
In many cases you may want to use the NativeScript core theme instead
|
|
||||||
of writing your own CSS rules. You can learn more about the
|
|
||||||
NativeScript core theme at https://github.com/nativescript/theme
|
|
||||||
The imported CSS rules must precede all other types of rules.
|
|
||||||
*/
|
|
||||||
@import "~@nativescript/theme/css/core.css";
|
|
||||||
@import "~@nativescript/theme/css/default.css";
|
|
||||||
|
|
||||||
/* Place any CSS rules you want to apply on both iOS and Android here.
|
|
||||||
This is where the vast majority of your CSS code goes. */
|
|
||||||
|
|
||||||
/*
|
|
||||||
The following CSS rule changes the font size of all Buttons that have the
|
|
||||||
"-primary" class modifier.
|
|
||||||
*/
|
|
||||||
Button.-primary {
|
|
||||||
font-size: 18;
|
font-size: 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.home-panel{
|
||||||
|
vertical-align: center;
|
||||||
|
font-size: 20;
|
||||||
|
margin: 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-label{
|
||||||
|
margin-bottom: 15;
|
||||||
|
}
|
||||||
|
63
e2e/appTestTs/app/home/data.ts
Executable file
63
e2e/appTestTs/app/home/data.ts
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
export function getData() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const dataCopy = JSON.parse(JSON.stringify(data));
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const featured: boolean = i % 5 === 0;
|
||||||
|
(<any>dataCopy[i]).featured = featured;
|
||||||
|
|
||||||
|
const randomImageId = Math.floor(Math.random() * 5);
|
||||||
|
(<any>dataCopy[i]).image = "~/images/news" + randomImageId + ".jpg";
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(dataCopy);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" },
|
||||||
|
{ "id": 1, "title": "Aliquam erat volutpat.", "date": "12/26/2018" },
|
||||||
|
{ "id": 2, "title": "Aenean fermentum.", "date": "5/8/2018" },
|
||||||
|
{ "id": 3, "title": "Vestibulum rutrum rutrum neque.", "date": "6/19/2018" }
|
||||||
|
];
|
43
e2e/appTestTs/app/home/home-page.css
Executable file
43
e2e/appTestTs/app/home/home-page.css
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
.action-bar {
|
||||||
|
background-color: #12127D;
|
||||||
|
color: #BACECA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group {
|
||||||
|
background-color: #7A7878;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-featured {
|
||||||
|
background-color: #BACECA;
|
||||||
|
margin: 15 5 15 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-regular {
|
||||||
|
margin: 0 5 0 5;
|
||||||
|
padding: 5;
|
||||||
|
background-color: #BACECA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-regular {
|
||||||
|
color: #142D63;
|
||||||
|
padding: 0 0 0 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-regular {
|
||||||
|
color: #4F77A5;
|
||||||
|
padding: 0 0 0 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-featured {
|
||||||
|
margin: 20 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-featured {
|
||||||
|
color: #142D63;
|
||||||
|
padding: 5 10 5 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-featured {
|
||||||
|
color: #4F77A5;
|
||||||
|
padding: 5 10 5 10;
|
||||||
|
}
|
87
e2e/appTestTs/app/home/home-page.ts
Executable file
87
e2e/appTestTs/app/home/home-page.ts
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
import { EventData } from "tns-core-modules/data/observable";
|
||||||
|
import { Page, View } from "tns-core-modules/ui/page";
|
||||||
|
|
||||||
|
import { HomeViewModel } from "./home-view-model";
|
||||||
|
import { ListView, ItemEventData } from "tns-core-modules/ui/list-view/list-view";
|
||||||
|
|
||||||
|
import * as TKUnit from "./tk-unit";
|
||||||
|
import { Frame } from "@nativescript/core/ui/frame/frame";
|
||||||
|
|
||||||
|
export function onPageLoaded(args: EventData) {
|
||||||
|
console.log("---> Page Loaded!");
|
||||||
|
// let page = <Page>args.object;
|
||||||
|
// let listView = <ListView>page.getViewById("list-view");
|
||||||
|
// let indexes = {};
|
||||||
|
// let completed = false;
|
||||||
|
|
||||||
|
// listView.on(ListView.itemLoadingEvent, function (args: ItemEventData) {
|
||||||
|
// if (!args.view) {
|
||||||
|
// // args.view = new Label();
|
||||||
|
// console.log("---> Fail!!!");
|
||||||
|
// }
|
||||||
|
// // (<Label>args.view).text = "item " + args.index;
|
||||||
|
|
||||||
|
// indexes[args.index] = indexes[args.index] ? indexes[args.index] + 1 : 1;
|
||||||
|
// completed = args.index === (listView.items.length - 1);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let expected = 1;
|
||||||
|
// TKUnit.waitUntilReady(() => completed);
|
||||||
|
// console.log("---> Yeah!");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onItemLoading(args: EventData) {
|
||||||
|
console.log("--->", args.object);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onListViewLoaded(args: EventData) {
|
||||||
|
console.log("---> onListViewLoaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onTemplateLoaded(args: EventData) {
|
||||||
|
console.log("---> Template Loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onGridLoaded(args: EventData) {
|
||||||
|
console.log("---> Grid Loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function navigatingTo(args: EventData) {
|
||||||
|
const page = <Page>args.object;
|
||||||
|
|
||||||
|
page.bindingContext = new HomeViewModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function selectItemTemplate(item, index, items) {
|
||||||
|
return item.featured ? "featured" : "regular";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function waitUntilNavigatedTo(page: Page, action: Function) {
|
||||||
|
let completed = false;
|
||||||
|
function navigatedTo(args) {
|
||||||
|
args.object.page.off("navigatedTo", navigatedTo);
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
page.on("navigatedTo", navigatedTo);
|
||||||
|
action();
|
||||||
|
TKUnit.waitUntilReady(() => completed, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitUntilNavigatedFrom(action: Function, topFrame?: Frame) {
|
||||||
|
const currentPage = topFrame ? topFrame.currentPage : Frame.topmost().currentPage;
|
||||||
|
let completed = false;
|
||||||
|
function navigatedFrom(args) {
|
||||||
|
args.object.page.off("navigatedFrom", navigatedFrom);
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage.on("navigatedFrom", navigatedFrom);
|
||||||
|
action();
|
||||||
|
TKUnit.waitUntilReady(() => completed);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitUntilLayoutReady(view: View): void {
|
||||||
|
TKUnit.waitUntilReady(() => view.isLayoutValid);
|
||||||
|
}
|
28
e2e/appTestTs/app/home/home-page.xml
Executable file
28
e2e/appTestTs/app/home/home-page.xml
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
<Page navigatingTo="navigatingTo" class="page" xmlns="http://www.nativescript.org/tns.xsd" loaded="onPageLoaded">
|
||||||
|
|
||||||
|
<!-- <ActionBar title="News" class="action-bar">
|
||||||
|
</ActionBar> -->
|
||||||
|
|
||||||
|
<GridLayout>
|
||||||
|
<ListView id="list-view" class="list-group" items="{{ dataItems }}"
|
||||||
|
itemTemplateSelector="selectItemTemplate" separatorColor="transparent"
|
||||||
|
loadMoreItems="{{ onLoadMoreItems }}" loaded="onListViewLoaded" itemLoading="onItemLoading">
|
||||||
|
<ListView.itemTemplates>
|
||||||
|
<template key="regular">
|
||||||
|
<GridLayout>
|
||||||
|
<GridLayout rows="40, 30" columns="70, *" class="list-item-regular" loaded="onGridLoaded">
|
||||||
|
<Image row="0" col="0" rowSpan="2" src="{{ image }}"
|
||||||
|
stretch="aspectFill" />
|
||||||
|
<Label row="0" col="1" text="{{ title }}" class="h3 title-regular"
|
||||||
|
textWrap="true" height="40" />
|
||||||
|
<Label row="1" col="1" text="{{ date }}" class="h4 date-regular"
|
||||||
|
textWrap="true" height="30" />
|
||||||
|
</GridLayout>
|
||||||
|
</GridLayout>
|
||||||
|
</template>
|
||||||
|
</ListView.itemTemplates>
|
||||||
|
</ListView>
|
||||||
|
|
||||||
|
<ActivityIndicator busy="{{ isBusy }}" class="activity-indicator" />
|
||||||
|
</GridLayout>
|
||||||
|
</Page>
|
27
e2e/appTestTs/app/home/home-view-model.ts
Executable file
27
e2e/appTestTs/app/home/home-view-model.ts
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
import { ObservableProperty } from "../observable-property-decorator";
|
||||||
|
import { ObservableArray } from "tns-core-modules/data/observable-array";
|
||||||
|
import { Observable } from "tns-core-modules/data/observable";
|
||||||
|
|
||||||
|
import { getData } from "./data";
|
||||||
|
|
||||||
|
export class HomeViewModel extends Observable {
|
||||||
|
@ObservableProperty() isBusy: boolean = true;
|
||||||
|
@ObservableProperty() dataItems: ObservableArray<any>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isBusy = true;
|
||||||
|
this.dataItems = new ObservableArray<any>();
|
||||||
|
|
||||||
|
getData().then((doctorsData) => {
|
||||||
|
this.dataItems.push(doctorsData);
|
||||||
|
this.isBusy = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoadMoreItems(args) {
|
||||||
|
getData().then((doctorsData) => {
|
||||||
|
this.dataItems.push(doctorsData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
464
e2e/appTestTs/app/home/tk-unit.ts
Normal file
464
e2e/appTestTs/app/home/tk-unit.ts
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
|
||||||
|
/* Notes:
|
||||||
|
|
||||||
|
1. all test function names should begin with 'test'
|
||||||
|
2. (if exists) at the beginning of module test setUpModule() module function is called
|
||||||
|
3. (if exists) at the beginning of each test setUp() module function is called
|
||||||
|
4. tests should use TKUnit.assert(condition, message) to mark error. If no assert fails test is successful
|
||||||
|
5. (if exists) at the end of each test tearDown() module function is called
|
||||||
|
6. (if exists) at the end of module test tearDownModule() module function is called
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as application from "@nativescript/core/application";
|
||||||
|
import * as platform from "@nativescript/core/platform";
|
||||||
|
import * as timer from "@nativescript/core/timer";
|
||||||
|
import * as trace from "@nativescript/core/trace";
|
||||||
|
import * as types from "@nativescript/core/utils/types";
|
||||||
|
|
||||||
|
const sdkVersion = parseInt(platform.device.sdkVersion);
|
||||||
|
|
||||||
|
trace.enable();
|
||||||
|
|
||||||
|
export interface TestInfoEntry {
|
||||||
|
testFunc: () => void;
|
||||||
|
instance: Object;
|
||||||
|
isTest: boolean;
|
||||||
|
testName: string;
|
||||||
|
isPassed: boolean;
|
||||||
|
errorMessage: string;
|
||||||
|
testTimeout: number;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function time(): number {
|
||||||
|
if (global.android) {
|
||||||
|
return java.lang.System.nanoTime() / 1000000; // 1 ms = 1000000 ns
|
||||||
|
} else {
|
||||||
|
return CACurrentMediaTime() * 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function write(message: string, type?: number) {
|
||||||
|
trace.write(message, trace.categories.Test, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest(testInfo: TestInfoEntry) {
|
||||||
|
let start = time();
|
||||||
|
let duration;
|
||||||
|
try {
|
||||||
|
if (testInfo.instance) {
|
||||||
|
testInfo.testFunc.apply(testInfo.instance);
|
||||||
|
} else {
|
||||||
|
testInfo.testFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testInfo.isTest) {
|
||||||
|
duration = time() - start;
|
||||||
|
testInfo.duration = duration;
|
||||||
|
write(`--- [${testInfo.testName}] OK, duration: ${duration.toFixed(2)}`, trace.messageType.info);
|
||||||
|
testInfo.isPassed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (testInfo.isTest) {
|
||||||
|
duration = time() - start;
|
||||||
|
testInfo.duration = duration;
|
||||||
|
write(`--- [${testInfo.testName}] FAILED: ${e.message}, Stack: ${e.stack}, duration: ${duration.toFixed(2)}`, trace.messageType.error);
|
||||||
|
testInfo.isPassed = false;
|
||||||
|
testInfo.errorMessage = e.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TestFailure {
|
||||||
|
moduleName: string;
|
||||||
|
testName: string;
|
||||||
|
errorMessage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TestModuleRunResult {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
succeeded: number;
|
||||||
|
failed: Array<TestFailure>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let testsQueue: Array<TestInfoEntry>;
|
||||||
|
const defaultTimeout = 5000;
|
||||||
|
|
||||||
|
function runAsync(testInfo: TestInfoEntry, recursiveIndex: number, testTimeout?: number) {
|
||||||
|
let error;
|
||||||
|
let isDone = false;
|
||||||
|
let handle;
|
||||||
|
const testStartTime = time();
|
||||||
|
//write("--- [" + testInfo.testName + "] Started at: " + testStartTime, trace.messageType.info);
|
||||||
|
const doneCallback = (e: Error) => {
|
||||||
|
if (e) {
|
||||||
|
error = e;
|
||||||
|
} else {
|
||||||
|
isDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeout = testTimeout || testInfo.testTimeout || defaultTimeout;
|
||||||
|
|
||||||
|
let duration;
|
||||||
|
const checkFinished = () => {
|
||||||
|
duration = time() - testStartTime;
|
||||||
|
testInfo.duration = duration;
|
||||||
|
if (isDone) {
|
||||||
|
write(`--- [${testInfo.testName}] OK, duration: ${duration.toFixed(2)}`, trace.messageType.info);
|
||||||
|
testInfo.isPassed = true;
|
||||||
|
runTests(testsQueue, recursiveIndex + 1);
|
||||||
|
} else if (error) {
|
||||||
|
write(`--- [${testInfo.testName}] FAILED: ${error.message}, duration: ${duration.toFixed(2)}`, trace.messageType.error);
|
||||||
|
testInfo.errorMessage = error.message;
|
||||||
|
runTests(testsQueue, recursiveIndex + 1);
|
||||||
|
} else {
|
||||||
|
const testEndTime = time();
|
||||||
|
if (testEndTime - testStartTime > timeout) {
|
||||||
|
write(`--- [${testInfo.testName}] TIMEOUT, duration: ${duration.toFixed(2)}`, trace.messageType.error);
|
||||||
|
testInfo.errorMessage = "Test timeout.";
|
||||||
|
runTests(testsQueue, recursiveIndex + 1);
|
||||||
|
} else {
|
||||||
|
setTimeout(checkFinished, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (testInfo.instance) {
|
||||||
|
testInfo.testFunc.apply(testInfo.instance, [doneCallback]);
|
||||||
|
} else {
|
||||||
|
const func: any = testInfo.testFunc;
|
||||||
|
func(doneCallback);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
doneCallback(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(checkFinished, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runTests(tests: Array<TestInfoEntry>, recursiveIndex) {
|
||||||
|
testsQueue = tests;
|
||||||
|
|
||||||
|
for (let i = recursiveIndex; i < testsQueue.length; i++) {
|
||||||
|
const testEntry = testsQueue[i];
|
||||||
|
|
||||||
|
if (testEntry.testFunc.length > 0) {
|
||||||
|
return runAsync(testEntry, i);
|
||||||
|
} else {
|
||||||
|
runTest(testEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
let equals = false;
|
||||||
|
if (types.isUndefined(actual) && types.isUndefined(expected)) {
|
||||||
|
equals = true;
|
||||||
|
} else if (!types.isNullOrUndefined(actual) && !types.isNullOrUndefined(expected)) {
|
||||||
|
if (types.isFunction(actual.equals)) {
|
||||||
|
// Use the equals method
|
||||||
|
if (actual.equals(expected)) {
|
||||||
|
equals = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
equals = actual === expected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equals) {
|
||||||
|
throw new Error(message + " Actual: " + actual + " Not_Expected: " + expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertEqual<T extends { equals?(arg: T): boolean } | any>(actual: T, expected: T, message: string = '') {
|
||||||
|
if (!types.isNullOrUndefined(actual)
|
||||||
|
&& !types.isNullOrUndefined(expected)
|
||||||
|
&& types.getClass(actual) === types.getClass(expected)
|
||||||
|
&& types.isFunction(actual.equals)) {
|
||||||
|
|
||||||
|
// Use the equals method
|
||||||
|
if (!actual.equals(expected)) {
|
||||||
|
throw new Error(`${message} Actual: <${actual}>(${typeof (actual)}). Expected: <${expected}>(${typeof (expected)})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (actual !== expected) {
|
||||||
|
throw new Error(`${message} Actual: <${actual}>(${typeof (actual)}). Expected: <${expected}>(${typeof (expected)})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert two json like objects are deep equal.
|
||||||
|
*/
|
||||||
|
export function assertDeepEqual(actual, expected, message: string = '', path: any[] = []): void {
|
||||||
|
let typeofActual: string = typeof actual;
|
||||||
|
let typeofExpected: string = typeof expected;
|
||||||
|
if (typeofActual !== typeofExpected) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " types of actual " + typeofActual + " and expected " + typeofExpected + " differ.");
|
||||||
|
} else if (typeofActual === "object" || typeofActual === "array") {
|
||||||
|
if (expected instanceof Map) {
|
||||||
|
if (actual instanceof Map) {
|
||||||
|
expected.forEach((value, key) => {
|
||||||
|
if (actual.has(key)) {
|
||||||
|
assertDeepEqual(actual.get(key), value, message, path.concat([key]));
|
||||||
|
} else {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " expected Map has key '" + key + "' but actual does not.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actual.forEach((value, key) => {
|
||||||
|
if (!expected.has(key)) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " actual Map has key '" + key + "' but expected does not.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " expected is Map but actual is not.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expected instanceof Set) {
|
||||||
|
if (actual instanceof Set) {
|
||||||
|
expected.forEach(i => {
|
||||||
|
if (!actual.has(i)) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " expected Set has item '" + i + "' but actual does not.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actual.forEach(i => {
|
||||||
|
if (!expected.has(i)) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " actual Set has item '" + i + "' but expected does not.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " expected is Set but actual is not.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let key in actual) {
|
||||||
|
if (!(key in expected)) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " found unexpected key " + key + ".");
|
||||||
|
}
|
||||||
|
assertDeepEqual(actual[key], expected[key], message, path.concat([key]));
|
||||||
|
}
|
||||||
|
for (let key in expected) {
|
||||||
|
if (!(key in actual)) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " expected a key " + key + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (actual !== expected) {
|
||||||
|
throw new Error(message + ' ' + "At /" + path.join("/") + " actual: '" + actual + "' and expected: '" + expected + "' differ.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertDeepSuperset(actual, expected, path: any[] = []): void {
|
||||||
|
let typeofActual: string = typeof actual;
|
||||||
|
let typeofExpected: string = typeof expected;
|
||||||
|
if (typeofActual !== typeofExpected) {
|
||||||
|
throw new Error("At /" + path.join("/") + " types of actual " + typeofActual + " and expected " + typeofExpected + " differ.");
|
||||||
|
} else if (typeofActual === "object" || typeofActual === "array") {
|
||||||
|
for (let key in expected) {
|
||||||
|
if (!(key in actual)) {
|
||||||
|
throw new Error("At /" + path.join("/") + " expected a key " + key + ".");
|
||||||
|
}
|
||||||
|
assertDeepSuperset(actual[key], expected[key], path.concat([key]));
|
||||||
|
}
|
||||||
|
} else if (actual !== expected) {
|
||||||
|
throw new Error("At /" + path.join("/") + " actual: '" + actual + "' and expected: '" + expected + "' differ.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 assertMatches(actual: string, expected: RegExp, message?: string) {
|
||||||
|
if (expected.test(actual) !== true) {
|
||||||
|
throw new Error(`"${actual}" doesn't match "${expected}". ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function arrayAssert(actual: Array<any>, expected: Array<any>, message?: string) {
|
||||||
|
if (actual.length !== expected.length) {
|
||||||
|
throw new Error(message + " Actual array length: " + actual.length + " Expected array length: " + expected.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertThrows(testFunc: () => void, assertMessage?: string, expectedMessage?: string) {
|
||||||
|
const re = expectedMessage ? new RegExp(`^${expectedMessage}$`) : null;
|
||||||
|
return assertThrowsRegExp(testFunc, assertMessage, re);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertThrowsRegExp(testFunc: () => void, assertMessage?: string, expectedMessage?: RegExp) {
|
||||||
|
let actualError: Error;
|
||||||
|
try {
|
||||||
|
testFunc();
|
||||||
|
} catch (e) {
|
||||||
|
actualError = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!actualError) {
|
||||||
|
throw new Error("Missing expected exception. " + assertMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedMessage && !expectedMessage.test(actualError.message)) {
|
||||||
|
throw new Error("Got unwanted exception. Actual error: " + actualError.message + " Expected to match: " + expectedMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wait(seconds: number): void {
|
||||||
|
waitUntilReady(() => false, seconds, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function waitUntilReady(isReady: () => boolean, timeoutSec: number = 3, shouldThrow: boolean = true) {
|
||||||
|
if (!isReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (application.ios) {
|
||||||
|
const timeoutMs = timeoutSec * 1000;
|
||||||
|
let totalWaitTime = 0;
|
||||||
|
while (true) {
|
||||||
|
const begin = time();
|
||||||
|
const currentRunLoop = NSRunLoop.currentRunLoop;
|
||||||
|
currentRunLoop.limitDateForMode(currentRunLoop.currentMode);
|
||||||
|
if (isReady()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalWaitTime += (time() - begin);
|
||||||
|
if (totalWaitTime >= timeoutMs) {
|
||||||
|
if (shouldThrow) {
|
||||||
|
throw new Error("waitUntilReady Timeout.");
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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)
|
||||||
|
let nextMethod;
|
||||||
|
let targetField;
|
||||||
|
let prepared;
|
||||||
|
|
||||||
|
function prepareModal() {
|
||||||
|
if (prepared) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = clsMsg.getDeclaredFields();
|
||||||
|
for (let i = 0; i < fields.length; i++) {
|
||||||
|
if (fields[i].getName() === "target") {
|
||||||
|
targetField = fields[i];
|
||||||
|
targetField.setAccessible(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doModalAndroid(quitLoop: () => boolean, timeoutSec: number, shouldThrow: boolean = true) {
|
||||||
|
if (!quitLoop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareModal();
|
||||||
|
|
||||||
|
const queue = android.os.Looper.myQueue();
|
||||||
|
|
||||||
|
let quit = false;
|
||||||
|
let timeout = false;
|
||||||
|
timer.setTimeout(() => {
|
||||||
|
quit = true;
|
||||||
|
timeout = true;
|
||||||
|
}, timeoutSec * 1000);
|
||||||
|
|
||||||
|
let msg;
|
||||||
|
|
||||||
|
while (!quit) {
|
||||||
|
msg = nextMethod.invoke(queue, null);
|
||||||
|
if (msg) {
|
||||||
|
const target = targetField.get(msg);
|
||||||
|
if (!target) {
|
||||||
|
quit = true;
|
||||||
|
} else {
|
||||||
|
target.dispatchMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdkVersion < 21) {//https://code.google.com/p/android-test-kit/issues/detail?id=84
|
||||||
|
msg.recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldThrow && timeout) {
|
||||||
|
throw new Error("waitUntilReady Timeout.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quit && quitLoop()) {
|
||||||
|
quit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
e2e/appTestTs/app/images/news0.jpg
Executable file
BIN
e2e/appTestTs/app/images/news0.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
BIN
e2e/appTestTs/app/images/news1.jpg
Executable file
BIN
e2e/appTestTs/app/images/news1.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 147 KiB |
BIN
e2e/appTestTs/app/images/news2.jpg
Executable file
BIN
e2e/appTestTs/app/images/news2.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
BIN
e2e/appTestTs/app/images/news3.jpg
Executable file
BIN
e2e/appTestTs/app/images/news3.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
e2e/appTestTs/app/images/news4.jpg
Executable file
BIN
e2e/appTestTs/app/images/news4.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 120 KiB |
33
e2e/appTestTs/app/observable-property-decorator.ts
Executable file
33
e2e/appTestTs/app/observable-property-decorator.ts
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
This file defines a decorator you can use to enable two-way
|
||||||
|
binding on view-model properties.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
import { ObservableProperty } from "../observable-property-decorator";
|
||||||
|
|
||||||
|
@ObservableProperty() myProperty: boolean = true;
|
||||||
|
|
||||||
|
Read more at https://www.nativescript.org/blog/nativescript-observable-magic-string-property-name-be-gone
|
||||||
|
**/
|
||||||
|
import { Observable } from 'tns-core-modules/data/observable';
|
||||||
|
|
||||||
|
export function ObservableProperty() {
|
||||||
|
return (target: Observable, propertyKey: string) => {
|
||||||
|
Object.defineProperty(target, propertyKey, {
|
||||||
|
get() {
|
||||||
|
return this["_" + propertyKey];
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
if (this["_" + propertyKey] === value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this["_" + propertyKey] = value;
|
||||||
|
this.notifyPropertyChange(propertyKey, value);
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
@ -1,9 +1,46 @@
|
|||||||
import { EventData } from "tns-core-modules/data/observable";
|
import { EventData, fromObject } from "tns-core-modules/data/observable";
|
||||||
|
import { ListView, ItemEventData } from "tns-core-modules/ui/list-view";
|
||||||
import { Page } from "tns-core-modules/ui/page";
|
import { Page } from "tns-core-modules/ui/page";
|
||||||
|
|
||||||
import { HelloWorldModel } from "./main-view-model";
|
export function onNavigatingTo(args: EventData) {
|
||||||
|
|
||||||
export function navigatingTo(args: EventData) {
|
|
||||||
const page = <Page>args.object;
|
const page = <Page>args.object;
|
||||||
page.bindingContext = new HelloWorldModel();
|
const vm = fromObject({
|
||||||
|
// Setting the listview binding source
|
||||||
|
myTitles: [
|
||||||
|
{ title: "The Da Vinci Code" },
|
||||||
|
{ title: "Harry Potter and the Chamber of Secrets" },
|
||||||
|
{ title: "The Alchemist" },
|
||||||
|
{ title: "The Godfather" },
|
||||||
|
{ title: "Goodnight Moon" },
|
||||||
|
{ title: "The Hobbit" },
|
||||||
|
{ title: "The Da Vinci Code" },
|
||||||
|
{ title: "Harry Potter and the Chamber of Secrets" },
|
||||||
|
{ title: "The Alchemist" },
|
||||||
|
{ title: "The Godfather" },
|
||||||
|
{ title: "Goodnight Moon" },
|
||||||
|
{ title: "The Hobbit" },
|
||||||
|
{ title: "The Da Vinci Code" },
|
||||||
|
{ title: "Harry Potter and the Chamber of Secrets" },
|
||||||
|
{ title: "The Alchemist" },
|
||||||
|
{ title: "The Godfather" },
|
||||||
|
{ title: "Goodnight Moon" },
|
||||||
|
{ title: "The Hobbit" },
|
||||||
|
{ title: "The Da Vinci Code" },
|
||||||
|
{ title: "Harry Potter and the Chamber of Secrets" },
|
||||||
|
{ title: "The Alchemist" },
|
||||||
|
{ title: "The Godfather" },
|
||||||
|
{ title: "Goodnight Moon" },
|
||||||
|
{ title: "The Hobbit" },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
page.bindingContext = vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onListViewLoaded(args: EventData) {
|
||||||
|
const listView = <ListView>args.object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onItemTap(args: ItemEventData) {
|
||||||
|
const index = args.index;
|
||||||
|
console.log(`Second ListView item tap ${index}`);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" id="page" navigatingTo="navigatingTo">
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" id="page" navigatingTo="onNavigatingTo">
|
||||||
<StackLayout id="stack">
|
<StackLayout id="stack">
|
||||||
<Label id="label" text="{{ message }}"></Label>
|
|
||||||
|
<!-- <Button id="label" text="{{ message }}" height="100" width="100" color="blue" backgroundColor="red"></Button> -->
|
||||||
|
|
||||||
|
<ListView items="{{ myTitles }}"
|
||||||
|
itemTap="onItemTap"
|
||||||
|
loaded="{{ onListViewLoaded }}"
|
||||||
|
separatorColor="orangered" rowHeight="50"
|
||||||
|
class="list-group" id="listView" row="2">
|
||||||
|
<ListView.itemTemplate>
|
||||||
|
<!-- The item template can only have a single root view container (e.g. GriLayout, StackLayout, etc.) -->
|
||||||
|
<StackLayout class="list-group-item">
|
||||||
|
<Label text="{{ title || 'Downloading...' }}" textWrap="true" class="title" />
|
||||||
|
<Label text="{{ title || 'Downloading...' }}" textWrap="true" class="title" />
|
||||||
|
<Label text="{{ title || 'Downloading...' }}" textWrap="true" class="title" />
|
||||||
|
</StackLayout>
|
||||||
|
</ListView.itemTemplate>
|
||||||
|
</ListView>
|
||||||
|
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</Page>
|
</Page>
|
||||||
|
138
e2e/appTestTs/app/tests/asdf.ts
Normal file
138
e2e/appTestTs/app/tests/asdf.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { renderFixture } from "@nativescript/core/testing";
|
||||||
|
import { assert } from "chai";
|
||||||
|
import { Page } from "@nativescript/core/ui/page/page";
|
||||||
|
import { ListView } from "@nativescript/core/ui/list-view/list-view";
|
||||||
|
import { waitUntilLayoutReady } from "../home/home-page";
|
||||||
|
import { waitUntilReady } from "../home/tk-unit";
|
||||||
|
|
||||||
|
// const snippet = `
|
||||||
|
// <StackLayout id="stack">
|
||||||
|
// <Label id="label" text="Label"></Label>
|
||||||
|
// </StackLayout>`
|
||||||
|
|
||||||
|
function asdf() {
|
||||||
|
// `delay` returns a promise
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
// Only `delay` is able to resolve or reject the promise
|
||||||
|
// setTimeout(function () {
|
||||||
|
// resolve(42); // After 3 seconds, resolve the promise with value 42
|
||||||
|
console.log("---> pro");
|
||||||
|
const page = <Page>renderFixture(true, "home/home-page");
|
||||||
|
const listView = <ListView>page.getViewById("list-view");
|
||||||
|
waitUntilReady(() => listView.isLayoutValid);
|
||||||
|
console.log("---> middle");
|
||||||
|
waitUntilReady(() => page.isLayoutValid);
|
||||||
|
console.log("---> end");
|
||||||
|
resolve(page);
|
||||||
|
// }, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("---> describe", function () {
|
||||||
|
// // it("---> snippet", function () {
|
||||||
|
// // const rootView = renderFixture(false, snippet);
|
||||||
|
// // const label = <Label>rootView.getViewById("label");
|
||||||
|
|
||||||
|
// // const actualText = label.text;
|
||||||
|
// // const expectedText = "Labe";
|
||||||
|
|
||||||
|
// // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // it("---> page", function () {
|
||||||
|
// // const rootView = renderFixture(true, "test-page");
|
||||||
|
// // const label = <Label>rootView.getViewById("label");
|
||||||
|
|
||||||
|
// // const actualText = label.text;
|
||||||
|
// // const expectedText = "Test Page";
|
||||||
|
|
||||||
|
// // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
|
// // });
|
||||||
|
|
||||||
|
it("---> navigate to module", function (done) {
|
||||||
|
|
||||||
|
asdf().then(p => {
|
||||||
|
console.log("---> page", p);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
// const page = <Page>renderFixture(true, "home/home-page");
|
||||||
|
// listView.on(ListView.itemLoadingEvent, function (args) {
|
||||||
|
// console.log("aaa");
|
||||||
|
// counter++;
|
||||||
|
// console.log("bbb");
|
||||||
|
// console.log(counter);
|
||||||
|
// console.log(listView.items.length);
|
||||||
|
// if (counter === listView.items.length) {
|
||||||
|
// console.log("sdf");
|
||||||
|
// // waitUntilLayoutReady(listView.items[0]);
|
||||||
|
// // waitUntilReady(() => );
|
||||||
|
// console.log("yey");
|
||||||
|
// done();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// console.log("--->", listView);
|
||||||
|
// const listView = <ListView>page.getViewById("list-view");
|
||||||
|
// waitUntilReady(() => listView.isLayoutValid);
|
||||||
|
// waitUntilReady(() => page.isLayoutValid);
|
||||||
|
|
||||||
|
// const p = new Promise(function (resolve, reject) {
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.l}og("--->", listView.items.length);
|
||||||
|
// const items = listView.items;
|
||||||
|
// console.log("--->", items.size);
|
||||||
|
|
||||||
|
// const actualText = label.text;
|
||||||
|
// const size = label.size;
|
||||||
|
// const height = label.height;
|
||||||
|
// const width = label.width;
|
||||||
|
// const position = label.position;
|
||||||
|
// const style = label.style.backgroundColor;
|
||||||
|
// const color = label.style.color;
|
||||||
|
|
||||||
|
// const nativeView = label.nativeView;
|
||||||
|
// const x = label.nativeView.originX;
|
||||||
|
|
||||||
|
// const asdf = label.getLocationInWindow();
|
||||||
|
|
||||||
|
// const expectedText = "42 taps";
|
||||||
|
// // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
|
// console.log("---> sssize", size);
|
||||||
|
// console.log("---> height", height);
|
||||||
|
// console.log("---> width", width);
|
||||||
|
// console.log("---> position", position);
|
||||||
|
// console.log("---> style", style);
|
||||||
|
// console.log("---> color", color);
|
||||||
|
// console.log("---> nativeView", nativeView);
|
||||||
|
// console.log("---> x", x);
|
||||||
|
// console.log("---> asdf", asdf);
|
||||||
|
});
|
||||||
|
|
||||||
|
// // it("this is a test", () => {
|
||||||
|
// // // .when()
|
||||||
|
// // // .waitUntilReady()
|
||||||
|
// // // .waitUntilLayoutIsValid()
|
||||||
|
// // setup("test-module").then(fixture => {
|
||||||
|
// // const rootView = fixture.root;
|
||||||
|
// // const label = rootView.getViewById("label");
|
||||||
|
// // const labelText = label.text;
|
||||||
|
// // const labelHeight = label.labelHeight;
|
||||||
|
// // // label size
|
||||||
|
// // // label position
|
||||||
|
// // // label.style. ...
|
||||||
|
// // // label.nativeView
|
||||||
|
// // // label vizualise
|
||||||
|
|
||||||
|
// // // assert
|
||||||
|
|
||||||
|
// // // list view async loading
|
||||||
|
// // // list view async loading
|
||||||
|
|
||||||
|
// // // tab view
|
||||||
|
// // // tab view
|
||||||
|
// // });
|
||||||
|
// // });
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -1,40 +1,156 @@
|
|||||||
import { Builder, Label, Frame } from "@nativescript/core/ui";
|
// import { renderFixture } from "@nativescript/core/testing";
|
||||||
|
// import { assert } from "chai";
|
||||||
|
// import { Page } from "@nativescript/core/ui/page/page";
|
||||||
|
// import { ListView } from "@nativescript/core/ui/list-view/list-view";
|
||||||
|
// import { waitUntilLayoutReady } from "../home/home-page";
|
||||||
|
// import { waitUntilReady } from "../home/tk-unit";
|
||||||
|
|
||||||
import { navigateToModule, asdf, render } from "@nativescript/core/testing/ui-helper";
|
// // const snippet = `
|
||||||
import { assert } from "@nativescript/core/testing/tk-unit";
|
// // <StackLayout id="stack">
|
||||||
|
// // <Label id="label" text="Label"></Label>
|
||||||
|
// // </StackLayout>`
|
||||||
|
|
||||||
const snippet = `
|
// describe("---> describe", function () {
|
||||||
<StackLayout id="stack">
|
// // // it("---> snippet", function () {
|
||||||
<Label id="label" text="Label"></Label>
|
// // // const rootView = renderFixture(false, snippet);
|
||||||
</StackLayout>`
|
// // // const label = <Label>rootView.getViewById("label");
|
||||||
|
|
||||||
describe("---> describe", function () {
|
// // // const actualText = label.text;
|
||||||
// it("---> snippet", function (done) {
|
// // // const expectedText = "Labe";
|
||||||
// const rootView = Builder.parse(snippet);
|
|
||||||
// const label = <Label>rootView.getViewById("label");
|
|
||||||
|
|
||||||
// const actualText = label.text;
|
// // // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
// const expectedText = "Label";
|
// // // });
|
||||||
|
|
||||||
// assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
// // // it("---> page", function () {
|
||||||
// done();
|
// // // const rootView = renderFixture(true, "test-page");
|
||||||
// });
|
// // // const label = <Label>rootView.getViewById("label");
|
||||||
|
|
||||||
// it("---> page", function () {
|
// // // const actualText = label.text;
|
||||||
// const rootView = Builder.load("test-page");
|
// // // const expectedText = "Test Page";
|
||||||
// const label = <Label>rootView.getViewById("label");
|
|
||||||
|
|
||||||
// const actualText = label.text;
|
// // // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
// const expectedText = "Test Page Stack Label";
|
// // // });
|
||||||
|
|
||||||
// assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
// it("---> navigate to module", async () => {
|
||||||
// });
|
// // const page = <Page>renderFixture(true, "home/home-page");
|
||||||
|
// // listView.on(ListView.itemLoadingEvent, function (args) {
|
||||||
|
// // console.log("aaa");
|
||||||
|
// // counter++;
|
||||||
|
// // console.log("bbb");
|
||||||
|
// // console.log(counter);
|
||||||
|
// // console.log(listView.items.length);
|
||||||
|
// // if (counter === listView.items.length) {
|
||||||
|
// // console.log("sdf");
|
||||||
|
// // // waitUntilLayoutReady(listView.items[0]);
|
||||||
|
// // // waitUntilReady(() => );
|
||||||
|
// // console.log("yey");
|
||||||
|
// // done();
|
||||||
|
// // }
|
||||||
|
// // });
|
||||||
|
// // console.log("--->", listView);
|
||||||
|
// // const listView = <ListView>page.getViewById("list-view");
|
||||||
|
// // waitUntilReady(() => listView.isLayoutValid);
|
||||||
|
// // waitUntilReady(() => page.isLayoutValid);
|
||||||
|
|
||||||
|
// // const p = new Promise(function (resolve, reject) {
|
||||||
|
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// async function asdf() {
|
||||||
|
// // `delay` returns a promise
|
||||||
|
// return new Promise(function (resolve, reject) {
|
||||||
|
// // Only `delay` is able to resolve or reject the promise
|
||||||
|
// // setTimeout(function () {
|
||||||
|
// // resolve(42); // After 3 seconds, resolve the promise with value 42
|
||||||
|
// console.log("---> pro");
|
||||||
|
// const page = <Page>renderFixture(true, "home/home-page");
|
||||||
|
// const listView = <ListView>page.getViewById("list-view");
|
||||||
|
// waitUntilReady(() => listView.isLayoutValid);
|
||||||
|
// console.log("---> middle");
|
||||||
|
// waitUntilReady(() => page.isLayoutValid);
|
||||||
|
// console.log("---> end");
|
||||||
|
// resolve(page);
|
||||||
|
// // }, 0);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function good(page) {
|
||||||
|
// console.log("---> page", page);
|
||||||
|
// // cb();
|
||||||
|
// // done();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function bad(e) {
|
||||||
|
// console.error(e);
|
||||||
|
// // cb();done
|
||||||
|
// // done();
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const awef = await asdf();
|
||||||
|
// good(awef);
|
||||||
|
// // .then(
|
||||||
|
// // good,
|
||||||
|
// // bad
|
||||||
|
// // // ).then(
|
||||||
|
// // // done()
|
||||||
|
// // );
|
||||||
|
// // done();
|
||||||
|
|
||||||
|
// // console.log("--->", listView.items.length);
|
||||||
|
// // const items = listView.items;
|
||||||
|
// // console.log("--->", items.size);
|
||||||
|
|
||||||
|
// // const actualText = label.text;
|
||||||
|
// // const size = label.size;
|
||||||
|
// // const height = label.height;
|
||||||
|
// // const width = label.width;
|
||||||
|
// // const position = label.position;
|
||||||
|
// // const style = label.style.backgroundColor;
|
||||||
|
// // const color = label.style.color;
|
||||||
|
|
||||||
|
// // const nativeView = label.nativeView;
|
||||||
|
// // const x = label.nativeView.originX;
|
||||||
|
|
||||||
|
// // const asdf = label.getLocationInWindow();
|
||||||
|
|
||||||
|
// // const expectedText = "42 taps";
|
||||||
|
// // // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
|
// // console.log("---> sssize", size);
|
||||||
|
// // console.log("---> height", height);
|
||||||
|
// // console.log("---> width", width);
|
||||||
|
// // console.log("---> position", position);
|
||||||
|
// // console.log("---> style", style);
|
||||||
|
// // console.log("---> color", color);
|
||||||
|
// // console.log("---> nativeView", nativeView);
|
||||||
|
// // console.log("---> x", x);
|
||||||
|
// // console.log("---> asdf", asdf);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // // it("this is a test", () => {
|
||||||
|
// // // // .when()
|
||||||
|
// // // // .waitUntilReady()
|
||||||
|
// // // // .waitUntilLayoutIsValid()
|
||||||
|
// // // setup("test-module").then(fixture => {
|
||||||
|
// // // const rootView = fixture.root;
|
||||||
|
// // // const label = rootView.getViewById("label");
|
||||||
|
// // // const labelText = label.text;
|
||||||
|
// // // const labelHeight = label.labelHeight;
|
||||||
|
// // // // label size
|
||||||
|
// // // // label position
|
||||||
|
// // // // label.style. ...
|
||||||
|
// // // // label.nativeView
|
||||||
|
// // // // label vizualise
|
||||||
|
|
||||||
|
// // // // assert
|
||||||
|
|
||||||
|
// // // // list view async loading
|
||||||
|
// // // // list view async loading
|
||||||
|
|
||||||
|
// // // // tab view
|
||||||
|
// // // // tab view
|
||||||
|
// // // });
|
||||||
|
// // // });
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
it("---> navigate to module", () => {
|
|
||||||
const page = navigateToModule("test-module");
|
|
||||||
const label = page.getViewById("label");
|
|
||||||
const actualText = label.text;
|
|
||||||
const expectedText = "42 taps left";
|
|
||||||
assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
186
e2e/appTestTs/app/tests/lv-tests.ts
Normal file
186
e2e/appTestTs/app/tests/lv-tests.ts
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
// // import { RadListView, ListViewEventData, ListViewLinearLayout, ListViewScrollDirection } from "nativescript-ui-listview";
|
||||||
|
// import { topmost } from "tns-core-modules/ui/frame";
|
||||||
|
// import { Page } from "tns-core-modules/ui/page";
|
||||||
|
// import { Label } from "tns-core-modules/ui/label";
|
||||||
|
// import { isAndroid, isIOS } from "tns-core-modules/platform";
|
||||||
|
// import { ObservableArray } from "tns-core-modules/data/observable-array/observable-array";
|
||||||
|
// import * as TKUnit from "../home/tk-unit";
|
||||||
|
// import { ListView } from "tns-core-modules/ui/list-view/list-view";
|
||||||
|
|
||||||
|
// interface Item {
|
||||||
|
// text: string;
|
||||||
|
// age: number;
|
||||||
|
// loadedCount: number;
|
||||||
|
// unloadedCount: number;
|
||||||
|
// onViewLoaded: (args) => void;
|
||||||
|
// onViewUnloaded: (args) => void;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function generateCollection(count: number): ObservableArray<string> {
|
||||||
|
// let obsArray = new ObservableArray<any>();
|
||||||
|
// for (let i = 0; i < count; i++) {
|
||||||
|
// obsArray.push(" Item " + i);
|
||||||
|
// }
|
||||||
|
// return obsArray;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function generateItemsForMultipleTemplatesTests(count: number): ObservableArray<Item> {
|
||||||
|
// let items = new ObservableArray<Item>();
|
||||||
|
// for (let i = 0; i < count; i++) {
|
||||||
|
// items.push({
|
||||||
|
// text: "Item " + i,
|
||||||
|
// age: i,
|
||||||
|
// loadedCount: 0,
|
||||||
|
// unloadedCount: 0,
|
||||||
|
// onViewLoaded: function onViewLoaded(args) {
|
||||||
|
// this.loadedCount++;
|
||||||
|
// },
|
||||||
|
// onViewUnloaded: function onViewUnloaded(args) {
|
||||||
|
// this.unloadedCount++;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// return items;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function navigate(listView) {
|
||||||
|
// topmost().navigate({
|
||||||
|
// create: () => {
|
||||||
|
// const page = new Page();
|
||||||
|
// page.content = listView;
|
||||||
|
// return page;
|
||||||
|
// },
|
||||||
|
// clearHistory: true
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// describe("example tests", () => {
|
||||||
|
// let listView = null;
|
||||||
|
|
||||||
|
// beforeEach(() => {
|
||||||
|
// listView = new ListView();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// afterEach(() => {
|
||||||
|
// // if (listView) {
|
||||||
|
// // listView.removeAllListeners();
|
||||||
|
// // }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it("test_default_TNS_values", () => {
|
||||||
|
// assert.isUndefined(listView.items);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it("test_set_items_to_array_loads_all_items", (done) => {
|
||||||
|
// const colors = ["red", "green", "blue"];
|
||||||
|
// const indexes = {};
|
||||||
|
// let counter = 0;
|
||||||
|
// listView.items = colors;
|
||||||
|
// listView.on(ListView.itemLoadingEvent, function (args) {
|
||||||
|
// console.log("aaa");
|
||||||
|
// counter++;
|
||||||
|
// console.log("bbb");
|
||||||
|
// console.log(counter);
|
||||||
|
// console.log(listView.items.length);
|
||||||
|
// if (counter === listView.items.length) {
|
||||||
|
// console.log("sdf");
|
||||||
|
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("---> counter", counter);
|
||||||
|
// console.log("---");
|
||||||
|
// navigate(listView);
|
||||||
|
// console.log("+++");
|
||||||
|
// console.log("---> counter", listView.items.length);
|
||||||
|
// done();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // it("test_set_items_to_obs_array_loads_items_horizontally", (done) => {
|
||||||
|
// // const linearLayout = new ListViewLinearLayout();
|
||||||
|
// // linearLayout.scrollDirection = ListViewScrollDirection.Vertical;
|
||||||
|
// // listView.listViewLayout = linearLayout;
|
||||||
|
|
||||||
|
// // // let isScrolled = false;
|
||||||
|
// // const loadedIndexes = [];
|
||||||
|
// // const items = generateCollection(50);
|
||||||
|
// // listView.items = items;
|
||||||
|
|
||||||
|
// // listView.on(ListView.itemLoadingEvent, function (args: ListViewEventData) {
|
||||||
|
// // loadedIndexes[args.index] = true;
|
||||||
|
|
||||||
|
// // if (args.index === 48) {
|
||||||
|
// // done();
|
||||||
|
// // }
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // navigate(listView);
|
||||||
|
|
||||||
|
// // TKUnit.waitUntilReady(() => loadedIndexes[5] === true);
|
||||||
|
// // listView.scrollToIndex(49);
|
||||||
|
// // TKUnit.waitUntilReady(() => loadedIndexes[48] === true);
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // it("test_set_items_to_obs_array_scroll_horizontally", () => {
|
||||||
|
// // const linearLayout = new ListViewLinearLayout();
|
||||||
|
// // listView.listViewLayout = linearLayout;
|
||||||
|
// // linearLayout.scrollDirection = ListViewScrollDirection.Vertical;
|
||||||
|
|
||||||
|
// // const loadedIndexes = [];
|
||||||
|
// // listView.on(RadListView.itemLoadingEvent, function (args: ListViewEventData) {
|
||||||
|
// // loadedIndexes[args.index] = true;
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // const items = generateCollection(50);
|
||||||
|
// // listView.items = items;
|
||||||
|
|
||||||
|
// // navigate(listView);
|
||||||
|
|
||||||
|
// // TKUnit.waitUntilReady(() => loadedIndexes[5] === true);
|
||||||
|
// // listView.scrollToIndex(35);
|
||||||
|
// // TKUnit.waitUntilReady(() => loadedIndexes[35] === true);
|
||||||
|
|
||||||
|
// // // assert the next item is not loaded
|
||||||
|
// // assert.isFalse(!!loadedIndexes[36]);
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // it("test_getScrollOffset_respects_safe_areas", () => {
|
||||||
|
// // const loadedIndexes = [];
|
||||||
|
// // listView.on(RadListView.itemLoadingEvent, function (args: ListViewEventData) {
|
||||||
|
// // loadedIndexes[args.index] = true;
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // const items = generateCollection(10);
|
||||||
|
// // listView.items = items;
|
||||||
|
|
||||||
|
// // navigate(listView);
|
||||||
|
|
||||||
|
// // TKUnit.waitUntilReady(() => loadedIndexes[5] === true);
|
||||||
|
// // assert.isTrue(listView.getScrollOffset() === 0);
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // it("test_set_items_to_huge_obs_array", () => {
|
||||||
|
// // listView.itemTemplate = `
|
||||||
|
// // <StackLayout>
|
||||||
|
// // <Label text='{{ text }}' />
|
||||||
|
// // <Label text='{{ age }}' />
|
||||||
|
// // </StackLayout>
|
||||||
|
// // `;
|
||||||
|
|
||||||
|
// // const start = TKUnit.time();
|
||||||
|
|
||||||
|
// // const items = generateItemsForMultipleTemplatesTests(10000);
|
||||||
|
// // listView.items = items;
|
||||||
|
|
||||||
|
// // const loadedIndexes = [];
|
||||||
|
// // listView.on(RadListView.itemLoadingEvent, function (args: ListViewEventData) {
|
||||||
|
// // loadedIndexes[args.index] = true;
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // TKUnit.waitUntilReady(() => loadedIndexes[10] === true);
|
||||||
|
// // assert.isTrue(loadedIndexes[10]);
|
||||||
|
|
||||||
|
// // const end = TKUnit.time() - start;
|
||||||
|
// // console.log("================= END ============= ", end);
|
||||||
|
// // });
|
||||||
|
// });
|
@ -38,24 +38,24 @@
|
|||||||
// // });
|
// // });
|
||||||
|
|
||||||
// // it("---> module", function (done) {
|
// // it("---> module", function (done) {
|
||||||
// // // render done
|
// // render done
|
||||||
// // asdf("test-module").then((fixture) => {
|
// asdf("test-module").then((done) => {
|
||||||
// // const label = fixture.getViewById("label");
|
// const label = fixture.getViewById("label");
|
||||||
// // const actualText = label.text;
|
// const actualText = label.text;
|
||||||
// // const expectedText = "42 taps ";
|
// const expectedText = "42 taps ";
|
||||||
// // assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
// assert(actualText === expectedText, `Actual: ${actualText}, Expected: ${expectedText}`);
|
||||||
// // done();
|
// done();
|
||||||
// // });//.finally(done);
|
// });//.finally(done);
|
||||||
// // });
|
// // });
|
||||||
|
|
||||||
// // it('resolves', (done) => {
|
// it('resolves', (done) => {
|
||||||
// // const resolvingPromise = new Promise((resolve) => {
|
// const resolvingPromise = new Promise((resolve) => {
|
||||||
// // resolve('promiseresolved');
|
// resolve('promiseresolved');
|
||||||
// // });
|
// });
|
||||||
// // resolvingPromise.then((result) => {
|
// resolvingPromise.then((result) => {
|
||||||
// // expect(result).to.equal('promise resolved');
|
// expect(result).to.equal('promise resolved');
|
||||||
// // }).finally(done);
|
// }).finally(done);
|
||||||
// // });
|
// });
|
||||||
// // });
|
// // });
|
||||||
|
|
||||||
// const resolvingPromise = new Promise((resolve) =>
|
// const resolvingPromise = new Promise((resolve) =>
|
||||||
|
Reference in New Issue
Block a user