Overview
In 3.0.0
we had to include a dependency that automatically bundled in the typescript
binary. This added some significant weight to the overall app size (35mb) which begs the question- why not just provide native support for typescript? We originally decided not to do this because of the added weight. Now that's no longer a reason. Additionally, support for typescript has continuously expanded, and as part of our overall philosophy of being zero-config, I think it's time to add support for it out of the box. We already have several dedicated doc guides for this.
As we're coming closer to bridging the gap between the browser + the node context shifts, it means that we also need to think about the plugin support for both of these contexts.
For instance we have file:preprocessor
event, but this is really only for spec + support files going to the browser.
What if users want to write their plugins/index.js
file using newer node features that the current version doesn't support? What if they want to write that file in typescript? What if they want to include or require other node files or lib code that also needs this?
Proposal
typescript
as an official dependency in Cypress..ts
file extensions for node files found in plugins
, etc.ts
extension.tsconfig
that your project would be using in node normally, but with a preference for .tsconfig
files in cypress
folder.ts-node
to do typescript compilation on demand / in memory. Potentially do either transpileOnly
or leave full blown type checking on.Questions
require
the one built into your project, and if none is installed fall back to ours.cypress.json
that prefers the bundled/native version of typescript even if a system/project typescript dependency was foundts-node
options we use by default such as transpileOnly
? We could add more cypress.json
configuration options but then we're back to preferring static configuration vs configuration with code.Concerns
Thinking about this more and looking at other frameworks. It is super nice to have Cypress "automatically" transpile things for you, because it has to work in both the node
and browser
environment. The problem is that customization is much harder. We have to expose to you the ability to modify the options. This worked well for the file:preprocessor
plugin event - because the browser context is always executed later in the testing lifecycle. However, trying to do the same thing with node
is not possible because there has to be some kind of entry point.
If we think about this outside of just Typescript we have the same issue. Imagine someone wanting to write their node
plugin files using ES2018 - they'd have the same problem as they do whenever they're starting a vanilla node project for the first time. In both cases, you'd have to use babel
to automatically transpile the .js
or .mjs
files on the fly. The difference is that it would be totally controllable by the user (we should just write some docs outlining this behavior). If you think about Typescript in this way you could argue that we should not add built in native support for it so that the user retains total control of both the node and browser context. On the other hand we could simply avoid adding lots of configuration options and instead just allow the user to turn off built in typescript support and then provide docs on how to manually wire things up in the case that you need to customize things beyond what we support.
/cc @amirrustam @bahmutov @chrisbreiding
With regards to TypeScript support, here are current ts-node
register options I'm using within the API. Documenting here for discussion.
require('ts-node').register({
pretty: true, // Use pretty diagnostic formatter
typeCheck: false, // Turn off type checking
transpileOnly: true, // Use TypeScript's faster `transpileModule`
ignoreDiagnostics: true, // Ignore TypeScript warnings by diagnostic code
})
Full ts-node
register options:
// Register options.
pretty?: boolean
typeCheck?: boolean
transpileOnly?: boolean
cache?: boolean
cacheDirectory?: string
compiler?: string
ignore?: string | string[]
project?: string
skipIgnore?: boolean
skipProject?: boolean
ignoreDiagnostics?: string | string[]
compilerOptions?: string
I don't know as much about the implementation details of this, but I would like automatic TypeScript support, without having to set up my own preprocessor api if I have a .ts
file extension in my test directories. Would love to hear @NicholasBoll opinion.
@jennifer-shehane sure, that is the goal, but if you read my proposal you'll see that we need to give you the ability to configure ts-node
to achieve this. If we read in your .ts
files without going through a hook or index.js
that sets these options, then there's no way to configure the way ts-node
works.
We could support these options via cypress.json
but then we're back to the same ol' configuration for everything problem vs just letting people write code to do the stuff they want to do.
Just read the proposal and you'll see what the challenges are. When those questions are answered and we come up with a reasonable implementation then we can do it. Saying we want to support this is like saying we want to support all browsers. Naturally we do, but that's completely glossing over the implementation details that need to be worked out.
Whats the need for processing the file in memory, why not write them out to some temp directory?
We do write them out to a temp directory
Gotcha, is there a reason why you cant use typescript directly then? it'll reduce a dependancy and give you more options for config.
I would love to remove the need for messing with plugins/index.js
along with needing to install webpack @cypress/webpack-preprocessor typescript ts-loader
Current process https://github.com/basarat/typescript-book/blob/master/docs/testing/cypress.md
Ideally cypress ships with ts-node
and all we (the users) need to do is npm install cypress typescript
, write a tsconfig.json
and start cracking with .spec.ts
files :rose:
@basarat that's a great guide, thank you! I would love to have a shorter typescript way too.
Currently we're using typescript for the intellisense and omit typescript features like type annotations so that the code looks like es5/es6. Not optimal but works for simple use cases.
First of all, nice project, i just R&D cy and its looks promising, anyway to consider the topic ts integration
documentation is laked, when i used configs in eg. tests wont run, thank of all tsconfig form git repository work better. To works with chia/mocha assertions you need extend litle bit tsconfig
yml
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"skipLibCheck": true, // do not check types in node_modules folder
"noImplicitAny": false,
/* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true,
/* Enable strict null checks. */
"noImplicitThis": true,
/* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true,
"lib": ["es5", "dom"],
"types": ["cypress"],
"typeRoots": [
"node_modules/@types"
],
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
},
"strict": true,
"sourceMap": true,
"experimentalDecorators": true
},
"include": [
"node_modules/cypress",
"cypress/*/*.ts"
],
"compileOnSave": false
}
and add to each ts file eg.:
```ts
///
import { expect } from 'chai';
````
consider to buildin ts support in Pm2 - has solution for it but this solution has +/-, what is
pros 👍
Are there any updates on this issue?
@SeriousM No updates on this issue. It is still in a proposal stage.
This might be an obvious thing to say but looking directly into webpack codebase might be a good idea. Webpack does exactly what this proposal wants to achieve. You can write configs in typescript and it just uses ts-node underneath with zero additional configuration needed - you just need to install ts-node as a devDep in you project. If you want to use different tsconfig, you just run it like this: TS_NODE_PROJECT="tsconfig-ts-node.json" webpack
.
And how do we connect webpack with cypress?
@aczekajski do you have a complete example, even a very simple one that shows what you are doing in action? Because for me, configuring Webpack like this https://webpack.js.org/guides/typescript/ plus adding https://github.com/cypress-io/cypress-webpack-preprocessor is not as simple, and trying to make it "built-in" seems a little bit premature
@bahmutov I think @aczekajski is only talking about that https://webpack.js.org/configuration/configuration-languages/. Seems indeed to be only a subset of this issue's objective :)
would this step by step instruction webpack + Cypress help? https://glebbahmutov.com/blog/use-typescript-with-cypress/
This guide should be on the cypress.io docs!
Now with @babel\preset-typescript
, this can be accomplished by just modifying the default browserify preprocessor.
To do this manually:
install @cypress/browserify-preprocessor
and @babel/preset-typescript
Modify the plugins/index.js
file:
const browserify = require('@cypress/browserify-preprocessor');
module.exports = (on, config) => {
const options = browserify.defaultOptions;
options.browserifyOptions.extensions.push('.ts', '.tsx');
const babelifyConfig = options.browserifyOptions.transform[1][1];
babelifyConfig.presets.push(require.resolve('@babel/preset-typescript'));
babelifyConfig.extensions = ['.js', '.jsx', '.ts', '.tsx'];
on('file:preprocessor', browserify(options));
};
Ohh this is good
Sent from my iPhone
On Mar 25, 2019, at 23:07, Nathan Brown notifications@github.com wrote:
Now with @babelpreset-typescript, this can be accomplished by just modifying the default browserify preprocessor.
To do this manually:
install @cypress/browserify-preprocessor and @babel/preset-typescript
Modify the plugin/index.js file:
const browserify = require('@cypress/browserify-preprocessor');
module.exports = (on, config) => {
const options = browserify.defaultOptions;
options.browserifyOptions.extensions.push('.ts');
const babelifyConfig = options.browserifyOptions.transform[1][1];
babelifyConfig.presets.push(require.resolve('@babel/preset-typescript'));
babelifyConfig.extensions = ['.js', '.jsx', '.ts', '.tsx'];on('file:preprocessor', browserify(options));
};
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
I would be happy built-in babel doing the ts->js transform.
I use the IDE / tsc --noEmit
to tell me any type errors anyways :rose:
Is that a command parameter?
@SeriousM --noEmit
is a TypeScript compiler parameter. It tells TypeScript not to emit any .js
(or .d.ts
) files. You can use it to tell TypeScript to do a full type check but leave the transpilation to something else. In cypress case the emit will be done in memory by cypress+ts-loader OR hopefully cypress+internalBabelWithTsSupportWithZeroConfigNeeded :rose:
Hi everyone. I was recently trying to write tests for my Typescript+React Application and faced a lot of issues with respect to Typescript configuration. I faced a lot of issues in getting started with Jest+react-testing-library in Typescript then, making me switch to the amazing Cypress library. For the past 3 days, I have been continuously struggling to integrate Cypress+Typescript+React together. The issues are:
webpack
preprocessor, it clashes with Create-React-App requirements and breaks the project. Integrating webpack
itself is a lot of hassle, esp. if you're already using it in different parts of the project.tsify
causes some issues with the following 2 errors continuously coming up: SyntaxError: 'import' and 'export' may appear only with 'sourceType: module'
Cannot compile namespaces when the '--isolatedModules' flag is provided.
Though these seem like some pretty straightforward issues, I really couldn't figure them out till now.
- Handling multiple
tsconfig.json
and which folder to run which command from + setting uppackage.json
seem like a lot of clashing configuration to do as React and Cypress both have strict & differenttsconfig.json
requirements.
Just like Cypress, it's difficult to switch back to Javascript after tasting Typescript capabilities. (As of now I have shifted to JS tests.)
80% of us would like to use or learn TypeScript in their next project and it is one of the most loved languages by devs. I really believe we should take this proposal forward to facilitate and encourage Typescript usage.
How about using our a "simple" TypeScript transpiler using just
tsc
programmatically (#3430): Would something on these lines might help: https://medium.com/bratislava-angular/up-and-running-with-cypress-and-typescript-5b9065eedbd3
@mayurdhurpate I have went through a fresh CRA + TypeScript + Cypress setup last night, there are a few gotchas related to the compiler flags CRA uses. Nothing complicated, I will describe the steps in a blog post on https://www.cypress.io/blog/ soon
I have described CRA v3 + writing Cypress tests using TypeScript in this blog post https://www.cypress.io/blog/2019/05/13/code-create-react-app-v3-and-its-cypress-tests-using-typescript/ for anyone interested
Thanks! :rose:
Would still wish a native, non additional webpack + @bahmutov/add-typescript-to-cypress
process (which is already existing). The additional install + a later flicker caused by a webpack compile whenever a test loads is what I would wish gone :heart:
PS: Minor typo
.env
file
Thanks @basarat for noticing it - I should fix it :)
Would really appreciate Typescript just working out of the box. Especially commands.
@brian-mann @jennifer-shehane what's the status of this?
The goal of this proposal is these 2 in summary:
But after reading cypress
code, I realized that files under cypress
folder are handled in different ways.
integration
, support
: They're transpiled by browserify
and sent to client.plugins
: They're require
d.So, the goal can be broken into 4 like this:
test
files.plugin
files.test
files.plugin
files. I've created PR(#5906) to fix these problems. Here are the notes and thoughts about the process.
test
files.There were 2 options to make this possible.
tsify
and bundled/user-installed typescript
.@babel/preset-typescript
.I decided to go with babel
. Although it doesn't support type check, modern editors check TypeScript types. And tsify
is too slow for the job.
We need to bundle webpack and loaders. It increases bundle size too much. So, I didn't do that.
When there is a user-installed @babel/preset-typescript
, use it. If not, use bundled one.
I'm thinking about going with no config for this. It's hard to find a reason to prefer bundled @babel/preset-typescript
to user-installed one.
plugin
files.ts-node
has to be added to packages/server
dependencies. I created 4 options for this and register
options accordingly.
Add typescript
option in cypress.json
. It can have one of these 4 values.
default
: use user-installed typescript
if exists, use bundled one if not.project
: use user-installed typescript
if exists, throw error if not.bundled
: always use bundled typescript
none
: don't use typescript
.test
files.I think it's solved by "file:preprocessor"
.
When you want something complicated than out-of-the-box TypeScript, it should be done with this event.
plugin
files.I think there are 3 things that users want to customize.
tsconfig
ts-node
optionsWe can support them like this:
tsconfig
Add tsconfig
option in cypress.json
. It should have 4 options:
default
: use user-installed tsconfig
if exists, use bundled one if not.project
: use user-installed tsconfig
if exists, throw error if not.bundled
: always use bundled tsconfig
typescript
option is none
and this value is defined, throw an error.ts-node
optionsAdd tsnode
option in cypress.json
. You can add options if it is supported in ts-node
.
Note: when typescript
option is none
and it is defined, throw an error.
Add setupNodeFile
option in cypress.json
. Its default value is plugins/setup_node.js
. It must be js
file.
In this file, users can define whatever they want here. If they want to set up babel-node
with a bunch of stage-0/1 features, this is the place to do it.
If this file exists, all typescript
-related options will be ignored.
// plugins/setup_node.js
module.exports = () => {
require('@babel/node')
}
//.babelrc
{
// presets and plugins...
}
This setup_node.js
file will be executed before plugins/index.js
is loaded.
setup_node.js
exports a function for the future.
These are not implemented in #5906.
It's because of the noImplicitAny
option in tsconfig
. When it is set to true
, server will throw an error because in packages/server
, noImplicitAny
is false
.
Because of this, transpileOnly
must be always true
. If not, server will fail.
I think we should revisit this issue after #2690 is done. Or close this and create new issue for these options and wait for users' opinions.
These options might be over-engineering.
This is an excellent proposal and I’m excited about it. I love the fact how you split it into four stages for quickly merges and also how you are thinking what should be a peer dependency. I’m even thinking that if the project is not using TS already we should not bundle our TS code but instead show and error asking the user to install ts modules
Sent from my iPhone
On Dec 6, 2019, at 20:25, Kukhyeon Heo notifications@github.com wrote:
The goal of this proposal is these 2 in summary:Out-of-the-box TypeScript support.
Allow customization for it. (Even with Babel)
But after reading cypress code, I realized that files under cypress folder are handled in different ways.integration, support: They're transpiled by browserify and sent to client.
plugins: They're required.
So, the goal can be broken into 4 like this:Out-of-the-box TypeScript support for test files.
Out-of-the-box TypeScript support for plugin files.
Allow customization for test files.
Allow customization for plugin files.
I've created PR(#5906) to fix these problems. Here are the notes and thoughts about the process.
- Out-of-the-box TypeScript support for test files.
About implementation
There were 2 options to make this possible.
Use tsify and bundled/user-installed typescript.
Use @babel/preset-typescript.
I decided to go with babel. Although it doesn't support type check, modern editors check TypeScript types. And tsify is too slow for the job.Why not webpack?
We need to bundle webpack and loaders. It increases bundle size too much. So, I didn't do that.
How it works
When there is a user-installed @babel/preset-typescript, use it. If not, use bundled one.
Options
I'm thinking about going with no config for this. It's hard to find a reason to prefer bundled @babel/preset-typescript to user-installed one.
- Out-of-the-box TypeScript support for plugin files.
About implementation
ts-node has to be added to packages/server dependencies. I created 4 options for this and register options accordingly.
Options & How it works
Add typescript option in cypress.json. It can have one of these 4 values.
undefined or default: use user-installed typescript if exists, use bundled one if not.
project: use user-installed typescript if exists, throw error if not.
bundled: always use bundled typescript
none: don't use typescript.
- Allow customization for test files.
I think it's solved by "file:preprocessor".
When you want something complicated than out-of-the-box TypeScript, it should be done with this event.
- Allow customization for plugin files.
Option ideas
I think there are 3 things that users want to customize.
tsconfig
ts-node options
Set up everything you like
We can support them like this:tsconfig
Add tsconfig option in cypress.json. It should have 4 options:
undefined or default: use user-installed tsconfig if exists, use bundled one if not.
project: use user-installed tsconfig if exists, throw error if not.
bundled: always use bundled tsconfig
when typescript option is none and this value is defined, throw an error.
ts-node optionsAdd tsnode option in cypress.json. You can add options if it is supported in ts-node.
Note: when typescript option is none and it is defined, throw an error.
Set up everything you like
Add setupNodeFile option in cypress.json. Its default value is plugins/setup_node.js. It must be js file.
In this file, users can define whatever they want here. If they want to set up babel-node with a bunch of stage-0/1 features, this is the place to do it.
If this file exists, all typescript-related options will be ignored.
Example Code
// plugins/setup_node.js
module.exports = () => {
require('@babel/node')
}
//.babelrc
{
// presets and plugins...
}
This setup_node.js file will be executed before plugins/index.js is loaded.setup_node.js exports a function for the future.
The Problem
These are not implemented in #5906.
It's because of the noImplicitAny option in tsconfig. When it is set to true, server will throw an error because in packages/server, noImplicitAny is false.
Because of this, transpileOnly must be always true. If not, server will fail.
I think we should revisit this issue after #2690 is done. Or close this and create new issue for these options and wait for users' opinions.
These options might be over-engineering.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
I don't think we should ever bundle typescript, and always require the user to have it installed. Adding the tsc
binary increases the size of Cypress by too much. I also don't like the idea of the version of typescript not being specified. It makes more sense to always require the user to supply typescript
- since they likely already are in their project in the first place.
You are right that we need to handle both the plugin
files and the spec
files separately, and because of that - that's where all the complexity emerges. I think your ideas do satisfy all the conditions, but that overall its still far too complex and would require far too much documentation and edge case handling. I also really don't like the idea of introducing yet another setupNodeFile
configuration option.
I don't think we need to actually introduce any new configuration options - we could automatically detect what the user is trying to do via the .ts
file extension and attempt to do the right thing.
I also think that we could just use tsconfig.json
by default, and avoid needing to support any ts-node
options - or at the very least, if the user supplies their own environment variables, then those would "just work".
@brian-mann Sorry for the late reply. I was investigating to find the answer.
My second proposal is this:
Focus on transpiling typescript files. Let editors and CIs do type checking.
With this, we don't have to worry about tsconfig.json
, ts-node
options, etc. All we do is these 2:
.ts
files are used. Throw error like now. With this, new dependency we need to add is ts-node
(resolve
and through2
are added by babel
and browserify
). If that's too much, then we can give up typescript
for plugin
and remove ts-node
.
Please check #5906 for code. (The failed test is flaky test to be fixed in #6030)
NOTE: To remove typescript
from server
entirely, we need to remove dependency-tree
and find/make alternative. (I opened an issue in #6051)
The code for this is done in cypress-io/cypress#5906, but has yet to be released.
We'll update this issue and reference the changelog when it's released.
Released in 4.4.0
.
This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v4.4.0, please open a new issue.
Most helpful comment
I would love to remove the need for messing with
plugins/index.js
along with needing to installwebpack @cypress/webpack-preprocessor typescript ts-loader
Current process https://github.com/basarat/typescript-book/blob/master/docs/testing/cypress.md
Ideally cypress ships with
ts-node
and all we (the users) need to do isnpm install cypress typescript
, write atsconfig.json
and start cracking with.spec.ts
files :rose: