-
Notifications
You must be signed in to change notification settings - Fork 11.9k
feat(@angular-devkit/build-angular): option to build and test only specified spec files #13423
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
Conversation
Original PR (#12955) was closed because of inactivity - 1 day too soon. This one is as ready as I can make it without input |
b9badfa
to
f3cd052
Compare
Hi @FDIM! This PR has merge conflicts due to recent upstream merges. |
f3cd052
to
e8943f3
Compare
@filipesilva let me know if you need any help with pushing this futher/making solution better |
Heya @FDIM, thank you for tackling this feature! I want to give you an update on the status of this PR. We're looking at the feature as you have designed it so far and thinking about the pros and cons. We're also considering what extra work needs to be done to update projects to use it (e.g. ignoring the generated file). I should have some news soon as I drive it forward within the team! |
@FDIM heya, we got together and discussed this PR yesterday. This PR adds two new pieces of functionality: running targeted specs, and changing the targeted spec of a running process. We feel there's a lot of value in the former, but comparatively less so in the latter since it's a subset of the usescases of the first. The main gripe the team has with it is the temporary file. In this PR the temporary file is used to transform the original test code via regexes running it, and communicate between processes when updating the targeted spec Creating temporary files on disk has a few problems though:
So for now we'd like to not add the temporary file at all. There are some ways of limiting the specs without it so we can still have targeted specs. But changing targeted specs mid-run without it would not be easy. So for now we propose to have targeted specs but not changing them on the fly, and later we could add a way to do that as well. If we ignore the cross process communication we could easily avoid the temporary file by either
I favor the first option myself because it also makes for a smaller, TS compilation, which should make both initial build and rebuilds faster. I understand it's disappointing to be asked to reduce the scope of something you've designed and that covers your usecase very well. But for us as maintainers these questions of migration and usability are always key concerns. For instance, anything that requires a migration can only be on a major since our policy is to only require migrations for majors. On the other hand something that requires no interaction with the user source is much easier to land. Things that have any chance of leaving artifacts in the user sources are also scrutinized because they are hard to clean after. Please let me know what you think. |
@filipesilva I agree 100% that generated/temp file is not ideal, but I do not know how else scope could be limited effectively without a way to feed webpack/typescript a stream/string instead of an entry point file. I'll test if your theory holds by changing tsconfig On a flip side, I do not really agree with other team concerns:
These steps can be fairly easily handled manually and documented as a quirk of
I'd say this is more like a limitation that you can have only single targeted test run at the same time per project. Isn't it safe to assume that one would use this option when working on a specific feature/task? Thanks for looking into this! |
This is where we manipulate the custom context for lazy routes: angular-cli/packages/ngtools/webpack/src/angular_compiler_plugin.ts Lines 697 to 753 in 6fc6e84
Generally speaking, anything that requires a user to go figure out the quirks of the tool isn't great. And anything that requires a user to manually change their project isn't going to happen for the vast majority of projects. Yes, the performance would be better. And I also understand that it would be much preferable for your usecase to have the "hot switch" feature. But I think that for most users, the base "targetted spec" feature gets them most of the way to faster test turnaround time without any quirks, pitfalls, needed upgrades, etc. Then the feature can be enhanced over time. One thing I ask you to keep in mind is that we have a two release cycle deprecation policy. Since we release roughly every six months, that means that a new feature will need to be around and maintained for at least one year. I hope this puts into perspective why we favor less user-facing complexity and things that don't require upgrade paths. |
You have very valid points from maintenance point of view and I agree, but this does not help in landing such feature to the 'core'. I am also a bit puzzled why there is no demand for such option (maybe not many enterprise apps have tests... I hope not!) or what people do after they pass certain number of tests (gonna have to check jest). Anyway, I've tried tinkering and customizing tsconfig include option and from my understanding solution would not be simpler. Basically I'd have to recursively find all related files to targeted specs and pass them via To make matters worse, consider this tsconfig:
One could expect that only files related to the listed ones would be included, but no - typescript also tries to compile files that are not referenced directly or indirectly (such as Could you share the solution that worked for you when you discussed include option as a potential alternative? In the meantime I'll investigate what custom context does and how it works - thanks for that! |
The tsconfig you showed is quite different from the ones we generate for specs, mind you. We explicitly set both Tried my hand at manipulating the tsconfig manually:
I expected that to work. But it doesn't because our webpack plugin errors out when requested TS files that aren't in the compilation. We added this error specifically to avoid implicitly importing TS files. Maybe this is a restriction that we can relax on this particular case, and serve an empty file instead. But either way this approach got more complicated. |
If you want to check how ignoring that error looks like, open angular-cli/packages/ngtools/webpack/src/angular_compiler_plugin.ts Lines 1016 to 1030 in 6fc6e84
Doing that will work with my previous example and only run I'm unsure of what the best API within the plugin for this would be, but probably an option that alters the include array, and ignores the error above if the file matches the alteration. |
e8943f3
to
6d064b8
Compare
@filipesilva I think I found a perfect solution! I'll make a webpack loader (see last commit) that will be registered in karma builder for test.ts files which will transform it in the same way as in original suggestion. I tested the idea in angular 8 project by modifying karma js file manually in node_modules and it seemed to work. Now I have to figure out again how to work on cli locally, finalize formatter and update previous test. Hopefully I'll wrap this up this week. EDIT: I also looked into your previous suggestion with tsconfig and files list, sadly this approach would not prevent entire project from being build as |
6d064b8
to
9337f19
Compare
I think I have it working! Only missing 2 things now:
|
49b98c1
to
75f0a2b
Compare
75f0a2b
to
90f3317
Compare
PR is ready for review. @filipesilva would you mind having a look at current implementation and provide some feedback? Thanks! Aside of that some help regarding failing circleci test would be great. Is it supposed to start actual chrome and run dummy tests? The same tests are passing locally and the feature is working as intended when EDIT: nevermind about the failing test, I've changed suffix to |
packages/angular_devkit/build_angular/src/angular-cli-files/plugins/single-test-transform.ts
Show resolved
Hide resolved
90f3317
to
2c2fa09
Compare
84ffdf0
to
5df02a3
Compare
998a5eb
to
1cc47d7
Compare
PR should be ready now. I've rebased from master and updated karma/schema.json with more details about |
1cc47d7
to
eaea7f5
Compare
I just had to adjust the text in |
eaea7f5
to
b479e04
Compare
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 it looks great! LGTM from my side, just waiting for @clydin to also take a look atm.
@@ -95,6 +112,31 @@ export function execute( | |||
} | |||
} | |||
|
|||
// prepend special webpack loader that will transform test.ts | |||
if (webpackConfig && webpackConfig.module && options.spec) { | |||
const sourceRoot = workspace.getProject(projectName).sourceRoot || ''; |
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.
Why is sourceRoot
used here?
The current behavior with the require.context
call is that the files are relative to the test.ts
(mainFilePath
in this case).
However, I think it would be more intuitive if the option's base directory was the workspace root as this would be consist with all other options. A project might also not have the concept of a source root (its currently really an extension option for the browser builder).
This would also eliminate the need for all the extra code to find the source root.
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.
Well, option's base directory is workspace root - path relative to source root is an alternative that is exposed, but mainly needed internally. sourceRoot
is simply subtracted from what is passed as spec
, so that typescript would be able to find these files in test.ts
(main) as path relative to it is needed (see findSpecs).
Any suggestions on how to refactor this to not rely on sourceRoot?
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.
The glob.sync
call's cwd
option can be the workspace root and the absolute
option would also be needed. From there, get the absolute path of the directory name of the main file; and then loop and convert the test file list from the glob call to relative paths from the main file.
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've ended up with a bit different solution and sourceRoot is no longer used. I also reverted some of the other changes. I hope it's OK now.
@filipesilva I see you've added 8.1 milestone, this is great news! |
89ec427
to
c41b1f8
Compare
…ecified spec files
c41b1f8
to
905a6ce
Compare
I've rebased from master and I think this is ready to go. |
@FDIM I updated your original PR message to list the new |
Shouldn't this work? Omitting the project name produces double error messages:
Edit: Started to work after i upgraded the @Angular-devkit packages |
@krokofant yeah you need to update |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
A new
--include
option is added. It is a glob/pattern that specifies which specs should be included in the build.Command:
ng test --include=app/services/auth*
Few rules are applied to the pattern to make certain things possible:
.spec.ts
is added automatically if missing (less typing)*.ts
and doesn't have.spec.ts
, extension will be replaced with.spec.ts
Behind the scenes
test.ts
is transformed which instead of usingrequire.context
imports all matching files. This gives quite a big boost in the project at work (at least 10s on each iterative build!)Fixes #3603
Motivation: It is a pain in a big application to wait until entire app is rebuilt just to run single
fit
block. Takes almost a minute with 4000+ tests and barely works when code coverage is enabled.Missing: docs(?)
Example tasks for vscode:
PS. The setup for writing tests is quite nice!