-
Notifications
You must be signed in to change notification settings - Fork 22
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
Conversation
romaniam
commented
Dec 13, 2018
- Added tests for build command handler
|
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 |
… (required for testing)
…eve the key from a specific path
… base and logger middleware
lib/cli/commands/init.js
Outdated
@@ -1,44 +1,29 @@ | |||
const validate = require("../../utils/validate"); |
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.
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.
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.
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)
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.
Didn't review the tests yet as I would like to clarify the mocking of require
first.
lib/cli/commands/init.js
Outdated
} | ||
} | ||
} | ||
initCommand.lazyRequireDependencies = async function() { |
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.
What about using mock-require here instead of adding this function to the productive code just for resting purposes?
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 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...
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.
As discussed, module-require is now used to mock module loading
lib/cli/commands/serve.js
Outdated
@@ -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) { |
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.
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.
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.
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)
lib/cli/commands/serve.js
Outdated
}; | ||
return !serverConfig.h2 | ||
? {serverConfig, tree} | ||
: ui5Server.sslUtil.getSslCertificate(serverConfig.key, serverConfig.cert).then(({key, cert}) => { |
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.
This is really hard to read. Please use if/else
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.
Yeah sorry about that. Is fixed with in c2b125f
lib/utils/validate.js
Outdated
@@ -0,0 +1,43 @@ | |||
const {promisify} = require("util"); |
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.
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.
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.
Good point. renamed as requested c2b125f
lib/cli/middlewares/base.js
Outdated
logger.getLogger("cli:middlewares:base").verbose(`using node version ${process.version}`); | ||
} | ||
} | ||
module.exports = function(argv = {}) { |
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 default argv
to an empty object just to return null if argv
is an empty object?
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 default param is there to avoid errors when properties are accessed...
lib/cli/middlewares/logger.js
Outdated
* @param {Object} argv logger arguments | ||
* @returns {Object} logger instance or null | ||
*/ | ||
function init(argv = {}) { |
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.
argv
is not optional, why defaulting it then?
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 default param is there to avoid errors when properties are accessed...
lib/cli/commands/serve.js
Outdated
return opn(browserUrl); | ||
}; | ||
|
||
serve.handler = function(argv = {}) { |
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 the defaulting to empty object? argv should always be supplied shouldn't it?
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 default param is there to avoid errors when properties are accessed e.g.
normalizer.generateProjectTree({
translator: argv.translator,
configPath: argv.config
})
test/lib/cli/commands/build.js
Outdated
await build.handler(args); | ||
t.deepEqual( | ||
builderStub.getCall(0).args[0], | ||
Object.assign({}, {dev: true}, defaultBuilderArgs), |
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.
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.
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.
Done with 30dd0b7
… base and logger middleware
…-cli into increasing-test-coverage
lib/cli/commands/init.js
Outdated
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() { |
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.
What is the point of having this lazyRequireDependencie
function still in the code?
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.
You are right, it's totally useless. Removed...
test/lib/cli/commands/build.js
Outdated
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(); |
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.
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.
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.
Great, I like it 👍
Fixed in b282427
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 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.
5957e91
to
b282427
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.
Resolved suggested fixes. Please re-review
test/lib/cli/commands/build.js
Outdated
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(); |
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 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.
18fce64
to
ef6289c
Compare
Ok from my side but we need to make sure to squash all commits while merging (but not before!). |
Also remove messages from hooks. They don't seem to have any effect.
514d07e
to
0824ad1
Compare