ci: run apps/automated on CI (#9196)

This commit is contained in:
Igor Randjelovic
2021-02-05 20:21:16 +01:00
committed by GitHub
parent abc78800f2
commit 4945702620
13 changed files with 182 additions and 97 deletions

39
.github/workflows/apps_automated.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: 'apps/automated'
on:
push:
branches:
- master
pull_request:
workflow_dispatch:
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Install Python
uses: actions/setup-python@v1
- name: Install NativeScript
run: |
python -m pip install --upgrade pip six
npm i -g nativescript --ignore-scripts
ns usage-reporting disable
ns error-reporting disable
ns doctor
- name: Setup
run: npm run setup
- name: Create Emulator
uses: rigor789/action-create-emulator@master
- name: Test (Android)
run: node tools/scripts/run-automated.js android
- name: Test (iOS)
if: always() # run iOS tests even if Android tests failed
run: node tools/scripts/run-automated.js ios

1
apps/automated/src/globals.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare var __CI__;

View File

@ -41,16 +41,18 @@ allTests['PLATFORM'] = platformTests;
import * as fsTests from './file-system/file-system-tests'; import * as fsTests from './file-system/file-system-tests';
allTests['FILE-SYSTEM'] = fsTests; allTests['FILE-SYSTEM'] = fsTests;
// Disabled tests as they have external dependencies import * as httpTests from './http/http-tests';
// TODO: find a way to run these tests locally, but don't run them on the CI as they are flaky import * as xhrTests from './xhr/xhr-tests';
// import * as httpTests from "./http/http-tests"; import * as fetchTests from './fetch/fetch-tests';
// allTests["HTTP"] = httpTests; import * as timerTests from './timer/timer-tests';
// import * as xhrTests from "./xhr/xhr-tests"; // don't run these on CI as they are flaky
// allTests["XHR"] = xhrTests; if (!__CI__) {
allTests['HTTP'] = httpTests;
// import * as fetchTests from "./fetch/fetch-tests"; allTests['XHR'] = xhrTests;
// allTests["FETCH"] = fetchTests; allTests['FETCH'] = fetchTests;
allTests['TIMER'] = timerTests;
}
import * as appSettingsTests from './application-settings/application-settings-tests'; import * as appSettingsTests from './application-settings/application-settings-tests';
allTests['APPLICATION-SETTINGS'] = appSettingsTests; allTests['APPLICATION-SETTINGS'] = appSettingsTests;
@ -70,9 +72,6 @@ allTests['VIRTUAL-ARRAY'] = virtualArrayTests;
import * as observableTests from './data/observable-tests'; import * as observableTests from './data/observable-tests';
allTests['OBSERVABLE'] = observableTests; allTests['OBSERVABLE'] = observableTests;
import * as timerTests from './timer/timer-tests';
allTests['TIMER'] = timerTests;
import * as animationFrameTests from './animation-frame/animation-frame'; import * as animationFrameTests from './animation-frame/animation-frame';
allTests['ANIMATION-FRAME'] = animationFrameTests; allTests['ANIMATION-FRAME'] = animationFrameTests;

View File

@ -155,6 +155,7 @@ export function test_setInterval_callbackCalledDuringPeriod(done) {
export function test_setInterval_callbackCalledWithExtraArgs(done) { export function test_setInterval_callbackCalledWithExtraArgs(done) {
let counter: number = 0; let counter: number = 0;
const rnd: number = Math.random(); const rnd: number = Math.random();
const threshold = 100;
const start = TKUnit.time(); const start = TKUnit.time();
const id = timer.setInterval( const id = timer.setInterval(
@ -163,10 +164,10 @@ export function test_setInterval_callbackCalledWithExtraArgs(done) {
if (counter === 4) { if (counter === 4) {
const end = TKUnit.time(); const end = TKUnit.time();
timer.clearInterval(id); timer.clearInterval(id);
done(end - start > 250 ? new Error('setInterval too slow.') : null); done(end - start > 1000 + threshold ? new Error('setInterval too slow.') : null);
} }
}, },
50, 250,
rnd rnd
); );
} }
@ -179,11 +180,11 @@ export function test_setInterval_callbackNotDelayedByBusyWork() {
calls++; calls++;
if (firstCall) { if (firstCall) {
firstCall = false; firstCall = false;
TKUnit.wait(0.025); TKUnit.wait(0.125);
} }
}, 50); }, 250);
TKUnit.wait(0.11); TKUnit.wait(0.55);
timer.clearInterval(id); timer.clearInterval(id);
TKUnit.assertEqual(calls, 2, 'Callback should be called multiple times with busy wait'); TKUnit.assertEqual(calls, 2, 'Callback should be called multiple times with busy wait');
} }

View File

@ -1,53 +1,53 @@
import * as buttonModule from '@nativescript/core/ui/button'; import { Color, Button, Utils, Enums } from '@nativescript/core';
import * as colorModule from '@nativescript/core/color';
import * as utilsModule from '@nativescript/core/utils/utils';
import * as enums from '@nativescript/core/ui/enums';
export function getNativeText(button: buttonModule.Button): string { export function getNativeText(button: Button): string {
return button.android.getText(); return button.android.getText();
} }
export function getNativeTextWrap(button: buttonModule.Button): boolean { export function getNativeTextWrap(button: Button): boolean {
return (<android.widget.Button>button.android).getLineCount() === 1; return (<android.widget.Button>button.android).getLineCount() === 1;
} }
export function getNativeFontSize(button: buttonModule.Button): number { export function getNativeFontSize(button: Button): number {
var density = utilsModule.layout.getDisplayDensity(); let density = Utils.layout.getDisplayDensity();
return button.android.getTextSize() / density; return button.android.getTextSize() / density;
} }
export function getNativeColor(button: buttonModule.Button): colorModule.Color { export function getNativeColor(button: Button): Color {
return new colorModule.Color(button.android.getTextColors().getDefaultColor()); return new Color(button.android.getTextColors().getDefaultColor());
} }
export function getNativeBackgroundColor(button: buttonModule.Button): colorModule.Color { export function getNativeBackgroundColor(button: Button): Color {
var bkg = <any>button.android.getBackground(); let bg = <any>button.android.getBackground();
if (bkg instanceof org.nativescript.widgets.BorderDrawable) { if (bg instanceof org.nativescript.widgets.BorderDrawable) {
return new colorModule.Color((<org.nativescript.widgets.BorderDrawable>bkg).getBackgroundColor()); return new Color(bg.getBackgroundColor());
} else if (bg instanceof android.graphics.drawable.ColorDrawable) {
console.log(bg);
return new Color(bg.getColor());
} else { } else {
return new colorModule.Color(bkg.backgroundColor); return new Color(bg.backgroundColor);
} }
} }
export function getNativeTextAlignment(button: buttonModule.Button): string { export function getNativeTextAlignment(button: Button): string {
var gravity = button.android.getGravity(); let gravity = button.android.getGravity();
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) {
return enums.TextAlignment.left; return Enums.TextAlignment.left;
} }
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.CENTER_HORIZONTAL) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.CENTER_HORIZONTAL) {
return enums.TextAlignment.center; return Enums.TextAlignment.center;
} }
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.RIGHT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.RIGHT) {
return enums.TextAlignment.right; return Enums.TextAlignment.right;
} }
return 'unexpected value'; return 'unexpected value';
} }
export function performNativeClick(button: buttonModule.Button): void { export function performNativeClick(button: Button): void {
button.android.performClick(); button.android.performClick();
} }

View File

