Skip to content

Commit 586e9bd

Browse files
committed
feat: update tests
1 parent cd95840 commit 586e9bd

File tree

9 files changed

+234
-272
lines changed

9 files changed

+234
-272
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ CDK project using TypeScript. It contains 2 stacks:
2929
- `S3` (as artifactory in CodePipeline)
3030

3131
Architecture diagram - autogenerated with [cdk-dia](https://github.com/pistazie/cdk-dia)
32-
- ```npm run dia```
33-
![architecture-diagram](diagrams/diagram.png)
32+
33+
- ```npm run dia```
34+
- ![architecture-diagram](diagrams/diagram.png)
3435

3536
## Type
3637

backend/blog-backend-infrastructure-stack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class BlogInfrastructureStack extends Stack {
3636
// DynamoDB tables
3737
const tableSubscriptions = createTableSubscriptions(this);
3838
const tableContact = createTableContact(this);
39-
const tableFeedback = createTableFeedbackForm(this);
39+
createTableFeedbackForm(this);
4040

4141
// Create SNS topic to notify myself
4242
const topicMyNotification = retrieveTopicMyNotification(this);

diagrams/diagram.png

192 KB
Loading
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import * as cdk from 'aws-cdk-lib';
2+
import { Template, Match } from 'aws-cdk-lib/assertions';
3+
import { BlogInfrastructureStack } from '../../../../backend/blog-backend-infrastructure-stack';
4+
5+
/*****************************
6+
* List of tests in this file:
7+
*
8+
* 1. Stack contains API Gateway RestApi with correct name
9+
* 2. API Gateway has correct endpoint configuration
10+
* 3. API Gateway has /api resource
11+
* 4. API Gateway has POST method for /api/contact
12+
* 5. Lambda function is created for contact resource
13+
* 6. Stack contains API Gateway Deployment with Retain policy
14+
* 7. Stack contains API Gateway Stage of prod that follows best practices
15+
* 8. API Gateway has POST method for /api/subscription
16+
* 9. Step Functions is created for subscription resource
17+
*****************************/
18+
19+
describe('Validate Api Gateway', () => {
20+
let app: cdk.App;
21+
let stack: BlogInfrastructureStack;
22+
let template: Template;
23+
24+
beforeEach(() => {
25+
app = new cdk.App();
26+
stack = new BlogInfrastructureStack(app, 'blog-backend-infrastructure', {
27+
env: {
28+
account:
29+
process.env.CDK_DEPLOY_ACCOUNT || process.env.CDK_DEFAULT_ACCOUNT,
30+
region: 'eu-west-1',
31+
},
32+
});
33+
template = Template.fromStack(stack);
34+
});
35+
36+
test('Stack contains API Gateway RestApi with correct name', () => {
37+
template.hasResourceProperties('AWS::ApiGateway::RestApi', {
38+
Name: 'blog-backend-infrastructure',
39+
});
40+
});
41+
42+
// test('API Gateway has correct endpoint configuration', () => {
43+
// template.hasResourceProperties('AWS::ApiGateway::RestApi', {
44+
// EndpointConfiguration: {
45+
// Types: ['EDGE'],
46+
// },
47+
// });
48+
// });
49+
50+
test('Stack contains API Gateway Deployment with Retain policy', () => {
51+
template.hasResource('AWS::ApiGateway::Deployment', {
52+
UpdateReplacePolicy: 'Retain',
53+
DeletionPolicy: 'Retain',
54+
});
55+
});
56+
57+
test('Stack contains API Gateway Stage of prod that follows best practices', () => {
58+
template.hasResourceProperties('AWS::ApiGateway::Stage', {
59+
StageName: 'prd',
60+
TracingEnabled: true,
61+
CacheClusterEnabled: false, // TODO: DISABLED
62+
MethodSettings: Match.arrayWith([
63+
{
64+
CacheDataEncrypted: false, // TODO: DISABLED
65+
CachingEnabled: false, // TODO: DISABLED
66+
DataTraceEnabled: false,
67+
HttpMethod: '*',
68+
LoggingLevel: 'ERROR',
69+
MetricsEnabled: true,
70+
ResourcePath: '/*',
71+
},
72+
]),
73+
});
74+
});
75+
76+
test('API Gateway has /api resource', () => {
77+
template.hasResourceProperties('AWS::ApiGateway::Resource', {
78+
PathPart: 'api',
79+
});
80+
});
81+
82+
test('API Gateway has POST method for /api/contact', () => {
83+
template.hasResourceProperties('AWS::ApiGateway::Method', {
84+
HttpMethod: 'POST',
85+
Integration: {
86+
IntegrationHttpMethod: 'POST',
87+
Type: 'AWS_PROXY',
88+
},
89+
});
90+
});
91+
92+
test('API Gateway has POST method for /api/subscription', () => {
93+
template.hasResourceProperties('AWS::ApiGateway::Method', {
94+
HttpMethod: 'POST',
95+
Integration: {
96+
IntegrationHttpMethod: 'POST',
97+
Type: 'AWS_PROXY',
98+
},
99+
});
100+
});
101+
102+
test('API Gateway has POST method for /api/feedback', () => {
103+
template.hasResourceProperties('AWS::ApiGateway::Method', {
104+
HttpMethod: 'POST',
105+
Integration: {
106+
IntegrationHttpMethod: 'POST',
107+
Type: 'AWS_PROXY',
108+
},
109+
});
110+
});
111+
112+
// test('/api/subscription resource is using a Lambda function', () => {
113+
// template.hasResourceProperties('AWS::ApiGateway::Method', {
114+
// HttpMethod: 'POST',
115+
// Integration: {
116+
// Type: 'AWS_PROXY',
117+
// IntegrationHttpMethod: 'POST',
118+
// Uri: {
119+
// 'Fn::Join': [
120+
// '',
121+
// [
122+
// 'arn:',
123+
// { Ref: 'AWS::Partition' },
124+
// ':apigateway:',
125+
// { Ref: 'AWS::Region' },
126+
// ':lambda:path/2015-03-31/functions/',
127+
// {
128+
// 'Fn::GetAtt': [
129+
// expect.stringMatching(/^SubscriptionLambda[A-Z0-9]+$/),
130+
// 'Arn',
131+
// ],
132+
// },
133+
// '/invocations',
134+
// ],
135+
// ],
136+
// },
137+
// },
138+
// });
139+
// });
140+
141+
// test('/api/contact resource is using Step Functions', () => {
142+
// template.hasResourceProperties('AWS::ApiGateway::Method', {
143+
// HttpMethod: 'POST',
144+
// Integration: {
145+
// Type: 'AWS',
146+
// IntegrationHttpMethod: 'POST',
147+
// Uri: {
148+
// 'Fn::Join': [
149+
// '',
150+
// [
151+
// 'arn:',
152+
// { Ref: 'AWS::Partition' },
153+
// ':apigateway:',
154+
// { Ref: 'AWS::Region' },
155+
// ':states:action/StartExecution',
156+
// ],
157+
// ],
158+
// },
159+
// IntegrationResponses: [
160+
// {
161+
// StatusCode: '200',
162+
// },
163+
// ],
164+
// },
165+
// });
166+
// });
167+
168+
// test('/api/feedback resource is using Step Functions', () => {
169+
// template.hasResourceProperties('AWS::ApiGateway::Method', {
170+
// HttpMethod: 'POST',
171+
// Integration: {
172+
// Type: 'AWS',
173+
// IntegrationHttpMethod: 'POST',
174+
// Uri: {
175+
// 'Fn::Join': [
176+
// '',
177+
// [
178+
// 'arn:',
179+
// { Ref: 'AWS::Partition' },
180+
// ':apigateway:',
181+
// { Ref: 'AWS::Region' },
182+
// ':states:action/StartExecution',
183+
// ],
184+
// ],
185+
// },
186+
// IntegrationResponses: [
187+
// {
188+
// StatusCode: '200',
189+
// },
190+
// ],
191+
// },
192+
// });
193+
// });
194+
});

tests/unit/runtime/contact/index.test.ts renamed to tests/unit/api/runtime/contact/index.test.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import {
22
validateInput,
33
getContactItem,
44
getEmailMessageItem,
5-
getResponseHandler,
6-
} from '../../../../backend/api/runtime/contact';
5+
} from '../../../../../backend/api/runtime/contact';
76

87
const mockFormData = {
98
name: 'John Doe',
@@ -19,13 +18,13 @@ describe('validateInput', () => {
1918
reply_to: '[email protected]',
2019
message: 'test message',
2120
});
22-
}).toThrowError('Name is required');
21+
}).toThrow('Name is required');
2322
});
2423

2524
test('throws error if reply_to is not provided', () => {
2625
expect(() => {
2726
validateInput({ name: 'Test', message: 'test message' });
28-
}).toThrowError('Email is required');
27+
}).toThrow('Email is required');
2928
});
3029

3130
test('throws an error if email is invalid', () => {
@@ -41,13 +40,13 @@ describe('validateInput', () => {
4140
test('throws error if message is not provided', () => {
4241
expect(() => {
4342
validateInput({ name: 'Test', reply_to: '[email protected]' });
44-
}).toThrowError('Message is required');
43+
}).toThrow('Message is required');
4544
});
4645

4746
test('does not throw error if form data is valid', () => {
4847
expect(() => {
4948
validateInput(mockFormData);
50-
}).not.toThrowError();
49+
}).not.toThrow();
5150
});
5251
});
5352

@@ -99,18 +98,18 @@ describe('getEmailMessageItem', () => {
9998
});
10099
});
101100

102-
describe('getResponseHandler', () => {
103-
test('should return a response with 200 status code and success message', () => {
104-
const expectedResponse = {
105-
statusCode: 200,
106-
headers: {
107-
'Content-Type': 'application/json',
108-
'Access-Control-Allow-Origin': 'https://www.playingaws.com',
109-
'Access-Control-Allow-Credentials': false,
110-
},
111-
body: JSON.stringify({ message: 'Success' }),
112-
};
113-
const response = getResponseHandler();
114-
expect(response).toEqual(expectedResponse);
115-
});
116-
});
101+
// describe('getResponseHandler', () => {
102+
// test('should return a response with 200 status code and success message', () => {
103+
// const expectedResponse = {
104+
// statusCode: 200,
105+
// headers: {
106+
// 'Content-Type': 'application/json',
107+
// 'Access-Control-Allow-Origin': 'https://www.playingaws.com',
108+
// 'Access-Control-Allow-Credentials': false,
109+
// },
110+
// body: JSON.stringify({ message: 'Success' }),
111+
// };
112+
// const response = getResponseHandler();
113+
// expect(response).toEqual(expectedResponse);
114+
// });
115+
// });

