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
Tracking doc: rewrite @wdio/sauce-service
package into TypeScript
#6001
Tracking doc: rewrite @wdio/sauce-service
package into TypeScript
#6001
Conversation
f8db4f8
to
fd4258c
Compare
After rebasing I still get the error:
(see builds here) Any idea @christian-bromann ? |
@christian-bromann I think it could be because of the order in which we build the typescript files here, as generated by
At least I noticed if I run the command |
cd0aefb
to
79201d3
Compare
@christian-bromann sorry for the spam, but I now added a commit (79201d3) where I made it possible to define packages that should be compiled first, to avoid the issue I described in #6001 (comment) Should I open up a separate PR for that or should we keep it in this one? |
Good catch with the compile order. This could complain some other side issues I experienced. |
8304374
to
80e0845
Compare
@christian-bromann just resolved your comments, thanks! |
cff79b2
to
2431b46
Compare
@@ -1,151 +0,0 @@ | |||
declare module WebdriverIO { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can't remove this file as the package.json points to it https://github.com/webdriverio/webdriverio/pull/6001/files#diff-1e974f46805437badbcd51209a7a5b716c7c08ec4b9c1554ffcbc9ca9fa48ef3R45
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't remove it though - only its contents, and I did so since they are outdated (and now included in node-saucelabs
, do we need to do anything differently here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's keep this file for now because it is still being referred to in the package.json ("types": "sauce-service.d.ts"
)
6f88f90
to
7336e59
Compare
10f6498
to
979d246
Compare
979d246
to
a2ccb3a
Compare
@christian-bromann can you have a look again please? Seems like only one question from you that I answered is left. |
"devDependencies": { | ||
"webdriverio": "6.7.0", | ||
"webdriver": "6.7.0", | ||
"@wdio/cucumber-framework": "6.7.0", | ||
"@wdio/jasmine-framework": "6.7.0", | ||
"@wdio/reporter": "6.7.0", | ||
"@types/cucumber": "6.0.1", | ||
"cucumber": "6.0.5" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be problematic if we release. As we are in a production environment it won't install dev dependencies and therefor the compile step will fail. I would suggest:
- remove
cucumber
- move
@types/cucumber
into the dependencies - reference all wdio types through tsconfig.json and use them through their namespace, e.g. WebDriver.DesiredCapabilities rather than importing them.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, I'll try it and see if it works and report back if I run into issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@christian-bromann by reference all wdio types through tsconfig.json
you did mean to do it like that, right?:
"types": ["webdriverio", "webdriver", "@wdio/jasmine-framework" ,"@wdio/cucumber-framework", "@wdio/mocha-framework", "@wdio/utils"]
Or did you mean something else?
Because I'm getting an error, see launcher.ts:21
:
TS2503: Cannot find namespace 'Webdriver'.
TS4063: Parameter 'capabilities' of constructor from exported class has or is using private name 'Webdriver'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I guess this solution doesn't work then and we have to use references like Jest does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I googled a bit and came to the same conclusion, I also found this:
https://medium.com/@NiGhTTraX/how-to-set-up-a-typescript-monorepo-with-lerna-c6acda7d4559
https://github.com/NiGhTTraX/ts-monorepo
In this case, I guess we need to change the root tsconfig.json
to the following, right?:
{
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"inlineSourceMap": true,
"baseUrl": ".",
"paths": {
"@wdio/*": ["packages/wdio-*/src"],
"devtools": ["packages/devtools/src"],
"eslint-plugin-wdio": ["packages/eslint-plugin-wdio/src"],
"webdriver": ["packages/webdriver/src"],
"werbdriverio": ["packages/webdriverio/src"]
}
}
}
If the build
command runs fine, does this indicate it will work in production as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you try specifying types
in package.json
? I hope this can solve typescript monorepo problem
https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#including-declarations-in-your-npm-package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hieuxlu the source code is right there for you to check yourself, but yes I did so ;)
interface MultiRemoteBrowser extends WebdriverIO.BrowserObject { | ||
instances: string[] | ||
isMultiremote: boolean | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not reusable for other services @christian-bromann @martinfrancois. We have browserstack service, testingbot services eagerly waiting to use multiremote browser types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do they have the same kind of type annotation? If so, we could think about extracting it somewhere more global, but anyways we could always move this in a later PR into a different package when there is the need for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes its common properties in global browser object, but not define yet. And yes, I agree it could be a separate issue. I just wonder if you guys could think of any better solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally like not to prematurely optimize things - my preferred approach is usually to adapt things to be as generic as they need to be, once it's needed. So I would rather start with having this interface
here (as it's the only place it's used right now) and refactoring it to a different place as soon as the need for it arises. And where to put it then will be something to look at specifically in the context. Especially considering we are not exporting this type, so we don't run risk of any breaking changes when we move this to a different place.
const browserName = global.browser.instances.filter( | ||
(browserName) => global.browser[browserName].sessionId === newSessionId)[0] | ||
const browserName = this.multiRemoteBrowser.instances.filter( | ||
(browserName: string) => (global.browser[browserName as keyof BrowserObject] as BrowserObject).sessionId === newSessionId)[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say this as quite hacky @christian-bromann. browserName
is definitely not in the list of keyof BrowserObject
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the type of global.browser
is BrowserObject
, and you are trying to access a key from global.browser
here, what else could it be other than a key of BrowserObject
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the case of accessing something like Record<string, BrowserObject>
. If you use <keyOf>
, the property will be casted to any
, so the typecheck would provide no value.
So using global.browser[browserName as keyof BrowserObject]
is equivalent to (global.browser as any)[browserName]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you use
<keyOf>
, the property will be casted toany
, so the typecheck would provide no value.
That's actually incorrect, have a look at the following example:
const myObj = {
Hello: "world"
};
type ObjKey = keyof typeof myObj
const foo: ObjKey = "foo";
If what you are saying was correct, that keyof
would cast it to any
, then I would expect this example to compile without any errors (since ObjKey
would be any
). However, this results in the following error:
Initializer type "foo" is not assignable to variable type ObjKey
If I change the last line to be const foo: ObjKey = "Hello";
, it compiles fine without any errors.
So clearly TypeScript preserves the types when using keyof
.
But you are right in a way that by using browserName as keyof BrowserObject
we are implicitly telling TypeScript to assume that browserName
is a key of BrowserObject
, even though it comes from this.multiRemoteBrowser.instances
(which is a plain array of strings, with no guarantee of those strings being keyof BrowserObject
). To be 100% correct we would need to either type instance
as (keyof BrowserObject)[]
and or run checks on runtime to ensure that instances
are indeed keys of BrowserObject
. But this would limit the instances that can be used, which could get annoying to maintain (as the code needs to be changed for each new type of instance) and it would most likely be overkill here and the risk of breaking things would be much higher than the benefit of the type safety we would gain in this situation, in my opinion.
Considering the code has been running fine previously, I'm quite hesitant with adding any more checks here, we could always consider improving type safety here in the future, but probably this would be a bigger undertaking. Of course I could be totally missing something, in which case I would be glad if you could point it out or make suggestions on how to improve the situation.
…ve `cucumber` Signed-off-by: martinfrancois <f.martin@fastmail.com>
Signed-off-by: martinfrancois <f.martin@fastmail.com>
@martinfrancois there still seem to be some legit compiling errors:
|
@christian-bromann yes, I mentioned the reason for them here: #6001 (comment) |
@martinfrancois can we update the branch as have added a bunch of more rewrites to I think the following way of handling external types works best: add e.g. in {
"extends": "../../tsconfig",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./build",
"rootDir": "./src",
"types": ["webdriverio", "@wdio/protocols"],
},
"include": [
"src/**/*"
]
} Then you can use the types in all files via, e.g. in static async newSession (options: WebDriver.Options = {}, modifier?: Function, userPrototype = {}, customCommandWrapper?: Function) {
const params: WebDriver.Options = validateConfig(DEFAULTS, options) Note: the difference between Happy to help in any way to get this landed. |
@martinfrancois do you plan to continue working on this? |
@christian-bromann excuse me, didn't notice your update here: #6001 (comment) Yes, I'll try your suggestion and will get back to you! |
@martinfrancois we are aiming for a v7 release by end of January. Do you think you can push this over the line until then? If not, no problem. I am happy to pick this one up. |
I will go ahead and take this over. I will use what you have done so far. |
Closing in favor of #6274 |
Proposed changes
Rewrite
@wdio/sauce-service
package into TypeScript, see #5843Types of changes
Checklist
Further comments
Reviewers: @webdriverio/project-committers