What does the exception "ArgumentError: a promise has already been chained" mean, and how do I debug it? - voltrb

I'm going a little nuts working with Volt at the moment. The moment I try to do something a bit more complicated I end up getting the exception "ArgumentError: a promise has already been chained" in the browser console.
The stack trace doesn't point to anything I can interpret as useful.
That does this error actually mean, and how do I go about trying to track down the cause?
I'd post some code, but some of these errors appear on page load with no indication of where the problem is, so I'd need to post the entire app :/

Volt uses Opal's promise implementation, which I believe is based on the A+ spec in JS land. The error your seeing is because a promise can only have a single .then or .fail block on it. Each .then or .fail will return a new promise that you can then chain off of.
So you can do this:
promise = Promise.new
promise2 = promise.then do
..
end
promise2.then do
..
end
(notice I'm assigning promise2 instead of chaining off of the first one again)
But you can not do something like this:
promise = Promise.new
promise.then do
...
end
promise.then do
..
end
(Notice how I called .then on promise more than once)
A more compact way to write the first is to chain off of the end's
promise = Promise.new
promise.then do
..
end.then do
..
end.fail do
..
end
Volt bindings expect a promise that hasn't been chained on. Also, I think I can make it work where you can chain multiple times, though I haven't thought through all of the implications of this, so I could be wrong. If I get some time I might write a new promise implementation that can handle this. If your still seeing that error and the above doesn't explain why its there, let me know. Thanks!

Related

SweetAlert2 does not work properly as I expect

It may be a dumb question, but I just cannot figure out why sometimes Swal.fire works and sometimes it doesn't.
The alert I am using is quite simple -
Swal.fire({
title:'Slow response!',
text:'Please indicate the side as quickly and accurately as possible',
icon:'warning'
})
But it only works when within a function starts as:
$(document).keydown(function (e) {...})
Since this function is built in a constructor, I add .bind(this) at the end to make use of "this" object. Nevertheless, my sweetalert does not work in this situation. It also does not work if the inner function starts as:
$(document).keydown((e)=> {...})
I did not see any errors in console. Any comments are highly appreciated!

Cypress: Switching from cy.route() to cy.intercept()

It seems that most people I read about experence zero trouble with this. I, on the other hand, have a test suite which someone else wrote, in which I'm trying to replace route() with intercept(). The API intercepts are done to handle button clicks etc., and about 99.9% percent of them fails if I just replace it. So, there's obviously some syntax in/use of intercept() I've not found a description for.
Example:
This works:
cy.route('POST', getApiPrefix() + '/prosjektfinansiering/'+ pfId +'/eiendom', result);
This does not work. The button click is not executed:
cy.intercept('POST', getApiPrefix() + '/prosjektfinansiering/'+ pfId +'/eiendom', result);
I've tried adding '**' in front of "/prosjekt...", and I've tried removing 'POST', with no luck.
Any ideas? I'll gladly post more info if necessary.
UPDATE:
Futher attempts:
Getting some hints here and there, it seems that this is a more correct way of using intercept():
return cy.intercept('POST', getApiPrefix() + '/prosjektfinansiering/'+ pfId +'/eiendom', {
body: result
});
This doesn't work, either.
The variables result in these examples is an object describing what is sent back to the frontend of the POST-request in the route matches the api path.
For troubleshooting, I can see that when using intercept(), there is ONE route that is not working when using intercept (the bottom one in the picture). However, I cannot for the life of me see why, and how the route match can be written differently?
Most likely, you're mixing the old use of cy.route() and cy.server(). In my experience, those two won't work well together. It's easier when you're starting fresh with just cy.intercept().
Your update is correct too; You have to encapsulate the return value you want mocked in {body: value}.
from what I am seeing in your circled screenshot, the API is not called after you try to intercept it. (the count under # column is -)
You need to track when the API is to be called and ensure you intercept before the call is made. Cypres can help you with this. You can go through the run steps in the cypress window.
You could also share this if you don't mind.
If you are 100% certain the button makes the call. Steps should be:
cy.intercept()
cy.get('button').click()
In the cypress window, right after the click, you should see the API being called.

Relevant Http Response Code using graphql-js

Ok here's the thing, I'm trying to figure out how to deal with error handling with graphql-js. (In a case without Relay)
Not specific enough !? Ok so, since graphql-js is catching all errors thrown within resolve functions, I'm kind of confuse on how to deal properly with errors and http responses.
So I had few ideas and would like to know what you think about it !
Always return 200 OK with the graphql response even if containing errors. (Don't like that one)
Switch case on the result.errors[0] and return an http response in respect of the error, returning result.data if no errors. (which could end up being a veeeery long switch case)
Deal with the error handling in the resolve function and throw and object (e.g. { httpCode: 404, msg: 'No X found with the requested id' } )
In the express app.post function(or whatever web framework), having something like:
app.post('/graphql', function(req, res) {
let result = await graphql(req.body);
if(result.errors.size) {
let e = result.errors[0];
res.status(e.httpCode).send(e.msg);
}
res.json(result.data);
}
This doesn't currently work because of the way the error object is marshalled... or at least I haven't found how to get it out of graphql yet. I'm thinking of maybe looking into graphql-js source but I thought I better ask you guys first since I might be missing something obvious.
Obviously, a better idea is welcome !
Cheers :D
I am also trying to figure this out.
The best I have managed to come up with is throwing a custom error in my resolver. Check out apollo-errors. I am not sure if this is the best way, but it could work for you.

VoltRB rspec testing a method can't convert Promise into Array

I am trying to do some rspec unit tests on a method in my model. The method returns a promise, and when resolved, the name of the person. The method is not the problem as I know that it works correctly. Here is my test code:
it 'should return correct name' do
report = Report.new(first_name: 'Testy', last_name: 'Testerson')
report.save!
expect(report.name).to eql('Testy Testerson')
end
When I test it, I get the following error:
Failure/Error: expect(report.name).to eql('Testy Testerson')
TypeError:
can't convert Promise to Array (Promise#to_ary gives Promise)
While debugging, I used the following line to inspect the returned value of the method:
puts report.name.inspect
And I got the following response:
#<Promise(70319926955580): "Testy Testerson">
The error seems to be happening because it tests the promise against the expected value. Why am I getting this error?
Using report.name.value fixes this issue
When running code on the server, calls to store return a promise that is already resolved. But on the client the promise won't be resolved yet. Someone (forget the name atm) is working on adding support to promise directly into opal-rspec, but at the moment a returned promise won't wait for opal-rspec. The plan is once thats ready we'll add more tools to volt to make it easier for developers to test in both MRI and opal (like we do with Volt itself).
You can call .value on a promise to get back its value, but only if the promise has resolved. The safer way to do it is to use a .then block:
report.name.then do |name|
expect(name).to eq('Bob')
end
Hopefully that helps.

Ruby on Rails Exceptions

I am a junior rails developer and was advised to use Class.find(id) to query the database instead of Class.find_by_id(id) which I previously had. The reason I was told is because the former would raise an exception while the latter would return nil. I realize this happens but I am wondering what the high level conceptual logic is for doing it this way. Why do I want the exception? Is this a rails standard where I would always prefer a method that returns an exception as opposed to nil?
You typically want the exception because you're typically doing Foo.find(id) based on data input coming from the user, such as clicking on a link.
For example, you show the user a list of items. There are links like this:
http://example.com/items/100
http://example.com/items/101
http://example.com/items/102
The user clicks the first link, and expects to see item 100.
Your code does this:
Item.find(100)
You expect to find the item, because app created the item link. You'd be surprised if the item didn't exist.
(Corner case surprises are possible: perhaps the item was deleted, or perhaps a hacker is sending in missing ids, etc. Using exceptions helps you handle this as an exceptional circumstance.)
Exceptions are preferred to nil for this, because you want the code to fail immediately so you don't accidentally send the nil on to some other method.
Ruby nil objects can be confusing because they evaluate to falsey and also because nil.id == 4 because of how Ruby uses C. Error messages show up like "Warning: Object#id will be deprecated" or "undefined method for 4:Fixnum".
Nils are problematic as a return type in Ruby in general. There's a great (paid) screencast by Gary Bernhardt that explains why you want to avoid returning nil from methods, but in a nutshell: when a method returns nil, and that nil gets passed up through a chain of method calls and something goes wrong somewhere, it can be extremely difficult to figure out where the actual problem occurred.
Say, for example, you have something like this:
foo_model = MyModel.find_by_name('foo')
# some more lines of code
do_something(foo_model)
and a method:
def do_something(model)
# some stuff stuff
some_other_method(model)
end
Now, if MyModel.find_by_name('foo') returns nil, that nil will be carried along without any errors until it actually has to do something. Say, in some_other_method, you actually try to call something on model, say model.save, you will get an error:
undefined method 'save' for nil:NilClass (NoMethodError)
The trace will carry you back up the method calls, but it will not mention the line that was actually problematic, where you assign MyModel.find_by_name('foo') (which evaluates to nil) to foo_model.
You can imagine that in a real application, the code can be much more complex, and returning nil can make it much more difficult to figure out the source of an error.
An exception, in contrast, tells you immediately where the problem is, and the trace will go back to the line where it occurred. That's one reason (there are others, I imagine) why in general, returning nil is not a good idea.
Hope that helps.

Resources