Hey, while working with TestBuilders, the experien...
# apollo-kotlin
s
Hey, while working with TestBuilders, the experience of the following could be improved a bit. When I am missing things that I haven’t specified, instead of getting a clear error of what it is that is missing, I get a random “__typename is not known at compile-time for this type. Please specify it explicitly” but this is in some seemingly random builder. Following the stacktrace I can see this comes from how the build() is specified, where there is the place where it says for example:
"variables" to resolve("variables", some type, emptyList(), { ctors here })
and the list of constructors is of all the possible things this could be. But some of those alternatives are builders that require the __typename to be specified, so it crashes when it tries to resolve them all. I then need to go back that stacktrace and find the last reference to my code to see which field it is that I need to define but isn’t there. Where this happens is places where there is a field which inside the generated builder has the type
List<Map<String, Any?>>
, so it’s not nullable and it needs to be specified. (The type inside the schema is [SomeType!]!. I am sure I’ve not explained this very well, but just wanted to type it out here for now and if it makes sense to you that’d be awesome, if not I will try to make a better explanation some other day 😅
Playing a bit more with this today and I found that I don’t think the issue is specifically happening for those who are
List<Map<String, Any?>>
, because I’ve seen it in a normal
Map<String, Any?>?
as well. It probably comes from the behavior of the test builders trying to fill some defaults for the not-specified variables. And in this effort I guess from all the different things that are passed as
ctors
in the resolve function some of them call builders which crash if they don’t have a __typename provided to them. As a side-note the fact that Lists specifically try to fill with 3 values did catch me super off-guard as I couldn’t understand where I was specifying that in my test builder. I initially thought it’d simply be an emptyList. In hindsight I don’t think it’s a bad idea for the default resolver though. Maybe worth a mention in the docs? If maybe you hear more people feeling that that was an unexpected behavior.
b
👋 About the error message, do you think it would help if it contained the type in question. Something like
YourType: __typename is not known at compile-time for this type. Please specify it explicitly
?
(it could also contain the allowed values)
s
Oh that would be amazing, both containing the type and especially containing the allowed values in there too!
b
All right, that's definitely doable, I'm having a look.
s
But this extra message is only part of the problem right? I am having a bit of a hard time explaining myself on what the issue is, I will try again here and if I don’t succeed maybe I’ll have to come with some other way 😄 The problem didn’t just happen when I didn’t specify a __typename in a builder which I explicitly wrote. This problem, was that I was constructing an object using the builder, and I was only specifying some of the fields, not all of them. The way the test builders handle that is that they try to generate a sane default for those cases. In that generation is where this error was triggered, and is what made it super hard for me to understand what I was doing wrong. The fix was that I had to explicitly set that field into something that wouldn’t try to generate the object which required the __typename which broke this process. The code looks like this. Otherwise it was trying to create those objects and failing to do so with what I explained above. Optimally I’d like to somehow be able to not have to specify those fields, but still not have the build break. The resolver would probably have to somehow be able to when trying to generate a field that requires a __typename to pick the first one and generate that maybe. Or I guess I could as a first step change from the
DefaultTestResolver()
and override it with one that returns a list size of 0 instead of 3 to avoid most of them. And for those who aren’t lists still have to manually fix those. Makes me think again whether the 3 items as a default is a good default, I wonder what your opinions are on this. Does this make any more sense?
b
Yeah got it - it would be nice if it picked the first possible typename instead of complaining it must be set 🙂 Not sure this is doable - I'll have a look.
m
I think all of this goes away if we generate schema-based test builders?
Then the user has to choose a concrete object type all the time and there no "interface type" anymore?
b
I think so yes 😅
m
With schema-based test builders, the user chooses the typename when writing the code:
Copy code
Hero.Data {
  character = droid { ... }
  // or 
  // character = human { ... }
}
but this case doesn't exist anymore:
Copy code
Hero.Data {
  character = character { 
    // cannot determine typename
    ... 
  }
}
👍 1
b
Improved error message here. Didn't look like it's a simple change to provide __typename automatically though.
😍 1
🎉 1
s
That’s amazing Benoit, thank you a lot!
👍 1