TypeScript users often have multiple `protractor` installations floating around
See original GitHub issueWe encourage typescript users to do something like:
import {browser, promise} from 'protractor';
...
browser.wait(promise.when(something));
The problem here is that often users will invoke their tests from a globally installed protractor
package, but they’ll import from a locally installed protractor
package. Because of the way we use registerGlobal
in index.ts, we’ll get browser
from the global protractor
package, but promise
will still come from the local package.
This could be a problem in many ways. For promise
specifically, this is a problem because you many end up with inconsistent settings for USE_PROMISE_MANAGER
. This could be mitigated slightly by setting process.env.SELENIUM_PROMISE_MANAGER
in the runner (currently we only set wdpromise.USE_PROMISE_MANAGER
), but there would still be plenty of ways this could go wrong.
Solution 1: Breaking change - only export types from index.ts
We can use syntax like export type Runner = Runner
to export types without exporting the actual classes. If we did this for everything, our compiled index.js
would be empty but our compiled index.d.ts
would still have the types people need.
This solution has the advantage of being unlikely to cause users unexpected problems
Drawback: Users would have to declare
globals
This would force users to do a lot of
declare let protractor: Ptor; // Set globally by Protractor's runner
declare let browser: ProtractorBrowser; // Set globally by Protractor's runner
...
We could simplify this for our users by using declare global
, though we’d really only be able to declare protractor
since we don’t know if someone is using the noGlobals
option until runtime.
Alternately, we could continue to export by reference things like browser
, but stop exporting everything else (except types).
Drawback: Helper functions would be slightly harder to access
This would break syntax like:
import {Key as ptorKey} from 'protractor';
element.sendKeys("text was", ptorKey.CONTROL, "a", ptorKey.NULL, "now text is");
...
Solution 2: Export more properties by reference
Export more of the properties on the Ptor
class using registerGlobal
. This solves the problem of multiple instances in some cases, though it could make the problem even worse if:
- The global and local installations are on different versions
- The file importing
protractor
was never invoked by Protractor (and thus the globalprotractor
instance has never been set) - Properties other than the ones on the
Ptor
class have issues similar to the onespromise
has. - Someone in some other way makes the (totally reasonable) assumption that when they require/import Protractor, they’re getting instances from their local installation, not the global installation.
Solution 3: Breaking change - throw error if multiple installations are detected
This would force users to import
from the same Protractor installation they use to run their tests. It may be difficult for users to point import
to the Protractor installation which runs their tests, however.
Solution 4: Make importing protractor
redirect to the invoking protractor
installation
In runner.ts
we could do something like:
global.PROTRACTOR_EXPORTS_ = require('./index');
and then at the top of index.ts
we could do something like:
if (global.PROTRACTOR_EXPORTS_) {
module.exports = global.PROTRACTOR_EXPORTS_;
return;
}
This could go wrong in a number of ways, and would be very difficult for our users to debug.
Solution 5: Detect local installations and use those
Back in cli.ts
, use npm ls
to detect if there is a local Protractor installation. If there is, use npm run
to redirect to that installation. There are a huge number of ways that this could go wrong, and I highly doubt this is the correct solution.
Solution 6: Magic???
I’m not totally satisfied with any of the solutions thus far. Solution 1 is probably the least likely to cause our users unexpected problems, but it could still be a pain.
Issue Analytics
- State:
- Created 7 years ago
- Comments:8 (2 by maintainers)
Top GitHub Comments
yes fallowing the protractor/exampleTypescript/ example, looking at the package.json why does reference the conf.js javascript file and not the typescript conf.ts file. Do we still need the conf.js file even if we plan to work on typescript.
{ “name”: “example-typescript”, “version”: “1.0.0”, “description”: “a typescript example”, “author”: “”, “license”: “MIT”, “scripts”: { “tsc”: “tsc”, “pretest”: “npm run tsc”, “test”: “protractor tmp/conf.js” }, “dependencies”: { “@types/jasmine”: “2.5.41”, “@types/jasminewd2”: “^2.0.0”, “jasmine”: “^2.4.1”, “protractor”: “file:…/”, “typescript”: “~2.0.0” }, “devDependencies”: { “@types/jasminewd2”: “^2.0.0” } }
After compiling typescript files to js files via command “npm runt tsc” (follow this) , a tmp folder is created in the project with all the js files. We need to run protractor.conf.js from that tmp folder. On running it, everything is working fine.