Skip to content
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

[INTERNAL] test: improved test coverage #91

Merged
merged 49 commits into from
Jan 9, 2019
Merged

Conversation

romaniam
Copy link
Contributor

  • Added tests for build command handler

@romaniam romaniam requested a review from RandomByte December 13, 2018 13:15
@CLAassistant
Copy link

CLAassistant commented Dec 13, 2018

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coveralls
Copy link

coveralls commented Dec 13, 2018

Coverage Status

Coverage increased (+42.4%) to 82.117% when pulling 1a78601 on increasing-test-coverage into ba6f368 on master.

@romaniam
Copy link
Contributor Author

romaniam commented Dec 13, 2018

In some files I had to add test.serial, otherwise the tests fail because the stub references are shared... This is a known issue with ava and sinon stackoverflow: Problems with ava async tests when stubbing with sinon

@romaniam romaniam changed the title [INTERNAL] build: added tests. Slightly refactored build handler method. [INTERNAL] test: improved test coverage Dec 19, 2018
@romaniam romaniam requested a review from matz3 December 19, 2018 15:22
matz3
matz3 previously requested changes Dec 21, 2018
@@ -1,44 +1,29 @@
const validate = require("../../utils/validate");
Copy link
Member

Choose a reason for hiding this comment

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

We move the require statements into the handler function to not load the dependencies all the time.
This had a significant impact e.g. when just calling ui5 --version as all command files need to be required, but not all code in there needs to be executed.

A better approach might be to move the handler functions in a separate module that is then required from the yargs handler function once it's called.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good points, thanks. Personally I would prefer not to move the handler to a separate module. How about this approach: 29fc902 ? (just saw the async flag which is not required, will remove it after your next review)

Copy link
Member

@RandomByte RandomByte left a comment

Choose a reason for hiding this comment

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

Didn't review the tests yet as I would like to clarify the mocking of require first.

}
}
}
initCommand.lazyRequireDependencies = async function() {
Copy link
Member

Choose a reason for hiding this comment

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

What about using mock-require here instead of adding this function to the productive code just for resting purposes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to avoid adding a new dependency with a module which was maintained 9 months ago and "only" 300 stars + mocking module loaders is not really a good solution e.g. switching to ES6 modules will not be so easy anymore...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, module-require is now used to mock module loading

@@ -46,8 +46,12 @@ serve.builder = function(cli) {
"Listen to port 1337 and launch default browser with http://localhost:1337/test/QUnit.html");
};

