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

chore(tests): [RO-26598] Improve test coverage #83

Merged
merged 7 commits into from
Apr 8, 2024

Conversation

otrreeves
Copy link
Contributor

@otrreeves otrreeves commented Apr 4, 2024

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.

Sceenshot
Before image
After image

package.json Outdated
@@ -65,6 +65,7 @@
"devDependencies": {
"@types/jest": "29.5.12",
"colors": "1.4.0",
"ejs": "3.1.9",
Copy link
Contributor Author

@otrreeves otrreeves Apr 4, 2024

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...

Copy link
Collaborator

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. :)

Copy link
Contributor Author

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;
Copy link
Contributor Author

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

Copy link
Collaborator

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

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 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.
image

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

Comment on lines -17 to -18
this.app.response.renderAsync = function (view, properties = {}) {
return Promise.props(properties)
Copy link
Contributor Author

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.

Comment on lines -19 to -25
let port = config.Port;

if (this.server) {
port = this.server.address().port || port;
}

return port;
Copy link
Contributor Author

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()

@otrreeves otrreeves requested a review from acolchado April 4, 2024 03:43
@acolchado acolchado changed the title Chore/ro 26598 improve test coverage chore(): [RO-26598} Improve test coverage Apr 4, 2024
Copy link
Collaborator

@acolchado acolchado left a 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 }));
Copy link
Collaborator

@acolchado acolchado Apr 4, 2024

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?

Copy link
Contributor Author

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;
Copy link
Collaborator

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 = {};
}
Copy link
Collaborator

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.

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 updated logic does the same thing:
image

configure(app) {
super.configure(app);

app.set('view engine', 'ejs');
app.set('views', `${__dirname}/views`);
Copy link
Collaborator

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;
      });

Copy link
Contributor Author

@otrreeves otrreeves Apr 5, 2024

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'));
Copy link
Collaborator

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.

Copy link
Contributor Author

@otrreeves otrreeves Apr 4, 2024

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>
Copy link
Collaborator

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.

Copy link
Contributor Author

@otrreeves otrreeves Apr 5, 2024

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

@otrreeves otrreeves requested a review from acolchado April 5, 2024 03:10
Copy link
Contributor Author

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

Copy link
Contributor Author

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

@otrreeves otrreeves changed the title chore(): [RO-26598} Improve test coverage chore(tests): [RO-26598] Improve test coverage Apr 5, 2024
@acolchado acolchado merged commit 939d3fc into main Apr 8, 2024
3 checks passed
@acolchado acolchado deleted the chore/ro-26598-improve-test-coverage branch April 8, 2024 07:08
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.

2 participants