Chai with promises is not waiting for previous promises to be resolved - protractor

I have below function and I am using it in expect.
function Create() {
var that = this;
// Goto home page of App.
// Async call
that.homePage();
// Async call
Utils.click(projectsSelectors.project_create, false, that.browser);
// Async call
Utils.elementIsVisible(stock_avatar, that.browser);
// Async call
Utils.fill(name_input, that.name, that.browser);
// Async call
stockAvatar.call(that);
// Async call
Utils.click(create_save, false, that.browser);
// Verify if it's created.
// Async call
return that.$is_Created();
}
But when I use like below
expect(Create()).to.eventually.equal(true);
The expectation is just passed without doing anything. The above Create method contains multiple asynchronous calls.
I even chained all the calls inside Create method, but still, the expectation is just passing without doing anything on the screen.

Your test method must return the promise
it("should do something", function()
{
return expect(Create()).to.eventually.equal(true);
}

Related

Jest + Axios: Test Whether Promise Was Fulfilled

Using Vue test utils with Jest, I am attempting to spy on an axios.get call which runs in my component's created() lifecycle hook. I would like to test that the promise has been fulfilled (i.e. was not rejected) based on a method that runs in the then() block, but not the catch() block.
The way I have the test setup right now, the spyOn always resolves because I am using .mockResolveValue(). I tried declaring mockResolveValue() in the it('') portion of the test, but it says the axios get is called 0 times when I do that.
DeptPrefs.vue
<script>
import axios from 'axios'
export default {
name: "DeptPrefs",
data () {
return {
...
}
},
async created () {
await this.getPrefs()
},
computed: {},
methods: {
async getPrefs () {
await axios.get('/coolsite/api/admin/getstuff?dept=216001')
.then(r => {
this.setDeptPrefs(r.data)
}).catch((e) => {})
}
...
</script>
And this is how the deptprefs.spec.js currently looks.
describe('when prefs created() hook loads', () => {
const localVue = createLocalVue()
localVue.use(Vuex)
...
const getPrefs = jest.spyOn(DeptPrefs.methods, 'getPrefs') // spy on getPrefs() method
jest.spyOn(axios, 'get').mockResolvedValue([]) // spy on axios .get() method
const wrapper = mount(DeptPrefs, {
...
})
it('makes an api call to get the dept prefs', async () => {
await expect(getPrefs).toHaveBeenCalled() // works fine
await expect(axios.get).toHaveBeenCalledTimes(1) // works fine
const setDeptPrefs = jest.spyOn(appModule.mutations, 'setDeptPrefs')
expect(setDeptPrefs).toHaveBeenCalledTimes(1) // this is the expectation in question. It's always 1.
})
})
So let's say I change the URL of the API call to be a non-existent route. The test will still say that the setDeptPrefs() method has been called 1 time. It shouldn't be called at all because the axios should've hit the catch block, where that method does not run.
I want to amend my test to reflect this; when the then() block is hit, setDeptPrefs should NOT be called. When it does, it should be.
Also please feel free to chime in on if this is something I should even be unit testing. I am trying to get a feel for what's test-worthy and what isn't.

Cancel execution of method after it starts in Flutter

Consider this method:
Future<void> methodWithAlotOfSteps()async{
callMethodA();
await callMethodB();
...
return ...;
}
which makes some computation. Suppose I want the user to be able to stop this process at any point in time (when he taps cancel button for example).
How can I stop the execution of the above method no matter what line in the method the "program counter" has reached when the user presses cancel.
I am looking for something like methodWithAlotOfSteps.cancel();.
I tried using CancelableCompleter, but even though the Future is cancelled and onCancel method of the completer is called, but the function continues execution.
I know I can set a boolean flag and check it after each "step" ("line", "call to a method"),such as :
Future<void> methodWithAlotOfSteps()async{
if(!completer.isCancelled)
callMethodA();
if(!completer.isCancelled)
await callMethodB();
...
return ...;
}
but is there a better way of doing this?
As #Jamesdlin suggested, the apparent way is to check the cancelable completer's state after each async gap:
class MyService{
CancelableCompleter completer = CancelableCompleter();
Future<void> doSomething() async {
doSomeSyncWork(); // Sync work
doAnotherSyncWork(); // Sync work
await doSomeAsyncWork(); // Async work, this will return control to event loop and make it possible to, for example, press a button to cancel the future.
// here we know we have lost control for a while, so we must check if we have been cancelled
if (completer.isCompleted) {
return;
}
doSomeMoreSyncWork();
await doSomeMoreAsyncWork();
// here we know we have lost control for a while, so we must check if we have been cancelled
if (completer.isCompleted) {
return;
}
...
completer.complete();
}
}

How to handle reading from database when API-request hasn't finished yet to save to database in Flutter?

For my App i'm loading the link for the background-image for each screen from my API.
Right after the query that downloads and saves the image-link, i'm querying the link from the database.
The problem now is, that the function isn't waiting for the download and saving to finish although i'm using await, therefor i get an empty result from the database and get an error from the imageloader.
Future<String> downloadAsset(String name) async {
final Map<String, String> _json = {
'mandant': Config.mandant,
'name': name
};
final query = MakePost('get_app_assets', false, _json, saveAsset);
await query.queryAPI(); // Function won't wait for this to finish
String ret = await dbAppAssets.getText(name); // Get link from database
return ret;
}
I've already tried to use .then(), but the same thing happens.
This only happens initially on the first call of each screen, but how is this normally beeing handled?
I'm using riverpod with futureProviders if that matters.
I do not know where you are using the downloadAsset function, but when you use Future on a function you should also await the function where you are using it, for example:
Future<void> _reverseScrollToTopAnimation() async {
await controller!.reverse();
_showBackToTopButton = false; // hide the back-to-top button
}
then, wherever you call it you should also await that function:
await _reverseScrollToTopAnimation();
If not the function will act as a synchronous operation even though you are using await inside the function.

why the dart function did not return the sub function result

I am now using this functon to fetch new music in flutter:
class QuietPlayQueueInterceptor extends PlayQueueInterceptor {
#override
Future<List<MusicMetadata>> fetchMoreMusic(BackgroundPlayQueue queue, PlayMode playMode) async {
if (queue.queueId == kFmPlayQueueId) {
final musics = await (neteaseRepository!.getPersonalFmMusicsFromQueue() as FutureOr<List<Music>>);
final musicListExt= musics.toMetadataList();
return musicListExt;
}
return super.fetchMoreMusic(queue, playMode);
}
}
and this is the function getPersonalFmMusicsFromQueue define:
Future<List<Music>?> getPersonalFmMusicsFromQueue() async {
if(fmPlayQueue.isEmpty){
return getPersonalFmMusics();
}else{
final Music music = fmPlayQueue.first;
final List<Music> musics = List.empty(growable: true);
musics.add(music);
return Future.value(musics);
}
}
what makes me confusing is that the getPersonalFmMusicsFromQueue function did not return any result. I make a breakpoint on the line final musicListExt= musics.toMetadataList(); but did not hited. The console is no error output. where am I doing wrong? what should I do to fix this problem?
getPersonalFmMusics looks asynchronous? Perhaps you're not awaiting
Future<List<Music>?> getPersonalFmMusicsFromQueue() async {
if(fmPlayQueue.isEmpty){
return await getPersonalFmMusics();
}
// ...
I would also advise against casting unless you're sure you need it. Instead, have the return type of getPersonalFmMusicsFromQueue return a FutureOr
(neteaseRepository!.getPersonalFmMusicsFromQueue() as FutureOr<List<Music>>); // Remove FutureOr<List<Music>>
// and make the function signature instead look like this:
FutureOr<List<Music>> getPersonalFmMusicsFromQueue(); // Force unwrapping with a `!` but also throwing proper exceptions when null.
The reason being is that casting usually hides errors the compiler would otherwise be warning you about.
Another idea I have if the above isn't the issue is the .first call.
final Music music = fmPlayQueue.first;
If this is a first getter on a stream then that need to be awaited and it likely isn't working because it's just indefinitely waiting for the stream to output a value.

wait for http request to complete in protractor

I am trying to wait for spinner to disappear and then for my steps to execute but nothing is working for me.
browser.wait(function () {
return this.spinner.isDisplayed().then(function (result) {
return !result;});}, 20000);
and i even tried with
browser.wait(function () {
return !browser.isElementPresent(this.spinner);}, 20000);
even with below method
browser.sleep(1000);
this.spinner.isPresent().then(function (result) {
if (result === true) {
var EC = protractor.ExpectedConditions;
browser.wait(EC.invisibilityOf(this.spinner), 10000);}});
then only thing that works is
browse.sleep(10000);
i don't want to use sleep in my code. can anyone help me with how to wait for complete http request to complete and then process with testing
you should consider using Expected Conditions since they return true/false based on current conditions
http://www.protractortest.org/#/api?view=ProtractorExpectedConditions.prototype.invisibilityOf
so your test case would become:
browser.wait(EC.invisibilityOf(this.spinner),20000).then(function(){
...continue test, spinner gone
});
UPDATE
in order to use done, you would generally pass this cb into your it() function. This means your test could look like
describe("example describe",function(){
it("should be an example only", function(done){
request.get("www.google.com",function(res){
//done with async request, now call done
done();
})
})
});
Since your entire code isn't posted up here, you should have something similar to:
it("should wait for spinner to go bye-bye",function(done){
browser.wait(EC.invisibilityOf(this.spinner),20000).then(function(){
done()
});
});