Protractor - get result of sendChromiumCommand - protractor

The goal: obtain a result of chromium command execution, e.g. Profiler report data
What I've done: I'm able to call chrome devtools command using browser.driver.sendChromiumCommand.
E.g. await browser.driver.sendChromiumCommand('Page.reload', {}) reloads page, so I can confirm that this is working.
The problem: the result of any command execution is always null
Here is my code
describe('Protractor Demo App', function() {
it('whatever', async function() {
await browser.get('http://juliemr.github.io/protractor-demo/');
const data = await browser.driver.sendChromiumCommand('Page.reload', {
scriptToEvaluateOnLoad: `(function(){return '123 })()`
});
console.log(data); // expected '123' but got 'null'
});
});
Note: the issue isn't connected to a particular command, all of the devtools commands return null

This is not a Protractor issue per se.
The problem is that underlying selenium-webdriver for Node.js uses send_command(which does not return result), but does not implement usage of send_command_and_get_result.
According to response from developers it's going to be fixed in next alpha release (current one is 4.0.0-alpha.7)
I suppose that, in order for this to work, Protractor's sendChromiumCommand is gotta get a sendChromiumCommandAndGetResult counterpart, once selenium-webdriver fix is available.

Related

Flutter - Riverpod Future Provider: How to keep old data when error occurs

