Skip to content

Commit

Permalink
refactor: extract business rules
Browse files Browse the repository at this point in the history
  • Loading branch information
collettemathieu committed Oct 17, 2024
1 parent 8477301 commit fd28269
Show file tree
Hide file tree
Showing 23 changed files with 259 additions and 148 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { PDCBPR_titleRules } from './lib/title/title.rules';
export { pDCBPRDescriptionRules } from './lib/description/description.rules';
export { pDCBPRPathwayIdRules } from './lib/pathway-id/pathway-id.rules';
export { pDCBPRResearchFieldRules } from './lib/research-field/research-field.rules';
export { pDCBPRTitleRules } from './lib/title/title.rules';
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Rules } from '../types';

export const pDCBPRDescriptionRules: Rules<string | null | undefined> = {
isValid: function (value) {
return (
value !== undefined &&
value !== null &&
value.trim().length !== 0 &&
value.trim().length >= this.minLength &&
value.trim().length <= this.maxLength
);
},
isRequired: true,
maxLength: 100,
minLength: 1,
textError: function () {
return `The description is required and it must be between ${this.minLength} and ${this.maxLength} characters long.`;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, expect, test } from 'bun:test';
import { pDCBPRDescriptionRules } from './description.rules';

describe('Description business rules', () => {
test('should return true for a valid description', () => {
const validDescription = 'A valid description';
expect(pDCBPRDescriptionRules.isValid(validDescription)).toBe(true);
});

test('should return false for a null value', () => {
expect(pDCBPRDescriptionRules.isValid(null)).toBe(false);
});

test('should return false for an undefined value', () => {
expect(pDCBPRDescriptionRules.isValid(undefined)).toBe(false);
});

test('should return false for an empty description', () => {
const emptyDescription = '';
expect(pDCBPRDescriptionRules.isValid(emptyDescription)).toBe(false);
});

test('should return false for a description longer than the maxLength', () => {
const longDescription = 'A'.repeat(pDCBPRDescriptionRules.maxLength + 1);
expect(pDCBPRDescriptionRules.isValid(longDescription)).toBe(false);
});

test('should return true for a description exactly at maxLength', () => {
const maxLengthDescription = 'A'.repeat(pDCBPRDescriptionRules.maxLength);
expect(pDCBPRDescriptionRules.isValid(maxLengthDescription)).toBe(true);
});

test('should return false for a description shorter than minLength', () => {
const shortDescription = 'A'.repeat(pDCBPRDescriptionRules.minLength - 1);
expect(pDCBPRDescriptionRules.isValid(shortDescription)).toBe(false);
});

test('should return true for a description exactly at minLength', () => {
const minLengthDescription = 'A'.repeat(pDCBPRDescriptionRules.minLength);
expect(pDCBPRDescriptionRules.isValid(minLengthDescription)).toBe(true);
});

test('should return false for a description with only spaces', () => {
const spacesDescription = ' ';
expect(pDCBPRDescriptionRules.isValid(spacesDescription)).toBe(false);
});

test('should return correct error message textError', () => {
const expectedErrorMessage = `The description is required and it must be between ${pDCBPRDescriptionRules.minLength} and ${pDCBPRDescriptionRules.maxLength} characters long.`;
expect(pDCBPRDescriptionRules.textError()).toBe(expectedErrorMessage);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Rules } from '../types';

export const pDCBPRPathwayIdRules: Omit<Rules<string | null | undefined>, 'minLength' | 'maxLength'> = {
isValid: (value) => {
const uuidV4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return value !== null && value !== undefined && uuidV4Regex.test(value);
},
isRequired: true,
textError: () => 'The pathway id is required and it must be a uuid v4',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, expect, test } from 'bun:test';
import { pDCBPRPathwayIdRules } from './pathway-id.rules';

describe('Pathway id business rules', () => {
test('should return true for a valid uuid v4 pathway id', () => {
const validPathwayId = 'e24054b9-92ca-4a22-be67-cf14cc94e6f8';
expect(pDCBPRPathwayIdRules.isValid(validPathwayId)).toBe(true);
});

test('should return false for a non uuid v4 value', () => {
expect(pDCBPRPathwayIdRules.isValid(null)).toBe(false);
expect(pDCBPRPathwayIdRules.isValid(undefined)).toBe(false);
expect(pDCBPRPathwayIdRules.isValid('')).toBe(false);
expect(pDCBPRPathwayIdRules.isValid('12345')).toBe(false);
expect(pDCBPRPathwayIdRules.isValid('e24054b9-92ca-7a22-be67-cf14cc94e6f8')).toBe(false);
});

test('should return correct error message textError', () => {
const expectedErrorMessage = 'The pathway id is required and it must be a uuid v4';
expect(pDCBPRPathwayIdRules.textError()).toBe(expectedErrorMessage);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Rules } from '../types';

export const pDCBPRResearchFieldRules: Rules<string | null | undefined> = {
isValid: function (value) {
return (
value !== undefined &&
value !== null &&
value.trim().length !== 0 &&
value.trim().length >= this.minLength &&
value.trim().length <= this.maxLength
);
},
isRequired: true,
maxLength: 100,
minLength: 1,
textError: function () {
return `The research field is required and it must be between ${this.minLength} and ${this.maxLength} characters long.`;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, expect, test } from 'bun:test';
import { pDCBPRResearchFieldRules } from './research-field.rules';

describe('Research field business rules', () => {
test('should return true for a valid research field', () => {
const validResearchField = 'A valid research field';
expect(pDCBPRResearchFieldRules.isValid(validResearchField)).toBe(true);
});

test('should return false for a null value', () => {
expect(pDCBPRResearchFieldRules.isValid(null)).toBe(false);
});

test('should return false for an undefined value', () => {
expect(pDCBPRResearchFieldRules.isValid(undefined)).toBe(false);
});

test('should return false for an empty research field', () => {
const emptyResearchField = '';
expect(pDCBPRResearchFieldRules.isValid(emptyResearchField)).toBe(false);
});

test('should return false for a research field longer than the maxLength', () => {
const longResearchField = 'A'.repeat(pDCBPRResearchFieldRules.maxLength + 1);
expect(pDCBPRResearchFieldRules.isValid(longResearchField)).toBe(false);
});

test('should return true for a research field exactly at maxLength', () => {
const maxLengthResearchField = 'A'.repeat(pDCBPRResearchFieldRules.maxLength);
expect(pDCBPRResearchFieldRules.isValid(maxLengthResearchField)).toBe(true);
});

test('should return false for a research field shorter than minLength', () => {
const shortResearchField = 'A'.repeat(pDCBPRResearchFieldRules.minLength - 1);
expect(pDCBPRResearchFieldRules.isValid(shortResearchField)).toBe(false);
});

test('should return true for a research field exactly at minLength', () => {
const minLengthResearchField = 'A'.repeat(pDCBPRResearchFieldRules.minLength);
expect(pDCBPRResearchFieldRules.isValid(minLengthResearchField)).toBe(true);
});

test('should return false for a research field with only spaces', () => {
const spacesResearchField = ' ';
expect(pDCBPRResearchFieldRules.isValid(spacesResearchField)).toBe(false);
});

test('should return correct error message textError', () => {
const expectedErrorMessage = `The research field is required and it must be between ${pDCBPRResearchFieldRules.minLength} and ${pDCBPRResearchFieldRules.maxLength} characters long.`;
expect(pDCBPRResearchFieldRules.textError()).toBe(expectedErrorMessage);
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import type { Rules } from '../types';

export const PDCBPR_titleRules: Rules = {
textError: function () {
return `Renseigner un nom entre 1 et ${this.maxLength} caractères.`;
},
isValid: function (value: string | null | undefined) {
return value !== undefined && value !== null && value.trim().length !== 0 && value.trim().length <= this.maxLength;
export const pDCBPRTitleRules: Rules<string | null | undefined> = {
isValid: function (value) {
return (
value !== undefined &&
value !== null &&
value.trim().length !== 0 &&
value.trim().length >= this.minLength &&
value.trim().length <= this.maxLength
);
},
isRequired: true,
maxLength: 100,
minLength: 1,
textError: function () {
return `The title is required and it must be between ${this.minLength} and ${this.maxLength} characters long.`;
},
};
Original file line number Diff line number Diff line change
@@ -1,38 +1,52 @@
import { describe, expect, test } from 'bun:test';
import { PDCBPR_titleRules } from './title.rules';
import { pDCBPRTitleRules } from './title.rules';

describe('PDCBPR_titleRules', () => {
describe('Title business rules', () => {
test('should return true for a valid title', () => {
const validTitle = 'A valid title';
expect(PDCBPR_titleRules.isValid(validTitle)).toBe(true);
expect(pDCBPRTitleRules.isValid(validTitle)).toBe(true);
});

test('should return false for a null value', () => {
expect(PDCBPR_titleRules.isValid(null)).toBe(false);
expect(pDCBPRTitleRules.isValid(null)).toBe(false);
});

test('should return false for an undefined value', () => {
expect(pDCBPRTitleRules.isValid(undefined)).toBe(false);
});

test('should return false for an empty title', () => {
const emptyTitle = '';
expect(PDCBPR_titleRules.isValid(emptyTitle)).toBe(false);
expect(pDCBPRTitleRules.isValid(emptyTitle)).toBe(false);
});

test('should return false for a title longer than the maxLength', () => {
const longTitle = 'A'.repeat(PDCBPR_titleRules.maxLength + 1);
expect(PDCBPR_titleRules.isValid(longTitle)).toBe(false);
const longTitle = 'A'.repeat(pDCBPRTitleRules.maxLength + 1);
expect(pDCBPRTitleRules.isValid(longTitle)).toBe(false);
});

test('should return true for a title exactly at maxLength', () => {
const maxLengthTitle = 'A'.repeat(PDCBPR_titleRules.maxLength);
expect(PDCBPR_titleRules.isValid(maxLengthTitle)).toBe(true);
const maxLengthTitle = 'A'.repeat(pDCBPRTitleRules.maxLength);
expect(pDCBPRTitleRules.isValid(maxLengthTitle)).toBe(true);
});

test('should return false for a title shorter than minLength', () => {
const shortTitle = 'A'.repeat(pDCBPRTitleRules.minLength - 1);
expect(pDCBPRTitleRules.isValid(shortTitle)).toBe(false);
});

test('should return true for a title exactly at minLength', () => {
const minLengthTitle = 'A'.repeat(pDCBPRTitleRules.minLength);
expect(pDCBPRTitleRules.isValid(minLengthTitle)).toBe(true);
});

test('should return false for a title with only spaces', () => {
const spacesTitle = ' ';
expect(PDCBPR_titleRules.isValid(spacesTitle)).toBe(false);
expect(pDCBPRTitleRules.isValid(spacesTitle)).toBe(false);
});

test('should return correct error message textError', () => {
const expectedErrorMessage = `Renseigner un nom entre 1 et ${PDCBPR_titleRules.maxLength} caractères.`;
expect(PDCBPR_titleRules.textError()).toBe(expectedErrorMessage);
const expectedErrorMessage = `The title is required and it must be between ${pDCBPRTitleRules.minLength} and ${pDCBPRTitleRules.maxLength} characters long.`;
expect(pDCBPRTitleRules.textError()).toBe(expectedErrorMessage);
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface Rules {
textError: () => string;
isValid: (value: string | null) => boolean;
export interface Rules<T> {
isValid: (value: T) => boolean;
readonly isRequired: boolean;
readonly maxLength: number;
readonly minLength: number;
textError: () => string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,6 @@ describe('pDSPBFPathwayFactory', () => {
expect(pathway.researchField).toBe(params.researchField);
});

it('should throw an error for an empty title', () => {
const params: PathwayFactoryParams = {
id: 'f7703737-186c-4c7c-8d46-925111c7c7c1',
title: '',
description: 'A test pathway',
researchField: 'biology',
};

expect(() => pDSPBFPathwayFactory(params)).toThrow('Title is required');
});

it('should throw an error for an empty description', () => {
const params: PathwayFactoryParams = {
id: 'f7703737-186c-4c7c-8d46-925111c7c7c1',
title: 'My Pathway',
description: '',
researchField: 'biology',
};

expect(() => pDSPBFPathwayFactory(params)).toThrow('Description is required');
});

it('should throw an error for an empty research field', () => {
const params: PathwayFactoryParams = {
id: 'f7703737-186c-4c7c-8d46-925111c7c7c1',
title: 'My Pathway',
description: 'A test pathway',
researchField: '',
};

expect(() => pDSPBFPathwayFactory(params)).toThrow('Research field is required');
});

it('should throw an error for an invalid UUID', () => {
const params: PathwayFactoryParams = {
id: 'invalid-uuid',
title: 'My Pathway',
description: 'A test pathway',
researchField: 'biology',
};

expect(() => pDSPBFPathwayFactory(params)).toThrow('Pathway id must be a valid uuid');
});

it('should generate a valid UUID if none is provided', () => {
const params: PathwayFactoryParams = {
title: 'My Pathway',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Feature: Business - Change the title of a pathway
Then It should apply an event indicating that the title of the pathway has been changed
Then I should see the title of the pathway in business changed to "My New Pathway"

Scenario: I want to change the title of a pathway with an empty title
Scenario: I want to change the title of a pathway with an invalid title
Given I have a pathway in business with these data
| title | description | researchField |
| My Pathway | A test pathway | biology |
When I change the title of the pathway in business to ""
Then I should see an error message from business "Title is required" during the title change
Then I should see an error message from business during the title change
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ export default class ControllerSteps {
assert.strictEqual(this.pDSPBEPathwayEntity.title, title);
}

@then('I should see an error message from business {string} during the title change')
public thenIShouldSeeAnErrorMessageDuringTitleChange(errorMessage: string) {
@then('I should see an error message from business during the title change')
public thenIShouldSeeAnErrorMessageDuringTitleChange() {
assert.notEqual(this.error, undefined);
assert.strictEqual(this.error?.message, errorMessage);
assert.notEqual(this.error?.message, undefined);
assert.notEqual(this.error?.message, '');
}
}
Loading

0 comments on commit fd28269

Please sign in to comment.