@ -3,7 +3,7 @@ import * as enums from '@nativescript/core/ui/enums';
import * as colorModule from '@nativescript/core/color'; import * as colorModule from '@nativescript/core/color';
export function getNativeTextAlignment(label: labelModule.Label): string { export function getNativeTextAlignment(label: labelModule.Label): string {
var gravity = label.android.getGravity(); let gravity = label.android.getGravity();
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) {
return enums.TextAlignment.left; return enums.TextAlignment.left;
@ -21,10 +21,12 @@ export function getNativeTextAlignment(label: labelModule.Label): string {
} }
export function getNativeBackgroundColor(label: labelModule.Label): colorModule.Color { export function getNativeBackgroundColor(label: labelModule.Label): colorModule.Color {
var bkg = <any>label.android.getBackground(); let bg = <any>label.android.getBackground();
if (bkg instanceof org.nativescript.widgets.BorderDrawable) { if (bg instanceof org.nativescript.widgets.BorderDrawable) {
return new colorModule.Color((<org.nativescript.widgets.BorderDrawable>bkg).getBackgroundColor()); return new colorModule.Color(bg.getBackgroundColor());
} else if (bg instanceof android.graphics.drawable.ColorDrawable) {
return new colorModule.Color(bg.getColor());
} else { } else {
return new colorModule.Color(bkg.backgroundColor); return new colorModule.Color(bg.backgroundColor);
} }
} }

View File

@ -330,8 +330,8 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
normalColor = actualColors.getDefaultColor(); normalColor = actualColors.getDefaultColor();
TKUnit.assert(normalColor, 'Expected: ' + expColor + ', Actual: ' + normalColor); TKUnit.assert(normalColor, 'Expected: ' + expColor + ', Actual: ' + normalColor);
const bkg = <org.nativescript.widgets.BorderDrawable>testLabel.android.getBackground(); const bg = testLabel.android.getBackground();
actualBackgroundColor = bkg.getBackgroundColor(); actualBackgroundColor = bg['getBackgroundColor'] ? bg.getBackgroundColor() : bg.getColor();
expBackgroundColor = android.graphics.Color.parseColor(backgroundColor); expBackgroundColor = android.graphics.Color.parseColor(backgroundColor);
TKUnit.assertEqual(actualBackgroundColor, expBackgroundColor); TKUnit.assertEqual(actualBackgroundColor, expBackgroundColor);
} else { } else {

View File

@ -1,74 +1,74 @@
import * as textFieldModule from '@nativescript/core/ui/text-field'; import { TextField, Color, Utils, Enums } from '@nativescript/core';
import * as colorModule from '@nativescript/core/color';
import * as utilsModule from '@nativescript/core/utils/utils';
import * as enums from '@nativescript/core/ui/enums';
export function getNativeText(textField: textFieldModule.TextField): string { export function getNativeText(textField: TextField): string {
return textField.android.getText().toString(); return textField.android.getText().toString();
} }
export function getNativeHint(textField: textFieldModule.TextField): string { export function getNativeHint(textField: TextField): string {
return textField.android.getHint(); return textField.android.getHint();
} }
export function getNativeSecure(textField: textFieldModule.TextField): boolean { export function getNativeSecure(textField: TextField): boolean {
var inputType = textField.android.getInputType(); let inputType = textField.android.getInputType();
return (inputType & android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD) === android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD || (inputType & android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD) === android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD; return (inputType & android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD) === android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD || (inputType & android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD) === android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
} }
export function getNativeFontSize(textField: textFieldModule.TextField): number { export function getNativeFontSize(textField: TextField): number {
var density = utilsModule.layout.getDisplayDensity(); let density = Utils.layout.getDisplayDensity();
return textField.android.getTextSize() / density; return textField.android.getTextSize() / density;
} }
export function getNativeColor(textField: textFieldModule.TextField): colorModule.Color { export function getNativeColor(textField: TextField): Color {
return new colorModule.Color(textField.android.getTextColors().getDefaultColor()); return new Color(textField.android.getTextColors().getDefaultColor());
} }
export function getNativePlaceholderColor(textField: textFieldModule.TextField): colorModule.Color { export function getNativePlaceholderColor(textField: TextField): Color {
return new colorModule.Color(textField.android.getHintTextColors().getDefaultColor()); return new Color(textField.android.getHintTextColors().getDefaultColor());
} }
export function getNativeBackgroundColor(textField: textFieldModule.TextField): colorModule.Color { export function getNativeBackgroundColor(textField: TextField): Color {
var bkg = <any>textField.android.getBackground(); let bg = <any>textField.android.getBackground();
if (bkg instanceof org.nativescript.widgets.BorderDrawable) { if (bg instanceof org.nativescript.widgets.BorderDrawable) {
return new colorModule.Color((<org.nativescript.widgets.BorderDrawable>bkg).getBackgroundColor()); return new Color(bg.getBackgroundColor());
} else if (bg instanceof android.graphics.drawable.ColorDrawable) {
console.log(bg);
return new Color(bg.getColor());
} else { } else {
return new colorModule.Color(bkg.backgroundColor); return new Color(bg.backgroundColor);
} }
} }
export function getNativeTextAlignment(textField: textFieldModule.TextField): string { export function getNativeTextAlignment(textField: TextField): string {
var gravity = textField.android.getGravity(); var gravity = textField.android.getGravity();
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) {
return enums.TextAlignment.left; return Enums.TextAlignment.left;
} }
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.CENTER_HORIZONTAL) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.CENTER_HORIZONTAL) {
return enums.TextAlignment.center; return Enums.TextAlignment.center;
} }
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.RIGHT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.RIGHT) {
return enums.TextAlignment.right; return Enums.TextAlignment.right;
} }
return 'unexpected value'; return 'unexpected value';
} }
export function getNativeFocus(textField: textFieldModule.TextField): boolean { export function getNativeFocus(textField: TextField): boolean {
// //
return true; return true;
} }
export function typeTextNatively(textField: textFieldModule.TextField, text: string): void { export function typeTextNatively(textField: TextField, text: string): void {
textField.android.requestFocus(); textField.android.requestFocus();
textField.android.setText(text); textField.android.setText(text);
textField.android.clearFocus(); textField.android.clearFocus();
} }
export function typeTextNativelyWithReturn(textField: textFieldModule.TextField, text: string): void { export function typeTextNativelyWithReturn(textField: TextField, text: string): void {
// //
} }

View File

@ -1,13 +1,10 @@
import * as textViewModule from '@nativescript/core/ui/text-view'; import { TextView, Color, Utils, Enums } from '@nativescript/core';
import * as colorModule from '@nativescript/core/color';
import * as utilsModule from '@nativescript/core/utils/utils';
import * as enums from '@nativescript/core/ui/enums';
export function getNativeText(textView: textViewModule.TextView): string { export function getNativeText(textView: TextView): string {
return textView.android.getText().toString(); return textView.android.getText().toString();
} }
export function getNativeEditable(textView: textViewModule.TextView): boolean { export function getNativeEditable(textView: TextView): boolean {
if (textView.android.getKeyListener()) { if (textView.android.getKeyListener()) {
return true; return true;
} else { } else {
@ -15,53 +12,55 @@ export function getNativeEditable(textView: textViewModule.TextView): boolean {
} }
} }
export function getNativeHint(textView: textViewModule.TextView): string { export function getNativeHint(textView: TextView): string {
return textView.android.getHint(); return textView.android.getHint();
} }
export function getNativeFontSize(textView: textViewModule.TextView): number { export function getNativeFontSize(textView: TextView): number {
var density = utilsModule.layout.getDisplayDensity(); let density = Utils.layout.getDisplayDensity();
return textView.android.getTextSize() / density; return textView.android.getTextSize() / density;
} }
export function getNativeColor(textView: textViewModule.TextView): colorModule.Color { export function getNativeColor(textView: TextView): Color {
return new colorModule.Color(textView.android.getTextColors().getDefaultColor()); return new Color(textView.android.getTextColors().getDefaultColor());
} }
export function getNativeBackgroundColor(textView: textViewModule.TextView): colorModule.Color { export function getNativeBackgroundColor(textView: TextView): Color {
var bkg = <any>textView.android.getBackground(); let bg = <any>textView.android.getBackground();
if (bkg instanceof org.nativescript.widgets.BorderDrawable) { if (bg instanceof org.nativescript.widgets.BorderDrawable) {
return new colorModule.Color((<org.nativescript.widgets.BorderDrawable>bkg).getBackgroundColor()); return new Color(bg.getBackgroundColor());
} else if (bg instanceof android.graphics.drawable.ColorDrawable) {
return new Color(bg.getColor());
} else { } else {
return new colorModule.Color(bkg.backgroundColor); return new Color(bg.backgroundColor);
} }
} }
export function getNativeTextAlignment(textView: textViewModule.TextView): string { export function getNativeTextAlignment(textView: TextView): string {
var gravity = textView.android.getGravity(); let gravity = textView.android.getGravity();
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.LEFT) {
return enums.TextAlignment.left; return Enums.TextAlignment.left;
} }
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.CENTER_HORIZONTAL) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.CENTER_HORIZONTAL) {
return enums.TextAlignment.center; return Enums.TextAlignment.center;
} }
if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.RIGHT) { if ((gravity & android.view.Gravity.HORIZONTAL_GRAVITY_MASK) === android.view.Gravity.RIGHT) {
return enums.TextAlignment.right; return Enums.TextAlignment.right;
} }
return 'unexpected value'; return 'unexpected value';
} }
export function typeTextNatively(textView: textViewModule.TextView, text: string): void { export function typeTextNatively(textView: TextView, text: string): void {
textView.android.requestFocus(); textView.android.requestFocus();
textView.android.setText(text); textView.android.setText(text);
textView.android.clearFocus(); textView.android.clearFocus();
} }
export function getNativeMaxLines(textView: textViewModule.TextView): number { export function getNativeMaxLines(textView: TextView): number {
return textView.android.getMaxLines(); return textView.android.getMaxLines();
} }

