Skip to content

More tests - #41

Open
henrahmagix wants to merge 11 commits into
masterfrom
more-tests
Open

More tests#41
henrahmagix wants to merge 11 commits into
masterfrom
more-tests

Conversation

@henrahmagix

Copy link
Copy Markdown
Contributor

@incuna/js Please merge, ta!

henrahmagix added 11 commits May 5, 2017 14:41
Karma unit tests are run in a browser, not in node.
Statically list all modules in this library, gather the injectables that
are registered (all directives, services, constants, etc.), then test
that each one can be injected without error so as to uncover usage of
injetables that aren't given access to via the module dependencies.

Below are some examples of fixes made for errors found by this test. The
stack trace is removed for readability.

A fix has been made to auth-storage-factory as the following was found:
```
Dependencies for module angular-token-auth.auth-storage should not error when injected FAILED
    Expected angular-token-auth.auth-storage to have injectable factory authStorageFactory but it threw Error: [$injector:unpr] Unknown provider: authModuleSettingsProvider <- authModuleSettings <- authStorageFactory
    <stack trace>...
Dependencies for module angular-token-auth.auth should not error when injected FAILED
    Expected angular-token-auth.auth to have injectable factory authFactory but it threw Error: [$injector:unpr] Unknown provider: authModuleSettingsProvider <- authModuleSettings <- authStorageFactory <- authFactory
    <stack trace>...
```

Fixing `authStorageFactory` also fixed the error in `authFactory` because
the latter depended on the former.

The module dependencies fix in d82266f
with this test would have erred like so:
```
Dependencies for module angular-token-auth.auth-login-form should not error when injected FAILED
    Expected angular-token-auth.auth-login-form to have injectable directive loginForm but it threw Error: [$injector:unpr] Unknown provider: AuthLoginFormFactoryProvider <- AuthLoginFormFactory <- authLoginFormDirectiveFactory <- loginFormDirective
    <stack trace>...
Dependencies for module angular-token-auth.auth-login-form-directive-factory should not error when injected FAILED
    Expected angular-token-auth.auth-login-form-directive-factory to have injectable factory authLoginFormDirectiveFactory but it threw Error: [$injector:unpr] Unknown provider: AuthLoginFormFactoryProvider <- AuthLoginFormFactory <- authLoginFormDirectiveFactory
    <stack trace>...
Dependencies for module angular-token-auth.auth-login-form-factory should not error when injected FAILED
    Expected angular-token-auth.auth-login-form-factory to have injectable factory AuthLoginFormFactory but it threw Error: [$injector:unpr] Unknown provider: authActionsFactoryProvider <- authActionsFactory <- AuthLoginFormFactory
    <stack trace>...
```
Avoid missing new modules or module renames by overloading angular.module
to store all registered module names as `angular.registeredModules` array
and loop over that to create the test suites.
They can't have dependencies so there's no point testing them for
missing ones.
To ensure the other tests aren't false positives. Also improve the
matchers code for readability.
@@ -0,0 +1,167 @@
(function () {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maxpeterson This is the dependencies test I mentioned to you

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit funny that you need these test because of the pattern of putting everything into a separate module, so it's kind of solving a problem we have created ourselves ;)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean, but the core of the problem is the separation between module dependencies and the injectables they register. Though that problem is compounded by separate files (the issue with most Java code: one file per thing, it takes a long time to find what you want).

E.g. you can have a angular.module('bar', []) with module.factory('foo', ...), so you have to depend on the module bar to allow injecting the factory foo. There's no explicit connection there, only that which you create via naming.

The only advantage I see to Angular 1's module system is avoiding unnecessarily running config and run blocks that don't end up getting used. All the code is parsed anyway, so it's not really much of a saving.

The latest js frameworks use import/export so that simply importing something makes it available. That's way simpler and more descriptive.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that if every injectable in this package would just be under one module angular-token-auth then testing the availability wouldn't be necessary at all. It doesn't allow to specify which modules you do or don't want when using this package, but on the other hand maybe all injectables that require each other should be just under one module?

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #41 into master will increase coverage by 25.9%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #41      +/-   ##
==========================================
+ Coverage   48.18%   74.09%   +25.9%     
==========================================
  Files          18       18              
  Lines         193      193              
==========================================
+ Hits           93      143      +50     
+ Misses        100       50      -50
Impacted Files Coverage Δ
src/providers/auth-login-directive-factory.js 100% <ø> (+40%) ⬆️
src/providers/auth-login-form-factory.js 100% <ø> (+88.46%) ⬆️
src/providers/auth-storage-factory.js 54.54% <100%> (+15.15%) ⬆️
src/providers/auth-interceptor-factory.js 20% <0%> (+5%) ⬆️
src/controllers/auth-logout-controller.js 100% <0%> (+25%) ⬆️
src/directives/auth-login-form-directive.js 100% <0%> (+25%) ⬆️
src/providers/auth-factory.js 62.5% <0%> (+37.5%) ⬆️
src/providers/auth-actions-factory.js 100% <0%> (+78.57%) ⬆️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9f766e8...55a61f7. Read the comment docs.

});
it('should redirect to LOGIN_REDIRECT_URL', function () {
expect(this.$location.url).not.toHaveBeenCalled();
inject(function (AuthLoginFormFactory) { // eslint-disable-line no-unused-vars

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this magic?

@henrahmagix henrahmagix May 12, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an automatic login if an auth token has been saved: revisit the app and you'll be automatically logged back in.

When the AuthLoginFormFactory is first injected, the definition function is run and, as usual, Angular stores the return value as a singleton and doesn't run the definition again (thankfully). The "run once" bit is crucial here.

In the definition is this bit of code that runs at runtime. It means as soon as a thing injects AuthLoginFormFactory, the code checks for an auth token and redirects if it's there. Without "run once", the app would redirect multiple times and be quite buggy.

A better solution would be to have it as a method and call it in a run block, for the same effect. However that may be more difficult to test: not a reason to not do it, just a precaution. Or it could be left up to the project to call it.


it('should not error when injected', function () {
var moduleDefinition = angular.module(moduleName);
moduleDefinition._invokeQueue.forEach(function (providerArgs) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be separated tests? It feels like this test is doing a lot.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is doing a lot, yes. There's an individual suite for every module: the code here is creating multiple tests from one loop function, which allows us not only to be DRY, but also to ensure no module is missed. A static list of tests would mean any new module would not be automatically included.

I like the automatic inclusion, and it helps the meaning of this test: to let the dev know when module dependencies haven't been listed, so the src changes in d82266f aren't needed down the line, and tests don't fail confusingly (the error output for missing module dependencies is often truncated so much as to be useless).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants