fix preprod
Some checks failed
CD Preprod / Backend — Lint (push) Successful in 10m27s
CD Preprod / Frontend — Lint & Type-check (push) Successful in 10m55s
CD Preprod / Backend — Unit Tests (push) Successful in 10m10s
CD Preprod / Frontend — Unit Tests (push) Successful in 10m33s
CD Preprod / Backend — Integration Tests (push) Successful in 10m6s
CD Preprod / Build Backend (push) Successful in 16m5s
CD Preprod / Build Frontend (push) Successful in 35m0s
CD Preprod / Deploy to Preprod (push) Failing after 1s
CD Preprod / Smoke Tests (push) Has been skipped
CD Preprod / Notify Success (push) Has been skipped
CD Preprod / Notify Failure (push) Has been skipped
Some checks failed
CD Preprod / Backend — Lint (push) Successful in 10m27s
CD Preprod / Frontend — Lint & Type-check (push) Successful in 10m55s
CD Preprod / Backend — Unit Tests (push) Successful in 10m10s
CD Preprod / Frontend — Unit Tests (push) Successful in 10m33s
CD Preprod / Backend — Integration Tests (push) Successful in 10m6s
CD Preprod / Build Backend (push) Successful in 16m5s
CD Preprod / Build Frontend (push) Successful in 35m0s
CD Preprod / Deploy to Preprod (push) Failing after 1s
CD Preprod / Smoke Tests (push) Has been skipped
CD Preprod / Notify Success (push) Has been skipped
CD Preprod / Notify Failure (push) Has been skipped
This commit is contained in:
parent
fe7cd1f792
commit
72141c5f68
@ -21,12 +21,12 @@ describe('Subscription Entity', () => {
|
||||
};
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a subscription with default FREE plan', () => {
|
||||
it('should create a subscription with default BRONZE plan', () => {
|
||||
const subscription = createValidSubscription();
|
||||
|
||||
expect(subscription.id).toBe('sub-123');
|
||||
expect(subscription.organizationId).toBe('org-123');
|
||||
expect(subscription.plan.value).toBe('FREE');
|
||||
expect(subscription.plan.value).toBe('BRONZE');
|
||||
expect(subscription.status.value).toBe('ACTIVE');
|
||||
expect(subscription.cancelAtPeriodEnd).toBe(false);
|
||||
});
|
||||
@ -35,10 +35,10 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.starter(),
|
||||
plan: SubscriptionPlan.silver(),
|
||||
});
|
||||
|
||||
expect(subscription.plan.value).toBe('STARTER');
|
||||
expect(subscription.plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should create a subscription with Stripe IDs', () => {
|
||||
@ -59,7 +59,7 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.fromPersistence({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: 'PRO',
|
||||
plan: 'GOLD',
|
||||
status: 'ACTIVE',
|
||||
stripeCustomerId: 'cus_123',
|
||||
stripeSubscriptionId: 'sub_stripe_123',
|
||||
@ -71,57 +71,57 @@ describe('Subscription Entity', () => {
|
||||
});
|
||||
|
||||
expect(subscription.id).toBe('sub-123');
|
||||
expect(subscription.plan.value).toBe('PRO');
|
||||
expect(subscription.plan.value).toBe('GOLD');
|
||||
expect(subscription.status.value).toBe('ACTIVE');
|
||||
expect(subscription.cancelAtPeriodEnd).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maxLicenses', () => {
|
||||
it('should return correct limits for FREE plan', () => {
|
||||
it('should return correct limits for BRONZE plan', () => {
|
||||
const subscription = createValidSubscription();
|
||||
expect(subscription.maxLicenses).toBe(2);
|
||||
expect(subscription.maxLicenses).toBe(1);
|
||||
});
|
||||
|
||||
it('should return correct limits for STARTER plan', () => {
|
||||
it('should return correct limits for SILVER plan', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.starter(),
|
||||
plan: SubscriptionPlan.silver(),
|
||||
});
|
||||
expect(subscription.maxLicenses).toBe(5);
|
||||
});
|
||||
|
||||
it('should return correct limits for PRO plan', () => {
|
||||
it('should return correct limits for GOLD plan', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.pro(),
|
||||
plan: SubscriptionPlan.gold(),
|
||||
});
|
||||
expect(subscription.maxLicenses).toBe(20);
|
||||
});
|
||||
|
||||
it('should return -1 for ENTERPRISE plan (unlimited)', () => {
|
||||
it('should return -1 for PLATINIUM plan (unlimited)', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.enterprise(),
|
||||
plan: SubscriptionPlan.platinium(),
|
||||
});
|
||||
expect(subscription.maxLicenses).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUnlimited', () => {
|
||||
it('should return false for FREE plan', () => {
|
||||
it('should return false for BRONZE plan', () => {
|
||||
const subscription = createValidSubscription();
|
||||
expect(subscription.isUnlimited()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for ENTERPRISE plan', () => {
|
||||
it('should return true for PLATINIUM plan', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.enterprise(),
|
||||
plan: SubscriptionPlan.platinium(),
|
||||
});
|
||||
expect(subscription.isUnlimited()).toBe(true);
|
||||
});
|
||||
@ -137,7 +137,7 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.fromPersistence({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: 'FREE',
|
||||
plan: 'BRONZE',
|
||||
status: 'TRIALING',
|
||||
stripeCustomerId: null,
|
||||
stripeSubscriptionId: null,
|
||||
@ -154,7 +154,7 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.fromPersistence({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: 'FREE',
|
||||
plan: 'BRONZE',
|
||||
status: 'CANCELED',
|
||||
stripeCustomerId: null,
|
||||
stripeSubscriptionId: null,
|
||||
@ -170,21 +170,20 @@ describe('Subscription Entity', () => {
|
||||
|
||||
describe('canAllocateLicenses', () => {
|
||||
it('should return true when licenses are available', () => {
|
||||
const subscription = createValidSubscription();
|
||||
const subscription = createValidSubscription(); // BRONZE = 1 license
|
||||
expect(subscription.canAllocateLicenses(0, 1)).toBe(true);
|
||||
expect(subscription.canAllocateLicenses(1, 1)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when no licenses available', () => {
|
||||
const subscription = createValidSubscription();
|
||||
expect(subscription.canAllocateLicenses(2, 1)).toBe(false); // FREE has 2 licenses
|
||||
expect(subscription.canAllocateLicenses(1, 1)).toBe(false); // BRONZE has 1 license max
|
||||
});
|
||||
|
||||
it('should always return true for ENTERPRISE plan', () => {
|
||||
it('should always return true for PLATINIUM plan', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.enterprise(),
|
||||
plan: SubscriptionPlan.platinium(),
|
||||
});
|
||||
expect(subscription.canAllocateLicenses(1000, 100)).toBe(true);
|
||||
});
|
||||
@ -193,7 +192,7 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.fromPersistence({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: 'FREE',
|
||||
plan: 'BRONZE',
|
||||
status: 'CANCELED',
|
||||
stripeCustomerId: null,
|
||||
stripeSubscriptionId: null,
|
||||
@ -208,23 +207,23 @@ describe('Subscription Entity', () => {
|
||||
});
|
||||
|
||||
describe('canUpgradeTo', () => {
|
||||
it('should allow upgrade from FREE to STARTER', () => {
|
||||
it('should allow upgrade from BRONZE to SILVER', () => {
|
||||
const subscription = createValidSubscription();
|
||||
expect(subscription.canUpgradeTo(SubscriptionPlan.starter())).toBe(true);
|
||||
expect(subscription.canUpgradeTo(SubscriptionPlan.silver())).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow upgrade from FREE to PRO', () => {
|
||||
it('should allow upgrade from BRONZE to GOLD', () => {
|
||||
const subscription = createValidSubscription();
|
||||
expect(subscription.canUpgradeTo(SubscriptionPlan.pro())).toBe(true);
|
||||
expect(subscription.canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
|
||||
});
|
||||
|
||||
it('should not allow downgrade via canUpgradeTo', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.starter(),
|
||||
plan: SubscriptionPlan.silver(),
|
||||
});
|
||||
expect(subscription.canUpgradeTo(SubscriptionPlan.free())).toBe(false);
|
||||
expect(subscription.canUpgradeTo(SubscriptionPlan.bronze())).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -233,34 +232,34 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.starter(),
|
||||
plan: SubscriptionPlan.silver(),
|
||||
});
|
||||
expect(subscription.canDowngradeTo(SubscriptionPlan.free(), 1)).toBe(true);
|
||||
expect(subscription.canDowngradeTo(SubscriptionPlan.bronze(), 1)).toBe(true);
|
||||
});
|
||||
|
||||
it('should prevent downgrade when user count exceeds new plan', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.starter(),
|
||||
plan: SubscriptionPlan.silver(),
|
||||
});
|
||||
expect(subscription.canDowngradeTo(SubscriptionPlan.free(), 5)).toBe(false);
|
||||
expect(subscription.canDowngradeTo(SubscriptionPlan.bronze(), 5)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updatePlan', () => {
|
||||
it('should update to new plan when valid', () => {
|
||||
const subscription = createValidSubscription();
|
||||
const updated = subscription.updatePlan(SubscriptionPlan.starter(), 1);
|
||||
const updated = subscription.updatePlan(SubscriptionPlan.silver(), 1);
|
||||
|
||||
expect(updated.plan.value).toBe('STARTER');
|
||||
expect(updated.plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should throw when subscription is not active', () => {
|
||||
const subscription = Subscription.fromPersistence({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: 'FREE',
|
||||
plan: 'BRONZE',
|
||||
status: 'CANCELED',
|
||||
stripeCustomerId: null,
|
||||
stripeSubscriptionId: null,
|
||||
@ -271,7 +270,7 @@ describe('Subscription Entity', () => {
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
expect(() => subscription.updatePlan(SubscriptionPlan.starter(), 0)).toThrow(
|
||||
expect(() => subscription.updatePlan(SubscriptionPlan.silver(), 0)).toThrow(
|
||||
SubscriptionNotActiveException
|
||||
);
|
||||
});
|
||||
@ -280,10 +279,10 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.pro(),
|
||||
plan: SubscriptionPlan.gold(),
|
||||
});
|
||||
|
||||
expect(() => subscription.updatePlan(SubscriptionPlan.starter(), 10)).toThrow(
|
||||
expect(() => subscription.updatePlan(SubscriptionPlan.silver(), 10)).toThrow(
|
||||
InvalidSubscriptionDowngradeException
|
||||
);
|
||||
});
|
||||
@ -341,7 +340,7 @@ describe('Subscription Entity', () => {
|
||||
const subscription = Subscription.fromPersistence({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: 'STARTER',
|
||||
plan: 'SILVER',
|
||||
status: 'ACTIVE',
|
||||
stripeCustomerId: 'cus_123',
|
||||
stripeSubscriptionId: 'sub_123',
|
||||
@ -368,17 +367,17 @@ describe('Subscription Entity', () => {
|
||||
});
|
||||
|
||||
describe('isFree and isPaid', () => {
|
||||
it('should return true for isFree when FREE plan', () => {
|
||||
it('should return true for isFree when BRONZE plan', () => {
|
||||
const subscription = createValidSubscription();
|
||||
expect(subscription.isFree()).toBe(true);
|
||||
expect(subscription.isPaid()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for isPaid when STARTER plan', () => {
|
||||
it('should return true for isPaid when SILVER plan', () => {
|
||||
const subscription = Subscription.create({
|
||||
id: 'sub-123',
|
||||
organizationId: 'org-123',
|
||||
plan: SubscriptionPlan.starter(),
|
||||
plan: SubscriptionPlan.silver(),
|
||||
});
|
||||
expect(subscription.isFree()).toBe(false);
|
||||
expect(subscription.isPaid()).toBe(true);
|
||||
@ -397,7 +396,7 @@ describe('Subscription Entity', () => {
|
||||
|
||||
expect(obj.id).toBe('sub-123');
|
||||
expect(obj.organizationId).toBe('org-123');
|
||||
expect(obj.plan).toBe('FREE');
|
||||
expect(obj.plan).toBe('BRONZE');
|
||||
expect(obj.status).toBe('ACTIVE');
|
||||
expect(obj.stripeCustomerId).toBe('cus_123');
|
||||
});
|
||||
|
||||
@ -8,31 +8,56 @@ import { SubscriptionPlan } from './subscription-plan.vo';
|
||||
|
||||
describe('SubscriptionPlan Value Object', () => {
|
||||
describe('static factory methods', () => {
|
||||
it('should create FREE plan', () => {
|
||||
it('should create BRONZE plan via bronze()', () => {
|
||||
const plan = SubscriptionPlan.bronze();
|
||||
expect(plan.value).toBe('BRONZE');
|
||||
});
|
||||
|
||||
it('should create SILVER plan via silver()', () => {
|
||||
const plan = SubscriptionPlan.silver();
|
||||
expect(plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should create GOLD plan via gold()', () => {
|
||||
const plan = SubscriptionPlan.gold();
|
||||
expect(plan.value).toBe('GOLD');
|
||||
});
|
||||
|
||||
it('should create PLATINIUM plan via platinium()', () => {
|
||||
const plan = SubscriptionPlan.platinium();
|
||||
expect(plan.value).toBe('PLATINIUM');
|
||||
});
|
||||
|
||||
it('should create BRONZE plan via free() alias', () => {
|
||||
const plan = SubscriptionPlan.free();
|
||||
expect(plan.value).toBe('FREE');
|
||||
expect(plan.value).toBe('BRONZE');
|
||||
});
|
||||
|
||||
it('should create STARTER plan', () => {
|
||||
it('should create SILVER plan via starter() alias', () => {
|
||||
const plan = SubscriptionPlan.starter();
|
||||
expect(plan.value).toBe('STARTER');
|
||||
expect(plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should create PRO plan', () => {
|
||||
it('should create GOLD plan via pro() alias', () => {
|
||||
const plan = SubscriptionPlan.pro();
|
||||
expect(plan.value).toBe('PRO');
|
||||
expect(plan.value).toBe('GOLD');
|
||||
});
|
||||
|
||||
it('should create ENTERPRISE plan', () => {
|
||||
it('should create PLATINIUM plan via enterprise() alias', () => {
|
||||
const plan = SubscriptionPlan.enterprise();
|
||||
expect(plan.value).toBe('ENTERPRISE');
|
||||
expect(plan.value).toBe('PLATINIUM');
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should create plan from valid type', () => {
|
||||
const plan = SubscriptionPlan.create('STARTER');
|
||||
expect(plan.value).toBe('STARTER');
|
||||
it('should create plan from valid type SILVER', () => {
|
||||
const plan = SubscriptionPlan.create('SILVER');
|
||||
expect(plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should create plan from valid type BRONZE', () => {
|
||||
const plan = SubscriptionPlan.create('BRONZE');
|
||||
expect(plan.value).toBe('BRONZE');
|
||||
});
|
||||
|
||||
it('should throw for invalid plan type', () => {
|
||||
@ -41,9 +66,29 @@ describe('SubscriptionPlan Value Object', () => {
|
||||
});
|
||||
|
||||
describe('fromString', () => {
|
||||
it('should create plan from lowercase string', () => {
|
||||
it('should create SILVER from lowercase "silver"', () => {
|
||||
const plan = SubscriptionPlan.fromString('silver');
|
||||
expect(plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should map legacy "starter" to SILVER', () => {
|
||||
const plan = SubscriptionPlan.fromString('starter');
|
||||
expect(plan.value).toBe('STARTER');
|
||||
expect(plan.value).toBe('SILVER');
|
||||
});
|
||||
|
||||
it('should map legacy "free" to BRONZE', () => {
|
||||
const plan = SubscriptionPlan.fromString('free');
|
||||
expect(plan.value).toBe('BRONZE');
|
||||
});
|
||||
|
||||
it('should map legacy "pro" to GOLD', () => {
|
||||
const plan = SubscriptionPlan.fromString('pro');
|
||||
expect(plan.value).toBe('GOLD');
|
||||
});
|
||||
|
||||
it('should map legacy "enterprise" to PLATINIUM', () => {
|
||||
const plan = SubscriptionPlan.fromString('enterprise');
|
||||
expect(plan.value).toBe('PLATINIUM');
|
||||
});
|
||||
|
||||
it('should throw for invalid string', () => {
|
||||
@ -52,146 +97,150 @@ describe('SubscriptionPlan Value Object', () => {
|
||||
});
|
||||
|
||||
describe('maxLicenses', () => {
|
||||
it('should return 2 for FREE plan', () => {
|
||||
const plan = SubscriptionPlan.free();
|
||||
expect(plan.maxLicenses).toBe(2);
|
||||
it('should return 1 for BRONZE plan', () => {
|
||||
const plan = SubscriptionPlan.bronze();
|
||||
expect(plan.maxLicenses).toBe(1);
|
||||
});
|
||||
|
||||
it('should return 5 for STARTER plan', () => {
|
||||
const plan = SubscriptionPlan.starter();
|
||||
it('should return 5 for SILVER plan', () => {
|
||||
const plan = SubscriptionPlan.silver();
|
||||
expect(plan.maxLicenses).toBe(5);
|
||||
});
|
||||
|
||||
it('should return 20 for PRO plan', () => {
|
||||
const plan = SubscriptionPlan.pro();
|
||||
it('should return 20 for GOLD plan', () => {
|
||||
const plan = SubscriptionPlan.gold();
|
||||
expect(plan.maxLicenses).toBe(20);
|
||||
});
|
||||
|
||||
it('should return -1 (unlimited) for ENTERPRISE plan', () => {
|
||||
const plan = SubscriptionPlan.enterprise();
|
||||
it('should return -1 (unlimited) for PLATINIUM plan', () => {
|
||||
const plan = SubscriptionPlan.platinium();
|
||||
expect(plan.maxLicenses).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUnlimited', () => {
|
||||
it('should return false for FREE plan', () => {
|
||||
expect(SubscriptionPlan.free().isUnlimited()).toBe(false);
|
||||
it('should return false for BRONZE plan', () => {
|
||||
expect(SubscriptionPlan.bronze().isUnlimited()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for STARTER plan', () => {
|
||||
expect(SubscriptionPlan.starter().isUnlimited()).toBe(false);
|
||||
it('should return false for SILVER plan', () => {
|
||||
expect(SubscriptionPlan.silver().isUnlimited()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for PRO plan', () => {
|
||||
expect(SubscriptionPlan.pro().isUnlimited()).toBe(false);
|
||||
it('should return false for GOLD plan', () => {
|
||||
expect(SubscriptionPlan.gold().isUnlimited()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for ENTERPRISE plan', () => {
|
||||
expect(SubscriptionPlan.enterprise().isUnlimited()).toBe(true);
|
||||
it('should return true for PLATINIUM plan', () => {
|
||||
expect(SubscriptionPlan.platinium().isUnlimited()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPaid', () => {
|
||||
it('should return false for FREE plan', () => {
|
||||
expect(SubscriptionPlan.free().isPaid()).toBe(false);
|
||||
it('should return false for BRONZE plan', () => {
|
||||
expect(SubscriptionPlan.bronze().isPaid()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for STARTER plan', () => {
|
||||
expect(SubscriptionPlan.starter().isPaid()).toBe(true);
|
||||
it('should return true for SILVER plan', () => {
|
||||
expect(SubscriptionPlan.silver().isPaid()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for PRO plan', () => {
|
||||
expect(SubscriptionPlan.pro().isPaid()).toBe(true);
|
||||
it('should return true for GOLD plan', () => {
|
||||
expect(SubscriptionPlan.gold().isPaid()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for ENTERPRISE plan', () => {
|
||||
expect(SubscriptionPlan.enterprise().isPaid()).toBe(true);
|
||||
it('should return true for PLATINIUM plan', () => {
|
||||
expect(SubscriptionPlan.platinium().isPaid()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFree', () => {
|
||||
it('should return true for FREE plan', () => {
|
||||
expect(SubscriptionPlan.free().isFree()).toBe(true);
|
||||
it('should return true for BRONZE plan', () => {
|
||||
expect(SubscriptionPlan.bronze().isFree()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for STARTER plan', () => {
|
||||
expect(SubscriptionPlan.starter().isFree()).toBe(false);
|
||||
it('should return false for SILVER plan', () => {
|
||||
expect(SubscriptionPlan.silver().isFree()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canAccommodateUsers', () => {
|
||||
it('should return true for FREE plan with 2 users', () => {
|
||||
expect(SubscriptionPlan.free().canAccommodateUsers(2)).toBe(true);
|
||||
it('should return true for BRONZE plan with 1 user', () => {
|
||||
expect(SubscriptionPlan.bronze().canAccommodateUsers(1)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for FREE plan with 3 users', () => {
|
||||
expect(SubscriptionPlan.free().canAccommodateUsers(3)).toBe(false);
|
||||
it('should return false for BRONZE plan with 2 users', () => {
|
||||
expect(SubscriptionPlan.bronze().canAccommodateUsers(2)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for STARTER plan with 5 users', () => {
|
||||
expect(SubscriptionPlan.starter().canAccommodateUsers(5)).toBe(true);
|
||||
it('should return true for SILVER plan with 5 users', () => {
|
||||
expect(SubscriptionPlan.silver().canAccommodateUsers(5)).toBe(true);
|
||||
});
|
||||
|
||||
it('should always return true for ENTERPRISE plan', () => {
|
||||
expect(SubscriptionPlan.enterprise().canAccommodateUsers(1000)).toBe(true);
|
||||
it('should always return true for PLATINIUM plan', () => {
|
||||
expect(SubscriptionPlan.platinium().canAccommodateUsers(1000)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canUpgradeTo', () => {
|
||||
it('should allow upgrade from FREE to STARTER', () => {
|
||||
expect(SubscriptionPlan.free().canUpgradeTo(SubscriptionPlan.starter())).toBe(true);
|
||||
it('should allow upgrade from BRONZE to SILVER', () => {
|
||||
expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.silver())).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow upgrade from FREE to PRO', () => {
|
||||
expect(SubscriptionPlan.free().canUpgradeTo(SubscriptionPlan.pro())).toBe(true);
|
||||
it('should allow upgrade from BRONZE to GOLD', () => {
|
||||
expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow upgrade from FREE to ENTERPRISE', () => {
|
||||
expect(SubscriptionPlan.free().canUpgradeTo(SubscriptionPlan.enterprise())).toBe(true);
|
||||
it('should allow upgrade from BRONZE to PLATINIUM', () => {
|
||||
expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.platinium())).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow upgrade from STARTER to PRO', () => {
|
||||
expect(SubscriptionPlan.starter().canUpgradeTo(SubscriptionPlan.pro())).toBe(true);
|
||||
it('should allow upgrade from SILVER to GOLD', () => {
|
||||
expect(SubscriptionPlan.silver().canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
|
||||
});
|
||||
|
||||
it('should not allow downgrade from STARTER to FREE', () => {
|
||||
expect(SubscriptionPlan.starter().canUpgradeTo(SubscriptionPlan.free())).toBe(false);
|
||||
it('should not allow downgrade from SILVER to BRONZE', () => {
|
||||
expect(SubscriptionPlan.silver().canUpgradeTo(SubscriptionPlan.bronze())).toBe(false);
|
||||
});
|
||||
|
||||
it('should not allow same plan upgrade', () => {
|
||||
expect(SubscriptionPlan.pro().canUpgradeTo(SubscriptionPlan.pro())).toBe(false);
|
||||
expect(SubscriptionPlan.gold().canUpgradeTo(SubscriptionPlan.gold())).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canDowngradeTo', () => {
|
||||
it('should allow downgrade from STARTER to FREE when users fit', () => {
|
||||
expect(SubscriptionPlan.starter().canDowngradeTo(SubscriptionPlan.free(), 1)).toBe(true);
|
||||
it('should allow downgrade from SILVER to BRONZE when users fit', () => {
|
||||
expect(SubscriptionPlan.silver().canDowngradeTo(SubscriptionPlan.bronze(), 1)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not allow downgrade from STARTER to FREE when users exceed', () => {
|
||||
expect(SubscriptionPlan.starter().canDowngradeTo(SubscriptionPlan.free(), 5)).toBe(false);
|
||||
it('should not allow downgrade from SILVER to BRONZE when users exceed', () => {
|
||||
expect(SubscriptionPlan.silver().canDowngradeTo(SubscriptionPlan.bronze(), 5)).toBe(false);
|
||||
});
|
||||
|
||||
it('should not allow upgrade via canDowngradeTo', () => {
|
||||
expect(SubscriptionPlan.free().canDowngradeTo(SubscriptionPlan.starter(), 1)).toBe(false);
|
||||
expect(SubscriptionPlan.bronze().canDowngradeTo(SubscriptionPlan.silver(), 1)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('plan details', () => {
|
||||
it('should return correct name for FREE plan', () => {
|
||||
expect(SubscriptionPlan.free().name).toBe('Free');
|
||||
it('should return correct name for BRONZE plan', () => {
|
||||
expect(SubscriptionPlan.bronze().name).toBe('Bronze');
|
||||
});
|
||||
|
||||
it('should return correct prices for STARTER plan', () => {
|
||||
const plan = SubscriptionPlan.starter();
|
||||
expect(plan.monthlyPriceEur).toBe(49);
|
||||
expect(plan.yearlyPriceEur).toBe(470);
|
||||
it('should return correct name for SILVER plan', () => {
|
||||
expect(SubscriptionPlan.silver().name).toBe('Silver');
|
||||
});
|
||||
|
||||
it('should return features for PRO plan', () => {
|
||||
const plan = SubscriptionPlan.pro();
|
||||
expect(plan.features).toContain('Up to 20 users');
|
||||
expect(plan.features).toContain('API access');
|
||||
it('should return correct prices for SILVER plan', () => {
|
||||
const plan = SubscriptionPlan.silver();
|
||||
expect(plan.monthlyPriceEur).toBe(249);
|
||||
expect(plan.yearlyPriceEur).toBe(2739);
|
||||
});
|
||||
|
||||
it('should return features for GOLD plan', () => {
|
||||
const plan = SubscriptionPlan.gold();
|
||||
expect(plan.features).toContain("Jusqu'à 20 utilisateurs");
|
||||
expect(plan.features).toContain('Intégration API');
|
||||
});
|
||||
});
|
||||
|
||||
@ -200,24 +249,24 @@ describe('SubscriptionPlan Value Object', () => {
|
||||
const plans = SubscriptionPlan.getAllPlans();
|
||||
|
||||
expect(plans).toHaveLength(4);
|
||||
expect(plans.map(p => p.value)).toEqual(['FREE', 'STARTER', 'PRO', 'ENTERPRISE']);
|
||||
expect(plans.map(p => p.value)).toEqual(['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('equals', () => {
|
||||
it('should return true for same plan', () => {
|
||||
expect(SubscriptionPlan.free().equals(SubscriptionPlan.free())).toBe(true);
|
||||
expect(SubscriptionPlan.bronze().equals(SubscriptionPlan.bronze())).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for different plans', () => {
|
||||
expect(SubscriptionPlan.free().equals(SubscriptionPlan.starter())).toBe(false);
|
||||
expect(SubscriptionPlan.bronze().equals(SubscriptionPlan.silver())).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toString', () => {
|
||||
it('should return plan value as string', () => {
|
||||
expect(SubscriptionPlan.free().toString()).toBe('FREE');
|
||||
expect(SubscriptionPlan.starter().toString()).toBe('STARTER');
|
||||
expect(SubscriptionPlan.bronze().toString()).toBe('BRONZE');
|
||||
expect(SubscriptionPlan.silver().toString()).toBe('SILVER');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -55,7 +55,7 @@ const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
|
||||
name: 'Silver',
|
||||
maxLicenses: 5,
|
||||
monthlyPriceEur: 249,
|
||||
yearlyPriceEur: 2739, // 249 * 11 months
|
||||
yearlyPriceEur: 2739,
|
||||
maxShipmentsPerYear: -1,
|
||||
commissionRatePercent: 3,
|
||||
statusBadge: 'silver',
|
||||
@ -75,7 +75,7 @@ const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
|
||||
name: 'Gold',
|
||||
maxLicenses: 20,
|
||||
monthlyPriceEur: 899,
|
||||
yearlyPriceEur: 9889, // 899 * 11 months
|
||||
yearlyPriceEur: 9889,
|
||||
maxShipmentsPerYear: -1,
|
||||
commissionRatePercent: 2,
|
||||
statusBadge: 'gold',
|
||||
@ -225,59 +225,35 @@ export class SubscriptionPlan {
|
||||
return PLAN_DETAILS[this.plan].planFeatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this plan includes a specific feature
|
||||
*/
|
||||
hasFeature(feature: PlanFeature): boolean {
|
||||
return this.planFeatures.includes(feature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this plan has unlimited licenses
|
||||
*/
|
||||
isUnlimited(): boolean {
|
||||
return this.maxLicenses === -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this plan has unlimited shipments
|
||||
*/
|
||||
hasUnlimitedShipments(): boolean {
|
||||
return this.maxShipmentsPerYear === -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a paid plan
|
||||
*/
|
||||
isPaid(): boolean {
|
||||
return this.plan !== 'BRONZE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is the free (Bronze) plan
|
||||
*/
|
||||
isFree(): boolean {
|
||||
return this.plan === 'BRONZE';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this plan has custom pricing (Platinium)
|
||||
*/
|
||||
isCustomPricing(): boolean {
|
||||
return this.plan === 'PLATINIUM';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given number of users can be accommodated by this plan
|
||||
*/
|
||||
canAccommodateUsers(userCount: number): boolean {
|
||||
if (this.isUnlimited()) return true;
|
||||
return userCount <= this.maxLicenses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if upgrade to target plan is allowed
|
||||
*/
|
||||
canUpgradeTo(targetPlan: SubscriptionPlan): boolean {
|
||||
const planOrder: SubscriptionPlanType[] = ['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'];
|
||||
const currentIndex = planOrder.indexOf(this.plan);
|
||||
@ -285,15 +261,12 @@ export class SubscriptionPlan {
|
||||
return targetIndex > currentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if downgrade to target plan is allowed given current user count
|
||||
*/
|
||||
canDowngradeTo(targetPlan: SubscriptionPlan, currentUserCount: number): boolean {
|
||||
const planOrder: SubscriptionPlanType[] = ['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'];
|
||||
const currentIndex = planOrder.indexOf(this.plan);
|
||||
const targetIndex = planOrder.indexOf(targetPlan.value);
|
||||
|
||||
if (targetIndex >= currentIndex) return false; // Not a downgrade
|
||||
if (targetIndex >= currentIndex) return false;
|
||||
return targetPlan.canAccommodateUsers(currentUserCount);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user