@financial-times/dotcom-middleware-app-context 7.3.1 → 7.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/__test__/index.spec.ts +101 -0
- package/src/index.ts +38 -0
@@ -502,7 +502,7 @@
|
|
502
502
|
"affectsGlobalScope": false
|
503
503
|
},
|
504
504
|
"../../dotcom-server-app-context/package.json": {
|
505
|
-
"version": "
|
505
|
+
"version": "31daffc0f5d6063db80435e6e821b316796d34d18fd69a0f35b2e6be6c3b7b63",
|
506
506
|
"affectsGlobalScope": true
|
507
507
|
},
|
508
508
|
"../../dotcom-server-app-context/src/types.d.ts": {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@financial-times/dotcom-middleware-app-context",
|
3
|
-
"version": "7.3.
|
3
|
+
"version": "7.3.2",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/node/index.js",
|
6
6
|
"types": "src/index.ts",
|
@@ -31,7 +31,8 @@
|
|
31
31
|
"npm": "7.x || 8.x"
|
32
32
|
},
|
33
33
|
"files": [
|
34
|
-
"dist/"
|
34
|
+
"dist/",
|
35
|
+
"src/"
|
35
36
|
],
|
36
37
|
"repository": {
|
37
38
|
"type": "git",
|
@@ -0,0 +1,101 @@
|
|
1
|
+
jest.mock('@financial-times/dotcom-server-app-context')
|
2
|
+
|
3
|
+
import httpMocks from 'node-mocks-http'
|
4
|
+
import { AppContext } from '@financial-times/dotcom-server-app-context'
|
5
|
+
import { init } from '../index'
|
6
|
+
|
7
|
+
const appContext = {
|
8
|
+
appName: 'my-app-name',
|
9
|
+
appVersion: '123'
|
10
|
+
}
|
11
|
+
|
12
|
+
const headers = {
|
13
|
+
'ft-edition': 'international',
|
14
|
+
'ft-ab': '-',
|
15
|
+
'ft-anonymous-user': '-'
|
16
|
+
}
|
17
|
+
|
18
|
+
describe('dotcom-middleware-app-context', () => {
|
19
|
+
let instance
|
20
|
+
let request
|
21
|
+
let response
|
22
|
+
let next
|
23
|
+
|
24
|
+
beforeEach(() => {
|
25
|
+
request = httpMocks.createRequest({ headers })
|
26
|
+
response = httpMocks.createResponse({ locals: {} })
|
27
|
+
next = jest.fn()
|
28
|
+
instance = init({ appContext })
|
29
|
+
})
|
30
|
+
|
31
|
+
afterEach(() => {
|
32
|
+
jest.resetAllMocks()
|
33
|
+
})
|
34
|
+
|
35
|
+
it('returns a request handler function', () => {
|
36
|
+
expect(instance).toBeInstanceOf(Function)
|
37
|
+
})
|
38
|
+
|
39
|
+
describe('when handling a request', () => {
|
40
|
+
it('initialises app context with inferred data', () => {
|
41
|
+
const expected = {
|
42
|
+
appContext: expect.objectContaining({ edition: 'international' })
|
43
|
+
}
|
44
|
+
|
45
|
+
instance(request, response, next)
|
46
|
+
|
47
|
+
expect(AppContext).toHaveBeenCalledWith(expected)
|
48
|
+
})
|
49
|
+
|
50
|
+
it('ignores default "-" header values', () => {
|
51
|
+
const expectedA = {
|
52
|
+
appContext: expect.not.objectContaining({ abTestState: '-' })
|
53
|
+
}
|
54
|
+
|
55
|
+
const expectedB = {
|
56
|
+
appContext: expect.objectContaining({ isUserLoggedIn: false })
|
57
|
+
}
|
58
|
+
|
59
|
+
instance(request, response, next)
|
60
|
+
|
61
|
+
expect(AppContext).toHaveBeenCalledWith(expectedA)
|
62
|
+
expect(AppContext).toHaveBeenCalledWith(expectedB)
|
63
|
+
})
|
64
|
+
|
65
|
+
it('initialises app context with provided app context overrides', () => {
|
66
|
+
const expected = { appContext: expect.objectContaining(appContext) }
|
67
|
+
|
68
|
+
instance(request, response, next)
|
69
|
+
|
70
|
+
expect(AppContext).toHaveBeenCalledWith(expected)
|
71
|
+
})
|
72
|
+
|
73
|
+
it('appends the app context instance to response.locals', () => {
|
74
|
+
instance(request, response, next)
|
75
|
+
expect(response.locals.appContext).toBeInstanceOf(AppContext)
|
76
|
+
})
|
77
|
+
|
78
|
+
it('calls the fallthrough function', () => {
|
79
|
+
instance(request, response, next)
|
80
|
+
expect(next).toHaveBeenCalled()
|
81
|
+
})
|
82
|
+
})
|
83
|
+
|
84
|
+
describe('when the app context data is invalid', () => {
|
85
|
+
beforeEach(() => {
|
86
|
+
// NOTE: AppContext has been mocked but we must first
|
87
|
+
// tell TS it's a mock before we can use it like one.
|
88
|
+
const AppContextMock = AppContext as jest.Mock
|
89
|
+
|
90
|
+
AppContextMock.mockImplementation(() => {
|
91
|
+
throw Error('INVALID')
|
92
|
+
})
|
93
|
+
})
|
94
|
+
|
95
|
+
it('calls the fallthrough function with the error', () => {
|
96
|
+
instance(request, response, next)
|
97
|
+
|
98
|
+
expect(next).toHaveBeenCalledWith(expect.any(Error))
|
99
|
+
})
|
100
|
+
})
|
101
|
+
})
|
package/src/index.ts
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
import { Request, Response, NextFunction } from 'express'
|
2
|
+
import pkg from '@financial-times/dotcom-server-app-context/package.json'
|
3
|
+
import { AppContext, TAppContext } from '@financial-times/dotcom-server-app-context'
|
4
|
+
|
5
|
+
export type TMiddlewareOptions = {
|
6
|
+
appContext?: Partial<TAppContext>
|
7
|
+
}
|
8
|
+
|
9
|
+
export function init(options: TMiddlewareOptions = {}) {
|
10
|
+
return (request: Request, response: Response, next: NextFunction) => {
|
11
|
+
const appContext = {
|
12
|
+
// TODO: improve how we retrieve the app name.
|
13
|
+
// HACK: this is plucked from the debug headers set by n-express:
|
14
|
+
// https://github.com/Financial-Times/n-express/blob/HEAD/main.js#L76-L80
|
15
|
+
appName: response.get('ft-app-name'),
|
16
|
+
product: 'next',
|
17
|
+
edition: request.get('ft-edition'),
|
18
|
+
appVersion: process.env.CIRCLE_SHA1 || process.env.SOURCE_VERSION || process.env.HEROKU_SLUG_COMMIT,
|
19
|
+
// Many headers are set to a default value of "-" by the CDN so we need to ignore those
|
20
|
+
// https://github.com/Financial-Times/ft.com-cdn/blob/HEAD/src/vcl/next-preflight.vcl
|
21
|
+
abTestState: request.get('ft-ab') === '-' ? undefined : request.get('ft-ab'),
|
22
|
+
isProduction: process.env.NODE_ENV === 'production',
|
23
|
+
// This is set by the membership session service as part of preflight
|
24
|
+
// https://github.com/Financial-Times/next-preflight/blob/HEAD/server/tasks/membership/session.js
|
25
|
+
isUserLoggedIn: request.get('ft-anonymous-user') === 'false',
|
26
|
+
pageKitVersion: pkg.version === '0.0.0' ? 'development' : pkg.version,
|
27
|
+
...options.appContext
|
28
|
+
}
|
29
|
+
|
30
|
+
try {
|
31
|
+
response.locals.appContext = new AppContext({ appContext })
|
32
|
+
} catch (error) {
|
33
|
+
next(error)
|
34
|
+
}
|
35
|
+
|
36
|
+
next()
|
37
|
+
}
|
38
|
+
}
|