diff --git a/e2e/renderer/.gitignore b/e2e/renderer/.gitignore new file mode 100644 index 000000000..d3df84cc8 --- /dev/null +++ b/e2e/renderer/.gitignore @@ -0,0 +1,8 @@ +platforms +node_modules +hooks + +app/**/*.js +e2e/**/*.js +test-results.xml + diff --git a/e2e/renderer/app/App_Resources/Android/AndroidManifest.xml b/e2e/renderer/app/App_Resources/Android/AndroidManifest.xml new file mode 100644 index 000000000..9db832151 --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/e2e/renderer/app/App_Resources/Android/app.gradle b/e2e/renderer/app/App_Resources/Android/app.gradle new file mode 100644 index 000000000..b9e2b2982 --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/app.gradle @@ -0,0 +1,23 @@ +// Add your native dependencies here: + +// Uncomment to add recyclerview-v7 dependency +//dependencies { +// compile 'com.android.support:recyclerview-v7:+' +//} + +android { + defaultConfig { + generatedDensities = [] + applicationId = "org.nativescript.renderer" + + //override supported platforms + // ndk { + // abiFilters.clear() + // abiFilters "armeabi-v7a" + // } + + } + aaptOptions { + additionalParameters "--no-version-vectors" + } +} diff --git a/e2e/renderer/app/App_Resources/Android/drawable-hdpi/background.png b/e2e/renderer/app/App_Resources/Android/drawable-hdpi/background.png new file mode 100644 index 000000000..eb381c258 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-hdpi/background.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-hdpi/icon.png b/e2e/renderer/app/App_Resources/Android/drawable-hdpi/icon.png new file mode 100755 index 000000000..1034356e2 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-hdpi/icon.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-hdpi/logo.png b/e2e/renderer/app/App_Resources/Android/drawable-hdpi/logo.png new file mode 100644 index 000000000..5218f4c90 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-hdpi/logo.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-ldpi/background.png b/e2e/renderer/app/App_Resources/Android/drawable-ldpi/background.png new file mode 100644 index 000000000..748b2adf5 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-ldpi/background.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-ldpi/icon.png b/e2e/renderer/app/App_Resources/Android/drawable-ldpi/icon.png new file mode 100755 index 000000000..ddfc17a71 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-ldpi/icon.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-ldpi/logo.png b/e2e/renderer/app/App_Resources/Android/drawable-ldpi/logo.png new file mode 100644 index 000000000..b9e102a76 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-ldpi/logo.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-mdpi/background.png b/e2e/renderer/app/App_Resources/Android/drawable-mdpi/background.png new file mode 100644 index 000000000..efeaf2907 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-mdpi/background.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-mdpi/icon.png b/e2e/renderer/app/App_Resources/Android/drawable-mdpi/icon.png new file mode 100755 index 000000000..486e41091 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-mdpi/icon.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-mdpi/logo.png b/e2e/renderer/app/App_Resources/Android/drawable-mdpi/logo.png new file mode 100644 index 000000000..626338766 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-mdpi/logo.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-nodpi/splash_screen.xml b/e2e/renderer/app/App_Resources/Android/drawable-nodpi/splash_screen.xml new file mode 100644 index 000000000..ada77f92c --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/drawable-nodpi/splash_screen.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/background.png b/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/background.png new file mode 100644 index 000000000..612bbd072 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/background.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/icon.png b/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/icon.png new file mode 100644 index 000000000..f29188209 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/icon.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/logo.png b/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/logo.png new file mode 100644 index 000000000..ad8ee2f4b Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xhdpi/logo.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/background.png b/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/background.png new file mode 100644 index 000000000..0fa88e235 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/background.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/icon.png b/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/icon.png new file mode 100644 index 000000000..4f69cb25b Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/icon.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/logo.png b/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/logo.png new file mode 100644 index 000000000..668327832 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xxhdpi/logo.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/background.png b/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/background.png new file mode 100644 index 000000000..c650f6438 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/background.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/icon.png b/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/icon.png new file mode 100644 index 000000000..50887a856 Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/icon.png differ diff --git a/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/logo.png b/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/logo.png new file mode 100644 index 000000000..fa6331c8d Binary files /dev/null and b/e2e/renderer/app/App_Resources/Android/drawable-xxxhdpi/logo.png differ diff --git a/e2e/renderer/app/App_Resources/Android/values-v21/colors.xml b/e2e/renderer/app/App_Resources/Android/values-v21/colors.xml new file mode 100644 index 000000000..a64641a9d --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/values-v21/colors.xml @@ -0,0 +1,4 @@ + + + #3d5afe + \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/Android/values-v21/styles.xml b/e2e/renderer/app/App_Resources/Android/values-v21/styles.xml new file mode 100644 index 000000000..dac8727c8 --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/values-v21/styles.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/Android/values/colors.xml b/e2e/renderer/app/App_Resources/Android/values/colors.xml new file mode 100644 index 000000000..74ad8829c --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/values/colors.xml @@ -0,0 +1,7 @@ + + + #F5F5F5 + #757575 + #33B5E5 + #272734 + \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/Android/values/styles.xml b/e2e/renderer/app/App_Resources/Android/values/styles.xml new file mode 100644 index 000000000..1e8c7f29b --- /dev/null +++ b/e2e/renderer/app/App_Resources/Android/values/styles.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..1953734f4 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,92 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 000000000..9e15af09d Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 000000000..7b9e55537 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png new file mode 100644 index 000000000..76f61ec1f Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 000000000..15b06db11 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 000000000..585065f94 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png new file mode 100644 index 000000000..a450c421d Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png new file mode 100644 index 000000000..457b6d94c Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png new file mode 100644 index 000000000..fa5a6ac86 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 000000000..94abcf70d Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 000000000..2e71dd3a0 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png new file mode 100644 index 000000000..4abc9ec50 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/Contents.json b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/Contents.json new file mode 100644 index 000000000..da4a164c9 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 000000000..4414bad08 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,158 @@ +{ + "images" : [ + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "Default-736h@3x.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "Default-Landscape@3x.png", + "minimum-system-version" : "8.0", + "orientation" : "landscape", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "667h", + "filename" : "Default-667h@2x.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default@2x.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "Default-568h@2x.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "Default-Portrait.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "Default-Landscape.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "Default-Portrait@2x.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "Default-Landscape@2x.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default.png", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default@2x.png", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "filename" : "Default-568h@2x.png", + "extent" : "full-screen", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "Default-Portrait.png", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "Default-Landscape.png", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "Default-Portrait@2x.png", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "Default-Landscape@2x.png", + "extent" : "full-screen", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png new file mode 100644 index 000000000..d7f17fcd2 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png new file mode 100644 index 000000000..b88415405 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png new file mode 100644 index 000000000..faab4b631 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png new file mode 100644 index 000000000..3365ba3cd Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png new file mode 100644 index 000000000..a44945c1a Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png new file mode 100644 index 000000000..e6dca6269 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png new file mode 100644 index 000000000..1a5007962 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png new file mode 100644 index 000000000..73d8b920f Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png new file mode 100644 index 000000000..9f1f6ce3e Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png new file mode 100644 index 000000000..514fc5cde Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json new file mode 100644 index 000000000..4f4e9c506 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchScreen-AspectFill.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchScreen-AspectFill@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png new file mode 100644 index 000000000..c293f9c7a Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png new file mode 100644 index 000000000..233693a6e Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json new file mode 100644 index 000000000..23c0ffd7a --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchScreen-Center.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchScreen-Center@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png new file mode 100644 index 000000000..a5a775a2b Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png new file mode 100644 index 000000000..154c19343 Binary files /dev/null and b/e2e/renderer/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png differ diff --git a/e2e/renderer/app/App_Resources/iOS/Info.plist b/e2e/renderer/app/App_Resources/iOS/Info.plist new file mode 100644 index 000000000..ea3e3ea23 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiresFullScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/e2e/renderer/app/App_Resources/iOS/LaunchScreen.storyboard b/e2e/renderer/app/App_Resources/iOS/LaunchScreen.storyboard new file mode 100644 index 000000000..2ad9471e1 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/LaunchScreen.storyboard @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/e2e/renderer/app/App_Resources/iOS/build.xcconfig b/e2e/renderer/app/App_Resources/iOS/build.xcconfig new file mode 100644 index 000000000..4b0118490 --- /dev/null +++ b/e2e/renderer/app/App_Resources/iOS/build.xcconfig @@ -0,0 +1,7 @@ +// You can add custom settings here +// for example you can uncomment the following line to force distribution code signing +// CODE_SIGN_IDENTITY = iPhone Distribution +// To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html +// DEVELOPMENT_TEAM = YOUR_TEAM_ID; +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; +ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; diff --git a/e2e/renderer/app/README.md b/e2e/renderer/app/README.md new file mode 100644 index 000000000..ebe60c416 --- /dev/null +++ b/e2e/renderer/app/README.md @@ -0,0 +1,5 @@ +# NativeScript Tutorial Angular Template + +This repo serves as the starting point for NativeScript’s [Angular Getting Started Guide](https://docs.nativescript.org/angular/tutorial/ng-chapter-0). + +Please file any issues with this template on the [NativeScript/docs repository](https://github.com/nativescript/docs), which is where the tutorial content lives. \ No newline at end of file diff --git a/e2e/renderer/app/app-routing.module.ts b/e2e/renderer/app/app-routing.module.ts new file mode 100644 index 000000000..576923862 --- /dev/null +++ b/e2e/renderer/app/app-routing.module.ts @@ -0,0 +1,75 @@ +import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core"; +import { NativeScriptRouterModule } from "nativescript-angular/router"; + +import { ListComponent } from "./list.component"; +import { NgForComponent } from "./ngfor.component"; +import { NgForOfComponent } from "./ngforof.component"; +import { NgIfNoLayoutComponent } from "./ngif-no-layout.component"; +import { NgIfInbetweenComponent } from "./ngif-inbetween.component"; +import { NgIfElseComponent } from "./ngifelse.component"; +import { NgIfThenElseComponent } from "./ngif-then-else.component"; +import { NgIfSubsequent } from "./ngif-subsequent.component"; +import { ContentViewComponent } from "./content-view.component"; + +export const routes = [ + { + path: "", + redirectTo: "/list", + pathMatch: "full" + }, + { + path: "list", + component: ListComponent, + }, + { + path: "ngfor", + component: NgForComponent, + }, + { + path: "ngforof", + component: NgForOfComponent, + }, + { + path: "ngif-no-layout", + component: NgIfNoLayoutComponent, + }, + { + path: "ngif-inbetween", + component: NgIfInbetweenComponent, + }, + { + path: "ngifelse", + component: NgIfElseComponent, + }, + { + path: "ngif-then-else", + component: NgIfThenElseComponent, + }, + { + path: "ngif-subsequent", + component: NgIfSubsequent, + }, + { + path: "content-view", + component: ContentViewComponent, + }, +]; + +export const navigatableComponents = [ + ListComponent, + NgForComponent, + NgForOfComponent, + NgIfNoLayoutComponent, + NgIfInbetweenComponent, + NgIfElseComponent, + NgIfThenElseComponent, + NgIfSubsequent, + ContentViewComponent, +]; + +@NgModule({ + imports: [ NativeScriptRouterModule.forRoot(routes) ], + exports: [ NativeScriptRouterModule ], +}) +export class AppRoutingModule { } + diff --git a/e2e/renderer/app/app.component.ts b/e2e/renderer/app/app.component.ts new file mode 100644 index 000000000..2311d63e0 --- /dev/null +++ b/e2e/renderer/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + template: `` +}) +export class AppComponent { } + diff --git a/e2e/renderer/app/app.css b/e2e/renderer/app/app.css new file mode 100644 index 000000000..e69de29bb diff --git a/e2e/renderer/app/app.module.ts b/e2e/renderer/app/app.module.ts new file mode 100644 index 000000000..c5bf7e4dd --- /dev/null +++ b/e2e/renderer/app/app.module.ts @@ -0,0 +1,33 @@ +import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core"; +import { NativeScriptModule } from "nativescript-angular/nativescript.module"; + +import { + AppRoutingModule, + navigatableComponents, +} from "./app-routing.module"; + +import { AppComponent } from "./app.component"; +import { ItemsService } from "./items.service"; + +import { rendererTraceCategory, viewUtilCategory } from "nativescript-angular/trace"; +import { setCategories, enable } from "trace"; +setCategories(rendererTraceCategory + "," + viewUtilCategory); +enable(); + +@NgModule({ + declarations: [ + AppComponent, + ...navigatableComponents, + ], + bootstrap: [AppComponent], + providers: [ + ItemsService + ], + imports: [ + NativeScriptModule, + AppRoutingModule, + ], + schemas: [NO_ERRORS_SCHEMA], +}) +export class AppModule {} + diff --git a/e2e/renderer/app/content-view.component.ts b/e2e/renderer/app/content-view.component.ts new file mode 100644 index 000000000..6ec92a1ba --- /dev/null +++ b/e2e/renderer/app/content-view.component.ts @@ -0,0 +1,31 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "my-app", + template: ` + + + + + + + + + + + + + + + + + ` +}) +export class ContentViewComponent { + public show = true; + + toggle() { + this.show = !this.show; + } +} + diff --git a/e2e/renderer/app/items-accessor.ts b/e2e/renderer/app/items-accessor.ts new file mode 100644 index 000000000..58774bd5a --- /dev/null +++ b/e2e/renderer/app/items-accessor.ts @@ -0,0 +1,18 @@ +import { ItemsService } from "./items.service"; + +export class ItemsAccessor { + public items: number[]; + + constructor(public itemsService: ItemsService) { + this.items = itemsService.getAll(); + } + + add() { + this.items = this.itemsService.add(this.items); + } + + remove(item) { + this.items = this.itemsService.remove(this.items, item); + } + +} diff --git a/e2e/renderer/app/items.service.ts b/e2e/renderer/app/items.service.ts new file mode 100644 index 000000000..94a33ef3f --- /dev/null +++ b/e2e/renderer/app/items.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class ItemsService { + private items = [ 0 ]; + + getAll() { + return [...this.items]; + } + + add(items) { + return [ + ...items, + items.length, + ]; + } + + remove(items, item?: number) { + const index = item ? items.indexOf(item) : items.length - 1; + + return this.removeAt(items, index); + } + + private removeAt(items: any[], index: number) { + items = [ + ...items.slice(0, index), + ...items.slice(index + 1), + ]; + + console.log(`Removed ${index}th element`); + + return items; + } +} diff --git a/e2e/renderer/app/list.component.ts b/e2e/renderer/app/list.component.ts new file mode 100644 index 000000000..ec4ca839c --- /dev/null +++ b/e2e/renderer/app/list.component.ts @@ -0,0 +1,18 @@ +import { Component } from "@angular/core"; + +@Component({ + template: ` + + + + + + + + + + + ` +}) +export class ListComponent { +} diff --git a/e2e/renderer/app/main.aot.ts b/e2e/renderer/app/main.aot.ts new file mode 100644 index 000000000..98bf134fc --- /dev/null +++ b/e2e/renderer/app/main.aot.ts @@ -0,0 +1,4 @@ +import { platformNativeScript } from "nativescript-angular/platform-static"; +import { AppModuleNgFactory } from "./app.module.ngfactory"; + +platformNativeScript().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/e2e/renderer/app/main.ts b/e2e/renderer/app/main.ts new file mode 100644 index 000000000..639bfd513 --- /dev/null +++ b/e2e/renderer/app/main.ts @@ -0,0 +1,4 @@ +import { platformNativeScriptDynamic } from "nativescript-angular/platform"; +import { AppModule } from "./app.module"; + +platformNativeScriptDynamic().bootstrapModule(AppModule); diff --git a/e2e/renderer/app/ngfor.component.ts b/e2e/renderer/app/ngfor.component.ts new file mode 100644 index 000000000..a3a6238fc --- /dev/null +++ b/e2e/renderer/app/ngfor.component.ts @@ -0,0 +1,21 @@ +import { Component } from "@angular/core"; + +import { ItemsService } from "./items.service"; +import { ItemsAccessor } from "./items-accessor"; + +@Component({ + template: ` + + + + + + + ` +}) +export class NgForComponent extends ItemsAccessor { + constructor(public itemsService: ItemsService) { + super(itemsService); + } +} + diff --git a/e2e/renderer/app/ngforof.component.ts b/e2e/renderer/app/ngforof.component.ts new file mode 100644 index 000000000..79ad8e3d9 --- /dev/null +++ b/e2e/renderer/app/ngforof.component.ts @@ -0,0 +1,25 @@ +import { Component } from "@angular/core"; + +import { ItemsService } from "./items.service"; +import { ItemsAccessor } from "./items-accessor"; + +@Component({ + template: ` + + + + + + + + + + + ` +}) +export class NgForOfComponent extends ItemsAccessor { + constructor(public itemsService: ItemsService) { + super(itemsService); + } +} + diff --git a/e2e/renderer/app/ngif-inbetween.component.ts b/e2e/renderer/app/ngif-inbetween.component.ts new file mode 100644 index 000000000..a8a644186 --- /dev/null +++ b/e2e/renderer/app/ngif-inbetween.component.ts @@ -0,0 +1,30 @@ +import { Component } from "@angular/core"; + +@Component({ + template: ` + + + + + + + + + + + + + ` +}) +export class NgIfInbetweenComponent { + public show = true; + + toggle() { + this.show = !this.show; + } +} + diff --git a/e2e/renderer/app/ngif-no-layout.component.ts b/e2e/renderer/app/ngif-no-layout.component.ts new file mode 100644 index 000000000..087e14b55 --- /dev/null +++ b/e2e/renderer/app/ngif-no-layout.component.ts @@ -0,0 +1,24 @@ +import { Component } from "@angular/core"; + +@Component({ + template: ` + + + + + + + + + + + ` +}) +export class NgIfNoLayoutComponent { + public show = false; + + toggle() { + this.show = !this.show; + } +} + diff --git a/e2e/renderer/app/ngif-subsequent.component.ts b/e2e/renderer/app/ngif-subsequent.component.ts new file mode 100644 index 000000000..1e7125c95 --- /dev/null +++ b/e2e/renderer/app/ngif-subsequent.component.ts @@ -0,0 +1,23 @@ +import { Component} from "@angular/core"; + +@Component({ + moduleId: module.id, + selector: "renderer-test", + template: ` + + + + + + + + + + + + ` +}) +export class NgIfSubsequent { + public first: boolean = false; + public second: boolean = false; +} diff --git a/e2e/renderer/app/ngif-then-else.component.ts b/e2e/renderer/app/ngif-then-else.component.ts new file mode 100644 index 000000000..6d4113190 --- /dev/null +++ b/e2e/renderer/app/ngif-then-else.component.ts @@ -0,0 +1,33 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "ng-if-then-else", + template: ` + + + + + + + + + + + + + + + + + + ` +}) +export class NgIfThenElseComponent { + public show: boolean = true; + + toggle() { + this.show = !this.show; + } +} + + diff --git a/e2e/renderer/app/ngifelse.component.ts b/e2e/renderer/app/ngifelse.component.ts new file mode 100644 index 000000000..645c0a201 --- /dev/null +++ b/e2e/renderer/app/ngifelse.component.ts @@ -0,0 +1,26 @@ +import { Component } from "@angular/core"; + +@Component({ + template: ` + + + + + + + + + + + + + ` +}) +export class NgIfElseComponent { + public show: boolean = true; + + toggle() { + this.show = !this.show; + } +} + diff --git a/e2e/renderer/app/package.json b/e2e/renderer/app/package.json new file mode 100644 index 000000000..d5356c0cc --- /dev/null +++ b/e2e/renderer/app/package.json @@ -0,0 +1,5 @@ +{ + "main": "main.js", + "name": "nativescript-template-ng-tutorial", + "version": "3.1.0" +} \ No newline at end of file diff --git a/e2e/renderer/e2e/config/appium.capabilities.json b/e2e/renderer/e2e/config/appium.capabilities.json new file mode 100644 index 000000000..f3936d6ea --- /dev/null +++ b/e2e/renderer/e2e/config/appium.capabilities.json @@ -0,0 +1,84 @@ +{ + "nexus5": { + "browserName": "", + "appium-version": "1.6.5", + "platformName": "Android", + "platformVersion": "6.0", + "deviceName": "device", + "udid": "077e4a47003b7698", + "-lt": 60000, + "automationName": "Appium", + "appActivity": "com.tns.NativeScriptActivity", + "app": "" + }, + "android19": { + "browserName": "", + "appium-version": "1.6.5", + "platformName": "Android", + "platformVersion": "4.4", + "deviceName": "Emulator-Api19-Default", + "avd": "Emulator-Api19-Default", + "-lt": 60000, + "automationName": "Appium", + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": false, + "fullReset": true, + "app": "" + }, + "android21": { + "browserName": "", + "appium-version": "1.6.5", + "platformName": "Android", + "platformVersion": "5.0", + "deviceName": "Emulator-Api21-Default", + "avd": "Emulator-Api21-Default", + "-lt": 60000, + "automationName": "Appium", + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": false, + "fullReset": true, + "app": "" + }, + "android23": { + "browserName": "", + "appium-version": "1.6.5", + "platformName": "Android", + "platformVersion": "6.0", + "deviceName": "Emulator-Api23-Default", + "avd": "Emulator-Api23-Default", + "-lt": 60000, + "automationName": "Appium", + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": false, + "fullReset": true, + "app": "" + }, + "android24": { + "browserName": "", + "appium-version": "1.6.5", + "platformName": "Android", + "platformVersion": "7.0", + "deviceName": "Emulator-Api24-Default", + "avd": "Emulator-Api24-Default", + "-lt": 60000, + "automationName": "UIAutomator2", + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": false, + "fullReset": true, + "app": "" + }, + "sim.iPhone7.iOS100": { + "browserName": "", + "appium-version": "1.6.5", + "platformName": "iOS", + "platformVersion": "10.0", + "deviceName": "iPhone 7 100", + "noReset": true, + "fullReset": false, + "app": "" + } +} diff --git a/e2e/renderer/e2e/config/mocha.opts b/e2e/renderer/e2e/config/mocha.opts new file mode 100644 index 000000000..796ec4724 --- /dev/null +++ b/e2e/renderer/e2e/config/mocha.opts @@ -0,0 +1,4 @@ +--timeout 80000 +--recursive e2e +--reporter mocha-multi +--reporter-options spec=-,mocha-junit-reporter=test-results.xml \ No newline at end of file diff --git a/e2e/renderer/e2e/helpers/appium-elements.ts b/e2e/renderer/e2e/helpers/appium-elements.ts new file mode 100644 index 000000000..26a020a4d --- /dev/null +++ b/e2e/renderer/e2e/helpers/appium-elements.ts @@ -0,0 +1,41 @@ +import { AppiumDriver } from "nativescript-dev-appium"; + +import { UIElement } from "nativescript-dev-appium/ui-element"; + +export class ExtendedUIElement extends UIElement { + refetch(): Promise { + return Promise.resolve(this); + } +} + +const refetchable = () => + (target: any, propertyKey: string, descriptor: PropertyDescriptor): any => { + const originalMethod = descriptor.value; + const patchRefetch = async (args, fetchMethod) => { + const result = await fetchMethod() as ExtendedUIElement; + result.refetch = () => patchRefetch(args, fetchMethod); + + return result; + } + + descriptor.value = async function (...args: any[]): Promise { + const fetchMethod = () => originalMethod.apply(this, args); + const result = await patchRefetch(args, fetchMethod); + + return result; + } + + return descriptor; + }; + +export class DriverWrapper { + constructor(private driver: AppiumDriver) { + } + + @refetchable() + async findElementByText(...args: any[]): Promise { + const result = await (this.driver).findElementByText(...args); + + return result; + } +} diff --git a/e2e/renderer/e2e/helpers/location.ts b/e2e/renderer/e2e/helpers/location.ts new file mode 100644 index 000000000..189dfbbcc --- /dev/null +++ b/e2e/renderer/e2e/helpers/location.ts @@ -0,0 +1,13 @@ +import { assert } from "chai"; + +import { ExtendedUIElement } from "./appium-elements"; + +export const isAbove = async (first: ExtendedUIElement, second: ExtendedUIElement) => { + first = await first.refetch(); + second = await second.refetch(); + + const { y: firstY } = await first.location(); + const { y: secondY } = await second.location(); + + assert.isTrue(firstY < secondY); +} diff --git a/e2e/renderer/e2e/ngfor.e2e-spec.ts b/e2e/renderer/e2e/ngfor.e2e-spec.ts new file mode 100644 index 000000000..e1181aa13 --- /dev/null +++ b/e2e/renderer/e2e/ngfor.e2e-spec.ts @@ -0,0 +1,126 @@ +import { + AppiumDriver, + createDriver, + SearchOptions, +} from "nativescript-dev-appium"; + +import { isAbove } from "./helpers/location"; +import { DriverWrapper, ExtendedUIElement } from "./helpers/appium-elements"; + +describe("ngFor scenario", () => { + let driver: AppiumDriver; + let driverWrapper: DriverWrapper; + let addButton: ExtendedUIElement; + let removeButton: ExtendedUIElement; + let elements: ExtendedUIElement[] = []; + let lastAddedElementId = 0; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgFor", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("ngFor", SearchOptions.exact); + }); + + it("should find elements", async () => { + const first = await driverWrapper.findElementByText( + lastAddedElementId.toString(), SearchOptions.exact); + elements.push(first); + + addButton = await driverWrapper.findElementByText("add", SearchOptions.exact); + removeButton = await driverWrapper.findElementByText("remove", SearchOptions.exact); + + await isAbove(first, addButton); + }); + + it("should render elements in correct order", async () => { + await isAbove(elements[0], addButton); + await isAbove(addButton, removeButton); + }); + + it("should place new elements in the right places", async () => { + for (let i = 0; i < 5; i += 1) { + await addElement(); + await checkAppendedCorrectly(); + } + }); + + it("shouldn't reorder elements when last is removed", async () => { + while (elements.length) { + await removeElement(); + await checkCorrectOrderAll(); + } + }); + + it("should render new elements correctly after all old ones are removed", async () => { + for (let i = 0; i < 5; i += 1) { + await addElement(); + await checkCorrectOrderAll(); + } + }); + + it("shouldn't reorder elements when middle is removed", async () => { + const middleIndex = Math.floor(elements.length / 2); + await removeElement(middleIndex); + await checkCorrectOrderAll(); + }); + + const addElement = async () => { + addButton = await addButton.refetch(); + await addButton.click(); + + lastAddedElementId += 1; + const newElement = await driverWrapper.findElementByText( + lastAddedElementId.toString(), SearchOptions.exact); + + elements.push(newElement); + }; + + const removeElement = async (index?: number) => { + index; + if (index) { + let element = await elements[index]; + element = await element.refetch(); + await element.click(); + } else { + index = elements.length - 1; + removeButton = await removeButton.refetch(); + await removeButton.click(); + } + + elements.splice(index, 1); + lastAddedElementId -= 1; + }; + + const checkAppendedCorrectly = async () => { + const lastAdded = await driverWrapper.findElementByText( + lastAddedElementId.toString(), SearchOptions.exact); + + await isAbove(elements.slice(-2)[0], lastAdded); + await isAbove(lastAdded, addButton); + await isAbove(addButton, removeButton); + }; + + const checkCorrectOrderAll = async () => { + for (let i = 0; i < elements.length - 1; i += 1) { + await isAbove(elements[i], elements[i + 1]); + } + + if (elements.length) { + await isAbove(elements.slice(-1)[0], addButton); + } + await isAbove(addButton, removeButton); + }; +}); \ No newline at end of file diff --git a/e2e/renderer/e2e/ngforof.e2e-spec.ts b/e2e/renderer/e2e/ngforof.e2e-spec.ts new file mode 100644 index 000000000..db5fbf2c9 --- /dev/null +++ b/e2e/renderer/e2e/ngforof.e2e-spec.ts @@ -0,0 +1,156 @@ +import { + AppiumDriver, + createDriver, + SearchOptions, +} from "nativescript-dev-appium"; + +import { isAbove } from "./helpers/location"; +import { DriverWrapper, ExtendedUIElement } from "./helpers/appium-elements"; + +interface ElementTuple { + label: ExtendedUIElement, + button: ExtendedUIElement, +} + +describe("ngForOf scenario", () => { + let driver: AppiumDriver; + let driverWrapper: DriverWrapper; + let addButton: ExtendedUIElement; + let removeButton: ExtendedUIElement; + let elements: ElementTuple[] = []; + let lastAddedElementId = 0; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgForOf", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("ngForOf", SearchOptions.exact); + }); + + it("should find elements", async () => { + const firstElement = await getElement(lastAddedElementId); + elements.push(firstElement); + + addButton = await driverWrapper.findElementByText("add", SearchOptions.exact); + removeButton = await driverWrapper.findElementByText("remove", SearchOptions.exact); + + await elementTupleCorrectlyRendered(firstElement); + await isAbove(firstElement.button, addButton); + }); + + it("should render elements in correct order", async () => { + await elementTupleCorrectlyRendered(elements[0]); + await isAbove(elements[0].button, addButton); + await isAbove(addButton, removeButton); + }); + + + it("should place new elements in the right places", async () => { + for (let i = 0; i < 2; i += 1) { + await addElement(); + await checkAppendedCorrectly(); + } + }); + + it("shouldn't reorder elements when last is removed", async () => { + while (elements.length) { + await removeElement(); + await checkCorrectOrderAll(); + } + }); + + it("should render new elements correctly after all old ones are removed", async () => { + for (let i = 0; i < 5; i += 1) { + await addElement(); + await checkCorrectOrderAll(); + } + }); + + it("shouldn't reorder elements when middle is removed", async () => { + const middleIndex = Math.floor(elements.length / 2); + await removeElement(middleIndex); + await checkCorrectOrderAll(); + }); + + + const addElement = async () => { + addButton = await addButton.refetch(); + await addButton.click(); + + lastAddedElementId += 1; + const newElement = await getElement(lastAddedElementId); + + elements.push(newElement); + }; + + const removeElement = async (index?: number) => { + if (index) { + let { button } = await elements[index]; + button = await button.refetch(); + await button.click(); + } else { + index = elements.length - 1; + removeButton = await removeButton.refetch(); + await removeButton.click(); + } + + elements.splice(index, 1); + lastAddedElementId -= 1; + }; + + const checkAppendedCorrectly = async () => { + const lastAdded = await getElement(lastAddedElementId); + + await elementIsAbove(elements.slice(-2)[0], lastAdded); + await isAbove(lastAdded.button, addButton); + await isAbove(addButton, removeButton); + }; + + const checkCorrectOrderAll = async () => { + for (let i = 0; i < elements.length - 1; i += 1) { + await elementIsAbove(elements[i], elements[i + 1]); + } + + if (elements.length) { + const last = elements.slice(-1)[0]; + await elementTupleCorrectlyRendered(last); + await isAbove(last.button, addButton); + } + + await isAbove(addButton, removeButton); + }; + + const elementIsAbove = async (first: ElementTuple, second: ElementTuple) => { + await elementTupleCorrectlyRendered(first); + await elementTupleCorrectlyRendered(second); + + await isAbove(first.button, second.label); + }; + + const elementTupleCorrectlyRendered = async (element: ElementTuple) => { + await isAbove(element.label, element.button); + }; + + const getElement = async (id: number) => { + const label = await driverWrapper.findElementByText( + "label: " + id.toString(), SearchOptions.exact); + + const button = await driverWrapper.findElementByText( + id.toString(), SearchOptions.exact); + + return { label, button }; + }; +}); + diff --git a/e2e/renderer/e2e/ngif.e2e-spec.ts b/e2e/renderer/e2e/ngif.e2e-spec.ts new file mode 100644 index 000000000..53201e594 --- /dev/null +++ b/e2e/renderer/e2e/ngif.e2e-spec.ts @@ -0,0 +1,413 @@ +import { + AppiumDriver, + createDriver, + SearchOptions, +} from "nativescript-dev-appium"; + +import { isAbove } from "./helpers/location"; +import { DriverWrapper, ExtendedUIElement } from "./helpers/appium-elements"; + +import { assert } from "chai"; + +describe("ngIf scenario", () => { + let driver: AppiumDriver; + let driverWrapper: DriverWrapper; + let toggleButton: ExtendedUIElement; + + describe("without layout", async () => { + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgIf no layout", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("ngIf - no layout", SearchOptions.exact); + }); + + it("should find elements", async () => { + await driverWrapper.findElementByText("false", SearchOptions.exact); + toggleButton = await driverWrapper.findElementByText("Toggle", SearchOptions.exact); + }); + + it("show 'true' button when show is true", async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + + await driverWrapper.findElementByText("true", SearchOptions.exact); + }); + }); + + describe("label inbetween", async () => { + let firstButton: ExtendedUIElement; + let secondButton: ExtendedUIElement; + let conditionalLabel: ExtendedUIElement; + let toggle: ExtendedUIElement; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgIf inbetween", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("ngIf - inbetween", SearchOptions.exact); + }); + + it("should find elements", async () => { + firstButton = await driverWrapper.findElementByText("Button 1", SearchOptions.exact); + secondButton = await driverWrapper.findElementByText("Button 2", SearchOptions.exact); + toggleButton = await driverWrapper.findElementByText("Toggle", SearchOptions.exact); + + conditionalLabel = await driverWrapper.findElementByText("Label", SearchOptions.exact); + const labelIsDisplayed = await conditionalLabel.isDisplayed(); + assert.isTrue(labelIsDisplayed); + }); + + it("detach label when condition is false", done => { + (async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + + try { + await driverWrapper.findElementByText("Label", SearchOptions.exact); + } catch (e) { + done(); + } + })(); + }); + }); + + describe("with else template", async () => { + let ifButton: ExtendedUIElement; + let elseButton: ExtendedUIElement; + let toggle: ExtendedUIElement; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgIfElse", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("ngIfElse", SearchOptions.exact); + }); + + it("should find elements", async () => { + toggleButton = await driverWrapper.findElementByText("Toggle", SearchOptions.exact); + ifButton = await driverWrapper.findElementByText("If", SearchOptions.exact); + }); + + it("shouldn't render 'else' template when condition is true", done => { + driverWrapper.findElementByText("Else", SearchOptions.exact) + .then(_ => { throw new Error("Else template found!"); }) + .catch(() => done()); + }); + + it("should attach 'else' template when condition is changed to false", async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + + elseButton = await driverWrapper.findElementByText("Else", SearchOptions.exact); + }); + + it("should detach 'if' template when condition is changed to false", done => { + driverWrapper.findElementByText("If", SearchOptions.exact) + .then(_ => { throw new Error("If template found!"); }) + .catch(() => done()); + }); + + it("should swap the content when condition is changed", done => { + (async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + ifButton = await ifButton.refetch(); + + try { + await driverWrapper.findElementByText("Else", SearchOptions.exact); + } catch (e) { + done(); + } + })(); + }); + }); + + describe("with then-else template", async () => { + let thenButton: ExtendedUIElement; + let elseButton: ExtendedUIElement; + let toggle: ExtendedUIElement; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgIf Then Else", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("ngIf Then Else", SearchOptions.exact); + }); + + it("should find elements", async () => { + toggleButton = await driverWrapper.findElementByText("Toggle", SearchOptions.exact); + thenButton = await driverWrapper.findElementByText("Then", SearchOptions.exact); + }); + + it("shouldn't render 'else' template when condition is true", done => { + driverWrapper.findElementByText("Else", SearchOptions.exact) + .then(_ => { throw new Error("Else template found!"); }) + .catch(() => done()); + }); + + it("should attach 'else' template when condition is changed to false", async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + + elseButton = await driverWrapper.findElementByText("Else", SearchOptions.exact); + }); + + it("should detach 'then' template when condition is changed to false", done => { + driverWrapper.findElementByText("Then", SearchOptions.exact) + .then(_ => { throw new Error("Then template found!"); }) + .catch(() => done()); + }); + + it("should swap the content when condition is changed", done => { + (async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + thenButton = await thenButton.refetch(); + + try { + await driverWrapper.findElementByText("Else", SearchOptions.exact); + } catch (e) { + done(); + } + })(); + }); + }); + + describe("then-else templates inside content view", async () => { + let thenButton: ExtendedUIElement; + let elseButton: ExtendedUIElement; + let toggle: ExtendedUIElement; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("Content view", SearchOptions.exact); + await navigationButton.click(); + + const actionBar = + await driverWrapper.findElementByText("Content View", SearchOptions.exact); + }); + + it("should find elements", async () => { + toggleButton = await driverWrapper.findElementByText("Toggle", SearchOptions.exact); + thenButton = await driverWrapper.findElementByText("Then", SearchOptions.exact); + }); + + it("shouldn't render 'else' template when condition is true", done => { + driverWrapper.findElementByText("Else", SearchOptions.exact) + .then(_ => { throw new Error("Else template found!"); }) + .catch(() => done()); + }); + + it("should attach 'else' template when condition is changed to false", async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + + elseButton = await driverWrapper.findElementByText("Else", SearchOptions.exact); + }); + + it("should detach 'then' template when condition is changed to false", done => { + driverWrapper.findElementByText("Then", SearchOptions.exact) + .then(_ => { throw new Error("Then template found!"); }) + .catch(() => done()); + }); + + it("should swap the content when condition is changed", done => { + (async () => { + toggleButton = await toggleButton.refetch(); + await toggleButton.click(); + thenButton = await thenButton.refetch(); + + try { + await driverWrapper.findElementByText("Else", SearchOptions.exact); + } catch (e) { + done(); + } + })(); + }); + }); + + describe("subsequent ifs", async () => { + let firstButton: ExtendedUIElement; + let secondButton: ExtendedUIElement; + let firstLabel: ExtendedUIElement; + let secondLabel: ExtendedUIElement; + + before(async () => { + driver = await createDriver(); + driverWrapper = new DriverWrapper(driver); + }); + + after(async () => { + await driver.quit(); + console.log("Driver quits!"); + }); + + it("should navigate to page", async () => { + const navigationButton = + await driverWrapper.findElementByText("NgIf Subsequent Ifs", SearchOptions.exact); + await navigationButton.click(); + }); + + it("should find elements", async () => { + firstButton = await driverWrapper.findElementByText("Toggle first", SearchOptions.exact); + secondButton = await driverWrapper.findElementByText("Toggle second", SearchOptions.exact); + + firstLabel = await driverWrapper.findElementByText("== 1 ==", SearchOptions.exact); + secondLabel = await driverWrapper.findElementByText("== 2 ==", SearchOptions.exact); + + assert.isDefined(firstButton); + assert.isDefined(secondButton); + assert.isDefined(firstLabel); + assert.isDefined(secondLabel); + }); + + it("should toggle on first view", async () => { + await firstButton.click(); + + let conditional = await driverWrapper.findElementByText("first", SearchOptions.exact); + + await isAbove(firstLabel, conditional); + await isAbove(conditional, secondLabel); + }); + + it("should toggle off first view", done => { + (async () => { + await firstButton.click(); + + driverWrapper.findElementByText("first", SearchOptions.exact, 500) + .then(_ => { throw new Error("first label found!"); }) + .catch(() => done()); + })(); + }); + + it("should toggle on second view", async () => { + await secondButton.click(); + + let conditional = await driverWrapper.findElementByText("second", SearchOptions.exact); + await isAbove(firstLabel, conditional); + await isAbove(conditional, secondLabel); + }); + + it("should toggle off second view", done => { + (async () => { + await secondButton.click(); + + driverWrapper.findElementByText("first", SearchOptions.exact, 500) + .then(_ => { throw new Error("first label found!"); }) + .catch(() => done()); + })(); + }); + + it("should toggle on both views", async () => { + await firstButton.click(); + await secondButton.click(); + + let conditional1 = await driverWrapper.findElementByText("first", SearchOptions.exact); + let conditional2 = await driverWrapper.findElementByText("second", SearchOptions.exact); + await isAbove(firstLabel, conditional1); + await isAbove(conditional1, conditional2); + await isAbove(conditional2, secondLabel); + }); + + it("should toggle off both views", done => { + (async () => { + await firstButton.click(); + await secondButton.click(); + + driverWrapper.findElementByText("first", SearchOptions.exact, 500) + .then(_ => { throw new Error("first label found!"); }) + .catch(() => { + driverWrapper.findElementByText("second", SearchOptions.exact, 500) + .then(_ => { throw new Error("second label found!"); }) + .catch(() => done()); + }); + })(); + }); + + it("should toggle on both views in reverse", async () => { + await secondButton.click(); + await firstButton.click(); + + let conditional1 = await driverWrapper.findElementByText("first", SearchOptions.exact); + let conditional2 = await driverWrapper.findElementByText("second", SearchOptions.exact); + await isAbove(firstLabel, conditional1); + await isAbove(conditional1, conditional2); + await isAbove(conditional2, secondLabel); + }); + + it("should toggle off both views in reverse", done => { + (async () => { + await secondButton.click(); + await firstButton.click(); + + driverWrapper.findElementByText("first", SearchOptions.exact, 500) + .then(_ => { throw new Error("first label found!"); }) + .catch(() => { + driverWrapper.findElementByText("second", SearchOptions.exact, 500) + .then(_ => { throw new Error("second label found!"); }) + .catch(() => done()); + }); + })(); + }); + }); + +}); diff --git a/e2e/renderer/e2e/setup.ts b/e2e/renderer/e2e/setup.ts new file mode 100644 index 000000000..8b26e66e9 --- /dev/null +++ b/e2e/renderer/e2e/setup.ts @@ -0,0 +1,9 @@ +import { startServer, stopServer } from "nativescript-dev-appium"; + +before("start server", async () => { + await startServer(); +}); + +after("stop server", async () => { + await stopServer(); +}); diff --git a/e2e/renderer/e2e/tsconfig.json b/e2e/renderer/e2e/tsconfig.json new file mode 100644 index 000000000..040f56ed4 --- /dev/null +++ b/e2e/renderer/e2e/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig", + "compilerOptions": { + "importHelpers": true, + "types": [ + "node", + "mocha", + "chai" + ] + } +} diff --git a/e2e/renderer/package.json b/e2e/renderer/package.json new file mode 100644 index 000000000..3c32dff5b --- /dev/null +++ b/e2e/renderer/package.json @@ -0,0 +1,50 @@ +{ + "description": "NativeScript Application", + "license": "SEE LICENSE IN ", + "readme": "NativeScript Application", + "repository": "", + "nativescript": { + "id": "org.nativescript.renderer", + "tns-android": { + "version": "next" + } + }, + "dependencies": { + "@angular/animations": "~4.2.0", + "@angular/common": "~4.2.0", + "@angular/compiler": "~4.2.0", + "@angular/core": "~4.2.0", + "@angular/forms": "~4.2.0", + "@angular/http": "~4.2.0", + "@angular/platform-browser": "~4.2.0", + "@angular/router": "~4.2.0", + "nativescript-angular": "file:../../nativescript-angular", + "nativescript-intl": "^3.0.0", + "reflect-metadata": "~0.1.8", + "rxjs": "~5.3.0", + "tns-core-modules": "next", + "zone.js": "~0.8.2" + }, + "devDependencies": { + "@types/chai": "^4.0.2", + "@types/mocha": "^2.2.41", + "@types/node": "^7.0.5", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "chai": "~4.1.1", + "chai-as-promised": "~7.1.1", + "colors": "^1.1.2", + "lazy": "1.0.11", + "mocha": "~3.5.0", + "mocha-junit-reporter": "^1.13.0", + "mocha-multi": "^0.11.0", + "nativescript-dev-appium": "next", + "nativescript-dev-typescript": "~0.4.0", + "tslib": "^1.7.1", + "typescript": "~2.2.1" + }, + "scripts": { + "e2e": "tsc -p e2e && mocha --opts ./e2e/config/mocha.opts" + } +} diff --git a/e2e/renderer/tsconfig.json b/e2e/renderer/tsconfig.json new file mode 100644 index 000000000..17700d54e --- /dev/null +++ b/e2e/renderer/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "noEmitHelpers": true, + "noEmitOnError": true, + "lib": [ + "es6", + "dom", + "es2015.iterable" + ], + "baseUrl": ".", + "paths": { + "*": [ + "./node_modules/tns-core-modules/*", + "./node_modules/*" + ] + } + }, + "exclude": [ + "node_modules", + "platforms", + "**/*.aot.ts" + ] +} \ No newline at end of file diff --git a/nativescript-angular/element-registry.ts b/nativescript-angular/element-registry.ts index 9a0f044aa..8c0fad5f1 100644 --- a/nativescript-angular/element-registry.ts +++ b/nativescript-angular/element-registry.ts @@ -2,25 +2,30 @@ import { View } from "tns-core-modules/ui/core/view"; import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base"; export type NgView = (View & ViewExtensions); -export type NgElement = NgView | InvisibleNode; export interface ViewExtensions { + meta: ViewClassMeta; nodeType: number; nodeName: string; templateParent: NgView; + nextSibling: NgView; + firstChild: NgView; + lastChild: NgView; ngCssClasses: Map; - meta: ViewClassMeta; } export interface ViewClass { new (): View; } -export abstract class InvisibleNode extends View implements ViewExtensions { +export abstract class InvisibleNode extends View implements NgView { meta: { skipAddToDom: boolean }; - templateParent: NgView; nodeType: number; nodeName: string; + templateParent: NgView; + nextSibling: NgView; + firstChild: NgView; + lastChild: NgView; ngCssClasses: Map; constructor() { @@ -42,7 +47,7 @@ export class CommentNode extends InvisibleNode { super(); this.meta = { - skipAddToDom: false, + skipAddToDom: true, }; this.id = CommentNode.id.toString(); CommentNode.id += 1; @@ -67,7 +72,7 @@ const getClassName = instance => instance.constructor.name; export interface ViewClassMeta { skipAddToDom?: boolean; - insertChild?: (parent: NgView, child: NgView, atIndex: number) => void; + insertChild?: (parent: NgView, child: NgView) => void; removeChild?: (parent: NgView, child: NgView) => void; } diff --git a/nativescript-angular/renderer.ts b/nativescript-angular/renderer.ts index ddf247c0b..f4edba521 100644 --- a/nativescript-angular/renderer.ts +++ b/nativescript-angular/renderer.ts @@ -23,6 +23,11 @@ export const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`; export const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`; const ATTR_SANITIZER = /-/g; +export interface ElementReference { + previous: NgView; + next: NgView; +} + @Injectable() export class NativeScriptRendererFactory implements RendererFactory2 { private componentRenderers = new Map(); @@ -85,15 +90,16 @@ export class NativeScriptRenderer extends Renderer2 { } @profile - appendChild(parent: any, newChild: NgView): void { + appendChild(parent: NgView, newChild: NgView): void { traceLog(`NativeScriptRenderer.appendChild child: ${newChild} parent: ${parent}`); this.viewUtil.insertChild(parent, newChild); } @profile - insertBefore(parent: NgView, newChild: NgView, refChildIndex: number): void { - traceLog(`NativeScriptRenderer.insertBefore child: ${newChild} parent: ${parent}`); - this.viewUtil.insertChild(parent, newChild, refChildIndex); + insertBefore(parent: NgView, newChild: NgView, { previous, next }: ElementReference): void { + traceLog(`NativeScriptRenderer.insertBefore child: ${newChild} ` + + `parent: ${parent} previous: ${previous} next: ${next}`); + this.viewUtil.insertChild(parent, newChild, previous, next); } @profile @@ -110,14 +116,18 @@ export class NativeScriptRenderer extends Renderer2 { @profile parentNode(node: NgView): any { - traceLog("NativeScriptRenderer.parentNode for node: " + node); + traceLog(`NativeScriptRenderer.parentNode for node: ${node}`); return node.parent || node.templateParent; } @profile - nextSibling(node: NgView): number { - traceLog(`NativeScriptRenderer.nextSibling ${node}`); - return this.viewUtil.nextSiblingIndex(node); + nextSibling(node: NgView): ElementReference { + traceLog(`NativeScriptRenderer.nextSibling of ${node} is ${node.nextSibling}`); + + return { + previous: node, + next: node.nextSibling, + }; } @profile diff --git a/nativescript-angular/trace.ts b/nativescript-angular/trace.ts index 800b96b22..efe8ddab6 100644 --- a/nativescript-angular/trace.ts +++ b/nativescript-angular/trace.ts @@ -2,6 +2,7 @@ import { write, categories, messageType } from "tns-core-modules/trace"; export const animationsTraceCategory = "ns-animations"; export const rendererTraceCategory = "ns-renderer"; +export const viewUtilCategory = "ns-view-util"; export const routerTraceCategory = "ns-router"; export const listViewTraceCategory = "ns-list-view"; @@ -17,6 +18,10 @@ export function rendererError(message: string): void { write(message, rendererTraceCategory, messageType.error); } +export function viewUtilLog(msg): void { + write(msg, viewUtilCategory); +} + export function routerLog(message: string): void { write(message, routerTraceCategory); } diff --git a/nativescript-angular/view-util.ts b/nativescript-angular/view-util.ts index 99b196197..5532a39dc 100644 --- a/nativescript-angular/view-util.ts +++ b/nativescript-angular/view-util.ts @@ -6,7 +6,6 @@ import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base"; import { CommentNode, InvisibleNode, - NgElement, NgView, TextNode, ViewExtensions, @@ -17,10 +16,10 @@ import { } from "./element-registry"; import { platformNames, Device } from "tns-core-modules/platform"; -import { rendererLog as traceLog } from "./trace"; +import { viewUtilLog as traceLog } from "./trace"; -const XML_ATTRIBUTES = Object.freeze(["style", "rows", "columns", "fontAttributes"]); const ELEMENT_NODE_TYPE = 1; +const XML_ATTRIBUTES = Object.freeze(["style", "rows", "columns", "fontAttributes"]); const whiteSpaceSplitter = /\s+/; export type ViewExtensions = ViewExtensions; @@ -53,54 +52,168 @@ export class ViewUtil { this.isAndroid = device.os === platformNames.android; } - public insertChild(parent: any, child: NgElement, atIndex: number = -1) { + public insertChild( + parent: NgView, + child: NgView, + previous: NgView = parent.lastChild, + next?: NgView + ) { + if (!parent) { + return; + } + + this.addToQueue(parent, child, previous, next); + if (child instanceof InvisibleNode) { child.templateParent = parent; } - if (!parent || isDetachedElement(child)) { - return; + if (!isDetachedElement(child)) { + this.addToVisualTree(parent, child, next); } + } + private addToQueue( + parent: NgView, + child: NgView, + previous: NgView, + next: NgView + ): void { + if (previous) { + previous.nextSibling = child; + } else { + parent.firstChild = child; + } + + if (next) { + child.nextSibling = next; + } else { + this.appendToQueue(parent, child); + } + } + + private appendToQueue(parent: NgView, view: NgView) { + traceLog(`ViewUtil.appendToQueue parent: ${parent} view: ${view}`); + if (parent.lastChild) { + parent.lastChild.nextSibling = view; + } + + parent.lastChild = view; + } + + private addToVisualTree(parent: NgView, child: NgView, next: NgView): void { if (parent.meta && parent.meta.insertChild) { - parent.meta.insertChild(parent, child, atIndex); + parent.meta.insertChild(parent, child); } else if (isLayout(parent)) { - if (child.parent === parent) { - const index = (parent).getChildIndex(child); - if (index !== -1) { - parent.removeChild(child); - } - } - if (atIndex !== -1) { - parent.insertChild(child, atIndex); - } else { - parent.addChild(child); - } + this.insertToLayout(parent, child, next); } else if (isContentView(parent)) { parent.content = child; - } else if (parent && parent._addChildFromBuilder) { - parent._addChildFromBuilder(child.nodeName, child); + } else if (parent && (parent)._addChildFromBuilder) { + (parent)._addChildFromBuilder(child.nodeName, child); + } + } + + private insertToLayout( + parent: NgLayoutBase, + child: NgView, + next: NgView + ): void { + if (child.parent === parent) { + this.removeLayoutChild(parent, child); + } + + const nextVisual = this.findNextVisual(next); + if (nextVisual) { + const index = parent.getChildIndex(nextVisual); + parent.insertChild(child, index); + } else { + parent.addChild(child); + } + } + + private findNextVisual(view: NgView) { + let next = view; + while (next && isDetachedElement(next)) { + next = next.nextSibling; } + + return next; } - public removeChild(parent: any, child: NgElement) { - if (!parent || isDetachedElement(child)) { + public removeChild(parent: NgView, child: NgView) { + if (!parent) { return; } if (parent.meta && parent.meta.removeChild) { parent.meta.removeChild(parent, child); } else if (isLayout(parent)) { - parent.removeChild(child); - } else if (isContentView(parent)) { - if (parent.content === child) { - parent.content = null; - } + this.removeLayoutChild(parent, child); + } else if (isContentView(parent) && parent.content === child) { + parent.content = null; + parent.lastChild = null; + parent.firstChild = null; } else if (isView(parent)) { parent._removeView(child); } } + private removeLayoutChild(parent: NgLayoutBase, child: NgView): void { + const index = parent.getChildIndex(child); + this.removeFromQueue(parent, child, index); + if (index === -1) { + return; + } + + parent.removeChild(child); + } + + private removeFromQueue(parent: NgLayoutBase, child: NgView, index: number) { + traceLog(`ViewUtil.removeFromQueue ` + + `parent: ${parent} child: ${child} index: ${index}`); + + if (parent.firstChild === child && parent.lastChild === child) { + parent.firstChild = null; + parent.lastChild = null; + return; + } + + if (parent.firstChild === child) { + parent.firstChild = child.nextSibling; + } + + const previous = this.findPreviousElement(parent, child, index); + if (parent.lastChild === child) { + parent.lastChild = previous; + } + + if (previous) { + previous.nextSibling = child.nextSibling; + } + } + + // NOTE: This one is O(n) - use carefully + private findPreviousElement(parent: NgLayoutBase, child: NgView, elementIndex: number): NgView { + const previousVisual = this.getPreviousVisualElement(parent, elementIndex); + let previous = previousVisual || parent.firstChild; + + // since detached elements are not added to the visual tree, + // we need to find the actual previous sibling of the view, + // which may as well be an invisible node + while (previous && previous !== child && previous.nextSibling !== child) { + previous = previous.nextSibling; + } + + return previous; + } + + private getPreviousVisualElement(parent: NgLayoutBase, elementIndex: number): NgView { + if (elementIndex > 0) { + return parent.getChildAt(elementIndex - 1) as NgView; + } + } + + // NOTE: This one is O(n) - use carefully public getChildIndex(parent: any, child: NgView) { if (isLayout(parent)) { return parent.getChildIndex(child); @@ -131,9 +244,7 @@ export class ViewUtil { // we're setting the node type of the view // to 'element' because of checks done in the - // dom animation engine: - // tslint:disable-next-line:max-line-length - // https://github.com/angular/angular/blob/master/packages/animations/browser/src/render/dom_animation_engine.ts#L70-L81 + // dom animation engine view.nodeType = ELEMENT_NODE_TYPE; return view; @@ -168,34 +279,11 @@ export class ViewUtil { } } - // finds the node in the parent's views and returns the next index - // returns -1 if the node has no parent or next sibling - public nextSiblingIndex(node: NgView): number { - const parent = node.parent; - if (!parent) { - return -1; - } - - let index = 0; - let found = false; - parent.eachChild(child => { - if (child === node) { - found = true; - } - - index += 1; - return !found; - }); - - return found ? index : -1; - } - private runsIn(platform: string): boolean { return (platform === "ios" && this.isIos) || (platform === "android" && this.isAndroid); } - private setPropertyInternal(view: NgView, attributeName: string, value: any): void { traceLog(`Setting attribute: ${attributeName}=${value} to ${view}`); diff --git a/nativescript-angular/yarn.lock b/nativescript-angular/yarn.lock deleted file mode 100644 index 2ade79c72..000000000 --- a/nativescript-angular/yarn.lock +++ /dev/null @@ -1,381 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@angular/animations@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.1.0.tgz#97b642aee01b5406e03ec65e499342ba91e2dd38" - -"@angular/common@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.1.0.tgz#4370f569e51ddd99963b7f4aa58c1a5dcc5fea52" - -"@angular/compiler-cli@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.1.0.tgz#727aaada8bfd94285e9818995925048f7fdf1200" - dependencies: - "@angular/tsc-wrapped" "4.1.0" - minimist "^1.2.0" - reflect-metadata "^0.1.2" - -"@angular/compiler@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.1.0.tgz#be1ade5b6aec81f03c29d52bcb95925a28900dcb" - -"@angular/core@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.1.0.tgz#72ec173316879571880c9c483ed6dfc0caab94b0" - -"@angular/forms@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.1.0.tgz#8eae2a45c4ba064b377f9280e59c012b5dac6b80" - -"@angular/http@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.1.0.tgz#7ba0c4d044dee964021b7cf19cb146a2c31577a5" - -"@angular/platform-browser@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.1.0.tgz#b981386be1a36f2af7f0679447fd97b7267b25de" - -"@angular/router@~4.0.0 || ~4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.1.0.tgz#dd3563662f95ca3aa3dd9ff13c6ed4bea1d90b06" - -"@angular/tsc-wrapped@4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.1.0.tgz#07cbd61d91adde4c2daf9a41605152952b8832b3" - dependencies: - tsickle "^0.21.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -app-root-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46" - -babel-code-frame@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" - dependencies: - chalk "^1.1.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - -brace-expansion@^1.0.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" - dependencies: - balanced-match "^0.4.1" - concat-map "0.0.1" - -chalk@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -codelyzer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-3.0.1.tgz#ba66b7b2aa564fe9f45d6004b4003ad2cf116828" - dependencies: - app-root-path "^2.0.1" - css-selector-tokenizer "^0.7.0" - cssauron "^1.4.0" - semver-dsl "^1.0.1" - source-map "^0.5.6" - sprintf-js "^1.0.3" - -colors@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -css-selector-tokenizer@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" - -cssauron@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" - dependencies: - through X.X.X - -cssesc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" - -diff@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" - -escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -fastparse@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" - -findup-sync@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" - dependencies: - glob "~5.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -glob@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~5.0.0: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -"minimatch@2 || 3", minimatch@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" - dependencies: - brace-expansion "^1.0.0" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -nativescript-intl@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/nativescript-intl/-/nativescript-intl-3.0.0.tgz#82ee9be7d377172b3c4295734723037628e186a7" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -optimist@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -reflect-metadata@^0.1.2, reflect-metadata@^0.1.8: - version "0.1.10" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a" - -regenerate@^1.2.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" - -regexpu-core@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -resolve@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" - dependencies: - path-parse "^1.0.5" - -rxjs@^5.0.1: - version "5.3.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.3.0.tgz#d88ccbdd46af290cbdb97d5d8055e52453fabe2d" - dependencies: - symbol-observable "^1.0.1" - -semver-dsl@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0" - dependencies: - semver "^5.3.0" - -semver@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - -source-map-support@^0.4.2: - version "0.4.15" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" - dependencies: - source-map "^0.5.6" - -source-map@^0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - -sprintf-js@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -symbol-observable@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" - -through@X.X.X: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -tns-core-modules-widgets@internal-preview: - version "3.1.0-2017-04-28-266" - resolved "https://registry.yarnpkg.com/tns-core-modules-widgets/-/tns-core-modules-widgets-3.1.0-2017-04-28-266.tgz#56d82a9952604e064b76bbd232d56cad9a13337a" - -tns-core-modules@internal-preview: - version "3.1.0-2017-04-26-6412" - resolved "https://registry.yarnpkg.com/tns-core-modules/-/tns-core-modules-3.1.0-2017-04-26-6412.tgz#ae7717292d511e3e6fcac14330d0b0adc18e905d" - dependencies: - tns-core-modules-widgets internal-preview - -tsickle@^0.21.0: - version "0.21.6" - resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.21.6.tgz#53b01b979c5c13fdb13afb3fb958177e5991588d" - dependencies: - minimist "^1.2.0" - mkdirp "^0.5.1" - source-map "^0.5.6" - source-map-support "^0.4.2" - -tslint@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.1.0.tgz#51a47baeeb58956fcd617bd2cf00e2ef0eea2ed9" - dependencies: - babel-code-frame "^6.22.0" - colors "^1.1.2" - diff "^3.2.0" - findup-sync "~0.3.0" - glob "^7.1.1" - optimist "~0.6.0" - resolve "^1.3.2" - semver "^5.3.0" - tsutils "^1.4.0" - -tsutils@^1.4.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.8.0.tgz#bf8118ed8e80cd5c9fc7d75728c7963d44ed2f52" - -typescript@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.2.tgz#f0f045e196f69a72f06b25fd3bd39d01c3ce9984" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -zone.js@^0.8.4: - version "0.8.9" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.9.tgz#34aaa9a3ec6d0e4acebd1b761adafa590473638b" diff --git a/ng-sample/app/examples/list/list-test-async.ts b/ng-sample/app/examples/list/list-test-async.ts index 146ee9cba..ed635997c 100644 --- a/ng-sample/app/examples/list/list-test-async.ts +++ b/ng-sample/app/examples/list/list-test-async.ts @@ -15,11 +15,11 @@ import "rxjs/add/operator/combineLatest"; - + @@ -68,11 +68,11 @@ export class ListTestAsync { - + diff --git a/ng-sample/app/examples/list/list-test.ts b/ng-sample/app/examples/list/list-test.ts index ccec8a964..9390b6dfd 100644 --- a/ng-sample/app/examples/list/list-test.ts +++ b/ng-sample/app/examples/list/list-test.ts @@ -42,26 +42,26 @@ export class ItemComponent implements AfterViewChecked, DoCheck { - + ` // TEMPLATE WITH COMPONENT - // + // // IN-PLACE TEMPLATE - // + // }) export class ListTest { public myItems: Array; diff --git a/ng-sample/app/examples/list/template-selector.ts b/ng-sample/app/examples/list/template-selector.ts index 4557b7e9c..54c11b28e 100644 --- a/ng-sample/app/examples/list/template-selector.ts +++ b/ng-sample/app/examples/list/template-selector.ts @@ -43,13 +43,13 @@ export class HeaderComponent implements DoCheck { row="1" margin="10" [itemTemplateSelector]="templateSelector"> - + - + diff --git a/ng-sample/app/examples/router/clear-history-test.ts b/ng-sample/app/examples/router/clear-history-test.ts index c83b40936..dba5a8e86 100644 --- a/ng-sample/app/examples/router/clear-history-test.ts +++ b/ng-sample/app/examples/router/clear-history-test.ts @@ -40,10 +40,10 @@ class LocationLogService { (service.routerEvents$ | async)" margin="10"> - + diff --git a/ng-sample/app/examples/tab-view/tab-view-test.html b/ng-sample/app/examples/tab-view/tab-view-test.html index f66474024..5caed39c8 100644 --- a/ng-sample/app/examples/tab-view/tab-view-test.html +++ b/ng-sample/app/examples/tab-view/tab-view-test.html @@ -1,9 +1,9 @@ - + diff --git a/tests/app/tests/ns-location-strategy.ts b/tests/app/tests/ns-location-strategy.ts index 3a89ff541..13fd898a9 100644 --- a/tests/app/tests/ns-location-strategy.ts +++ b/tests/app/tests/ns-location-strategy.ts @@ -19,7 +19,7 @@ class FakeFrame extends View implements Frame { } } - navigate(entry: NavigationEntry) { } + navigate(entry: any) { } constructor(private backCB?: () => void) { super(); diff --git a/tests/app/tests/property-sets.ts b/tests/app/tests/property-sets.ts index e62bb8c74..e3d2694d4 100644 --- a/tests/app/tests/property-sets.ts +++ b/tests/app/tests/property-sets.ts @@ -11,11 +11,14 @@ import {Red} from "color/known-colors"; import {device, platformNames} from "platform"; import {createDevice} from "./test-utils"; -class TestView extends View implements ViewExtensions { - public nodeName: string = "TestView"; +class TestView extends View implements NgView { + public meta: ViewClassMeta = { skipAddToDom: false }; public nodeType: number = 1; + public nodeName: string = "TestView"; public templateParent: NgView = null; - public meta: ViewClassMeta = { skipAddToDom: false }; + public nextSibling: NgView; + public firstChild: NgView; + public lastChild: NgView; public ngCssClasses: Map = new Map(); public stringValue: string = ""; diff --git a/tests/app/tests/renderer-tests.ts b/tests/app/tests/renderer-tests.ts index 6efc463c8..3c2ccd506 100644 --- a/tests/app/tests/renderer-tests.ts +++ b/tests/app/tests/renderer-tests.ts @@ -291,7 +291,7 @@ describe("Renderer E2E", () => { it("ngIf hides component when false", () => { return testApp.loadComponent(NgIfLabel).then((componentRef) => { const componentRoot = componentRef.instance.elementRef.nativeElement; - assert.equal("(ProxyViewContainer (CommentNode))", dumpView(componentRoot)); + assert.equal("(ProxyViewContainer)", dumpView(componentRoot)); }); }); @@ -302,7 +302,7 @@ describe("Renderer E2E", () => { component.show = true; testApp.appRef.tick(); - assert.equal("(ProxyViewContainer (CommentNode), (Label))", dumpView(componentRoot)); + assert.equal("(ProxyViewContainer (Label))", dumpView(componentRoot)); }); }); @@ -314,12 +314,11 @@ describe("Renderer E2E", () => { component.show = true; testApp.appRef.tick(); assert.equal( - "(ProxyViewContainer (StackLayout (CommentNode), (Label), (Button)))", + "(ProxyViewContainer (StackLayout (Label), (Button)))", dumpView(componentRoot)); }); }); - it("ngIf shows elements in correct order when multiple are rendered and there's *ngIf", () => { return testApp.loadComponent(NgIfMultiple).then((componentRef) => { const component = componentRef.instance; @@ -333,8 +332,7 @@ describe("Renderer E2E", () => { "(Label[text=1]), " + "(Label[text=2]), " + "(Label[text=3]), " + - "(CommentNode), " + // ng-reflect comment - "(Label[text=4]), " + // the content to be displayed and its anchor + "(Label[text=4]), " + // the content to be conditionally displayed "(Label[text=5])" + ")" + ")", @@ -348,13 +346,15 @@ describe("Renderer E2E", () => { const componentRoot = component.elementRef.nativeElement; testApp.appRef.tick(); + assert.equal( "(ProxyViewContainer " + "(StackLayout " + - "(CommentNode), " + // ng-reflect comment - "(Label[text=If]), (CommentNode)))", // the content to be displayed and its anchor + "(Label[text=If])" + + ")" + + ")", - dumpView(componentRoot, true)); + dumpView(componentRoot, true)); }); }); @@ -368,10 +368,11 @@ describe("Renderer E2E", () => { assert.equal( "(ProxyViewContainer " + "(StackLayout " + - "(CommentNode), " + // ng-reflect comment - "(Label[text=Else]), (CommentNode)))", // the content to be displayed and its anchor + "(Label[text=Else])" + + ")" + + ")", - dumpView(componentRoot, true)); + dumpView(componentRoot, true)); }); }); @@ -384,11 +385,11 @@ describe("Renderer E2E", () => { assert.equal( "(ProxyViewContainer " + "(StackLayout " + - "(CommentNode), " + // ng-reflect comment - "(Label[text=Then]), (CommentNode), " + // the content to be displayed and its anchor - "(CommentNode)))", // the anchor for the else template + "(Label[text=Then])" + + ")" + + ")", - dumpView(componentRoot, true)); + dumpView(componentRoot, true)); }); }); @@ -403,11 +404,11 @@ describe("Renderer E2E", () => { assert.equal( "(ProxyViewContainer " + "(StackLayout " + - "(CommentNode), " + // the content to be displayed - "(Label[text=Else]), (CommentNode), " + // the content to be displayed - "(CommentNode)))", // the content to be displayed + "(Label[text=Else])" + + ")" + + ")", - dumpView(componentRoot, true)); + dumpView(componentRoot, true)); }); }); @@ -415,7 +416,7 @@ describe("Renderer E2E", () => { return testApp.loadComponent(NgForLabel).then((componentRef) => { const componentRoot = componentRef.instance.elementRef.nativeElement; assert.equal( - "(ProxyViewContainer (CommentNode), (Label[text=one]), (Label[text=two]), (Label[text=three]))", + "(ProxyViewContainer (Label[text=one]), (Label[text=two]), (Label[text=three]))", dumpView(componentRoot, true)); }); }); @@ -429,7 +430,7 @@ describe("Renderer E2E", () => { testApp.appRef.tick(); assert.equal( - "(ProxyViewContainer (CommentNode), (Label[text=one]), (Label[text=three]))", + "(ProxyViewContainer (Label[text=one]), (Label[text=three]))", dumpView(componentRoot, true)); }); }); @@ -443,7 +444,7 @@ describe("Renderer E2E", () => { testApp.appRef.tick(); assert.equal( - "(ProxyViewContainer (CommentNode), " + + "(ProxyViewContainer " + "(Label[text=one]), (Label[text=new]), (Label[text=two]), (Label[text=three]))", dumpView(componentRoot, true)); });