-
-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@typescript-eslint/await-thenable issue with browser.asControl<T> #509
Comments
You can find working examples to retrieve an aggregation here:
and here:
The example contains a list in the
|
Thanks for the reply @dominikfeininger but I'm not sure if my question was misunderstood. The code is working fine that's not the issue. My question was related to the type check that complains that I My test looks pretty much the same as this sample: https://github.com/ui5-community/wdi5/blob/main/examples/ui5-ts-app/test/e2e/MultiInput.test.ts Currently I use But you linked another sample that looks differently. So I'm asking myself if the sample I used is wrong (but why would it part of the examples in the repo then)? As the return type of In the meantime (and to improve my generic type skills 🐱) I experimented a bit with converting the type (in my sample
then I can do the following
and get type support as now the return type of But if the sample I used is just wrong and I should go for the |
Hi, yep, I misunderstood your question. The sample is correct. Classic works on my machine ;) Can you please double check your development setup including TS config. |
Sorry for the delay (vacation). Of course you don't get the error if you don't enable the respective lint check 🐱 As said everything works fine from a functional perspective. But currently I have to use UI5 types where the return type does not fit the implementation as I have to await non-Promise values. And therefore I get no support from typescript for this scenario at all. In case of the above described type transformation (to promised return types) typescript will tell you that the response type is a promise and thus prevent the issues that arise of a non awaited promises. Sample:
will result in
will just lead to a failed test. So it all comes down to the question if you are aware of this mismatch and the issues that arise out of it or if this is not seen as an issue at all from your side and has to fix on consumer side (by either disabling the respective lint check for WDI5 tests or adjusting the return type of the used UI5 types as described above). |
Did not find a way to remove the "waiting for Input" label. Input has been provided 🤔 |
Hi Dominik, thanks for putting in the effort of that detailed description 👍 const fooList = await browser.asControl<List>(listSelector) // assuming List is of type sap.m.List
const fooListItems = await fooList.getItems() // <-- await was missing
expect(fooListItems.length).toEqual(1) ...this is the equivalent to proper typing at design-time - which works ok for most cases. wdi5/src/types/browser-commands.ts Line 18 in b3b4db3
We talked about the general challenge of providing better types also in the last steering committee meetings - but frankly, no TS wizard in sight that could help 😬 |
(btw: personally: also getting proper TS checks working for the fluent async api has become kind of a nemesis for me. await browser.asControl(selector).getVisible() ...I've yet to get working without TS constantly whining about |
With regards to the awaiting: For my project, I have written a complex type that takes a UI5 Control and makes all methods promise return promises. That doesn't allow for a fluent API anymore, but I was fine with that. // Advanced types for promise-based access of UI5 methods
// Helper type to be used in the types below
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- must be any, as otherwise `extends AnyFunction` doesn't match properly
type AnyFunction = (...args: any[]) => unknown;
// Helper type that takes a function type and returns the same function type, it just returns
// a promise and wraps the return value to be recursively wrapped again
type PromisifyFunction<NonPromisedFunction extends AnyFunction> =
(...args: Parameters<NonPromisedFunction>) => Promise<PromisifyObject<ReturnType<NonPromisedFunction>>>;
// Type that takes another type and wraps all functions as PromisedFunctions
// The idea: WDI5 gives access to all UI5 functions, but the results come back as promises
// When you wrap the UI5 type into this promised type, the WDI5-manipulated interface will be enforced
type PromisifyObject<Type> = {
[Property in keyof Type]: Type[Property] extends AnyFunction
? PromisifyFunction<Type[Property]>
: PromisifyObject<Type[Property]>
};
// The actual wrapper for WDI5 -- browser.asControl returns something that is both a WDI5 control
// as well as a proxy to UI5 methods of the control, just in a promised fashion
type WDI5<UI5Element extends Control> = WDI5Control & PromisifyObject<UI5Element>; |
can we havez this in |
hey 👋 - silence for 30 days 🤐 ... anybody? 😀 |
well, this is still a thing and hopes are still high that @LukasHeimann will get this into the core types of |
I'm not sure about how this can be made chainable, honestly... I've looked at the code you linked, but unfortunately it wasn't very helpful when it comes to mapping existing types to new ones... |
I have looked into this topic a bit and came up with the following idea. In the browser-commands.d.ts I did the following change to test it:
to
While this is obviously not perfect, it will allow chaining in typescript without casts to any. Opinions on this? |
I don't know if it is actually achievable, but ideally I would want to make sure that I must await the last call that returns a primitive value... You might want to have a mapped type that filters down to only the UI5Element-returning methods of the given type, and have it wrap their responses into the WDI5 interface recursively. All the other methods can still be kept in the recursive promisifier I've posted above: type UI5Function = (...args: any[]) => UI5Element;
type WDI5ifyFunction<NonWdi5edFunction extends UI5Function> =
(...args: Parameters<NonWdi5edFunction >) => WDI5<ReturnType<NonWdi5edFunction >>;
// Type that tykes a UI5 element and returns all its methods that return another UI5 element to allow chaining here
type ChainableMethods<Type extends UI5Element> = {
[Property in keyof Type as Type[Property] extends UI5Function
? Property
: never]: Type[Property] extends UI5Function ? WDI5ifyFunction<Type[Property]> : never
};
// base wdi5 methods + everything needs to be awaited recursively + methods returning a UI5 Element return WDI5<ReturnType> for chaining
type WDI5<Element extends UI5Element> = WDI5Control & PromisifyObject<Element> & ChainableMethods<Element>; This is what I think https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#:~:text=You%20can-,filter%20out%20keys,-by%20producing%20never wants me to do, but it doesn't yet work... Edit: I think, |
Hello, Do you have any update / plan to fix await-thenable issue with browser.asControl returned value ? Thanks. |
most definitely! |
Hello, I was not aware about wdio9 works in progress on that topic (see closed issues). Thanks for the quick update, |
Describe the bug
Comparable to the TS sample I wrote:
This works in general 👍 but gets me an error at
await fooList .getItems();
because methodgetItems
ofsap.m.List
is not async.But without the
await
the test fails.So my question is: Is there another way to solve this than to disable the rule
@typescript-eslint/await-thenable
for all WDI5 tests files?Runtime Env (please complete the following information):
wdi5/wdio-ui5-service
-version: 1.5.1UI5
version: 1.115.1node
-version: 16.18.0The text was updated successfully, but these errors were encountered: