Skip to content

Commit 8159f9f

Browse files
authored
Feature/test cases (#8)
* Add legacy codebase * test: - Add repository test. - Update mongo schema to avoid returning "control" fields. - Add membership and periods json samples for testing. * Add MONGO_CONNECTION_STRING as an action env var * Remove env vars for MONGODB
1 parent 15ca116 commit 8159f9f

15 files changed

+258
-105
lines changed

.github/workflows/deploy.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Deploy application
22
env:
33
environment: ${{ github.ref_name == 'main' && 'development' || github.event.pull_request.base.ref }}
4+
MONGO_CONNECTION_STRING: ${{ secrets.MONGO_CONNECTION_STRING }}
45

56
on:
67
workflow_dispatch:

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
"express": "^5.1.0",
2121
"fastify": "^5.3.3",
2222
"fastify-decorators": "^3.16.1",
23-
"mongoose": "^8.14.3",
2423
"nodemon": "^3.1.10",
2524
"uuid": "^10.0.0"
2625
},
@@ -34,6 +33,7 @@
3433
"@types/bunyan": "^1.8.11",
3534
"@types/express": "^5.0.1",
3635
"@types/jest": "^29.5.12",
36+
"@types/mongoose": "^5.11.96",
3737
"@types/node": "^22.0.0",
3838
"@types/supertest": "^6.0.2",
3939
"@types/uuid": "^10.0.0",
@@ -42,6 +42,7 @@
4242
"jest": "^29.7.0",
4343
"jest-extended": "^4.0.2",
4444
"jest-md-dashboard": "^0.8.0",
45+
"mongoose": "^8.15.0",
4546
"supertest": "^7.0.0",
4647
"ts-jest": "^29.2.3",
4748
"ts-node": "^10.9.2",

src/modern/model/schemas/db/mongo/MembershipPeriodSchema.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,16 @@ export const membershipPeriodSchema = new Schema<MembershipPeriod>({
2020
end: { type: Date, required: true },
2121
state: { type: String, required: true }
2222
}, {
23-
timestamps: true
23+
timestamps: true,
24+
versionKey: false
25+
});
26+
27+
membershipPeriodSchema.set('toObject', {
28+
transform: function (doc, ret) {
29+
ret.id = ret._id
30+
delete ret._id
31+
delete ret.__v
32+
}
2433
});
2534

2635
export const MembershipPeriodSchema = mongoose.model('MembershipPeriod', membershipPeriodSchema);

