From 34cc34c44acd55b17093b4a21786963ef8d459b4 Mon Sep 17 00:00:00 2001 From: Zdravko Branzov Date: Thu, 18 Apr 2019 17:06:20 +0300 Subject: [PATCH 1/4] fix: loading of css when using webpack bundle --- samples/app/app.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/app/app.css b/samples/app/app.css index d09caa8e..b9e25b2b 100644 --- a/samples/app/app.css +++ b/samples/app/app.css @@ -1,4 +1,4 @@ -@import 'nativescript-theme-core/css/core.light.css'; +@import '~nativescript-theme-core/css/core.light.css'; /* Your CSS goes here */ From b839f87cb6c9a425727c1e9c78d549d8fa448845 Mon Sep 17 00:00:00 2001 From: Zdravko Branzov Date: Thu, 18 Apr 2019 17:28:55 +0300 Subject: [PATCH 2/4] chore: add custom webpack.config in order to use bundle during the build using current nativescript-dev-webpack plugin 0.21 --- samples/package.json | 18 ++- samples/webpack.config.js | 275 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 samples/webpack.config.js diff --git a/samples/package.json b/samples/package.json index 9325b8b1..c2779804 100644 --- a/samples/package.json +++ b/samples/package.json @@ -17,11 +17,25 @@ "nativescript-socketio": "^3.2.1", "nativescript-theme-core": "^1.0.4", "nativescript-toasty": "^1.3.0", - "nativescript-ui-gauge": "^3.7.1", - "nativescript-ui-sidedrawer": "^4.3.0", + "nativescript-ui-gauge": "^4.0.0", + "nativescript-ui-sidedrawer": "^6.0.0", "nativescript-vue-devtools": "^1.1.0", "tns-core-modules": "^5.3.1", "vue-router": "^3.0.1", "vuex": "^3.0.1" + }, + "devDependencies": { + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.18", + "mocha": "~5.2.0", + "mocha-junit-reporter": "~1.18.0", + "mocha-multi": "~1.0.1", + "mochawesome": "^3.1.1", + "nativescript-dev-appium": "~5.2.0", + "nativescript-dev-webpack": "^0.21.0" + }, + "scripts": { + "e2e": "node ./node_modules/nativescript-dev-appium/check-dev-deps.js && mocha --opts ./e2e/config/mocha.opts " } } diff --git a/samples/webpack.config.js b/samples/webpack.config.js new file mode 100644 index 00000000..c86382ce --- /dev/null +++ b/samples/webpack.config.js @@ -0,0 +1,275 @@ +const { join, relative, resolve, sep } = require("path"); + +const webpack = require("webpack"); +const nsWebpack = require("nativescript-dev-webpack"); +const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target"); +const CleanWebpackPlugin = require("clean-webpack-plugin"); +const CopyWebpackPlugin = require("copy-webpack-plugin"); +const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); +const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); +const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const hashSalt = Date.now().toString(); + +module.exports = env => { + // Add your custom Activities, Services and other android app components here. + const appComponents = [ + "tns-core-modules/ui/frame", + "tns-core-modules/ui/frame/activity", + ]; + + const platform = env && (env.android && "android" || env.ios && "ios"); + if (!platform) { + throw new Error("You need to provide a target platform!"); + } + + const platforms = ["ios", "android"]; + const projectRoot = __dirname; + + // Default destination inside platforms//... + const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot)); + const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS"; + + const { + // The 'appPath' and 'appResourcesPath' values are fetched from + // the nsconfig.json configuration file + // when bundling with `tns run android|ios --bundle`. + appPath = "app", + appResourcesPath = "app/App_Resources", + + // You can provide the following flags when running 'tns run android|ios' + snapshot, // --env.snapshot + uglify, // --env.uglify + report, // --env.report + sourceMap, // --env.sourceMap + hmr, // --env.hmr, + unitTesting, // --env.unitTesting + } = env; + const externals = nsWebpack.getConvertedExternals(env.externals); + + const appFullPath = resolve(projectRoot, appPath); + const appResourcesFullPath = resolve(projectRoot, appResourcesPath); + + const entryModule = nsWebpack.getEntryModule(appFullPath); + const entryPath = `.${sep}${entryModule}.js`; + console.log("ENTRY", entryPath); + const entries = { bundle: entryPath }; + if (platform === "ios") { + entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules.js"; + }; + + const config = { + mode: uglify ? "production" : "development", + context: appFullPath, + externals, + watchOptions: { + ignored: [ + appResourcesFullPath, + // Don't watch hidden files + "**/.*", + ] + }, + target: nativescriptTarget, + entry: entries, + output: { + pathinfo: false, + path: dist, + libraryTarget: "commonjs2", + filename: "[name].js", + globalObject: "global", + hashSalt + }, + resolve: { + extensions: [".js", ".scss", ".css"], + // Resolve {N} system modules from tns-core-modules + modules: [ + "node_modules/tns-core-modules", + "node_modules", + ], + mainFields: ['main', 'module'], + alias: { + '~': appFullPath + }, + // don't resolve symlinks to symlinked modules + symlinks: false + }, + resolveLoader: { + // don't resolve symlinks to symlinked loaders + symlinks: false + }, + node: { + // Disable node shims that conflict with NativeScript + "http": false, + "timers": false, + "setImmediate": false, + "fs": "empty", + "__dirname": false, + }, + devtool: sourceMap ? "inline-source-map" : "none", + optimization: { + runtimeChunk: "single", + splitChunks: { + cacheGroups: { + vendor: { + name: "vendor", + chunks: "all", + test: (module, chunks) => { + const moduleName = module.nameForCondition ? module.nameForCondition() : ''; + return /[\\/]node_modules[\\/]/.test(moduleName) || + appComponents.some(comp => comp === moduleName); + + }, + enforce: true, + }, + } + }, + minimize: !!uglify, + minimizer: [ + new UglifyJsPlugin({ + parallel: true, + cache: true, + uglifyOptions: { + output: { + comments: false, + }, + compress: { + // The Android SBG has problems parsing the output + // when these options are enabled + 'collapse_vars': platform !== "android", + sequences: platform !== "android", + } + } + }) + ], + }, + module: { + rules: [ + { + test: nsWebpack.getEntryPathRegExp(appFullPath, entryPath), + use: [ + // Require all Android app components + platform === "android" && { + loader: "nativescript-dev-webpack/android-app-components-loader", + options: { modules: appComponents } + }, + + { + loader: "nativescript-dev-webpack/bundle-config-loader", + options: { + loadCss: !snapshot, // load the application css if in debug mode + unitTesting, + appFullPath, + projectRoot, + } + }, + ].filter(loader => !!loader) + }, + + { + test: /-page\.js$/, + use: "nativescript-dev-webpack/script-hot-loader" + }, + + { + test: /\.(css|scss)$/, + use: "nativescript-dev-webpack/style-hot-loader" + }, + + { + test: /\.(html|xml)$/, + use: "nativescript-dev-webpack/markup-hot-loader" + }, + + { test: /\.(html|xml)$/, use: "nativescript-dev-webpack/xml-namespace-loader"}, + + { + test: /\.css$/, + use: { loader: "css-loader", options: { minimize: false, url: false } } + }, + + { + test: /\.scss$/, + use: [ + { loader: "css-loader", options: { minimize: false, url: false } }, + "sass-loader" + ] + }, + ] + }, + plugins: [ + // Define useful constants like TNS_WEBPACK + new webpack.DefinePlugin({ + "global.TNS_WEBPACK": "true", + "process": undefined, + }), + // Remove all files from the out dir. + new CleanWebpackPlugin([ `${dist}/**/*` ]), + // Copy assets to out dir. Add your own globs as needed. + new CopyWebpackPlugin([ + { from: { glob: "fonts/**" } }, + { from: { glob: "**/*.jpg" } }, + { from: { glob: "**/*.png" } }, + ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }), + // Generate a bundle starter script and activate it in package.json + new nsWebpack.GenerateBundleStarterPlugin( + // Don't include `runtime.js` when creating a snapshot. The plugin + // configures the WebPack runtime to be generated inside the snapshot + // module and no `runtime.js` module exist. + (snapshot ? [] : ["./runtime"]) + .concat([ + "./vendor", + "./bundle", + ]) + ), + // For instructions on how to set up workers with webpack + // check out https://github.com/nativescript/worker-loader + new NativeScriptWorkerPlugin(), + new nsWebpack.PlatformFSPlugin({ + platform, + platforms, + }), + // Does IPC communication with the {N} CLI to notify events when running in watch mode. + new nsWebpack.WatchStateLoggerPlugin(), + ], + }; + + // Copy the native app resources to the out dir + // only if doing a full build (tns run/build) and not previewing (tns preview) + if (!externals || externals.length === 0) { + config.plugins.push(new CopyWebpackPlugin([ + { + from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, + to: `${dist}/App_Resources/${appResourcesPlatformDir}`, + context: projectRoot + }, + ])); + } + + if (report) { + // Generate report files for bundles content + config.plugins.push(new BundleAnalyzerPlugin({ + analyzerMode: "static", + openAnalyzer: false, + generateStatsFile: true, + reportFilename: resolve(projectRoot, "report", `report.html`), + statsFilename: resolve(projectRoot, "report", `stats.json`), + })); + } + + if (snapshot) { + config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({ + chunk: "vendor", + requireModules: [ + "tns-core-modules/bundle-entry-points", + ], + projectRoot, + webpackConfig: config, + })); + } + + if (hmr) { + config.plugins.push(new webpack.HotModuleReplacementPlugin()); + } + + + return config; +}; From bfd6ac7bb736fc5773f247b8749f7f54099bdc79 Mon Sep 17 00:00:00 2001 From: Zdravko Branzov Date: Thu, 18 Apr 2019 17:30:18 +0300 Subject: [PATCH 3/4] chore: add travis file to orchestrate the testing flow and tests --- .gitignore | 4 + .travis.yml | 97 +++++++++++++++++++ package.json | 1 + .../app-with-radsidedrawer-tabs-and-router.js | 9 +- samples/app/package.json | 2 +- samples/e2e/config/appium.capabilities.json | 83 ++++++++++++++++ samples/e2e/config/mocha.opts | 5 + samples/e2e/setup.js | 9 ++ samples/e2e/tests.e2e.js | 75 ++++++++++++++ 9 files changed, 280 insertions(+), 5 deletions(-) create mode 100644 .travis.yml create mode 100644 samples/e2e/config/appium.capabilities.json create mode 100644 samples/e2e/config/mocha.opts create mode 100644 samples/e2e/setup.js create mode 100644 samples/e2e/tests.e2e.js diff --git a/.gitignore b/.gitignore index 8eb56d04..70e9ae36 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ samples/package-lock.json samples/platforms samples/app/nativescript-vue.js samples/app/nativescript-vue.js.map +samples/hooks/ +samples/mochawesome-report/ +samples/e2e/reports/ +test-results.xml dist/ packages/nativescript-vue-template-compiler/index.js !docs/dist/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..198a4b0f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,97 @@ +env: + global: + - ANDROID_PACKAGE_VUE='demo-ns-vue.apk' + - ANDROID_PACKAGE_FOLDER_VUE=$TRAVIS_BUILD_DIR/samples/outputs + - SAUCE_STORAGE="https://saucelabs.com/rest/v1/storage/$SAUCE_USER" + - IOS_PACKAGE_VUE='demo-ns-vue.zip' + - IOS_PACKAGE_FOLDER_VUE=$TRAVIS_BUILD_DIR/samples/outputs + +git: + depth: 1 + +branches: + only: + - master + +matrix: + include: + - stage: "Unit Tests" + language: node_js + os: linux + node_js: "8" + script: npm i && npm run test + - stage: "Build app" + os: osx + env: + - WebpackiOS="12.0" + - Type="VueJS" + osx_image: xcode10.0 + language: node_js + node_js: "8" + jdk: oraclejdk8 + before_script: pod repo update + script: + - npm i && npm run prepare:test:app + - cd samples && npm i && tns build ios --bundle --env.uglify --copy-to "./outputs/demo-ns-vue.app" + - cd $IOS_PACKAGE_FOLDER_VUE && zip -r $IOS_PACKAGE_VUE demo-ns-vue.app + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$IOS_PACKAGE_VUE?overwrite=true --data-binary @$IOS_PACKAGE_FOLDER_VUE/$IOS_PACKAGE_VUE" + - language: android + os: linux + env: + - WebpackAndroid="28" + - Type="VueJS" + jdk: oraclejdk8 + before_install: nvm install 8 + script: + - npm i && npm run prepare:test:app + - cd samples && npm i && tns build android --bundle --env.uglify --copy-to "./outputs/demo-ns-vue.apk" + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$ANDROID_PACKAGE_VUE?overwrite=true --data-binary @$ANDROID_PACKAGE_FOLDER_VUE/$ANDROID_PACKAGE_VUE" + - stage: "UI Tests" + env: + - iOS="12.0" + - Type="VueJS" + language: node_js + os: linux + node_js: "8" + script: + - npm i -g appium + - cd samples && npm i + - travis_wait travis_retry npm run e2e -- --runType sim12iPhoneX --sauceLab --appPath $IOS_PACKAGE_VUE + - os: linux + env: + - Android="24" + - Type="VueJS" + language: node_js + os: linux + node_js: "8" + script: + - npm i -g appium + - cd samples && npm i + - travis_wait travis_retry npm run e2e -- --runType android24.sauce --sauceLab --appPath $ANDROID_PACKAGE_VUE + +android: + components: + - tools + - platform-tools + - build-tools-28.0.3 + - android-28 + - android-23 + - extra-android-m2repository + +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + +cache: + directories: + - .nvm + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + +before_install: + - sudo pip install --upgrade pip + - sudo pip install six + +install: + - echo no | npm install -g nativescript + - tns usage-reporting disable + - tns error-reporting disable \ No newline at end of file diff --git a/package.json b/package.json index 9c899aaf..8998e4a9 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "tdd": "jest --watch", "samples": "node build/sample-runner.js", "dev": "rollup -c build/config.js -w --o samples/app/nativescript-vue.js --environment TARGET:nativescript-vue", + "prepare:test:app": "rollup -c build/config.js --o samples/app/nativescript-vue.js --environment TARGET:nativescript-vue", "dev:dist": "rollup -c build/config.js -w --o dist/index.js --environment TARGET:nativescript-vue", "build": "node build/build.js", "build:docs": "cd docs && npm run build", diff --git a/samples/app/app-with-radsidedrawer-tabs-and-router.js b/samples/app/app-with-radsidedrawer-tabs-and-router.js index a38c8580..cecf6750 100644 --- a/samples/app/app-with-radsidedrawer-tabs-and-router.js +++ b/samples/app/app-with-radsidedrawer-tabs-and-router.js @@ -21,8 +21,8 @@ const Home = { const Tabs = { template: ` - + @@ -34,7 +34,8 @@ const Tabs = { - `, + + `, data() { return { selectedTabIndex: 0, @@ -103,7 +104,7 @@ new Vue({ - `, +`, data() { return {} }, diff --git a/samples/app/package.json b/samples/app/package.json index 9cea5c15..429371c3 100644 --- a/samples/app/package.json +++ b/samples/app/package.json @@ -1,5 +1,5 @@ { - "main": "modals.js", + "main": "app-with-radsidedrawer-tabs-and-router.js", "name": "nativescript-template-tutorial", "version": "1.0.1" } \ No newline at end of file diff --git a/samples/e2e/config/appium.capabilities.json b/samples/e2e/config/appium.capabilities.json new file mode 100644 index 00000000..e4927863 --- /dev/null +++ b/samples/e2e/config/appium.capabilities.json @@ -0,0 +1,83 @@ +{ + "android23.local": { + "platformName": "Android", + "platformVersion": "6.0", + "deviceName": "Emulator_Api23_Default", + "avd": "Emulator_Api23_Default", + "noReset": true + }, + "android23": { + "platformName": "Android", + "platformVersion": "6.0", + "deviceName": "Android Emulator", + "appium-version": "1.7.1", + "noReset": true + }, + "android25": { + "platformName": "Android", + "platformVersion": "7.1", + "deviceName": "Android GoogleAPI Emulator", + "appium-version": "1.7.1", + "noReset": true + }, + "android24": { + "platformName": "Android", + "platformVersion": "7.0", + "deviceName": "Android GoogleAPI Emulator", + "appium-version": "1.9.1", + "noReset": true, + "lt": 60000, + "newCommandTimeout": 720, + "fullReset": false, + "idleTimeout": 120, + "automationName": "Appium" + }, + "android24.sauce": { + "platformName": "Android", + "platformVersion": "7.0", + "deviceName": "Android GoogleAPI Emulator", + "lt": 60000, + "newCommandTimeout": 720, + "appiumVersion": "1.9.1", + "noReset": true, + "fullReset": false, + "app": "", + "idleTimeout": 120, + "automationName": "Appium" + }, + "sim11iPhone6": { + "platformName": "iOS", + "platformVersion": "11.0", + "deviceName": "iPhone 6", + "appium-version": "1.7.1", + "app": "" + }, + "sim103iPhone6": { + "browserName": "", + "appium-version": "1.7.1", + "platformName": "iOS", + "platformVersion": "10.3", + "deviceName": "iPhone 6", + "app": "" + }, + "sim10iPhone6": { + "platformName": "iOS", + "platformVersion": "10.0", + "deviceName": "iPhone 6", + "appium-version": "1.7.1", + "app": "" + }, + "sim12iPhoneX":{ + "platformName": "iOS", + "platformVersion": "12.0", + "deviceName": "iPhone X", + "appiumVersion": "1.9.1", + "app": "", + "noReset": true, + "fullReset": false, + "density": 3, + "offsetPixels": 87, + "idleTimeout": 120, + "automationName": "Appium" + } +} \ No newline at end of file diff --git a/samples/e2e/config/mocha.opts b/samples/e2e/config/mocha.opts new file mode 100644 index 00000000..635e0924 --- /dev/null +++ b/samples/e2e/config/mocha.opts @@ -0,0 +1,5 @@ +--timeout 200000 +--recursive e2e +--reporter mocha-multi +--reporter-options mochawesome=-,mocha-junit-reporter=test-results.xml +--exit \ No newline at end of file diff --git a/samples/e2e/setup.js b/samples/e2e/setup.js new file mode 100644 index 00000000..a8938a89 --- /dev/null +++ b/samples/e2e/setup.js @@ -0,0 +1,9 @@ +const nsAppium = require("nativescript-dev-appium"); + +before("start appium server", async () => { + await nsAppium.startServer(); +}); + +after("stop appium server", async () => { + await nsAppium.stopServer(); +}); diff --git a/samples/e2e/tests.e2e.js b/samples/e2e/tests.e2e.js new file mode 100644 index 00000000..2a92c31d --- /dev/null +++ b/samples/e2e/tests.e2e.js @@ -0,0 +1,75 @@ +const nsAppium = require("nativescript-dev-appium"); +const expect = require("chai").expect; +const fs = require('fs'); +const addContext = require('mochawesome/addContext'); +const rimraf = require('rimraf'); + +describe("Vue", () => { + let driver, isSauceRun; + + before(async function () { + driver = await nsAppium.createDriver(); + driver.defaultWaitTime = 15000; + isSauceRun = driver.nsCapabilities.isSauceLab; + let dir = "mochawesome-report"; + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + rimraf('mochawesome-report/*', function () { }); + }); + + after(async () => { + if (isSauceRun) { + driver.sessionId().then(function (sessionId) { + console.log("Report https://saucelabs.com/beta/tests/" + sessionId); + }); + } + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state && this.currentTest.state === "failed") { + let png = await driver.logScreenshot(this.currentTest.title); + fs.copyFile(png, './mochawesome-report/' + this.currentTest.title + '.png', function (err) { + if (err) { + throw err; + } + console.log('Screenshot saved.'); + }); + addContext(this, './' + this.currentTest.title + '.png'); + } + }); + + describe("app-with-radsidedrawer-tabs-and-router", () => { + it("Open sidedrawer", async () => { + const home = await driver.findElementByText("Home"); + expect(home).to.exist; + const menu = await driver.findElementByText("Menu"); + await menu.click(); + }); + + it("Open a menu item", async () => { + const item = await driver.findElementByText("Hello1"); + await item.click(); + const detail = await driver.findElementByText("Hello world"); + expect(detail).to.exist; + }); + + it("Open Tabs item", async () => { + const menu = await driver.findElementByText("Menu"); + await menu.click(); + const item = await driver.findElementByText("Tabs"); + await item.click(); + const tab1 = await driver.findElementByText("You are on Tab 1"); + expect(tab1).to.exist; + }); + + it("Click Tab 2", async () => { + const tab = await driver.findElementByText("Tab 2"); + await tab.click(); + const tab2Content = await driver.findElementByText("You are on Tab 2"); + expect(tab2Content).to.exist; + }); + }); +}); \ No newline at end of file From 44fba7c74da1474fe5a5ef3230723f1d7bcb050e Mon Sep 17 00:00:00 2001 From: Zdravko Branzov Date: Fri, 19 Apr 2019 09:03:05 +0300 Subject: [PATCH 4/4] fix: ios build in travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 198a4b0f..10a8115a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,6 @@ matrix: language: node_js node_js: "8" jdk: oraclejdk8 - before_script: pod repo update script: - npm i && npm run prepare:test:app - cd samples && npm i && tns build ios --bundle --env.uglify --copy-to "./outputs/demo-ns-vue.app"