const each = require('jest-each').default; const jestDateMock = require('jest-date-mock'); const helpers = require('./support/helpers.js'); const serviceNumber = '6658542f-0cad-491f-bec8-ab8457700ead'; const resourceURL = `/services/${serviceNumber}/notifications/email.json?status=sending%2Cdelivered%2Cfailed`; const updateKey = 'counts'; let responseObj = {}; let jqueryAJAXReturnObj; beforeAll(() => { // ensure all timers go through Jest jest.useFakeTimers(); // mock the bits of jQuery used jest.spyOn(window.$, 'ajax'); // set up the object returned from $.ajax so it responds with whatever responseObj is set to jqueryAJAXReturnObj = { done: callback => { // The server takes 1 second to respond jestDateMock.advanceBy(1000); callback(responseObj); return jqueryAJAXReturnObj; }, fail: () => {} }; $.ajax.mockImplementation(() => jqueryAJAXReturnObj); // RollupJS assigns our bundled module code, including morphdom, to window.GOVUK. // morphdom is assigned to its vendor property so we need to copy that here for the updateContent // code to pick it up. window.GOVUK.vendor = { morphdom: require('morphdom') }; require('../../app/assets/javascripts/updateContent.js'); }); afterAll(() => { require('./support/teardown.js'); }); describe('Update content', () => { let HTMLString; let initialHTMLString; beforeEach(() => { // store HTML in string to allow use in AJAX responses HTMLString = `
`; initialHTMLString = `
${HTMLString}
`; document.body.innerHTML = initialHTMLString; // default the response to match the content inside div[data-module] responseObj[updateKey] = HTMLString; }); afterEach(() => { document.body.innerHTML = ''; // tidy up record of mocked AJAX calls $.ajax.mockClear(); // ensure any timers set by continually starting the module are cleared jest.clearAllTimers(); }); test("It should make requests to the URL specified in the data-resource attribute", () => { // start the module window.GOVUK.modules.start(); jest.advanceTimersByTime(2000); expect($.ajax.mock.calls[0][0]).toEqual(resourceURL); }); test("If the response contains no changes, the DOM should stay the same", () => { // send the done callback a response with updates included responseObj[updateKey] = HTMLString; // start the module window.GOVUK.modules.start(); jest.advanceTimersByTime(2000); // check the right DOM node is updated expect(document.querySelectorAll('.big-number-number')[0].textContent.trim()).toEqual("0"); }); test("If the response contains changes, it should update the DOM with them", () => { // send the done callback a response with updates included responseObj[updateKey] = HTMLString.replace(/
0<\/div>{1}/, '
1
'); // start the module window.GOVUK.modules.start(); jest.advanceTimersByTime(2000); // check the right DOM node is updated expect(document.querySelectorAll('.big-number-number')[0].textContent.trim()).toEqual("1"); }); describe("By default", () => { beforeEach(() => { // start the module window.GOVUK.modules.start(); }); test("It should use the GET HTTP method", () => { jest.advanceTimersByTime(2000); expect($.ajax.mock.calls[0][1].method).toEqual('get'); }); test("It shouldn't send any data as part of the requests", () => { jest.advanceTimersByTime(2000); expect($.ajax.mock.calls[0][1].data).toEqual({}); }); test("It should request updates with a dynamic interval", () => { // First call doesn’t happen in the first 2000ms jest.advanceTimersByTime(1999); expect($.ajax).toHaveBeenCalledTimes(0); // But it happens after 2000ms by default jest.advanceTimersByTime(1); expect($.ajax).toHaveBeenCalledTimes(1); // It took the server 1000ms to respond to the first call so we // will back off – the next call shouldn’t happen in the next 6904ms jest.advanceTimersByTime(6904); expect($.ajax).toHaveBeenCalledTimes(1); // But it should happen after 6905ms jest.advanceTimersByTime(1); expect($.ajax).toHaveBeenCalledTimes(2); }); each([ [1000, 0], [1500, 100], [4590, 500], [6905, 1000], [24000, 10000], ]).test('It calculates a delay of %dms if the API responds in %dms', (waitTime, responseTime) => { expect( window.GOVUK.Modules.UpdateContent.calculateBackoff(responseTime) ).toBe( waitTime ); }); }); describe("If a form is used as a source for data, referenced in the data-form attribute", () => { beforeEach(() => { document.body.innerHTML += `
`; document.querySelector('[data-module=update-content]').setAttribute('data-form', 'service'); // start the module window.GOVUK.modules.start(); }); test("requests should use the same HTTP method as the form", () => { jest.advanceTimersByTime(2000); expect($.ajax.mock.calls[0][1].method).toEqual('post'); }) test("requests should use the data from the form", () => { jest.advanceTimersByTime(2000); expect($.ajax.mock.calls[0][1].data).toEqual(helpers.getFormDataFromPairs([ ['serviceName', 'Buckhurst surgery'], ['serviceNumber', serviceNumber] ])); }) }); });