Skip to content

Commit 1e0b285

Browse files
Merge pull request #21 from ModusCreateOrg/github-workflows
GitHub workflows
2 parents 7840c22 + 347a768 commit 1e0b285

File tree

9 files changed

+392
-1283
lines changed

9 files changed

+392
-1283
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Backend Tests
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
paths:
7+
- 'backend/**'
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: ./backend
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Set up Node.js
20+
uses: actions/setup-node@v3
21+
with:
22+
node-version: '18'
23+
cache: 'npm'
24+
cache-dependency-path: './backend/package-lock.json'
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Run linting
30+
run: npm run lint
31+
32+
- name: Run tests
33+
run: npm test
34+
35+
- name: Generate test summary
36+
if: always()
37+
run: |
38+
echo "# Backend Test Results" >> $GITHUB_STEP_SUMMARY
39+
if [ ${{ job.status }} == "success" ]; then
40+
echo "✅ All tests passed successfully!" >> $GITHUB_STEP_SUMMARY
41+
else
42+
echo "❌ Some tests failed. Please check the logs for details." >> $GITHUB_STEP_SUMMARY
43+
fi
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Frontend Tests
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
paths:
7+
- 'frontend/**'
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: ./frontend
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Set up Node.js
20+
uses: actions/setup-node@v3
21+
with:
22+
node-version: '18'
23+
cache: 'npm'
24+
cache-dependency-path: './frontend/package-lock.json'
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Run tests
30+
env:
31+
VITE_BASE_URL_API: https://jsonplaceholder.typicode.com
32+
VITE_BUILD_DATE: 1970-01-01
33+
VITE_BUILD_TIME: 00:00:00
34+
VITE_BUILD_TS: 1970-01-01T00:00:00+0000
35+
VITE_BUILD_COMMIT_SHA: test
36+
VITE_BUILD_ENV_CODE: test
37+
VITE_BUILD_WORKFLOW_RUNNER: test
38+
VITE_BUILD_WORKFLOW_NAME: test
39+
VITE_BUILD_WORKFLOW_RUN_NUMBER: 1
40+
VITE_BUILD_WORKFLOW_RUN_ATTEMPT: 1
41+
run: npm test

.husky/pre-commit

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
#!/usr/bin/env sh
2-
. "$(dirname -- "$0")/_/husky.sh"
3-
41
cd frontend && npm run lint

backend/src/iac/backend-stack.test.ts

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ describe('BackendStack', () => {
1313
beforeEach(() => {
1414
app = new cdk.App();
1515
stackProps = {
16-
env: { account: '123456789012', region: 'us-east-1' }
16+
env: { account: '123456789012', region: 'us-east-1' },
1717
};
1818

1919
// Create both staging and production stacks for testing
2020
stagingStack = new BackendStack(app, 'StagingStack', {
2121
...stackProps,
22-
environment: 'staging'
22+
environment: 'staging',
2323
});
2424
stagingTemplate = Template.fromStack(stagingStack);
2525

2626
productionStack = new BackendStack(app, 'ProductionStack', {
2727
...stackProps,
28-
environment: 'production'
28+
environment: 'production',
2929
});
3030
productionTemplate = Template.fromStack(productionStack);
3131
});
@@ -40,9 +40,9 @@ describe('BackendStack', () => {
4040
Tags: Match.arrayWith([
4141
{
4242
Key: 'Name',
43-
Value: Match.stringLikeRegexp('AIMedicalReportVPC')
44-
}
45-
])
43+
Value: Match.stringLikeRegexp('AIMedicalReportVPC'),
44+
},
45+
]),
4646
});
4747

4848
// Verify subnet count for staging (2 AZs = 4 subnets)
@@ -60,9 +60,9 @@ describe('BackendStack', () => {
6060
ClusterSettings: [
6161
{
6262
Name: 'containerInsights',
63-
Value: 'enabled'
64-
}
65-
]
63+
Value: 'enabled',
64+
},
65+
],
6666
});
6767
});
6868