tests/unit/runtime/subscription/index.test.ts renamed to tests/unit/api/runtime/subscription/index.test.ts

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {
22
validateInput,
33
getSubscriptionItem,
4-
getResponseHandler,
5-
} from '../../../../backend/api/runtime/subscription';
4+
} from '../../../../../backend/api/runtime/subscription';
65

76
describe('validateInput', () => {
87
test('throws an error if formData is missing email', () => {
@@ -46,18 +45,18 @@ describe('subscriptionItem', () => {
4645
});
4746
});
4847

49-
describe('getResponseHandler', () => {
50-
test('should return a response with 200 status code and success message', () => {
51-
const expectedResponse = {
52-
statusCode: 200,
53-
headers: {
54-
'Content-Type': 'application/json',
55-
'Access-Control-Allow-Origin': 'https://www.playingaws.com',
56-
'Access-Control-Allow-Credentials': false,
57-
},
58-
body: JSON.stringify({ message: 'Success' }),
59-
};
60-
const response = getResponseHandler();
61-
expect(response).toEqual(expectedResponse);
62-
});
63-
});
48+
// describe('getResponseHandler', () => {
49+
// test('should return a response with 200 status code and success message', () => {
50+
// const expectedResponse = {
51+
// statusCode: 200,
52+
// headers: {
53+
// 'Content-Type': 'application/json',
54+
// 'Access-Control-Allow-Origin': 'https://www.playingaws.com',
55+
// 'Access-Control-Allow-Credentials': false,
56+
// },
57+
// body: JSON.stringify({ message: 'Success' }),
58+
// };
59+
// const response = getResponseHandler();
60+
// expect(response).toEqual(expectedResponse);
61+
// });
62+
// });

0 commit comments

Comments
 (0)