This is my usecase:
data is downloaded
final dataProvider = FutureProvider<MyModel>((ref) async {
return fetchData();
});
and it's used like this within widget's build method:
ref.watch(dataProvider).when(
data: DataWidget(data),
error: ErrorWidget(),
loading: LoadingWidget())
user has option to refresh the data:
ref.refresh(dataProvider.future);
But when there is an error (for example phone is in airplane mode) error is provided so DataWidget is lost and replaced with ErrorWidget... Is there a way using Riverpod to provide/keep existing data instead of error ? I believe it's common scenario, but I didn't find any elegant solution for this problem. I've also read documentation too, but didn't find anything helpful related to this. Am I missing something ? (I'm new to Riverpod) Thank you
Preserving the previous data on refresh is behavior as part of 2.0.0.
Although there were some bugs that you may have encountered. Make sure youre using 2.1.3 or above, which should fix all the issues related to this.
As for using when to show the previous data/error, you can use various flags:
asyncValue.when(
// show previous data/error on loading
skipLoadingOnReload: true,
// show previous data if there's an error
skipError: true,
loading:...,
data:...,
error: ...,
)
In the new version of Riverpod (as of v.2.1.0), you can do this:
asyncValue.when(
skipLoadingOnReload: false,
skipLoadingOnRefresh: true,
skipError: false,
data: DataWidget(data),
error: ErrorWidget(),
loading: LoadingWidget(),
)
You can see more details here.

Flutter Firebase Cloud function can not be called

I am getting an error whilst using Firebase Cloud Functions when I try to call a callable function from Flutter.
flutter: caught generic exception
flutter: PlatformException(functionsError, Firebase function failed with exception., {message: NOT FOUND, code: NOT_FOUND})
Here is how I try to call the cloud function with using cloud_functions: ^0.4.2+3
import 'package:cloud_functions/cloud_functions.dart';
_check(String id) async {
HttpsCallable callable = CloudFunctions.instance
.getHttpsCallable(functionName: 'checkUserFavorites');
try {
final HttpsCallableResult result = await callable.call(
<String, dynamic>{
'id': id,
},
);
print(result.data);
} on CloudFunctionsException catch (e) {
print('caught firebase functions exception');
print(e.code);
print(e.message);
print(e.details);
} catch (e) {
print('caught generic exception');
print(e);
}
}
I have experienced similar issues, and with few days of debugging and experimenting I found the solution only after studying the source code of Cloud Functions Plugin for Flutter.
When you deploy Firebase Cloud function, you can choose any region of preference (closer to your application the better). For example
// using DigitalOcean spaces
exports.generateCloudImageUrl = functions
.region('europe-west3')
.https.onCall((reqData, context) => {
...
}
When you want to call this function from Flutter app, you must specify the region, otherwise all goes to us-central1 which is default. See example code on how to use a function deployed in a specific region
final HttpsCallable generateCloudImageUrl = new CloudFunctions(region: "europe-west3")
.getHttpsCallable(functionName: 'generateCloudImageUrl');
// NB! if you initialize with 'CloudFunctions.instance' then this uses 'us-central1' as default region!
see cloud_function source for init.
Update, as of recent release, you can initialize as below;
FirebaseFunctions.instanceFor(region: "europe-west3").httpsCallable(
"generateCloudImageUrl",
options:
HttpsCallableOptions(timeout: const Duration(seconds: 30)));
Cloud functions are supported in the regions that you are currently running them, according to the Cloud Functions Location Documentation, but not in all regions.
According to what you shared in the comments, I would say that there are 3 cenarios to your issue:
europe-west1: The function is probably out of date, since you are getting an unespected data format error, which suggest that it expects different data/format than your default function.
europe-west2: The function is not deployed in this region, this is hinted in the error message message: NOT FOUND.
Default Function (unknown region): This is the most recent version of the function, on a region different than europe-west1 and europe-west2, and it accepts the call
with the data in the format that you are sending.
NOTE: You can check which regions you currently have your cloud function deployed on the cloud functions dashboard, as you can see on the example image below:
Also, I suspect that the default region you using is us-central1, since according to the documentation:
By default, functions run in the us-central1 region
To fix your issue, I suggest that you redeploy your current version of the function to the europe-west regions that you intend to use.
There are three reasons this error mostly happens:
1. Call the correct function:
Make sure to call the correct function in its full name (visible when you start a local emulator). Espacially if you have additional exports of files in your index.js file make sure to call the export name as well.
Syntax: serverLocation-optionalExportParent-yourFunction
Example: us-central1-post_functions-updateShare
Note that the server location can also be configured in your instance
2. Emulator: Same WIFI
Make sure to be connected to the same wifi, when using the emulator. Otherwise, any call will end in unvailablity resulting in
Unhandled Exception: [firebase_functions/unavailable] UNAVAILABLE
3. Emulator: Correct host configuration
To connect to a physical device the host at all emulators at your firebase.json must be configured: Simply add "host": "0.0.0.0".
Now the host in flutter needs to be your ip-adress of the computer. More on that here
In my case, in addition to the regional issue, what really solved to me was to include the script below in index.html:
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-functions.js"></script>

Office JavaScript API: selecting a range in Word for Mac

I'm working on a side project using the Microsoft Office JavaScript APIs. I have some functionality working to select a range in order to scroll to a particular position within a document. This works as expected in Office for the web, but in Office for Mac I get the following error when calling context.sync().then():
Unhandled Promise Rejection: RichApi.Error: ItemNotFound
I can't find any documentation on that particular error, and I'm not sure how to troubleshoot what I might be doing wrong. What am I missing? Like I said, this works in the web interface.
Here is minimal sample of code that demonstrates the problem:
function UI(context) {
this.context = context;
}
UI.prototype.initialize = function() {
var paragraphs = this.context.document.body.paragraphs;
this.context.load(paragraphs);
document.querySelector('button').addEventListener('click', () => {
this.context.sync().then(() => {
this.goToRange(paragraphs.items[0]);
});
});
};
UI.prototype.goToRange = function(range) {
range.select();
this.context.sync();
};
document.addEventListener('DOMContentLoaded', () => {
Office.onReady(() => {
Word.run(context => {
return context.sync().then(() => {
new UI(context).initialize();
});
});
});
});
The only thing I can think of is that maybe the reference to the paragraph client object becomes "stale" in some sense, perhaps based on some resource limits that are lower in the Mac application than in the online interface? (That would be counterintuitive to me, but it's the only thing that comes to mind.)
I think I figured out the problem. I stumbled upon a hint while putting together the minimum code sample in the question; I removed a little too much code at first and encountered the following error:
Unhandled Promise Rejection: RichApi.Error: The batch function passed
to the ".run" method didn't return a promise. The function must return
a promise, so that any automatically-tracked objects can be released
at the completion of the batch operation.
I believe the issue is that, at least in Word for Mac, you can't use the context object provided by Word.run in an asynchronous event listener. I'm guessing this is because, as the above error states, some state has been released after resolving the promise returned. I can get the code to work by adding a dedicated call to Word.run (and using the fresh context provided) inside the event listener.
It is still a little odd that it works just fine in the browser. Presumably, the same state is not released as aggressively in the browser-based version.

How to perform soft assert in protractor cucumber

defineSupportCode(({Given, When,Then})=>{
When('click on search button', async () =>{
await browser.actions().sendKeys(protractor.Key.ENTER).perform();
await browser.sleep(3000)
await browser.actions().sendKeys(protractor.Key.ENTER).perform();
await browser.sleep(3000)
let element1 = element(by.xpath("//h3[text()='Selenium - Web Browser Automation']"))
await expect(element1.isDisplayed()).to.eventually.be.false;
});
Then('it should show search result', async () =>{
let element2 = element(by.xpath("//h3[text()='Downloads - Selenium']"))
await expect(element2.isDisplayed()).to.eventually.be.true;
});
})
My last then block was skipped.But I want to continue my all test steps even if it is pass or fail (then definitely i think i have to use soft assert).In testng we have a class called softassert. Is there something available here as well similar to that one. I am using chai package for assertion purpose
TIA
Background:
This is not a protractor or cucumber issue, it is actually chai(well it looks like you are using chai from your code snippet but feel free to correct me if I'm wrong).
Issue:
After reviewing chai docs https://www.chaijs.com/api/assert/ it looks like they do not support the concept of soft asserts like some other assertion frameworks.
Solution 1:
The only workaround I can think of is to wrap your assertion in a try catch and store the error received from the assertion in your world instance, then in your after hook throw the errors.
Solution 2:
Use a library that does support soft asserts. From a quick search, I see https://www.npmjs.com/package/soft-assert but FYI I have not tried this library
Notes:
One bad thing about this is that screenshots may capture incorrect information.

Protractor - getText as input to sendKeys and other actions

I am writing a protractor test, where I need to read a span/div with id='mylabel' using getText(). I then need to pass the value to an input (id='myinput') using sendKeys().
So, I do this:
var value;
element(by.id('mylabel')).getText().then(function(txt){
value = txt;
element(by.id('myinput')).sendKeys(value);
// do "other protractor tasks" with 'value'.
})
But, is there a way I can avoid the nesting, by asking protractor to perform sendKeys and subsequent actions only after the value variable is set?
The above is a simple case, but I soon find code getting into multiple nesting because of the waiting for promises to be resolved. Also, I observed that protractor does not provide a stacktrace if "other protractor tasks" throws an error due to an error somewhere down the line (it just hangs and times out).
I am using Protractor 2.1.0 and I am working with Angular JS pages.
I am specifically interested to know if it is a known issue to have silent errors in nested tasks with Protractor and is there anyway to solve it?
Protractor handle at least one level of promises without the need of then function. That way you can expect synchronous flow.
If you are looking for event based action like watching a value to update then you can setup something like this:
function waitForTextToUpdate(elm, defaultText, timeout) {
if (typeof(timeout) === 'undefined') {
timeout = 10000;
}
return browser.driver.wait(function() {
return elm.getText().then(function(value) {
return !(value.indexOf(defaultText) > -1);
});
}, timeout, "Expectation error (waitForTextToUpdate): Timed out waiting for element state to change.");
}
Promises are inevitable in protractor. There is no way to avoid handling promises, but if you want to avoid nesting it can be done easily using .then() chaining functionality. Here's an example -
var value = '';
element(by.id('mylabel')).getText()
.then(function(txt){
value = txt;
})
.then(function(){
element(by.id('myinput')).sendKeys(value);
// do "other protractor tasks" with 'value'.
});
There's also an npm package available for this feature. Q npm package. It works similar to the above example but is more extended.
Hope this helps.