View File

@ -1,6 +1,8 @@
const webpackConfig = require('./webpack.config'); const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpackConfig = require('./webpack.config');
module.exports = (env) => { module.exports = (env) => {
env = env || {}; env = env || {};
const baseConfig = webpackConfig(env); const baseConfig = webpackConfig(env);
@ -9,5 +11,9 @@ module.exports = (env) => {
{ from: { glob: 'ui/web-view/*.html', dot: false } } { from: { glob: 'ui/web-view/*.html', dot: false } }
])) ]))
baseConfig.plugins.push(new webpack.DefinePlugin({
__CI__: !!process.env.CI
}))
return baseConfig; return baseConfig;
}; };

View File

@ -55,6 +55,7 @@
"reduce-css-calc": "~2.1.7", "reduce-css-calc": "~2.1.7",
"shady-css-parser": "^0.1.0", "shady-css-parser": "^0.1.0",
"terser-webpack-plugin": "~3.0.6", "terser-webpack-plugin": "~3.0.6",
"tree-kill": "^1.2.2",
"ts-jest": "26.4.0", "ts-jest": "26.4.0",
"ts-node": "~8.10.2", "ts-node": "~8.10.2",
"ts-patch": "^1.2.5", "ts-patch": "^1.2.5",

View File

@ -45,12 +45,13 @@ export namespace ad {
androidView._cachedDrawable = constantState || drawable; androidView._cachedDrawable = constantState || drawable;
} }
const isBorderDrawable = drawable instanceof org.nativescript.widgets.BorderDrawable; const isBorderDrawable = drawable instanceof org.nativescript.widgets.BorderDrawable;
const isColorDrawable = drawable instanceof android.graphics.drawable.ColorDrawable;
const onlyColor = !background.hasBorderWidth() && !background.hasBorderRadius() && !background.clipPath && !background.image && !!background.color; const onlyColor = !background.hasBorderWidth() && !background.hasBorderRadius() && !background.clipPath && !background.image && !!background.color;
if (drawable instanceof android.graphics.drawable.ColorDrawable && onlyColor) { if (!isBorderDrawable && isColorDrawable && onlyColor) {
drawable.setColor(background.color.android); drawable.setColor(background.color.android);
drawable.invalidateSelf(); drawable.invalidateSelf();
} else if (isSetColorFilterOnlyWidget(nativeView) && drawable && onlyColor) { } else if (isSetColorFilterOnlyWidget(nativeView) && drawable && onlyColor) {
if (drawable instanceof org.nativescript.widgets.BorderDrawable && androidView._cachedDrawable) { if (isBorderDrawable && androidView._cachedDrawable) {
if (!(androidView._cachedDrawable instanceof android.graphics.drawable.Drawable.ConstantState)) { if (!(androidView._cachedDrawable instanceof android.graphics.drawable.Drawable.ConstantState)) {
return; return;
} }

View File

@ -0,0 +1,36 @@
/**
* Script to run the automated tests & exit after the tests are finished.
* Mainly intended to be used on CI
*
* Usage: node run-automated.js <platform>
*/
const spawn = require('child_process').spawn
const kill = require('tree-kill');
const spawned_process = spawn('npm', ['start', `apps.automated.${process.argv[2]}`], {
stdio: ['inherit', 'pipe', 'pipe']
})
const {stdout, stderr} = spawned_process
stdout.pipe(process.stdout)
stderr.pipe(process.stderr)
let lineBuffer = []
stdout.on('data', data => {
const line = data.toString();
// start buffering lines when tests are complete
if(lineBuffer.length || line.includes('=== ALL TESTS COMPLETE ===')) {
lineBuffer.push(line)
}
if(line.includes('Tests EOF!')) {
let ok = lineBuffer.join('\n').includes('OK, 0 failed')
console.log(ok ? 'Tests PASSED' : 'Tests FAILED');
kill(spawned_process.pid)
process.exit(ok ? 0 : 1)
}
})