avajs / ava

Node.js test runner that lets you develop with confidence πŸš€
MIT License
20.73k stars 1.41k forks source link

Support to Run TypeScript test file(.ts) directly without Precompiling(tsc) #1109

Closed huan closed 4 years ago

huan commented 7 years ago

Issuehunt badges

Description

AVA now support ES6 by using Babel, run directly without any precompiling, this is very convenience. But for TypeScript, AVA has to precompile ts files by run tsc.

I use TypeScript in my project wechaty, run TS code directly by ts-node like this: ts-node demo.ts. This is a convenience way for developing.

If we can run TypeScript file directly by AVA, just like ava test.ts, that will be wonderful.

About this topic, there has already an issue #631 on it. I saw @sindresorhus agree that use TypeScript without precompiling is a better way.

@niieani You can already use TypeScript by precompiling it. I know it's not optimal, but it's not like anyone has done a pull request fixing this. https://github.com/avajs/ava/issues/631#issuecomment-250368210

I love AVA, because I'm a TAP fan, and AVA is based on TAP. So I tried to hack AVA to support TypeScript directly. After some study & work, I finished it finally, and in the past month, I was using it in my own project and it worked as my expected.

I'll share my idea here, and send a Pull Request later. Hope we can support TypeScript without precompiling soon.

ava-typescript

About the Hack

I added a --ext ts argument parameter to CLI, then pass ext to AVA API. If ext is ts then I use TypeScript Compiler to replace the Babel Compiler, because TypeScript is the superset of ES6/7.

  1. Add CLI Arg: --ext/-e

    In order to support TypeScript without precompiling, first, we need to add a CLI args to support that. I use the name --ext and the alias -e for this, like ava -e ts. Set the ext automatically is considered, but I think maybe it should be done later. If set ext automatically, then we can just run TS tests by ava test.ts

  2. Get Test Files from ava-files

    AVA use a submodule ava-files to get all test files list. It had to be modified to support the ext parameter. I use exts in the ava-files module and it is an Array type, that's for the future support of multiple file extensions.

  3. new API options: ext

    in API call, we get file extension name from options.ext, pass it to AvaFiles/CachingPrecompiler/Watcher.

  4. Add a Switcher between Babel with TypeScript

    AVA compile ES6 by Babel in CachingPrecompiler, so we could compile TypeScript here. If the file extension is set to ts, then CachingPrecompiler will use a new module extTs to compile the source.

  5. Introduce a new Module: extTs(lib/ext/ts.js)

    For ts file extension, the compiler module ext/ts.js will be loaded. In the furture, other extension could modulize their own compile code in different file in ext/ directory. i.e. ext/jsx.js for a new extJsx compiling module.

  6. Enable Run TypeScript in test-worker.js

    AVA use subprocess to run tests, the worker needs to register to TypeScript compiler.

  7. Add TypeScript dependence to package.json

  8. Make XO happy

Test Source

test.ts:

import { test } from 'ava'

test('AVA run TypeScript without tsc', t => {
  let i: number = 42
  t.is(i, <number>42, 'meaning of life')
})

Run:

$ ava --ext ts test.ts

  βœ” AVA run TypeScript without tsc

  1 test passed [02:55:58]

Yeah~

Relevant Links

There is a $142.00 open bounty on this issue. Add more on Issuehunt.

huan commented 7 years ago

Hi,

Is there any feedback or suggestion?

I want to know:

  1. is the parameter name all right? now they are:
    1. --ext / -e for AVA CLI
    2. exts a new key for AvaFile options
  2. how about to set --ext automatically? if we run ava test.ts then let ava know .ts should support typescript.

looking forward to getting feedback, then I can make the Pull Request fit better.

sindresorhus commented 7 years ago

Thanks for picking this up @zixia :)

Your proposal looks pretty good.

Some random feedback:

huan commented 7 years ago

Got it.

I'll follow your great feedback then make the PR later. :)

huan commented 7 years ago

Hi @sindresorhus ,

I had followed all your feedbacks and made two PRs: one is for AvaFiles, the other is for AVA.

Please notice that CI for AVA will be expected to report failure because the ava-files NPM modules do not support extensions parameter now.

All unit tests had passed in my dev box with the PR code.

Please let me know if I missed anything in PR, thanks.

jednano commented 7 years ago

@zixia this is awesome work and I'm excited to use it, but can you tell me if it works fine with the --watch flag too? Or is there more work to do for that?

huan commented 7 years ago

@jedmao Hi buddy thanks you for like my work, and I'm sure you are a TypeScript fan like me.

In theory, I think it should work with the --watch flag, because I modified all the parts in AVA to support ts, including Watcher class and all the Watcher unit tests. But I did not test it yet, and there's possible I missed part of it. So if you find any problem with that, please let me know, and I'll get it worked.

If you want to try it before @sindresorhus merge this PR, you can pull my clone at https://github.com/zixia/ava (branch: typescript) , and also don't forget to link ava-files too: https://github.com/zixia/ava-files

patrick91 commented 7 years ago

Is there any update on this? I'm starting a new TS project and I really would like to use ava without compiling TS scripts first!

@zixia amazing work so far!

huan commented 7 years ago

@patrick91 Thanks!

AVA decide to re-design the total code structure of how to use Babel, which delayed the TypeScript support progress.

See: https://github.com/avajs/ava/pull/1159

bitjson commented 7 years ago

@patrick91 (and anyone else coming across this thread) – I've been getting into Typescript a lot recently, and had some trouble getting a lot of the packages I wanted to use working together.

I spent a little time starter project which I think it might accomplish what you're looking for: es7-typescript-starter

I'd love input/feedback on how it could be improved, especially when AVA restarts work on this issue.

lukescott commented 7 years ago

@novemberborn I know I can do tsc && ava, but that won't work with --watch, will it? Is there a solution to make it work with watch?

tomdavidson commented 7 years ago

@lukescott you can add "compileOnSave": true to your tsconfig.json if you use an editor that recognizes it. You can also change your watch/dev run script to be something like tsc -w & ava --watch so tsc will watch in the background while you run ava watch.

I think ava is super interesting but I have not replaced mocha over the typescript issue so the suggestion is not in use for me.

lukescott commented 7 years ago

Ah, got it. So I need need to run them separately. Tsc will watch and save files, which Ava will pick those up. It's too bad there isn't a way to do a single watcher and have it all happen in memory.

jednano commented 7 years ago

Yep, I've been waiting for the same feature.

novemberborn commented 7 years ago

The plan is here, but there hasn't been progress on that lately: https://github.com/avajs/ava/blob/master/docs/specs/001%20-%20Improving%20language%20support.md

unional commented 7 years ago

@lukescott for watch, you can do this: https://github.com/unional/color-map/blob/master/scripts/watch.js

'use strict';

const cp = require('child_process');

let ava;
cp.spawn('tsc', ['-w'], { shell: true })
  .stdout.on('data', (data) => {
    if (!ava) {
      ava = cp.spawn('ava', ['-w'], {
        stdio: 'inherit',
        shell: true
      })
    }
    const text = data.toString()
    process.stdout.write(text)
    if (/.*Compilation complete/.test(text)) {
      let lint = cp.spawnSync('npm', ['run', 'lint'], {
        stdio: 'inherit',
        shell: true
      })
      if (lint.status === 0) {
        cp.spawnSync('npm', ['run', 'build-commonjs'])
      }
    }
  })
sebinsua commented 7 years ago

The plan is here, but there hasn't been progress on that lately: https://github.com/avajs/ava/blob/master/docs/specs/001%20-%20Improving%20language%20support.md

Has there been any work on this since then?

patrick91 commented 7 years ago

babel has recently merged a PR that allows to parse typescript, so maybe soon enough we will be able to use ava for typescript via babel :)

https://github.com/babel/babylon/pull/523#event-1142533589

huan commented 7 years ago

Looking forward it, or I have to consider other solutions like tap which had already supported the TypeScript(https://github.com/tapjs/node-tap/issues/313) and Concurrency.

ORESoftware commented 7 years ago

https://github.com/TypeStrong/ts-node

novemberborn commented 7 years ago

If we can run TypeScript through Babel then yea we can land some sort of support for that. Though you'd still need the equivalent to babel-register to load TypeScript source files.

lukescott commented 7 years ago

With TypeScript support in babel, wouldn't babel-register (or what ever Ava uses) work? I would imagine babel adding the .ts extension w/ native support.

adieuadieu commented 7 years ago

I came to this thread/issue while trying to use Ava's --watch feature with TypeScript. @tomdavidson's suggestion of tsc --watch & ava --watch works well enough as an intermediate solution for anyone who wants to watch their TypeScript code for changes and rerun those tests.

bitjson commented 7 years ago

If anyone is interested, the solution @adieuadieu mentioned (from @tomdavidson) is what typescript-starter uses right now.

novemberborn commented 7 years ago

I'm closing this issue since it's not directly actionable.

Our plan for making AVA precompiler-agnostic can be found here: https://github.com/avajs/ava/blob/master/docs/specs/001%20-%20Improving%20language%20support.md β€”Β we'll need help achieving that.

Further, we'd be willing to support TypeScript test files sooner if we can run them through our existing Babel infrastructure.

huan commented 7 years ago

It's a pity that we still have no workaround for this after waiting almost a year...

novemberborn commented 7 years ago

@zixia well there are workarounds, but no proper solution, correct. Work on AVA is volunteer driven, so sometimes it just takes the time it takes.

aendra-rininsland commented 7 years ago

How difficult would be it be to just add the "extension" whitelist option? It seems like that plus ts-node/register in the require config stanza would be sufficient to make this possible.

novemberborn commented 7 years ago

Just adding the extension support makes it quite hard to understand which of AVA's behaviors is actually available, and as you say it requires further customizations to make the tests work. We want to land first-class support for TypeScript. We know how, but the work hasn't been done yet.

kirillgroshkov commented 7 years ago

I want to vote on this feature!

andywer commented 7 years ago

I know this is an old issue, but I needed the same thing, since a prior build step can be quite ugly.

So I quickly created ava-ts. Give it a try and leave feedback if you want :)

huan commented 7 years ago

@andywer You are awesome!

GantMan commented 7 years ago

@andywer - super cool! That's epic. I've already switched though: https://shift.infinite.red/switching-from-ava-to-jest-for-typescript-a6dac7d1712f

Sorry :(

andywer commented 7 years ago

@GantMan Thx. Pity, though! Would you mind mentioning ava-ts in your blog post? :)

Btw, thanks for all the great responses. Feel free to spread the word or 🌟 the repo, it feels a bit disregarded πŸ˜‰

GantMan commented 7 years ago

Added!!! And call-to action to star the repo added as well. Great work. Might see you cool kids again later. It seems the curse of JavaScript is that I have to switch libs as soon as I feel comfortable with them. πŸ˜†

andywer commented 7 years ago

@novemberborn Would you consider linking to ava-ts in the TypeScript recipe for the time being? I think that is where most folks will look for help and it makes using AVA with TS noticeably easier.

novemberborn commented 7 years ago

Hey @andywer! I've been thinking about this, and whilst I'm not adverse to linking to it I'd like to figure out an actionable plan to better support TypeScript directly, so we don't have to promote a fork for too long.

Following up on my earlier comment: https://github.com/avajs/ava/issues/1109#issuecomment-326801788

Further, we'd be willing to support TypeScript test files sooner if we can run them through our existing Babel infrastructure.

Here's what I think we can do pretty soon, which would provide minimal support for TypeScript. I'd like people's feedback on whether this would suit their needs.

I'm assuming people are OK with using ts-node/register for on-the-fly test file and source file compilation. The reason we didn't want to support .ts file extensions before is that AVA doesn't know not to precompile them using Babel. However we're talking about disabling Babel altogether in (amongst other issues) https://github.com/avajs/ava/issues/1556:

There's something to be said for separating AVA's file manipulations from syntax transforms. The babel option could refer to syntax transforms only, while we have a separate transpileEnhancements option. This would supersede the current powerAssert option.

Since we're still looking to integrate source transpilation and also support TypeScript, it makes sense (at least to me) that the enhancements are controlled separately.

https://github.com/avajs/ava/issues/1556#issuecomment-340003308

With #1556 out of the way we could add support for an extensions option. AVA would treat matched files with the configured extensions as test files. It won't precompile them so it won't break on .ts files. ts-node/register then takes care of transpilation.

Of course you could still precompile all files like you do now. It'd love for AVA to compile .ts files itself but that'd be follow-up work.

Ideally you wouldn't need to configure extensions either but currently when the globbing rules match directories we look for .js files specifically. I'm sure there are possible improvements but that's for later.

What do folks think about this approach?

impaler commented 7 years ago

ts-node support sounds like a convenient approach, there are probably other language-node libs that may work the same.

