Skip to content

Commit a61bc72

Browse files
Merge branch 'main' into feat/forms-1331-event-stream
2 parents a750fc4 + cdf4036 commit a61bc72

File tree

10 files changed

+251
-37
lines changed

10 files changed

+251
-37
lines changed

app/package-lock.json

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
"@json2csv/transforms": "^6.1.3",
5252
"api-problem": "^9.0.2",
5353
"aws-sdk": "^2.1376.0",
54-
"axios": "^0.28.1",
55-
"axios-oauth-client": "^1.5.0",
54+
"axios": "^1.7.4",
55+
"axios-oauth-client": "^2.2.0",
5656
"axios-token-interceptor": "^0.2.0",
5757
"bytes": "^3.1.2",
5858
"compression": "^1.7.4",

app/src/components/clientConnection.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ const tokenProvider = require('axios-token-interceptor');
44

55
const log = require('./log')(module.filename);
66

7+
// axios-oauth-client removed the "interceptor" in v2.2.0. Replicate it here.
8+
9+
const getMaxAge = (res) => {
10+
return res.expires_in * 1e3;
11+
};
12+
13+
const headerFormatter = (res) => {
14+
return 'Bearer ' + res.access_token;
15+
};
16+
17+
const interceptor = (tokenProvider, authenticate) => {
18+
const getToken = tokenProvider.tokenCache(authenticate, { getMaxAge });
19+
20+
return tokenProvider({ getToken, headerFormatter });
21+
};
22+
723
class ClientConnection {
824
constructor({ tokenUrl, clientId, clientSecret }) {
925
log.verbose(`Constructed with ${tokenUrl}, ${clientId}, clientSecret`, { function: 'constructor' });
@@ -19,15 +35,7 @@ class ClientConnection {
1935
// Wraps axios-token-interceptor with oauth-specific configuration,
2036
// fetches the token using the desired claim method, and caches
2137
// until the token expires
22-
oauth.interceptor(
23-
tokenProvider,
24-
oauth.client(axios.create(), {
25-
url: this.tokenUrl,
26-
grant_type: 'client_credentials',
27-
client_id: clientId,
28-
client_secret: clientSecret,
29-
})
30-
)
38+
interceptor(tokenProvider, oauth.clientCredentials(axios.create(), tokenUrl, clientId, clientSecret))
3139
);
3240
}
3341
}

app/tests/unit/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,36 @@ describe('my tests', () => {
5353
```
5454

5555
Similar to `.only` is the `.skip` modifier to skip a test or group of tests.
56+
57+
## Testing Strategy
58+
59+
The testing strategy for the backend unit tests can be broken down into the different layers of the backend. For all tests we should:
60+
61+
- ensure that the tests are consistent
62+
- ensure that we have 100% test coverage
63+
- ensure that we have complete test coverage: we should be testing additional corner cases even once we reach 100% test coverage
64+
- test the interface, not the implementation
65+
- test the unit under test, not its dependencies
66+
67+
### Middleware Testing
68+
69+
The tests for the middleware files should:
70+
71+
- mock all services calls used by the middleware, including both exception and minimal valid results
72+
- test all response codes produced by the middleware
73+
74+
### Route Testing
75+
76+
The tests for the `route.js` files should:
77+
78+
- mock all middleware used by the file
79+
- each route test should check that every middleware is called the proper number of times
80+
- each route test should mock the controller function that it calls
81+
- mock controller functions with `res.sendStatus(200)`, as doing something like `next()` will call multiple controller functions when route paths are overloaded
82+
- check that the mocked controller function is called - this will catch when a new route path accidentally overloads an old one
83+
- for consistency and ease of comparison, alphabetize the expect clauses ("alphabetize when possible")
84+
85+
Note:
86+
87+
- Some middleware is called when the `routes.js` is loaded, not when the route is called. For example, the parameters to `userAccess.hasFormPermissions` cannot be tested by calling the route using it. Even if we reload the `routes.js` for each route test, it would be hard to tell which call to `hasFormPermissions` was the call for the route under test
88+
- Maybe we should refactor and create a set of standard middleware mocks that live outside the `routes.spec.js` files

app/tests/unit/forms/form/externalApi/routes.spec.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ describe(`${basePath}/:formId/externalAPIs`, () => {
8383
expect(controller.listExternalAPIs).toBeCalledTimes(1);
8484
expect(hasFormPermissionsMock).toBeCalledTimes(1);
8585
expect(rateLimiter.apiKeyRateLimiter).toBeCalledTimes(0);
86+
expect(userAccess.currentUser).toBeCalledTimes(1);
8687
expect(validateParameter.validateExternalAPIId).toBeCalledTimes(0);
8788
expect(validateParameter.validateFormId).toBeCalledTimes(1);
8889
});
@@ -98,6 +99,7 @@ describe(`${basePath}/:formId/externalAPIs`, () => {
9899
expect(controller.createExternalAPI).toBeCalledTimes(1);
99100
expect(hasFormPermissionsMock).toBeCalledTimes(1);
100101
expect(rateLimiter.apiKeyRateLimiter).toBeCalledTimes(0);
102+
expect(userAccess.currentUser).toBeCalledTimes(1);
101103
expect(validateParameter.validateExternalAPIId).toBeCalledTimes(0);
102104
expect(validateParameter.validateFormId).toBeCalledTimes(1);
103105
});
@@ -125,6 +127,7 @@ describe(`${basePath}/:formId/externalAPIs/:externalAPIId`, () => {
125127
expect(controller.deleteExternalAPI).toBeCalledTimes(1);
126128
expect(hasFormPermissionsMock).toBeCalledTimes(1);
127129
expect(rateLimiter.apiKeyRateLimiter).toBeCalledTimes(0);
130+
expect(userAccess.currentUser).toBeCalledTimes(1);
128131
expect(validateParameter.validateExternalAPIId).toBeCalledTimes(1);
129132
expect(validateParameter.validateFormId).toBeCalledTimes(1);
130133
});
@@ -152,6 +155,7 @@ describe(`${basePath}/:formId/externalAPIs/:externalAPIId`, () => {
152155
expect(controller.updateExternalAPI).toBeCalledTimes(1);
153156
expect(hasFormPermissionsMock).toBeCalledTimes(1);
154157
expect(rateLimiter.apiKeyRateLimiter).toBeCalledTimes(0);
158+
expect(userAccess.currentUser).toBeCalledTimes(1);
155159
expect(validateParameter.validateExternalAPIId).toBeCalledTimes(1);
156160
expect(validateParameter.validateFormId).toBeCalledTimes(1);
157161
});
@@ -219,6 +223,7 @@ describe(`${basePath}/:formId/externalAPIs/statusCodes`, () => {
219223
expect(controller.listExternalAPIStatusCodes).toBeCalledTimes(1);
220224
expect(hasFormPermissionsMock).toBeCalledTimes(1);
221225
expect(rateLimiter.apiKeyRateLimiter).toBeCalledTimes(0);
226+
expect(userAccess.currentUser).toBeCalledTimes(1);
222227
expect(validateParameter.validateExternalAPIId).toBeCalledTimes(0);
223228
expect(validateParameter.validateFormId).toBeCalledTimes(1);
224229
});

0 commit comments

Comments
 (0)