-
Notifications
You must be signed in to change notification settings - Fork 7
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
chore(tests): [RO-26598] Improve test coverage #83
Conversation
…ttier instead of disabling formatOnSave
package.json
Outdated
@@ -65,6 +65,7 @@ | |||
"devDependencies": { | |||
"@types/jest": "29.5.12", | |||
"colors": "1.4.0", | |||
"ejs": "3.1.9", |
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 necessary for testing the express server's render method (called via renderAsync
from PromiseMiddleware
), which wasn't being tested at all previously. I also couldn't find usage within the OpenTable codebase, but this is a public repo so it could be used somewhere in the world.
The alternative would be to instruct the test coverage to ignore the code, but the code did contain errors...
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.
It'd be better if you replace it with a mock and add it as an injection override. This is one of the more annoying dependencies in the system. :)
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
}); | ||
|
||
next(); | ||
} | ||
|
||
logErrorStack(err) { | ||
const statusCode = err.statusCode || 0; |
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.
Assigning fallback statusCode
of 0
is not necessary, it's only use to check it the status code exists in EXCLUDE_STATUSCODE_FROM_LOGS
, which doesn't contains null
or undefined
.
According to the unit test coverage, the || 0
"branch" is never executed
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.
Weird. I thought this was added as a patch. I don't recall why but if you add this I can't guarantee you may not introduce a big issue.
Remember this is dependency injected, so there are callers outside of this code base that could trigger this, so I would refrain from refactoring code checks that are not needed. The intent of this project is to remove dependecies, not refactoring
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 don't follow, when using the middleware as expected, this.EXCLUDE_STATUSCODE_FROM_LOGS
will always be [404]
, and calling some
on this array with an undefined
value is the same as calling it with 0
, i.e. it returns false
.
When calling the method directly, e.g. ErrorMiddleware.logErrorState({statusCode: 404})
, this.EXCLUDE_STATUSCODE_FROM_LOGS
is undefined
and will always return false
, which obviously is not expected.
I will revert the change, but it defies logic
this.app.response.renderAsync = function (view, properties = {}) { | ||
return Promise.props(properties) |
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.
Moved the "default" value of {}
to a "fallback" value because the default value only gets used when the argument is undefined
or not provided, but if null
is provided, it will fail.
let port = config.Port; | ||
|
||
if (this.server) { | ||
port = this.server.address().port || port; | ||
} | ||
|
||
return port; |
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.
Simplified logic because port
property is always defined for this.server.address()
…r agent so it returns a value for the name field
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.
Overall it looks great. There are some problems introduced. The fact that code is not accessed because it's called locally only, doesn't mean something injecting it will not call it. So it's better to be extra safe. I think some of them were added as patches to fix the issues that this would reintroduce.
@@ -14,7 +14,7 @@ module.exports = function ( | |||
this.app.use(bodyParser.urlencoded({ extended: false })); | |||
this.app.use(bodyParser.json()); | |||
this.app.use(methodOverride()); | |||
this.app.use(expressDevice.capture()); | |||
this.app.use(expressDevice.capture({ parseUserAgent: true })); |
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 this for? And why was it working beore? what expectation does it change?
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 just adds the name of the device to the request.device
object. Previously it would return type: 'phone', name: ''
, with this change it will return type: 'phone', name: 'iPhone'
. Might be good for logging/stats or other reasons.
}); | ||
|
||
next(); | ||
} | ||
|
||
logErrorStack(err) { | ||
const statusCode = err.statusCode || 0; |
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.
Weird. I thought this was added as a patch. I don't recall why but if you add this I can't guarantee you may not introduce a big issue.
Remember this is dependency injected, so there are callers outside of this code base that could trigger this, so I would refrain from refactoring code checks that are not needed. The intent of this project is to remove dependecies, not refactoring
} | ||
} | ||
|
||
appendRequestData(err, req) { | ||
if (err.data == null) { | ||
err.data = {}; | ||
} |
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 this was a patch to something. The fact that it wasn't defaulted to 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.
configure(app) { | ||
super.configure(app); | ||
|
||
app.set('view engine', 'ejs'); | ||
app.set('views', `${__dirname}/views`); |
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 not needed. In the test you mock and inject ejs, where ever it's failing should be depending on PromiseMiddlewareTestController
You will need code like this in near the existing injector:
const ejsMock = {
render: jest.fn()
};
injector()
.addDependency('ejs', ejsMock, true)
.inject((TasksPrinter) => {
this.TasksPrinter = TasksPrinter;
});
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.
app.set('view engine', ...);
is not needed if the view name includes the extension (which I've done to remove it), but setting the views directory is still needed even when mocking the view engine, otherwise express
throws Internal Server Error
From my experience trying to implement your injection suggestion, express
doesn't seem pick up an injected view engine, even if it's a known engine like ejs
, you have to register the engine via app.engine(...)
@@ -28,7 +38,7 @@ module.exports = function (BaseController, Promise) { | |||
} | |||
|
|||
getFormatAsync(req, res) { | |||
res.formatAsync(Promise.resolve('formatAsync success')); | |||
res.formatAsync('innerHTML', Promise.resolve('formatAsync success')); |
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.
Not sure why this is needed.
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.
express().response.formatAsync
expects 2 arguments, this fixes a bug.
<body> | ||
No render view-props provided | ||
</body> | ||
</html> |
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.
If you mock ejs in the injector, you don't need any of this.
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.
Turns out mocking a view engine still requires view-files to exist, otherwise express
throws Internal Server Error
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.
Just a dummy view to test the view-engine, it's required event with a mocked view engine
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.
Just a dummy view to test the view-engine, it's required event with a mocked view engine
Ticket
https://opentable.atlassian.net/browse/RO-26598
Change Summary
This PR will improve test coverage. When I was working on cleaning out some unnecessary dependencies, test coverage fell below the coverage-threshold so this will improve the coverage before removing the dependencies. As a plus, this should make removing the dependencies more fool-proof.