For registering ts-node itself, would you use "require" in the package.json#ava? Since --require was depreciated from the cli options, is it a limiation now that you can't seem scope what to require for what?

For example say I didn't want to use ts-node or some global browser env for every test I want to use in ava:

"scripts": {
  "test:ts-node": "ava --require helpers/ts-node.js src/**/**.ava.ts",
  "test:ts-browser": "ava --require helpers/ts-browser-env.js src/**/**.ava-browser.tsx"
}
lukescott commented 6 years ago

Babel 7 has support for TypeScript, so all you have to do is use the typescript preset. I've found that enums and namespaces are not supported though. Everything else seems to work great.

In the latest betas they've changed from babel-core to @babel/core, and all the packages are now namespaced under @babel. All the plugins with the word "transform" have been changed to "proposal" and all the config options need to start with @babel/, such as "@babel/env" instead of just "env".

novemberborn commented 6 years ago

For registering ts-node itself, would you use "require" in the package.json#ava? Since --require was depreciated from the cli options, is it a limiation now that you can't seem scope what to require for what?

@impaler pending 1st class support in AVA itself I think that's how it'd play out, yes. You disable AVA's Babel-powered treatment of test files and rely on language-node libs to transpile test files.

Babel 7 has support for TypeScript, so all you have to do is use the typescript preset. I've found that enums and namespaces are not supported though. Everything else seems to work great.

@lukescott does it do type checking as well, or does it just remove the syntax annotations? Regardless, it might be an option. With what I'm suggesting AVA would still default to applying Babel to test files and it's up to you to ensure Babel doesn't choke. So once we switch to Babel 7 you could go this route if it's the right fit for your project.

btkostner commented 6 years ago

I'm not sure how babel has implimented typescript support, but if it's just removing the syntax annotations then some people will run into issues with type metadata. This could potentionally mess with IoC implementations.

I would strongly favor using a language-node package to transpile tests.

lukescott commented 6 years ago

It just removes the TypeScript specific syntax, similar to what it has already done with Flow. So far it has greatly simplified my build process as I don’t have to pre-process with tsc. I just run TypeScript in Atom for all the type checking.

I would imagine that the typescript preset would at least allow you to run Ava with TypeScript code. You can use tsc to validate the types are correct.

aendra-rininsland commented 6 years ago

Re: @lukescott's comment, according to the babel-plugin-transform-typescript docs, import = and export = aren't supported either. This, combined with lack of enums and namespaces, means I'd really be loathe to use it in place of something like ts-node.

FWIW, a number of test tools use ts-node already (NYC, Mocha), so it's a pretty well-established workflow when testing using TS.

jonahbron commented 6 years ago

Any recent activity on this? I'm choosing a test runner for a new application, and good TypeScript support is an important part of that decision.

sebinsua commented 6 years ago

@jonahbron As ava uses Babel 7 it should support TypeScript if you use @babel/plugin-transform-typescript. There are a few caveats though so it depends on whether you are using any of the unsupported features.

novemberborn commented 6 years ago

As ava uses Babel 7

To clarify, that's the 1.0 beta releases.

Architecturally we're in a pretty decent place to implement built-in TypeScript compilation. It's still a big chunk of work though. So… any volunteers? πŸ˜„

We can also start adding support for test file extensions that bypass the Babel pipeline, so that'd be a way to use AVA with the TS register hook. That has some performance issues of course, so it may not be right for some (or most) projects.

shirtleton commented 6 years ago

Any updates on Typescript support?

greym0uth commented 6 years ago

Hey @shirtleton I'm working on making it so you can configure ava to use file extensions like .jsx or .ts. It's almost done, were just adding tests and cleaning up a bit of the code written for it, so should be soon. Here is the PR for reference #1746 Thanks!

FrancescoBorzi commented 6 years ago

Any news about this?

vladimiry commented 6 years ago

@ShinDarth it's working with ts-node module installed and config shown here https://github.com/avajs/ava/blob/master/docs/recipes/typescript.md (first TS recipe)

novemberborn commented 6 years ago

Yes, AVA can now be configured to recognize the .ts file extension. With TypeScript 3 the build tooling has improved a lot, so I think we can make AVA compile a TypeScript project, without requiring ts-node.

I'd like to port some of my own projects to TypeScript so I'd really like to see improved TypeScript support in AVA. For now though my priority is getting the 1.0 release out.

If anybody would like to help out with this project please give me a shout.