src/modern/model/schemas/db/mongo/MembershipSchema.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const membershipSchema = new Schema<Membership>({
1616
id: { type: Number, required: true, unique: true },
1717
uuid: { type: String, required: true, minlength: 5 },
1818
name: { type: String, required: true, minlength: 5 },
19-
userId: { type: Number, required: true, unique: true },
19+
userId: { type: Number, required: true },
2020
recurringPrice: { type: Number, required: true },
2121
validFrom: { type: Date, required: true },
2222
validUntil: { type: Date, required: true },
@@ -26,7 +26,17 @@ export const membershipSchema = new Schema<Membership>({
2626
billingInterval: { type: String, required: true },
2727
billingPeriods: { type: Number, required: true }
2828
}, {
29-
timestamps: true
29+
timestamps: true,
30+
versionKey: false
3031
});
3132

33+
membershipSchema.set('toObject', {
34+
transform: function (doc, ret) {
35+
ret.id = ret._id
36+
delete ret._id
37+
delete ret.__v
38+
}
39+
});
40+
41+
3242
export const MembershipSchema = mongoose.model('Membership', membershipSchema);

src/modern/repository/MembershipRepository.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { BunyanLoggerFactory } from "../utils/factory/impl/BunyanLoggerFactory";
1717
*/
1818
export class MembershipRepository implements IMembershipRepository {
1919

20-
private readonly MODULE_NAME = 'MembershipRepository';
2120
private MONGO_DB_URI: string;
2221
private connection!: Mongoose;
2322
private connectionOptions = {
@@ -28,16 +27,13 @@ export class MembershipRepository implements IMembershipRepository {
2827
};
2928

3029
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31-
private logger: any = BunyanLoggerFactory.getInstance().createLogger({
32-
name: this.MODULE_NAME
33-
});
30+
private logger: any = BunyanLoggerFactory.getInstance().createLogger({ name: 'MembershipRepository' });
3431

3532
constructor() {
3633
this.MONGO_DB_URI = process.env.MONGO_CONNECTION_STRING || '';
3734
if (!this.MONGO_DB_URI) {
3835
throw new Error('MongoDB connection string is not configured');
3936
}
40-
this.connect();
4137
}
4238

4339
async connect() {
@@ -99,10 +95,13 @@ export class MembershipRepository implements IMembershipRepository {
9995
MembershipSchema.find({}, { _id: 0 }).lean(),
10096
MembershipPeriodSchema.find({}, { _id: 0 }).lean()
10197
]);
102-
98+
10399
return memberships.map(membership => ({
104100
membership,
105-
periods: periods.filter(period => period.membership === membership.id)
101+
periods: periods.filter(period => {
102+
//console.log(membership.id + " --- " + period.membership);
103+
return period.membership === membership.id
104+
})
106105
}));
107106
} catch (error) {
108107
this.logger.error("Failed to retrieve memberships", error);

src/modern/services/MembershipService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class MembershipService {
2121

2222
constructor() {
2323
this.membershipRepository = new MembershipRepository();
24+
this.membershipRepository.connect();
2425
}
2526

2627
/**
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { IMembershipRepository } from '../../src/modern/repository/interfaces/IMembershipRepository';
2+
import { MembershipRepository } from '../../src/modern/repository/MembershipRepository';
3+
import { MembershipSchema } from '../../src/modern/model/schemas/db/mongo/MembershipSchema';
4+
import { MembershipPeriodSchema } from '../../src/modern/model/schemas/db/mongo/MembershipPeriodSchema';
5+
import { membershipSchema } from '../schemas/MembershipSchema';
6+
import { loadTestJson } from './helpers/loadTestPayload.helper';
7+
import { Query } from 'mongoose';
8+
9+
/**
10+
* This test case validates the listed memberships (if exists).
11+
*/
12+
export const membershipRepositoryTestCase = () => {
13+
14+
let membershipRepository: IMembershipRepository;
15+
let allMemberships: Array<object>[];
16+
let allPeriods: Array<object>[];
17+
18+
beforeAll(async () => {
19+
allMemberships = loadTestJson(__dirname, 'allMemberships.json');
20+
allPeriods = loadTestJson(__dirname, 'allMembershipsPeriods.json');
21+
22+
membershipRepository = new MembershipRepository();
23+
const mockMembershipsQuery = {
24+
lean: jest.fn().mockResolvedValue(allMemberships),
25+
exec: jest.fn().mockResolvedValue(allMemberships),
26+
select: jest.fn().mockReturnThis()
27+
} as unknown as Query<typeof allMemberships, typeof allMemberships>;
28+
29+
const mockMembershipsPeriodQuery = {
30+
lean: jest.fn().mockResolvedValue(allPeriods),
31+
exec: jest.fn().mockResolvedValue(allPeriods),
32+
select: jest.fn().mockReturnThis()
33+
} as unknown as Query<typeof allPeriods, typeof allPeriods>;
34+
35+
jest.spyOn(MembershipSchema, 'find').mockReturnValue(mockMembershipsQuery);
36+
jest.spyOn(MembershipPeriodSchema, 'find').mockReturnValue(mockMembershipsPeriodQuery);
37+
38+
});
39+
40+
afterAll(async () => {
41+
jest.clearAllMocks();
42+
});
43+
44+
it('Should get all memberships', async () => {
45+
const allExistingMemberships = await membershipRepository.getAllMemberships();
46+
const expectedShape = membershipSchema;
47+
48+
allExistingMemberships.forEach(membership => {
49+
expect(membership).toEqual(expect.objectContaining(expectedShape));
50+
});
51+
52+
});
53+
54+
};

test/cases/membership.service.case.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import { membershipSchema } from '../schemas/MembershipSchema';
55
/**
66
* This test case validates the listed memberships (if exists).
77
*/
8-
export const membershipserviceTestCase = () => {
8+
export const membershipServiceTestCase = () => {
99

1010
let membershipService: MembershipService;
1111

12-
beforeAll(async () => {
12+
beforeAll(async () => {
1313
membershipService = new MembershipService();
1414
membershipService.membershipRepository = mockMembershipRepository;
1515
});
@@ -31,6 +31,5 @@ export const membershipserviceTestCase = () => {
3131
allExistingMemberships.forEach(membership => {
3232
expect(membership).toEqual(expect.objectContaining(expectedShape));
3333
});
34-
//TODO: Validar si falta el nombre o algo adicional que no valida el membershipvalidator
3534
});
3635
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[
2+
{
3+
"id": 1,
4+
"uuid": "123e4567-e89b-12d3-a456-426614174000",
5+
"name": "Platinum Plan",
6+
"userId": 2000,
7+
"recurringPrice": 150,
8+
"validFrom": "2023-01-01T00:00:00.000Z",
9+
"validUntil": "2023-12-31T00:00:00.000Z",
10+
"state": "active",
11+
"assignedBy": "Admin",
12+
"paymentMethod": "credit card",
13+
"billingInterval": "monthly",
14+
"billingPeriods": 12
15+
},
16+
{
17+
"id": 2,
18+
"uuid": "123e4567-e89b-12d3-a456-426614174001",
19+
"name": "Gold Plan",
20+
"userId": 2000,
21+
"recurringPrice": 100,
22+
"validFrom": "2023-02-01T00:00:00.000Z",
23+
"validUntil": "2023-12-31T00:00:00.000Z",
24+
"state": "active",
25+
"assignedBy": "Admin",
26+
"paymentMethod": "cash",
27+
"billingInterval": "monthly",
28+
"billingPeriods": 2
29+
},
30+
{
31+
"id": 3,
32+
"uuid": "123e4567-e89b-12d3-a456-426614174002",
33+
"name": "Gold Plan",
34+
"userId": 2000,
35+
"recurringPrice": 100,
36+
"validFrom": "2023-02-01T00:00:00.000Z",
37+
"validUntil": "2023-12-31T00:00:00.000Z",
38+
"state": "active",
39+
"assignedBy": "Admin",
40+
"paymentMethod": null,
41+
"billingInterval": "monthly",
42+
"billingPeriods": 6
43+
}
44+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"id": 1,
4+
"uuid": "123e4567-e89b-12d3-a456-426614174000",
5+
"membership": 1,
6+
"start": "2023-01-01T00:00:00.000Z",
7+
"end": "2023-01-31T00:00:00.000Z",
8+
"state": "issued"
9+
},
10+
{
11+
"id": 2,
12+
"uuid": "123e4567-e89b-12d3-a456-426614174001",
13+
"membership": 2,
14+
"start": "2023-02-01T00:00:00.000Z",
15+
"end": "2023-02-28T00:00:00.000Z",
16+
"state": "issued"
17+
},
18+
{
19+
"id": 3,
20+
"uuid": "123e4567-e89b-12d3-a456-426614174002",
21+
"membership": 3,
22+
"start": "2023-03-01T00:00:00.000Z",
23+
"end": "2023-03-31T00:00:00.000Z",
24+
"state": "issued"
25+
}
26+
]
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
[
2+
{
3+
"membership": {
4+
"id": 1,
5+
"uuid": "123e4567-e89b-12d3-a456-426614174000",
6+
"name": "Platinum Plan",
7+
"userId": 2000,
8+
"recurringPrice": 150,
9+
"validFrom": "2023-01-01",
10+
"validUntil": "2023-12-31",
11+
"state": "active",
12+
"assignedBy": "Admin",
13+
"paymentMethod": "credit card",
14+
"billingInterval": "monthly",
15+
"billingPeriods": 12
16+
},
17+
"periods": [
18+
{
19+
"id": 1,
20+
"uuid": "123e4567-e89b-12d3-a456-426614174000",
21+
"membership": 1,
22+
"start": "2023-01-01",
23+
"end": "2023-01-31",
24+
"state": "issued"
25+
}
26+
]
27+
},
28+
{
29+
"membership": {
30+
"id": 2,
31+
"uuid": "123e4567-e89b-12d3-a456-426614174001",
32+
"name": "Gold Plan",
33+
"userId": 2000,
34+
"recurringPrice": 100,
35+
"validFrom": "2023-02-01",
36+
"validUntil": "2023-12-31",
37+
"state": "active",
38+
"assignedBy": "Admin",
39+
"paymentMethod": "cash",
40+
"billingInterval": "monthly",
41+
"billingPeriods": 2
42+
},
43+
"periods": [
44+
{
45+
"id": 2,
46+
"uuid": "123e4567-e89b-12d3-a456-426614174001",
47+
"membership": 2,
48+
"start": "2023-02-01",
49+
"end": "2023-02-28",
50+
"state": "issued"
51+
}
52+
]
53+
},
54+
{
55+
"membership": {
56+
"id": 3,
57+
"uuid": "123e4567-e89b-12d3-a456-426614174002",
58+
"name": "Gold Plan",
59+
"userId": 2000,
60+
"recurringPrice": 100,
61+
"validFrom": "2023-02-01",
62+
"validUntil": "2023-12-31",
63+
"state": "active",
64+
"assignedBy": "Admin",
65+
"paymentMethod": null,
66+
"billingInterval": "monthly",
67+
"billingPeriods": 6
68+
},
69+
"periods": [
70+
{
71+
"id": 3,
72+
"uuid": "123e4567-e89b-12d3-a456-426614174002",
73+
"membership": 3,
74+
"start": "2023-03-01",
75+
"end": "2023-03-31",
76+
"state": "issued"
77+
}
78+
]
79+
}
80+
]

test/main.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { appTest } from './cases/app.case';
22
import { membershipControllerTestCase } from './cases/membership.controller.case';
3-
import { membershipserviceTestCase } from './cases/membership.service.case';
43
import { membershipCreationValidatorTestCase } from './cases/membership.validator.case';
4+
import { membershipRepositoryTestCase } from './cases/membership.repository.case';
55

6-
//describe('Test app startup', appTest);
7-
//describe('Test membership controller', membershipControllerTestCase);
8-
//describe('Test membership service', membershipserviceTestCase)
6+
describe('Test app startup', appTest);
7+
describe('Test membership controller', membershipControllerTestCase);
8+
describe('Test membership repository', membershipRepositoryTestCase);
99
describe('Test membership creation rules', membershipCreationValidatorTestCase);

0 commit comments

Comments
 (0)