Is it possible to use metadata inside the test script? - testing

Is there a way to do an IF condition on the metadata in the test script? For e.g
test.meta({ tablet: ‘true’, portrait: 'false', landscape: 'true' })(‘L0 | Tablet device’, async t => {
// Verify component exists in portrait and landscape mode
await t.expect(abc).ok();
// Verify component exists in landscape mode only
if (t.metadata.landscape == 'true') {
......
}
});

You can get the meta inside a test using the following code:
t.testRun.test.meta
However, I need to note that it's not a documented API, and it can be changed in the future, so you need to use it carefully.
I think in your case, the best solution will be something like this:
const isTablet = true;
test.meta({ tablet: isTablet })(‘L0 | Tablet device’, async t => {
if (isTablet) {
......
}
});

Related

A better way to handle async saving to backend server and cloud storage from React Native app

In my React Native 0.63.2 app, after user uploads images of artwork, the app will do 2 things:
1. save artwork record and image records on backend server
2. save the images into cloud storage
Those 2 things are related and have to be done successfully all together. Here is the code:
const clickSave = async () => {
console.log("save art work");
try {
//save artwork to backend server
let art_obj = {
_device_id,
name,
description,
tag: (tagSelected.map((it) => it.name)),
note:'',
};
let img_array=[], oneImg;
imgs.forEach(ele => {
oneImg = {
fileName:"f"+helper.genRandomstring(8)+"_"+ele.fileName,
path: ele.path,
width: ele.width,
height: ele.height,
size_kb:Math.ceil(ele.size/1024),
image_data: ele.image_data,
};
img_array.push(oneImg);
});
art_obj.img_array = [...img_array];
art_obj = JSON.stringify(art_obj);
//assemble images
let url = `${GLOBAL.BASE_URL}/api/artworks/new`;
await helper.getAPI(url, _result, "POST", art_obj); //<<==#1. send artwork and image record to backend server
//save image to cloud storage
var storageAccessInfo = await helper.getStorageAccessInfo(stateVal.storageAccessInfo);
if (storageAccessInfo && storageAccessInfo !== "upToDate")
//update the context value
stateVal.updateStorageAccessInfo(storageAccessInfo);
//
let bucket_name = "oss-hz-1"; //<<<
const configuration = {
maxRetryCount: 3,
timeoutIntervalForRequest: 30,
timeoutIntervalForResource: 24 * 60 * 60
};
const STSConfig = {
AccessKeyId:accessInfo.accessKeyId,
SecretKeyId:accessInfo.accessKeySecret,
SecurityToken:accessInfo.securityToken
}
const endPoint = 'oss-cn-hangzhou.aliyuncs.com'; //<<<
const last_5_cell_number = _myself.cell.substring(myself.cell.length - 5);
let filePath, objkey;
img_array.forEach(item => {
console.log("init sts");
AliyunOSS.initWithSecurityToken(STSConfig.SecurityToken,STSConfig.AccessKeyId,STSConfig.SecretKeyId,endPoint,configuration)
//console.log("before upload", AliyunOSS);
objkey = `${last_5_cell_number}/${item.fileName}`; //virtual subdir and file name
filePath = item.path;
AliyunOSS.asyncUpload(bucket_name, objkey, filePath).then( (res) => { //<<==#2 send images to cloud storage with callback. But no action required after success.
console.log("Success : ", res) //<<==not really necessary to have console output
}).catch((error)=>{
console.log(error)
})
})
} catch(err) {
console.log(err);
return false;
};
};
The concern with the code above is that those 2 async calls may take long time to finish while user may be waiting for too long. After clicking saving button, user may just want to move to next page on user interface and leaves those everything behind. Is there a way to do so? is removing await (#1) and callback (#2) able to do that?
if you want to do both tasks in the background, then you can't use await. I see that you are using await on sending the images to the backend, so remove that and use .then().catch(); you don't need to remove the callback on #2.
If you need to make sure #1 finishes before doing #2, then you will need to move the code for #2 intp #1's promise resolving code (inside the .then()).
Now, for catching error. You will need some sort of error handling that alerts the user that an error had occurred and the user should trigger another upload. One thing you can do is a red banner. I'm sure there are packages out there that can do that for you.

How goBack screen in test with detox

I make automatization react native test with detox, It has the next screen sequence A -> B -> C and i wish to go back to the screen B <- C.
Is there a solution for this?
There's a testId on the back button, so you can do this:
await element(by.id("header-back")).tap();
sometimes
await element(by.id("header-back")).tap();
does not work and
await element(by.traits(['button']))
.atIndex(0)
.tap();
selects another button. In that case, you can try to use swipe right on ios assuming that it is a stack navigator. Use the outer container view
await element(by.id('containerView')).swipe('right', 'fast', 0.1);
the solution was to use traits button as follows:
await element(by.traits(['button'])).atIndex(0).tap();
You could go ahead and create a utility
export const pressBack = async () => {
if (device.getPlatform() === 'android') {
await device.pressBack(); // Android only
} else {
await element(by.traits(['button']))
.atIndex(0)
.tap();
}
};
Android: device.pressBack()
iOS: go back last screen #828
If you are using react-native-navigation you can use:
const backButton = () => {
if (device.getPlatform() === 'ios') {
return element(by.type('_UIBackButtonContainerView'));
} else {
return element(by.label('Navigate Up'));
}
};
...
await backButton().tap();
For iOS in detox#17.3.6 & react-native-navigation#6.10.1 you can use:
return element(by.id('pop'));
Another way that works is
await element(by.id('header-back')).atIndex(0).tap()
This uses the built in testID that the default back button that comes with react-navigation v5. You may need to mess with the atIndex() number since for me it seems to match 2 back buttons but the first one was the one I was looking for.

Identify orientation with degrees on startup

Without a 3rd party lib, we can detect orientation changes with DeviceEventEmitter with this undocumented feature like this:
import { DeviceEventEmitter } from 'react-native'
function handleOrientationDidChange(data) {
console.log('orientation changed, data:', data)
}
DeviceEventEmitter.addListener('namedOrientationDidChange', handleOrientationDidChange);
This gives us data that looks like this:
{ rotationDegrees: -90, isLandscape: true, name: "landscape-primary" }
Note: I tested this only on Android. It would be nice to know if it works on iOS too.
However this only works ON CHANGE. Is there a way to get this info on startup?
Have you tried this library!
Here is example usage from the repo:
componentWillMount() {
// The getOrientation method is async. It happens sometimes that
// you need the orientation at the moment the JS runtime starts running on device.
// `getInitialOrientation` returns directly because its a constant set at the
// beginning of the JS runtime.
const initial = Orientation.getInitialOrientation();
if (initial === 'PORTRAIT') {
// do something
} else {
// do something else
}
}

Nativescript Webview callback uri

Can we have post back from external url to web view in nativescript and get the values from postback? It is the oauth2 flow with redirect uri where user display external link of website in native webview and get tokens value from postback url . Any suggestion or pointer to tut or blog? All the major players provide support for this and it is very much used for oauth.
This is my main-page.js where all the tokens and value i get within the function under args.url
var vmModule = require("./main-view-model");
var webViewModule = require('ui/web-view');
function pageLoaded(args) {
var page = args.object;
page.bindingContext = vmModule.mainViewModel;
var webView = page.getViewById('myWebView');
debugger;
//webView.url =
webView.on(webViewModule.WebView.loadFinishedEvent, function (args) {
alert(JSON.stringify(args.url));
});
webView.src = vmModule.mainViewModel.url;
}
exports.pageLoaded = pageLoaded;
And my view is
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
<GridLayout>
<WebView id="myWebView" />
</GridLayout>
</Page>
All the time it was written there in documentation and i just didn't look at it carefully. Hopefully it will help others.
You should be able to watch the urlProperty for changes. E.g.
Given you have a view which looks like this:
<Page loaded="loaded">
<WebView id="myWebView" src="{{ url }}" />
</Page>
Then you can attach an observer to that WebView and react to changes to the URL property like this:
var webViewModule = require('ui/web-view');
function loaded(args) {
var page = args.object;
var webView = page.getViewById('myWebView');
webView.on(webViewModule.WebView.urlProperty, function (changeArgs) {
console.dir(changeArgs);
// Do something with the URL here.
// E.g. extract the token and hide the WebView.
});
}
I Know this is old. But the code below can help a lot of people.
YOUR_WEB_VIEW_OBJECT.on(webViewModule.WebView.loadFinishedEvent, function (args) {
args.object.android.getSettings().setJavaScriptEnabled(true);
args.object.android.evaluateJavascript('(function() { console.log("LOGS"); return "MESSAGE"; })();', new android.webkit.ValueCallback({
onReceiveValue: function (result) {
console.log(result);
}
}));
});
This code currently works for Android. You can create iOS version as well by digging into their APIs Reference then converting it into {N} Suitable.
On IOS you can do it like this:
args.object.ios.stringByEvaluatingJavaScriptFromString('YOUR_JAVASCRIPT_CODE');
Just for the record, now this is how you do it
var webViewNat = this.webView.nativeElement;
this.oLangWebViewInterface = new webViewInterfaceModule.WebViewInterface(webViewNat)
webViewNat.ios.evaluateJavaScriptCompletionHandler(`var myvar = document.getElementById('userNameInput').value = '${getString('Email')}';`, (id, err) => {
if (err) {
return err;
}
return id;
});

Detect focus of window in Adobe AIR

I have been building an app in Adobe AIR using HTML/JavaScript.
The windows are all Chromeless and use CSS to style them to look like an application.
How can I detect if the window is focused by the user so I can alter the colours of the windows in the same way that native windows have more subtle shadows etc.
An example might be:
var active = false;
$(document).ready(function() {
active = nativeWindow.active;
if(active) {
$('body').addClass('active');
} else {
$('body').removeClass('active');
}
});
But how do I properly handle the change of active event?
You can do this with: air.NativeWindow.active. See: http://help.adobe.com/en_US/air/reference/html/flash/display/NativeWindow.html#active
UPDATE:
window.nativeWindow.addEventListener(air.Event.ACTIVATE, function() {
$('body').addClass('active');
});
window.nativeWindow.addEventListener(air.Event.DEACTIVATE, function() {
$('body').removeClass('active');
});