@creator.co/wapi 1.2.2 → 1.2.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.
- package/.eslintrc.cjs +29 -22
- package/.github/workflows/npmpublish.yml +1 -1
- package/.github/workflows/prs.yml +1 -1
- package/index.ts +12 -10
- package/jest.config.ts +19 -19
- package/package.json +1 -1
- package/src/API/Request.ts +17 -35
- package/src/API/Response.ts +24 -42
- package/src/API/Utils.ts +5 -7
- package/src/BaseEvent/EventProcessor.ts +16 -24
- package/src/BaseEvent/Process.ts +7 -12
- package/src/BaseEvent/Transaction.ts +25 -43
- package/src/Config/Configuration.ts +8 -14
- package/src/Config/EnvironmentVar.ts +10 -20
- package/src/Crypto/Crypto.ts +10 -10
- package/src/Crypto/JWT.ts +4 -10
- package/src/Globals.ts +19 -25
- package/src/Logger/Logger.ts +36 -51
- package/src/Mailer/Mailer.ts +19 -31
- package/src/Publisher/Publisher.ts +7 -12
- package/src/Server/RouteResolver.ts +5 -6
- package/src/Server/Router.ts +7 -12
- package/src/Server/lib/ContainerServer.ts +5 -5
- package/src/Server/lib/Server.ts +26 -38
- package/src/Server/lib/container/GenericHandler.ts +8 -13
- package/src/Server/lib/container/GenericHandlerEvent.ts +21 -35
- package/src/Server/lib/container/HealthHandler.ts +2 -2
- package/src/Server/lib/container/Proxy.ts +26 -38
- package/src/Server/lib/container/Utils.ts +2 -2
- package/src/Validation/Validator.ts +6 -6
- package/tests/API/Request.test.ts +107 -111
- package/tests/API/Response.test.ts +86 -91
- package/tests/API/Utils.test.ts +64 -64
- package/tests/BaseEvent/EventProcessor.test.ts +68 -84
- package/tests/BaseEvent/Process.test.ts +11 -11
- package/tests/BaseEvent/Transaction.test.ts +44 -53
- package/tests/Config/Config.test.ts +50 -50
- package/tests/Config/EnvironmentVar.test.ts +50 -59
- package/tests/Crypto/Crypto.test.ts +20 -22
- package/tests/Crypto/JWT.test.ts +40 -40
- package/tests/Logger/Logger.test.ts +24 -36
- package/tests/Mailer/Mailer.test.ts +21 -29
- package/tests/Publisher/Publisher.test.ts +18 -18
- package/tests/Server/RouteResolver.test.ts +56 -59
- package/tests/Server/Router.test.ts +16 -16
- package/tests/Server/lib/ContainerServer.test.ts +83 -85
- package/tests/Server/lib/Server.test.ts +4 -4
- package/tests/Server/lib/container/GenericHandler.test.ts +31 -41
- package/tests/Server/lib/container/GenericHandlerEvent.test.ts +35 -36
- package/tests/Server/lib/container/HealthHandler.test.ts +7 -7
- package/tests/Server/lib/container/Proxy.test.ts +66 -79
- package/tests/Server/lib/container/Utils.test.ts +16 -17
- package/tests/Test.utils.ts +9 -9
- package/tests/Validation/Validator.test.ts +28 -40
- package/tests/main.test.ts +2 -2
package/tests/Crypto/JWT.test.ts
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
import { expect } from
|
|
1
|
+
import { expect } from 'chai'
|
|
2
2
|
|
|
3
|
-
import JWT from
|
|
4
|
-
import { foreignToken, privateKey } from
|
|
3
|
+
import JWT from '../../src/Crypto/JWT'
|
|
4
|
+
import { foreignToken, privateKey } from '../Test.utils'
|
|
5
5
|
|
|
6
|
-
describe(
|
|
7
|
-
const provider = new JWT(privateKey,
|
|
8
|
-
test(
|
|
6
|
+
describe('Creates token', () => {
|
|
7
|
+
const provider = new JWT(privateKey, '7d')
|
|
8
|
+
test('Creates token without explicity expiration', () => {
|
|
9
9
|
const token = provider.createToken({ userID: 123 })
|
|
10
|
-
expect(token).to.be.a(
|
|
10
|
+
expect(token).to.be.a('string')
|
|
11
11
|
expect(token).is.not.null
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
test(
|
|
15
|
-
const token = provider.createToken({ userID: 123 },
|
|
16
|
-
expect(token).to.be.a(
|
|
14
|
+
test('Creates token with explicity expiration', () => {
|
|
15
|
+
const token = provider.createToken({ userID: 123 }, '7d')
|
|
16
|
+
expect(token).to.be.a('string')
|
|
17
17
|
expect(token).is.not.null
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
test(
|
|
21
|
-
const token = provider.createToken({ userID: 123 },
|
|
22
|
-
expect(token).to.be.a(
|
|
20
|
+
test('Creates token with explicity token override', () => {
|
|
21
|
+
const token = provider.createToken({ userID: 123 }, '7d', privateKey)
|
|
22
|
+
expect(token).to.be.a('string')
|
|
23
23
|
expect(token).is.not.null
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
test(
|
|
26
|
+
test('Creates token with explicity token options', () => {
|
|
27
27
|
const token = provider.createToken({ userID: 123 }, undefined, undefined, {
|
|
28
|
-
expiresIn:
|
|
28
|
+
expiresIn: '7d',
|
|
29
29
|
})
|
|
30
|
-
expect(token).to.be.a(
|
|
30
|
+
expect(token).to.be.a('string')
|
|
31
31
|
expect(token).is.not.null
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
test(
|
|
34
|
+
test('Creates token with no expiration', () => {
|
|
35
35
|
const localProvider = new JWT(privateKey)
|
|
36
36
|
const token = localProvider.createToken({ userID: 123 })
|
|
37
|
-
expect(token).to.be.a(
|
|
37
|
+
expect(token).to.be.a('string')
|
|
38
38
|
expect(token).is.not.null
|
|
39
39
|
})
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
describe(
|
|
43
|
-
const provider = new JWT(privateKey,
|
|
44
|
-
test(
|
|
42
|
+
describe('Validates token', () => {
|
|
43
|
+
const provider = new JWT(privateKey, '7d')
|
|
44
|
+
test('Succeed to validate just created token', () => {
|
|
45
45
|
// Creates token
|
|
46
|
-
const token = provider.createToken({ userID: 123 },
|
|
47
|
-
expect(token).to.be.a(
|
|
46
|
+
const token = provider.createToken({ userID: 123 }, '7d', privateKey)
|
|
47
|
+
expect(token).to.be.a('string')
|
|
48
48
|
expect(token).is.not.null
|
|
49
49
|
// Validates token
|
|
50
50
|
const validationResp = provider.validateToken(token)
|
|
51
51
|
expect(validationResp).is.not.null
|
|
52
52
|
expect(validationResp.isValid).is.true
|
|
53
|
-
expect(validationResp[
|
|
54
|
-
expect(validationResp[
|
|
55
|
-
expect(validationResp[
|
|
56
|
-
expect(validationResp[
|
|
57
|
-
expect(validationResp[
|
|
53
|
+
expect(validationResp['isExpired']).is.undefined
|
|
54
|
+
expect(validationResp['decodedToken']).is.not.null
|
|
55
|
+
expect(validationResp['decodedToken'].userID).to.be.equals(123)
|
|
56
|
+
expect(validationResp['decodedToken'].exp).to.be.a('number')
|
|
57
|
+
expect(validationResp['decodedToken'].exp).to.be.above(Date.now() / 1000)
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
test(
|
|
60
|
+
test('Fails to validate invalid token', () => {
|
|
61
61
|
// Creates token
|
|
62
|
-
const token = provider.createToken({ userID: 123 },
|
|
62
|
+
const token = provider.createToken({ userID: 123 }, '7d', privateKey)
|
|
63
63
|
// Validates token
|
|
64
|
-
const validationResp = provider.validateToken(token +
|
|
64
|
+
const validationResp = provider.validateToken(token + '123')
|
|
65
65
|
expect(validationResp).is.not.null
|
|
66
66
|
expect(validationResp.isValid).is.false
|
|
67
|
-
expect(validationResp[
|
|
68
|
-
expect(validationResp[
|
|
67
|
+
expect(validationResp['isExpired']).is.undefined
|
|
68
|
+
expect(validationResp['decodedToken']).to.undefined
|
|
69
69
|
})
|
|
70
70
|
|
|
71
|
-
test(
|
|
71
|
+
test('Fails to validate expired token', () => {
|
|
72
72
|
// Creates token
|
|
73
|
-
const token = provider.createToken({ userID: 123 },
|
|
73
|
+
const token = provider.createToken({ userID: 123 }, '-7d', privateKey)
|
|
74
74
|
// Validates token
|
|
75
75
|
const validationResp = provider.validateToken(token)
|
|
76
76
|
expect(validationResp).is.not.null
|
|
77
77
|
expect(validationResp.isValid).is.false
|
|
78
|
-
expect(validationResp[
|
|
79
|
-
expect(validationResp[
|
|
78
|
+
expect(validationResp['isExpired']).is.true
|
|
79
|
+
expect(validationResp['decodedToken']).to.undefined
|
|
80
80
|
})
|
|
81
81
|
|
|
82
|
-
test(
|
|
82
|
+
test('Fails to validate foreign token', () => {
|
|
83
83
|
// Validates token
|
|
84
84
|
const validationResp = provider.validateToken(foreignToken)
|
|
85
85
|
expect(validationResp).is.not.null
|
|
86
86
|
expect(validationResp.isValid).is.false
|
|
87
|
-
expect(validationResp[
|
|
88
|
-
expect(validationResp[
|
|
87
|
+
expect(validationResp['isExpired']).is.undefined
|
|
88
|
+
expect(validationResp['decodedToken']).to.undefined
|
|
89
89
|
})
|
|
90
90
|
})
|
|
91
91
|
|
|
@@ -1,70 +1,58 @@
|
|
|
1
1
|
// get console ref and mock before logger import
|
|
2
2
|
const consoleProxy = console
|
|
3
|
-
const mock = jest.spyOn(consoleProxy,
|
|
3
|
+
const mock = jest.spyOn(consoleProxy, 'log')
|
|
4
4
|
// import logger after first ref
|
|
5
|
-
import Logger from
|
|
5
|
+
import Logger from '../../src/Logger/Logger'
|
|
6
6
|
// get console reference after logger import
|
|
7
|
-
const transactionID =
|
|
7
|
+
const transactionID = '123-456'
|
|
8
8
|
|
|
9
9
|
function setContainerFlag(isContainer: boolean) {
|
|
10
10
|
if (isContainer) {
|
|
11
|
-
process.env[
|
|
11
|
+
process.env['HYBRIDLESS_RUNTIME'] = 'true'
|
|
12
12
|
} else {
|
|
13
|
-
process.env[
|
|
13
|
+
process.env['HYBRIDLESS_RUNTIME'] = undefined
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function fixLogTypePrefix(logType: string) {
|
|
18
|
-
if (logType ==
|
|
19
|
-
if (logType ==
|
|
20
|
-
if (logType ==
|
|
18
|
+
if (logType == 'exception') return 'error'
|
|
19
|
+
if (logType == 'warning') return 'warn'
|
|
20
|
+
if (logType == 'log') return 'info'
|
|
21
21
|
return logType
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function testLogs(isContainer: boolean, provider?: Logger) {
|
|
25
|
-
const type = isContainer ?
|
|
26
|
-
const loggerType = !provider ?
|
|
25
|
+
const type = isContainer ? 'container' : 'serverless'
|
|
26
|
+
const loggerType = !provider ? 'Console' : 'Logger'
|
|
27
27
|
const localProvider = provider || console
|
|
28
28
|
|
|
29
29
|
test(`${type} - ${loggerType} Log - Suppress sensitive info`, async () => {
|
|
30
30
|
setContainerFlag(isContainer)
|
|
31
|
-
localProvider.log(
|
|
31
|
+
localProvider.log('TEST', { password: '123' })
|
|
32
32
|
expect(consoleProxy.log).toHaveBeenNthCalledWith(
|
|
33
33
|
1,
|
|
34
|
-
expect.stringContaining(
|
|
35
|
-
(isContainer ? `${transactionID} ` : "") + "[INFO] [Logger.test.ts:",
|
|
36
|
-
),
|
|
34
|
+
expect.stringContaining((isContainer ? `${transactionID} ` : '') + '[INFO] [Logger.test.ts:')
|
|
37
35
|
)
|
|
38
36
|
expect(consoleProxy.log).toHaveBeenNthCalledWith(
|
|
39
37
|
1,
|
|
40
|
-
expect.stringContaining(
|
|
38
|
+
expect.stringContaining('] TEST **SUPPRESSED_SENSITIVE_DATA**')
|
|
41
39
|
)
|
|
42
40
|
})
|
|
43
41
|
|
|
44
42
|
test(`${type} - ${loggerType} Log - Suppress sensitive info (array)`, async () => {
|
|
45
43
|
setContainerFlag(isContainer)
|
|
46
|
-
localProvider.log(
|
|
44
|
+
localProvider.log('TEST2', [{ password: '123' }])
|
|
47
45
|
expect(consoleProxy.log).toHaveBeenNthCalledWith(
|
|
48
46
|
1,
|
|
49
|
-
expect.stringContaining(
|
|
50
|
-
(isContainer ? `${transactionID} ` : "") + "[INFO] [Logger.test.ts:",
|
|
51
|
-
),
|
|
47
|
+
expect.stringContaining((isContainer ? `${transactionID} ` : '') + '[INFO] [Logger.test.ts:')
|
|
52
48
|
)
|
|
53
49
|
expect(consoleProxy.log).toHaveBeenNthCalledWith(
|
|
54
50
|
1,
|
|
55
|
-
expect.stringContaining(
|
|
51
|
+
expect.stringContaining('] TEST2 **SUPPRESSED_SENSITIVE_DATA**')
|
|
56
52
|
)
|
|
57
53
|
})
|
|
58
54
|
|
|
59
|
-
for (const logType of [
|
|
60
|
-
"log",
|
|
61
|
-
"debug",
|
|
62
|
-
"info",
|
|
63
|
-
"warn",
|
|
64
|
-
"warning",
|
|
65
|
-
"error",
|
|
66
|
-
"exception",
|
|
67
|
-
]) {
|
|
55
|
+
for (const logType of ['log', 'debug', 'info', 'warn', 'warning', 'error', 'exception']) {
|
|
68
56
|
test(`${type} - ${loggerType} ${logType}`, async () => {
|
|
69
57
|
setContainerFlag(isContainer)
|
|
70
58
|
localProvider[logType](logType.toUpperCase())
|
|
@@ -73,28 +61,28 @@ function testLogs(isContainer: boolean, provider?: Logger) {
|
|
|
73
61
|
expect(consoleProxy.log).toHaveBeenNthCalledWith(
|
|
74
62
|
1,
|
|
75
63
|
expect.stringContaining(
|
|
76
|
-
(isContainer ? `${transactionID} ` :
|
|
77
|
-
`[${logTypePrefix.toUpperCase()}] [Logger.test.ts
|
|
78
|
-
)
|
|
64
|
+
(isContainer ? `${transactionID} ` : '') +
|
|
65
|
+
`[${logTypePrefix.toUpperCase()}] [Logger.test.ts:`
|
|
66
|
+
)
|
|
79
67
|
)
|
|
80
68
|
expect(consoleProxy.log).toHaveBeenNthCalledWith(
|
|
81
69
|
1,
|
|
82
|
-
expect.stringContaining(`] ${logType.toUpperCase()}`)
|
|
70
|
+
expect.stringContaining(`] ${logType.toUpperCase()}`)
|
|
83
71
|
)
|
|
84
72
|
})
|
|
85
73
|
}
|
|
86
74
|
}
|
|
87
75
|
|
|
88
|
-
describe(
|
|
76
|
+
describe('Logger', () => {
|
|
89
77
|
beforeEach(() => {
|
|
90
78
|
mock.mockClear()
|
|
91
79
|
})
|
|
92
80
|
const provider = new Logger(
|
|
93
81
|
{
|
|
94
|
-
logLevel:
|
|
82
|
+
logLevel: 'DEBUG',
|
|
95
83
|
sensitiveFilteringKeywords: true,
|
|
96
84
|
},
|
|
97
|
-
transactionID
|
|
85
|
+
transactionID
|
|
98
86
|
)
|
|
99
87
|
provider.notGlobalLogger()
|
|
100
88
|
// Test serverless logs
|
|
@@ -1,41 +1,37 @@
|
|
|
1
|
-
import { SESClient, SendRawEmailCommand } from
|
|
2
|
-
import { mockClient } from
|
|
3
|
-
import { expect } from
|
|
1
|
+
import { SESClient, SendRawEmailCommand } from '@aws-sdk/client-ses'
|
|
2
|
+
import { mockClient } from 'aws-sdk-client-mock'
|
|
3
|
+
import { expect } from 'chai'
|
|
4
4
|
|
|
5
|
-
import Mailer from
|
|
5
|
+
import Mailer from '../../src/Mailer/Mailer'
|
|
6
6
|
|
|
7
7
|
const SESMock = mockClient(SESClient)
|
|
8
8
|
|
|
9
|
-
describe(
|
|
9
|
+
describe('SendRaw', () => {
|
|
10
10
|
// reset mock
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
SESMock.reset()
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
const provider = new Mailer(
|
|
15
|
+
const provider = new Mailer('dev+tests@creator.co', 'ca-central-1')
|
|
16
16
|
|
|
17
|
-
test(
|
|
18
|
-
const messageId =
|
|
17
|
+
test('Send raw with success', async () => {
|
|
18
|
+
const messageId = 'id-123'
|
|
19
19
|
SESMock.on(SendRawEmailCommand).resolves({
|
|
20
20
|
MessageId: messageId,
|
|
21
21
|
})
|
|
22
|
-
const res = await provider.sendRawEmail(
|
|
23
|
-
"test@test.com",
|
|
24
|
-
"My message",
|
|
25
|
-
"My subject",
|
|
26
|
-
)
|
|
22
|
+
const res = await provider.sendRawEmail('test@test.com', 'My message', 'My subject')
|
|
27
23
|
expect(res).is.not.null
|
|
28
24
|
console.log(res)
|
|
29
25
|
})
|
|
30
26
|
|
|
31
|
-
test(
|
|
32
|
-
const messageId =
|
|
33
|
-
const from =
|
|
34
|
-
const to =
|
|
35
|
-
const msg =
|
|
36
|
-
const subject =
|
|
37
|
-
const cc =
|
|
38
|
-
const replyTo =
|
|
27
|
+
test('Send raw with success', async () => {
|
|
28
|
+
const messageId = 'id-123'
|
|
29
|
+
const from = 'test@test.com'
|
|
30
|
+
const to = 'test@test2.com'
|
|
31
|
+
const msg = 'My message'
|
|
32
|
+
const subject = 'My subject'
|
|
33
|
+
const cc = 'test@test3.com'
|
|
34
|
+
const replyTo = 'test@test4.com'
|
|
39
35
|
SESMock.on(SendRawEmailCommand).resolves({
|
|
40
36
|
MessageId: messageId,
|
|
41
37
|
})
|
|
@@ -44,21 +40,17 @@ describe("SendRaw", () => {
|
|
|
44
40
|
console.log(res)
|
|
45
41
|
})
|
|
46
42
|
|
|
47
|
-
test(
|
|
48
|
-
SESMock.on(SendRawEmailCommand).rejects(new Error(
|
|
43
|
+
test('Send raw with failure', async () => {
|
|
44
|
+
SESMock.on(SendRawEmailCommand).rejects(new Error('failed!'))
|
|
49
45
|
let res: any = null,
|
|
50
46
|
err: any = null
|
|
51
47
|
try {
|
|
52
|
-
res = await provider.sendRawEmail(
|
|
53
|
-
"test@test.com",
|
|
54
|
-
"My message",
|
|
55
|
-
"My subject",
|
|
56
|
-
)
|
|
48
|
+
res = await provider.sendRawEmail('test@test.com', 'My message', 'My subject')
|
|
57
49
|
} catch (e) {
|
|
58
50
|
err = e
|
|
59
51
|
}
|
|
60
52
|
expect(res).is.null
|
|
61
|
-
expect(err?.message).to.be.equals(
|
|
53
|
+
expect(err?.message).to.be.equals('failed!')
|
|
62
54
|
expect(res).is.null
|
|
63
55
|
console.log(res)
|
|
64
56
|
})
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { SNSClient, PublishCommand } from
|
|
2
|
-
import { mockClient } from
|
|
3
|
-
import { expect } from
|
|
1
|
+
import { SNSClient, PublishCommand } from '@aws-sdk/client-sns'
|
|
2
|
+
import { mockClient } from 'aws-sdk-client-mock'
|
|
3
|
+
import { expect } from 'chai'
|
|
4
4
|
|
|
5
|
-
import Publisher from
|
|
5
|
+
import Publisher from '../../src/Publisher/Publisher'
|
|
6
6
|
|
|
7
7
|
const SNSMock = mockClient(SNSClient)
|
|
8
8
|
|
|
9
|
-
describe(
|
|
9
|
+
describe('Encryption', () => {
|
|
10
10
|
// reset mock
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
SNSMock.reset()
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
const provider = new Publisher({
|
|
16
|
-
region:
|
|
16
|
+
region: 'ca-central-1',
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
test(
|
|
20
|
-
const msg = { text:
|
|
21
|
-
const topic =
|
|
22
|
-
const messageId =
|
|
19
|
+
test('Publishes with success', async () => {
|
|
20
|
+
const msg = { text: '123' }
|
|
21
|
+
const topic = '123'
|
|
22
|
+
const messageId = 'id-123'
|
|
23
23
|
SNSMock.on(PublishCommand, {
|
|
24
24
|
Message: JSON.stringify(msg),
|
|
25
25
|
TopicArn: topic,
|
|
@@ -31,10 +31,10 @@ describe("Encryption", () => {
|
|
|
31
31
|
expect(res.MessageId).to.be.equals(messageId)
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
test(
|
|
35
|
-
const msg = { text:
|
|
36
|
-
const topic =
|
|
37
|
-
const messageId =
|
|
34
|
+
test('Publishes with success (additional props)', async () => {
|
|
35
|
+
const msg = { text: '123' }
|
|
36
|
+
const topic = '123'
|
|
37
|
+
const messageId = 'id-123'
|
|
38
38
|
SNSMock.on(PublishCommand, {
|
|
39
39
|
Message: JSON.stringify(msg),
|
|
40
40
|
TopicArn: topic,
|
|
@@ -48,10 +48,10 @@ describe("Encryption", () => {
|
|
|
48
48
|
expect(res.MessageId).to.be.equals(messageId)
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
test(
|
|
52
|
-
const msg = { text:
|
|
53
|
-
const topic =
|
|
54
|
-
SNSMock.on(PublishCommand).rejects(new Error(
|
|
51
|
+
test('Publish failure', async () => {
|
|
52
|
+
const msg = { text: '123' }
|
|
53
|
+
const topic = '123'
|
|
54
|
+
SNSMock.on(PublishCommand).rejects(new Error('failed!'))
|
|
55
55
|
const res = await provider.publishOnTopic(msg, topic)
|
|
56
56
|
expect(res).is.null
|
|
57
57
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Route } from
|
|
2
|
-
import RouteResolver from
|
|
1
|
+
import { Route } from '../../src/Server/Router'
|
|
2
|
+
import RouteResolver from '../../src/Server/RouteResolver'
|
|
3
3
|
|
|
4
4
|
const mockRoute = (method: Method, path: string) =>
|
|
5
5
|
({
|
|
@@ -8,99 +8,96 @@ const mockRoute = (method: Method, path: string) =>
|
|
|
8
8
|
}) as any as Route
|
|
9
9
|
|
|
10
10
|
type Method =
|
|
11
|
-
| Lowercase<
|
|
12
|
-
| Uppercase<
|
|
11
|
+
| Lowercase<'GET' | 'POST' | 'PUT' | 'DELETE'>
|
|
12
|
+
| Uppercase<'GET' | 'POST' | 'PUT' | 'DELETE'>
|
|
13
13
|
|
|
14
|
-
describe(
|
|
15
|
-
test(
|
|
14
|
+
describe('RouteResolver', () => {
|
|
15
|
+
test('no routes configured', () => {
|
|
16
16
|
parameterizedTest({}, () => [
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[
|
|
17
|
+
['GET', '/', undefined],
|
|
18
|
+
['GET', '', undefined],
|
|
19
|
+
['GET', 'hjdah', undefined],
|
|
20
20
|
])
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
test(
|
|
23
|
+
test('one route, case insensitive', () => {
|
|
24
24
|
parameterizedTest(
|
|
25
25
|
{
|
|
26
|
-
route: mockRoute(
|
|
26
|
+
route: mockRoute('get', '/'),
|
|
27
27
|
},
|
|
28
|
-
|
|
29
|
-
[
|
|
30
|
-
[
|
|
31
|
-
[
|
|
32
|
-
[
|
|
33
|
-
[
|
|
34
|
-
[
|
|
35
|
-
]
|
|
28
|
+
routes => [
|
|
29
|
+
['GET', '/', routes.route],
|
|
30
|
+
['get', '/', routes.route],
|
|
31
|
+
['GET', '', routes.route],
|
|
32
|
+
['GET', 'hjdah', undefined],
|
|
33
|
+
['POST', '/', undefined],
|
|
34
|
+
['DELETE', '/', undefined],
|
|
35
|
+
]
|
|
36
36
|
)
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
-
test(
|
|
39
|
+
test('basic matching', () => {
|
|
40
40
|
parameterizedTest(
|
|
41
41
|
{
|
|
42
|
-
getBase: mockRoute(
|
|
43
|
-
getA: mockRoute(
|
|
44
|
-
getB: mockRoute(
|
|
45
|
-
postBase: mockRoute(
|
|
46
|
-
postA: mockRoute(
|
|
47
|
-
variable: mockRoute(
|
|
48
|
-
getAb: mockRoute(
|
|
42
|
+
getBase: mockRoute('GET', '/'),
|
|
43
|
+
getA: mockRoute('GET', '/a'),
|
|
44
|
+
getB: mockRoute('GET', '/b'),
|
|
45
|
+
postBase: mockRoute('POST', '/'),
|
|
46
|
+
postA: mockRoute('POST', '/a'),
|
|
47
|
+
variable: mockRoute('GET', '/:a'),
|
|
48
|
+
getAb: mockRoute('GET', '/a/b'),
|
|
49
49
|
},
|
|
50
|
-
|
|
51
|
-
[
|
|
52
|
-
[
|
|
53
|
-
[
|
|
54
|
-
[
|
|
55
|
-
[
|
|
56
|
-
[
|
|
57
|
-
[
|
|
58
|
-
]
|
|
50
|
+
routes => [
|
|
51
|
+
['GET', '/', routes.getBase],
|
|
52
|
+
['GET', '/a', routes.getA],
|
|
53
|
+
['GET', '/b', routes.getB],
|
|
54
|
+
['POST', '/', routes.postBase],
|
|
55
|
+
['POST', '/a', routes.postA],
|
|
56
|
+
['GET', '/c', routes.variable],
|
|
57
|
+
['GET', '/a/b', routes.getAb],
|
|
58
|
+
]
|
|
59
59
|
)
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
-
test(
|
|
62
|
+
test('path variables', () => {
|
|
63
63
|
parameterizedTest(
|
|
64
64
|
{
|
|
65
|
-
path_vars: mockRoute(
|
|
66
|
-
abc: mockRoute(
|
|
67
|
-
abcd: mockRoute(
|
|
68
|
-
abc_path: mockRoute(
|
|
65
|
+
path_vars: mockRoute('get', '/base/:a/:b/:c'),
|
|
66
|
+
abc: mockRoute('get', '/base/a/b/c'),
|
|
67
|
+
abcd: mockRoute('get', '/base/a/b/c/d'),
|
|
68
|
+
abc_path: mockRoute('get', '/base/a/b/c/:d'),
|
|
69
69
|
},
|
|
70
|
-
|
|
71
|
-
[
|
|
72
|
-
[
|
|
73
|
-
[
|
|
74
|
-
[
|
|
75
|
-
[
|
|
76
|
-
[
|
|
77
|
-
[
|
|
78
|
-
]
|
|
70
|
+
routes => [
|
|
71
|
+
['GET', '/base/1/2/3', routes.path_vars],
|
|
72
|
+
['GET', '/base/a/b/c', routes.abc],
|
|
73
|
+
['GET', '/base/a/b/c/d', routes.abcd],
|
|
74
|
+
['GET', '/base/a/b/c/u', routes.abc_path],
|
|
75
|
+
['GET', '/base/a/b', undefined],
|
|
76
|
+
['GET', '/base/a/b/c/d/e', undefined],
|
|
77
|
+
['GET', '/base/a/b/c/d/e/f', undefined],
|
|
78
|
+
]
|
|
79
79
|
)
|
|
80
80
|
})
|
|
81
81
|
|
|
82
|
-
test(
|
|
82
|
+
test('fails to construct with duplicate routes', () => {
|
|
83
83
|
expect(
|
|
84
84
|
() =>
|
|
85
85
|
new RouteResolver({
|
|
86
|
-
routes: [
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
],
|
|
90
|
-
}),
|
|
91
|
-
).toThrowError("Duplicate route: GET: /a/b/c/:jshj/:e/b")
|
|
86
|
+
routes: [mockRoute('GET', '/a/b/c/:d/:e/b'), mockRoute('GET', '/a/b/c/:jshj/:e/b')],
|
|
87
|
+
})
|
|
88
|
+
).toThrowError('Duplicate route: GET: /a/b/c/:jshj/:e/b')
|
|
92
89
|
})
|
|
93
90
|
})
|
|
94
91
|
|
|
95
92
|
const parameterizedTest = <T extends { [k: string]: Route }>(
|
|
96
93
|
routes: T,
|
|
97
|
-
tests: (routes: T) => [Method, string, Route?][]
|
|
94
|
+
tests: (routes: T) => [Method, string, Route?][]
|
|
98
95
|
) => {
|
|
99
96
|
const underTest = new RouteResolver({
|
|
100
97
|
routes: Object.values(routes),
|
|
101
98
|
})
|
|
102
99
|
|
|
103
100
|
tests(routes).forEach(([method, path, expected]) =>
|
|
104
|
-
expect(underTest.resolveRoute(method, path)).toBe(expected)
|
|
101
|
+
expect(underTest.resolveRoute(method, path)).toBe(expected)
|
|
105
102
|
)
|
|
106
103
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { expect } from
|
|
1
|
+
import { expect } from 'chai'
|
|
2
2
|
|
|
3
|
-
import ContainerServer from
|
|
4
|
-
import Server from
|
|
5
|
-
import Router from
|
|
3
|
+
import ContainerServer from '../../src/Server/lib/ContainerServer'
|
|
4
|
+
import Server from '../../src/Server/lib/Server'
|
|
5
|
+
import Router from '../../src/Server/Router'
|
|
6
6
|
|
|
7
|
-
describe(
|
|
7
|
+
describe('Router basics', () => {
|
|
8
8
|
// @ts-ignore
|
|
9
|
-
let mockExit = jest.spyOn(process,
|
|
9
|
+
let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
|
|
10
10
|
beforeAll(() => {
|
|
11
11
|
// @ts-ignore
|
|
12
|
-
mockExit = jest.spyOn(process,
|
|
12
|
+
mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
|
|
13
13
|
})
|
|
14
14
|
afterAll(() => {
|
|
15
15
|
mockExit.mockRestore()
|
|
@@ -18,20 +18,20 @@ describe("Router basics", () => {
|
|
|
18
18
|
mockExit.mockReset()
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
-
test(
|
|
22
|
-
process.env[
|
|
21
|
+
test('Serverless server', async () => {
|
|
22
|
+
process.env['HYBRIDLESS_RUNTIME'] = undefined
|
|
23
23
|
const router = new Router({ routes: [] })
|
|
24
24
|
expect(router.getExport()).to.not.be.undefined
|
|
25
|
-
expect(router[
|
|
26
|
-
expect(router[
|
|
25
|
+
expect(router['server']).to.be.an.instanceof(Server)
|
|
26
|
+
expect(router['server']).to.not.be.an.instanceof(ContainerServer)
|
|
27
27
|
})
|
|
28
|
-
test(
|
|
29
|
-
process.env[
|
|
28
|
+
test('Container server', async () => {
|
|
29
|
+
process.env['HYBRIDLESS_RUNTIME'] = 'true'
|
|
30
30
|
const router = new Router({ routes: [] })
|
|
31
31
|
expect(router.getExport()).to.not.be.undefined
|
|
32
|
-
expect(router[
|
|
33
|
-
expect(router[
|
|
34
|
-
await router[
|
|
32
|
+
expect(router['server']).to.be.an.instanceof(Server)
|
|
33
|
+
expect(router['server']).to.be.an.instanceof(ContainerServer)
|
|
34
|
+
await router['server']['stop']()
|
|
35
35
|
})
|
|
36
36
|
})
|
|
37
37
|
|