serve.handler = function(argv) {
serve.openUrl = async function(browserUrl) {
Copy link
Member

Choose a reason for hiding this comment

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

Same here, adding a function just to make testing easier should be avoided if possible. What about mock-require?

The function is called just one time, so no real need to have it in a separate function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How should we test the functionality of the url opening then? e.g. spy on opn call will not work.

  • the method adds more flexibility in my opinion e.g. adding validation if browser, easier to test, easier to maintain (e.g. dependency replacement)

};
return !serverConfig.h2
? {serverConfig, tree}
: ui5Server.sslUtil.getSslCertificate(serverConfig.key, serverConfig.cert).then(({key, cert}) => {
Copy link
Member

Choose a reason for hiding this comment

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

This is really hard to read. Please use if/else

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah sorry about that. Is fixed with in c2b125f

@@ -0,0 +1,43 @@
const {promisify} = require("util");
Copy link
Member

Choose a reason for hiding this comment

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

Could we rename this file to fsHelper or something alike?

In my opinion it doesn't really "validate" anything or throws errors if some validation failed. It currently just offers convenience wrappers for some fs APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. renamed as requested c2b125f

logger.getLogger("cli:middlewares:base").verbose(`using node version ${process.version}`);
}
}
module.exports = function(argv = {}) {
Copy link
Member

Choose a reason for hiding this comment

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

Why default argv to an empty object just to return null if argv is an empty object?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The default param is there to avoid errors when properties are accessed...

* @param {Object} argv logger arguments
* @returns {Object} logger instance or null
*/
function init(argv = {}) {
Copy link
Member

Choose a reason for hiding this comment

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

argv is not optional, why defaulting it then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The default param is there to avoid errors when properties are accessed...

return opn(browserUrl);
};

serve.handler = function(argv = {}) {
Copy link
Member

Choose a reason for hiding this comment

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

Why the defaulting to empty object? argv should always be supplied shouldn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The default param is there to avoid errors when properties are accessed e.g.

normalizer.generateProjectTree({
		translator: argv.translator,
		configPath: argv.config
})

await build.handler(args);
t.deepEqual(
builderStub.getCall(0).args[0],
Object.assign({}, {dev: true}, defaultBuilderArgs),
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't this still result into dev: false as the defaultBuilderArgs are passed as last arg?
Assignment is from right to left.

It seems that the fact that args and the stubs are shared across tests and they are executed in parallel, this seems to somehow work.

Copy link
Member

Choose a reason for hiding this comment

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

Done with 30dd0b7

command: "init",
describe: "Initialize the UI5 Build and Development Tooling configuration for an application or library project.",
middlewares: [require("../middlewares/base.js")]
};

init.handler = async function(argv) {
initCommand.lazyRequireDependencies = async function() {
Copy link
Member

Choose a reason for hiding this comment

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

What is the point of having this lazyRequireDependencie function still in the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right, it's totally useless. Removed...

normalizerStub = sinon.stub(normalizer, "generateProjectTree");
builderStub = sinon.stub(builder, "build").returns(Promise.resolve());
loggerStub = sinon.stub(logger, "setShowProgress");
});

test.after("Restore mocks after test exection", (t) => {
test.afterEach("Restore mocks after test exection", (t) => {
loggerStub.restore();
Copy link
Member

Choose a reason for hiding this comment

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

We could also use sinon.restore() in a test.afterEach.always callback as described here:
https://sinonjs.org/releases/v7.2.2/general-setup/

But we can also change that in a follow up PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great, I like it 👍
Fixed in b282427

Copy link
Member

Choose a reason for hiding this comment

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

I think it would be even better to use test.afterEach.always. That way, even if a test fails, the stubs created in that test are reset and can't influence any other tests.

Also, I'm not sure whether you need to supply a message to the beforeEach and afterEach hooks. I couldn't find this mentioned anywhere in the ava docs.

@romaniam romaniam force-pushed the increasing-test-coverage branch from 5957e91 to b282427 Compare January 8, 2019 08:39
Copy link
Contributor Author

@romaniam romaniam left a comment

Choose a reason for hiding this comment

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

Resolved suggested fixes. Please re-review

normalizerStub = sinon.stub(normalizer, "generateProjectTree");
builderStub = sinon.stub(builder, "build").returns(Promise.resolve());
loggerStub = sinon.stub(logger, "setShowProgress");
});

test.after("Restore mocks after test exection", (t) => {
test.afterEach("Restore mocks after test exection", (t) => {
loggerStub.restore();
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be even better to use test.afterEach.always. That way, even if a test fails, the stubs created in that test are reset and can't influence any other tests.

Also, I'm not sure whether you need to supply a message to the beforeEach and afterEach hooks. I couldn't find this mentioned anywhere in the ava docs.

@romaniam romaniam force-pushed the increasing-test-coverage branch from 18fce64 to ef6289c Compare January 8, 2019 16:08
@RandomByte
Copy link
Member

Ok from my side but we need to make sure to squash all commits while merging (but not before!).

@romaniam romaniam force-pushed the increasing-test-coverage branch from 514d07e to 0824ad1 Compare January 9, 2019 15:21
@romaniam romaniam merged commit c6893d0 into master Jan 9, 2019
@romaniam romaniam deleted the increasing-test-coverage branch January 9, 2019 15:47
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.

5 participants