@financial-times/dotcom-middleware-app-context 7.3.1 → 7.3.3

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.
@@ -502,7 +502,7 @@
502
502
  "affectsGlobalScope": false
503
503
  },
504
504
  "../../dotcom-server-app-context/package.json": {
505
- "version": "9cacddca94231e361078ef269cc8b899cd9399e88e2ceb3e1142b9e06fc920fe",
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.1",
3
+ "version": "7.3.3",
4
4
  "description": "",
5
5
  "main": "dist/node/index.js",
6
6
  "types": "src/index.ts",
@@ -24,14 +24,15 @@
24
24
  "node-mocks-http": "^1.7.5"
25
25
  },
26
26
  "dependencies": {
27
- "@financial-times/dotcom-server-app-context": "file:../dotcom-server-app-context"
27
+ "@financial-times/dotcom-server-app-context": "^7.3.3"
28
28
  },
29
29
  "engines": {
30
30
  "node": ">= 14.0.0",
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",
@@ -42,4 +43,4 @@
42
43
  "volta": {
43
44
  "extends": "../../package.json"
44
45
  }
45
- }
46
+ }
@@ -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
+ }