Skip to content
This repository has been archived by the owner on Oct 15, 2023. It is now read-only.

Commit

Permalink
Refacto Jest tests for the steps
Browse files Browse the repository at this point in the history
  • Loading branch information
yoriiis committed Apr 3, 2020
1 parent 94cc8b4 commit c58bb8e
Show file tree
Hide file tree
Showing 3 changed files with 310 additions and 24 deletions.
3 changes: 1 addition & 2 deletions src/__tests__/manager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,11 @@ const getInstance = () => {
};

beforeEach(() => {
window.sessionStorage.removeItem('stepManager');
document.body.innerHTML = '<div id="steps"></div>';
manager = getInstance();
});

afterEach(() => {
window.sessionStorage.removeItem('stepManager');
document.body.innerHTML = '';
});

Expand Down Expand Up @@ -163,6 +161,7 @@ describe('Manager addEvents', () => {
);
});
});

describe('Manager triggerNextStep', () => {
it('Should cal the triggerNextStep function', () => {
mockRouter(manager);
Expand Down
278 changes: 278 additions & 0 deletions src/__tests__/steps.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
import Steps from '../steps';

let steps;
const datas = { people: true };

class StepPeople extends Steps {
route = 'people';
selector = '.step-people';
canTheStepBeDisplayed () {
return {
canBeDisplayed: true,
fallbackRoute: null
};
}

getTemplate () {
return '<div class="step-people"></div>';
}

getDatasFromStep () {
return {};
}
}

const getInstance = () => {
return new StepPeople();
};

const getOptions = () => {
return {
element: document.querySelector('#steps')
};
};

const getEventObject = selector => {
return {
target: document.querySelector(selector)
};
};

beforeEach(() => {
document.body.innerHTML =
'<div id="steps"><div class="step-people"><button data-step-previous></button><button data-step-next></button></div></div>';
steps = getInstance();
steps.options = getOptions();
});

afterEach(() => {});

describe('Steps fields', () => {
it('Should initialize public instance fields', () => {
expect(steps.fallbackRoute).toBe(null);
expect(steps.optionalStep).toBe(false);
});
});

describe('Steps render', () => {
it('Should call the render function', () => {
steps.requestOptions = jest.fn().mockImplementation(() => getOptions());
steps.afterRender = jest.fn();
steps.getTemplate = jest.fn().mockImplementation(() => 'CONTENT');

steps.render({ datas });

expect(steps.requestOptions).toHaveBeenCalled();
expect(steps.getTemplate).toHaveBeenCalled();
expect(document.body.innerHTML).toBe(
'<div id="steps"><div class="step-people"><button data-step-previous=""></button><button data-step-next=""></button></div>CONTENT</div>'
);
expect(steps.afterRender).toHaveBeenCalledWith({ datas });
});
});

describe('Steps afterRender', () => {
it('Should call the afterRender function', () => {
steps.addEvents = jest.fn();
steps.renderDatasFromCache = jest.fn();

document.querySelector('#steps').innerHTML = '<div class="step-people"></div>';
steps.afterRender({ datas });

expect(steps.currentStep).toBe(document.querySelector('.step-people'));
expect(steps.addEvents).toHaveBeenCalled();
expect(steps.renderDatasFromCache).toHaveBeenCalledWith(datas);
});

it('Should call the afterRender function without cache datas', () => {
steps.addEvents = jest.fn();
steps.renderDatasFromCache = jest.fn();

steps.afterRender({ datas: null });

expect(steps.renderDatasFromCache).not.toHaveBeenCalled();
});

it('Should call the afterRender function with empty object datas', () => {
steps.addEvents = jest.fn();
steps.renderDatasFromCache = jest.fn();

steps.afterRender();

expect(steps.renderDatasFromCache).not.toHaveBeenCalled();
});
});

describe('Steps destroy', () => {
it('Should call the destroy function', () => {
steps.removeEvents = jest.fn();

document.querySelector('#steps').innerHTML = '<div class="step-people"></div>';
steps.currentStep = document.querySelector('.step-people');
steps.currentStep.remove = jest.fn();

steps.destroy();

expect(steps.removeEvents).toHaveBeenCalled();
expect(steps.currentStep.remove).toHaveBeenCalled();
});
});

describe('Steps addEvents', () => {
it('Should call the addEvents function', () => {
document.querySelector('#steps').innerHTML = '<div class="step-people"></div>';
steps.currentStep = document.querySelector('.step-people');

steps.currentStep.addEventListener = jest.fn();

steps.addEvents();

expect(steps.currentStep.addEventListener).toHaveBeenCalledWith(
'click',
steps.clickOnCurrentStep,
false
);
});
});

describe('Steps clickOnCurrentStep', () => {
it('Should call the clickOnCurrentStep function without element', () => {
steps.clickToPreviousStep = jest.fn();
steps.clickToNextStep = jest.fn();

steps.clickOnCurrentStep(getEventObject('#steps'));

expect(steps.clickToPreviousStep).not.toHaveBeenCalled();
expect(steps.clickToNextStep).not.toHaveBeenCalled();
});

it('Should call the clickOnCurrentStep function with previous click', () => {
steps.clickToPreviousStep = jest.fn();
steps.clickToNextStep = jest.fn();

steps.clickOnCurrentStep(getEventObject('[data-step-previous]'));

expect(steps.clickToPreviousStep).toHaveBeenCalled();
expect(steps.clickToNextStep).not.toHaveBeenCalled();
});

it('Should call the clickOnCurrentStep function with next click', () => {
steps.clickToPreviousStep = jest.fn();
steps.clickToNextStep = jest.fn();

steps.clickOnCurrentStep(getEventObject('[data-step-next]'));

expect(steps.clickToPreviousStep).not.toHaveBeenCalled();
expect(steps.clickToNextStep).toHaveBeenCalled();
});
});

describe('Steps clickToNextStep', () => {
it('Should call the clickToNextStep with step not ready to submit', () => {
steps.options.element.dispatchEvent = jest.fn();

steps.stepIsReadyToSubmit = false;
steps.clickToNextStep({ preventDefault: () => {} });

expect(steps.options.element.dispatchEvent).not.toHaveBeenCalled();
});

it('Should call the clickToNextStep with step ready to submit', () => {
steps.options.element.dispatchEvent = jest.fn();

steps.stepIsReadyToSubmit = true;
steps.clickToNextStep({ preventDefault: () => {} });

expect(steps.options.element.dispatchEvent).toHaveBeenCalledWith(
new window.CustomEvent('nextStep')
);
});
});

describe('Steps clickToPreviousStep', () => {
it('Should call the clickToPreviousStep with step not ready to submit', () => {
steps.options.element.dispatchEvent = jest.fn();

steps.clickToPreviousStep({ preventDefault: () => {} });

expect(steps.options.element.dispatchEvent).toHaveBeenCalledWith(
new window.CustomEvent('previousStep')
);
});
});

describe('Steps checkIfStepIsReadyToSubmit', () => {
it('Should call the checkIfStepIsReadyToSubmit function', () => {
steps.getDatasFromStep = jest.fn().mockImplementation(() => true);
steps.updateButtonToValidateStep = jest.fn();

steps.checkIfStepIsReadyToSubmit();

expect(steps.stepIsReadyToSubmit).toBe(true);
expect(steps.updateButtonToValidateStep).toHaveBeenCalled();
});

it('Should call the checkIfStepIsReadyToSubmit function without datas from steps', () => {
steps.getDatasFromStep = jest.fn().mockImplementation(() => null);
steps.updateButtonToValidateStep = jest.fn();

steps.checkIfStepIsReadyToSubmit();

expect(steps.stepIsReadyToSubmit).toBe(false);
expect(steps.updateButtonToValidateStep).toHaveBeenCalled();
});
});

describe('Steps updateButtonToValidateStep', () => {
it('Should call the updateButtonToValidateStep function with step not ready', () => {
steps.currentStep = document.querySelector('.step-people');

steps.stepIsReadyToSubmit = false;
steps.optionalStep = false;
steps.updateButtonToValidateStep();

expect(document.querySelector('[data-step-next]').classList.contains('disabled')).toBe(
true
);
});

it('Should call the updateButtonToValidateStep function with step ready', () => {
steps.currentStep = document.querySelector('.step-people');

steps.stepIsReadyToSubmit = true;
steps.optionalStep = false;
steps.updateButtonToValidateStep();

expect(document.querySelector('[data-step-next]').classList.contains('disabled')).toBe(
false
);
});

it('Should call the updateButtonToValidateStep function with step optional', () => {
steps.currentStep = document.querySelector('.step-people');

steps.stepIsReadyToSubmit = false;
steps.optionalStep = true;
steps.updateButtonToValidateStep();

expect(document.querySelector('[data-step-next]').classList.contains('disabled')).toBe(
false
);
});
});

describe('Steps removeEvents', () => {
it('Should call the removeEvents function', () => {
document.querySelector('#steps').innerHTML = '<div class="step-people"></div>';
steps.currentStep = document.querySelector('.step-people');

steps.currentStep.removeEventListener = jest.fn();

steps.removeEvents();

expect(steps.currentStep.removeEventListener).toHaveBeenCalledWith(
'click',
steps.clickOnCurrentStep
);
});
});
53 changes: 31 additions & 22 deletions src/steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ export default class Steps {
fallbackRoute = null;
optionalStep = false;

constructor () {
this.clickOnCurrentStep = this.clickOnCurrentStep.bind(this);
}

/**
* Render the step
*
Expand All @@ -26,7 +30,7 @@ export default class Steps {
*
* @param {Object} datas Datas from the cache
*/
afterRender ({ datas }) {
afterRender ({ datas } = {}) {
// Set cached selector
this.currentStep = this.options.element.querySelector(this.selector);

Expand Down Expand Up @@ -55,32 +59,30 @@ export default class Steps {
* All listeners are created on class properties to facilitate the deletion of events
*/
addEvents () {
this.onClickOnCurrentStep = e => {
const target = e.target;
if (
target.nodeName.toLowerCase() === 'button' &&
target.hasAttribute('data-step-previous')
) {
// Click on the next step button
this.clickToPreviousStep(e);
} else if (
target.nodeName.toLowerCase() === 'button' &&
target.hasAttribute('data-step-next')
) {
// Click on the next step button
this.clickToNextStep(e);
}
};

// Use event delegation for better performance
this.currentStep.addEventListener('click', this.onClickOnCurrentStep, false);
this.currentStep.addEventListener('click', this.clickOnCurrentStep, false);
}

/**
* Remove steps event listeners
* Click event listener on the step
*
* @param {Object} e Event listener datas
*/
removeEvents () {
this.currentStep.removeEventListener('click', this.onClickOnCurrentStep, false);
clickOnCurrentStep (e) {
const target = e.target;
if (
target.nodeName.toLowerCase() === 'button' &&
target.hasAttribute('data-step-previous')
) {
// Click on the previous step button
this.clickToPreviousStep(e);
} else if (
target.nodeName.toLowerCase() === 'button' &&
target.hasAttribute('data-step-next')
) {
// Click on the next step button
this.clickToNextStep(e);
}
}

/**
Expand Down Expand Up @@ -130,4 +132,11 @@ export default class Steps {
button.classList.add('disabled');
}
}

/**
* Remove steps event listeners
*/
removeEvents () {
this.currentStep.removeEventListener('click', this.clickOnCurrentStep);
}
}

0 comments on commit c58bb8e

Please sign in to comment.