@@ -78,25 +78,25 @@ describe('BackendStack', () => {
7878
Environment: Match.arrayWith([
7979
{ Name: 'NODE_ENV', Value: 'staging' },
8080
{ Name: 'PERPLEXITY_MODEL', Value: 'sonar' },
81-
{ Name: 'PERPLEXITY_MAX_TOKENS', Value: '2048' }
81+
{ Name: 'PERPLEXITY_MAX_TOKENS', Value: '2048' },
8282
]),
8383
LogConfiguration: Match.objectLike({
84-
LogDriver: 'awslogs'
84+
LogDriver: 'awslogs',
8585
}),
8686
PortMappings: [
8787
{
8888
ContainerPort: 3000,
89-
Protocol: 'tcp'
90-
}
91-
]
92-
})
93-
])
89+
Protocol: 'tcp',
90+
},
91+
],
92+
}),
93+
]),
9494
});
9595

9696
// Test production task definition has higher resources
9797
productionTemplate.hasResourceProperties('AWS::ECS::TaskDefinition', {
9898
Cpu: '512',
99-
Memory: '1024'
99+
Memory: '1024',
100100
});
101101
});
102102

@@ -107,14 +107,14 @@ describe('BackendStack', () => {
107107
DesiredCount: 1,
108108
NetworkConfiguration: Match.objectLike({
109109
AwsvpcConfiguration: {
110-
AssignPublicIp: 'DISABLED'
111-
}
112-
})
110+
AssignPublicIp: 'DISABLED',
111+
},
112+
}),
113113
});
114114

115115
// Test production service has higher count
116116
productionTemplate.hasResourceProperties('AWS::ECS::Service', {
117-
DesiredCount: 2
117+
DesiredCount: 2,
118118
});
119119
});
120120

@@ -125,13 +125,13 @@ describe('BackendStack', () => {
125125
// Production should have auto-scaling
126126
productionTemplate.hasResourceProperties('AWS::ApplicationAutoScaling::ScalableTarget', {
127127
MinCapacity: 2,
128-
MaxCapacity: 10
128+
MaxCapacity: 10,
129129
});
130130

131131
productionTemplate.hasResourceProperties('AWS::ApplicationAutoScaling::ScalingPolicy', {
132132
TargetTrackingScalingPolicyConfiguration: {
133-
TargetValue: 70
134-
}
133+
TargetValue: 70,
134+
},
135135
});
136136
});
137137
});
@@ -141,13 +141,13 @@ describe('BackendStack', () => {
141141
// Staging log group with 1 week retention
142142
stagingTemplate.hasResourceProperties('AWS::Logs::LogGroup', {
143143
LogGroupName: '/ecs/AIMedicalReport-staging',
144-
RetentionInDays: 7
144+
RetentionInDays: 7,
145145
});
146146

147147
// Production log group with 1 month retention
148148
productionTemplate.hasResourceProperties('AWS::Logs::LogGroup', {
149149
LogGroupName: '/ecs/AIMedicalReport-production',
150-
RetentionInDays: 30
150+
RetentionInDays: 30,
151151
});
152152
});
153153
});
@@ -156,7 +156,7 @@ describe('BackendStack', () => {
156156
it('should create a Cognito domain', () => {
157157
stagingTemplate.hasResourceProperties('AWS::Cognito::UserPoolDomain', {
158158
Domain: 'aimedicalreport-auth',
159-
UserPoolId: Match.anyValue()
159+
UserPoolId: Match.anyValue(),
160160
});
161161
});
162162

@@ -165,12 +165,9 @@ describe('BackendStack', () => {
165165
GenerateSecret: true,
166166
AllowedOAuthFlows: ['code'],
167167
CallbackURLs: Match.arrayWith([
168-
Match.stringLikeRegexp('http://aimedicalreport.example.com/oauth2/idpresponse')
168+
Match.stringLikeRegexp('http://aimedicalreport.example.com/oauth2/idpresponse'),
169169
]),
170-
ExplicitAuthFlows: Match.arrayWith([
171-
'ALLOW_USER_PASSWORD_AUTH',
172-
'ALLOW_USER_SRP_AUTH'
173-
])
170+
ExplicitAuthFlows: Match.arrayWith(['ALLOW_USER_PASSWORD_AUTH', 'ALLOW_USER_SRP_AUTH']),
174171
});
175172
});
176173
});
@@ -182,10 +179,10 @@ describe('BackendStack', () => {
182179
LoadBalancerAttributes: Match.arrayWith([
183180
{
184181
Key: 'deletion_protection.enabled',
185-
Value: 'false'
186-
}
182+
Value: 'false',
183+
},
187184
]),
188-
Type: 'application'
185+
Type: 'application',
189186
});
190187
});
191188

@@ -196,7 +193,7 @@ describe('BackendStack', () => {
196193
TargetType: 'ip',
197194
HealthCheckPath: '/health',
198195
HealthCheckTimeoutSeconds: 5,
199-
HealthCheckIntervalSeconds: 30
196+
HealthCheckIntervalSeconds: 30,
200197
});
201198
});
202199

@@ -211,16 +208,16 @@ describe('BackendStack', () => {
211208
UserPoolArn: Match.anyValue(),
212209
UserPoolClientId: Match.anyValue(),
213210
UserPoolDomain: Match.anyValue(),
214-
OnUnauthenticatedRequest: 'authenticate'
211+
OnUnauthenticatedRequest: 'authenticate',
215212
},
216-
Order: 1
213+
Order: 1,
217214
}),
218215
Match.objectLike({
219216
Type: 'forward',
220217
TargetGroupArn: Match.anyValue(),
221-
Order: 2
222-
})
223-
])
218+
Order: 2,
219+
}),
220+
]),
224221
});
225222
});
226223
});

backend/src/iac/backend-stack.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@ import * as ecs from 'aws-cdk-lib/aws-ecs';
44
import * as logs from 'aws-cdk-lib/aws-logs';
55
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
66
import * as cognito from 'aws-cdk-lib/aws-cognito';
7-
import * as iam from 'aws-cdk-lib/aws-iam';
87
import * as elbv2_actions from 'aws-cdk-lib/aws-elasticloadbalancingv2-actions';
9-
import * as constructs from 'constructs';
8+
import { Construct } from 'constructs';
109

1110
interface BackendStackProps extends cdk.StackProps {
1211
environment: string;
1312
}
1413

1514
export class BackendStack extends cdk.Stack {
16-
constructor(scope: constructs.Construct, id: string, props: BackendStackProps) {
15+
constructor(scope: Construct, id: string, props: BackendStackProps) {
1716
super(scope, id, props);
1817

1918
const isProd = props.environment === 'production';
@@ -82,7 +81,7 @@ export class BackendStack extends cdk.Stack {
8281
const userPool = cognito.UserPool.fromUserPoolId(
8382
this,
8483
`${appName}UserPool`,
85-
'ai-cognito-medical-reports-user-pool'
84+
'ai-cognito-medical-reports-user-pool',
8685
);
8786

8887
// Create a Cognito domain if it doesn't exist
@@ -165,7 +164,7 @@ export class BackendStack extends cdk.Stack {
165164
defaultAction: new elbv2_actions.AuthenticateCognitoAction({
166165
userPool,
167166
userPoolClient,
168-
userPoolDomain: userPoolDomain.domainName,
167+
userPoolDomain: userPoolDomain,
169168
next: elbv2.ListenerAction.forward([targetGroup]),
170169
onUnauthenticatedRequest: elbv2.UnauthenticatedAction.AUTHENTICATE,
171170
}),

backend/src/iac/simple-stack.test.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

backend/src/iac/simple-stack.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)