mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-31 20:00:00 -04:00
More javascript converted
This commit is contained in:
@@ -12,24 +12,25 @@
|
||||
}
|
||||
};
|
||||
|
||||
let filter = ($searchBox, $searchLabel, $liveRegion, $targets) => () => {
|
||||
let filter = (searchBox, searchLabel, liveRegion, targets) => () => {
|
||||
|
||||
let query = normalize($searchBox.val());
|
||||
let query = normalize(searchBox.value);
|
||||
let results = 0;
|
||||
let $noResultsMessage = $('.js-live-search-no-results');
|
||||
let noResultsMessage = document.querySelector('.js-live-search-no-results');
|
||||
|
||||
$targets.each(function() {
|
||||
targets.forEach(function(target) {
|
||||
|
||||
let content = $('.live-search-relevant', this).text() || $(this).text();
|
||||
let relevantElement = target.querySelector('.live-search-relevant');
|
||||
let content = relevantElement ? relevantElement.textContent : target.textContent;
|
||||
|
||||
if ($(this).has(':checked').length) {
|
||||
$(this).show();
|
||||
if (target.querySelector(':checked')) {
|
||||
target.classList.remove('js-hidden');
|
||||
results++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (query == '') {
|
||||
$(this).removeClass('js-hidden');
|
||||
target.classList.remove('js-hidden');
|
||||
results++;
|
||||
return;
|
||||
}
|
||||
@@ -37,27 +38,29 @@
|
||||
let isMatch = normalize(content).includes(normalize(query));
|
||||
|
||||
if (isMatch) {
|
||||
$(this).removeClass('js-hidden');
|
||||
target.classList.remove('js-hidden');
|
||||
results++;
|
||||
} else {
|
||||
$(this).addClass('js-hidden');
|
||||
target.classList.add('js-hidden');
|
||||
}
|
||||
});
|
||||
|
||||
if (query !== '' && results === 0) {
|
||||
$noResultsMessage.removeClass('js-hidden');
|
||||
} else {
|
||||
$noResultsMessage.addClass('js-hidden');
|
||||
if (noResultsMessage) {
|
||||
if (query !== '' && results === 0) {
|
||||
noResultsMessage.classList.remove('js-hidden');
|
||||
} else {
|
||||
noResultsMessage.classList.add('js-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
if (state === 'loaded') {
|
||||
if (query !== '') {
|
||||
$searchBox.attr('aria-label', $searchLabel.text().trim() + ', ' + resultsSummary(results));
|
||||
searchBox.setAttribute('aria-label', searchLabel.textContent.trim() + ', ' + resultsSummary(results));
|
||||
}
|
||||
state = 'active';
|
||||
} else {
|
||||
$searchBox.removeAttr('aria-label');
|
||||
$liveRegion.text(resultsSummary(results));
|
||||
searchBox.removeAttribute('aria-label');
|
||||
liveRegion.textContent = resultsSummary(results);
|
||||
}
|
||||
|
||||
// make sticky JS recalculate its cache of the element's position
|
||||
@@ -73,22 +76,24 @@
|
||||
|
||||
this.start = function(component) {
|
||||
|
||||
let $component = $(component);
|
||||
let searchBox = component.querySelector('input');
|
||||
let searchLabel = component.querySelector('label');
|
||||
let liveRegion = component.querySelector('.live-search__status');
|
||||
|
||||
let $searchBox = $('input', $component);
|
||||
let $searchLabel = $('label', $component);
|
||||
let $liveRegion = $('.live-search__status', $component);
|
||||
let targetsSelector = component.dataset.targets;
|
||||
let targets = Array.from(document.querySelectorAll(targetsSelector));
|
||||
|
||||
let filterFunc = filter(
|
||||
$searchBox,
|
||||
$searchLabel,
|
||||
$liveRegion,
|
||||
$($component.data('targets'))
|
||||
searchBox,
|
||||
searchLabel,
|
||||
liveRegion,
|
||||
targets
|
||||
);
|
||||
|
||||
state = 'loaded';
|
||||
|
||||
$searchBox.on('keyup input', filterFunc);
|
||||
searchBox.addEventListener('keyup', filterFunc);
|
||||
searchBox.addEventListener('input', filterFunc);
|
||||
|
||||
filterFunc();
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
window.NotifyModules['update-status'] = function() {
|
||||
|
||||
const getRenderer = $component => response => $component.html(
|
||||
response.html
|
||||
);
|
||||
const getRenderer = component => response => {
|
||||
component.innerHTML = response.html;
|
||||
};
|
||||
|
||||
const throttle = (func, limit) => {
|
||||
|
||||
@@ -41,39 +41,38 @@
|
||||
|
||||
let id = 'update-status';
|
||||
|
||||
this.$component = $(component);
|
||||
this.$textbox = $('#' + this.$component.data('target'));
|
||||
this.component = component;
|
||||
this.textbox = document.getElementById(this.component.dataset.target);
|
||||
|
||||
this.$component
|
||||
.attr('id', id);
|
||||
this.component.setAttribute('id', id);
|
||||
|
||||
this.$textbox
|
||||
.attr(
|
||||
'aria-describedby',
|
||||
(
|
||||
this.$textbox.attr('aria-describedby') || ''
|
||||
) + (
|
||||
this.$textbox.attr('aria-describedby') ? ' ' : ''
|
||||
) + id
|
||||
)
|
||||
.on('input', throttle(this.update, 150))
|
||||
.trigger('input');
|
||||
const currentAriaDescribedBy = this.textbox.getAttribute('aria-describedby') || '';
|
||||
const newAriaDescribedBy = currentAriaDescribedBy + (currentAriaDescribedBy ? ' ' : '') + id;
|
||||
this.textbox.setAttribute('aria-describedby', newAriaDescribedBy);
|
||||
|
||||
this.textbox.addEventListener('input', throttle(this.update, 150));
|
||||
this.textbox.dispatchEvent(new Event('input'));
|
||||
|
||||
};
|
||||
|
||||
this.update = () => {
|
||||
|
||||
$.ajax(
|
||||
this.$component.data('updates-url'),
|
||||
{
|
||||
'method': 'post',
|
||||
'data': this.$textbox.parents('form').serialize()
|
||||
}
|
||||
).done(
|
||||
getRenderer(this.$component)
|
||||
).fail(
|
||||
() => {}
|
||||
);
|
||||
const form = this.textbox.closest('form');
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch(this.component.dataset.updatesUrl, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('HTTP error');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(getRenderer(this.component))
|
||||
.catch(() => {});
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -6,27 +6,19 @@ const serviceNumber = '6658542f-0cad-491f-bec8-ab8457700ead';
|
||||
const updatesURL = `/services/${serviceNumber}/templates/count-sms-length`;
|
||||
|
||||
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 => {
|
||||
// For these tests the server responds immediately
|
||||
callback(responseObj);
|
||||
return jqueryAJAXReturnObj;
|
||||
},
|
||||
fail: () => {}
|
||||
};
|
||||
|
||||
$.ajax.mockImplementation(() => jqueryAJAXReturnObj);
|
||||
// mock fetch
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve(responseObj)
|
||||
})
|
||||
);
|
||||
|
||||
require('../../app/assets/javascripts/updateStatus.js');
|
||||
|
||||
@@ -58,8 +50,8 @@ describe('Update content', () => {
|
||||
|
||||
document.body.innerHTML = '';
|
||||
|
||||
// tidy up record of mocked AJAX calls
|
||||
$.ajax.mockClear();
|
||||
// tidy up record of mocked fetch calls
|
||||
fetch.mockClear();
|
||||
|
||||
// ensure any timers set by continually starting the module are cleared
|
||||
jest.clearAllTimers();
|
||||
@@ -102,18 +94,21 @@ describe('Update content', () => {
|
||||
|
||||
window.NotifyModules.start();
|
||||
|
||||
expect($.ajax.mock.calls[0][0]).toEqual(updatesURL);
|
||||
expect($.ajax.mock.calls[0]).toEqual([
|
||||
updatesURL,
|
||||
{
|
||||
"data": "csrf_token=abc123&template_content=Content%20of%20message",
|
||||
"method": "post"
|
||||
}
|
||||
]);
|
||||
expect(fetch.mock.calls[0][0]).toEqual(updatesURL);
|
||||
expect(fetch.mock.calls[0][1]).toMatchObject({
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: expect.any(FormData)
|
||||
});
|
||||
|
||||
// Verify FormData contents
|
||||
const formData = fetch.mock.calls[0][1].body;
|
||||
expect(formData.get('csrf_token')).toBe('abc123');
|
||||
expect(formData.get('template_content')).toBe('Content of message');
|
||||
|
||||
});
|
||||
|
||||
test("It should replace the content of the div with the returned HTML", () => {
|
||||
test("It should replace the content of the div with the returned HTML", async () => {
|
||||
|
||||
responseObj = {'html': 'Updated content'}
|
||||
|
||||
@@ -123,14 +118,23 @@ describe('Update content', () => {
|
||||
"Initial content"
|
||||
);
|
||||
|
||||
// Use real timers for async operations
|
||||
jest.useRealTimers();
|
||||
|
||||
window.NotifyModules.start();
|
||||
|
||||
// Wait for the promise chain to complete
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
expect(
|
||||
document.querySelectorAll('[data-module=update-status]')[0].textContent.trim()
|
||||
).toEqual(
|
||||
"Updated content"
|
||||
);
|
||||
|
||||
// Restore fake timers
|
||||
jest.useFakeTimers();
|
||||
|
||||
});
|
||||
|
||||
test("It should fire when the content of the textarea changes", () => {
|
||||
@@ -139,13 +143,13 @@ describe('Update content', () => {
|
||||
|
||||
// Initial update triggered
|
||||
window.NotifyModules.start();
|
||||
expect($.ajax.mock.calls.length).toEqual(1);
|
||||
expect(fetch.mock.calls.length).toEqual(1);
|
||||
|
||||
// 150ms of inactivity
|
||||
jest.advanceTimersByTime(150);
|
||||
helpers.triggerEvent(textarea, 'input');
|
||||
|
||||
expect($.ajax.mock.calls.length).toEqual(2);
|
||||
expect(fetch.mock.calls.length).toEqual(2);
|
||||
|
||||
});
|
||||
|
||||
@@ -155,23 +159,23 @@ describe('Update content', () => {
|
||||
|
||||
// Initial update triggered
|
||||
window.NotifyModules.start();
|
||||
expect($.ajax.mock.calls.length).toEqual(1);
|
||||
expect(fetch.mock.calls.length).toEqual(1);
|
||||
|
||||
helpers.triggerEvent(textarea, 'input');
|
||||
jest.advanceTimersByTime(149);
|
||||
expect($.ajax.mock.calls.length).toEqual(1);
|
||||
expect(fetch.mock.calls.length).toEqual(1);
|
||||
|
||||
helpers.triggerEvent(textarea, 'input');
|
||||
jest.advanceTimersByTime(149);
|
||||
expect($.ajax.mock.calls.length).toEqual(1);
|
||||
expect(fetch.mock.calls.length).toEqual(1);
|
||||
|
||||
helpers.triggerEvent(textarea, 'input');
|
||||
jest.advanceTimersByTime(149);
|
||||
expect($.ajax.mock.calls.length).toEqual(1);
|
||||
expect(fetch.mock.calls.length).toEqual(1);
|
||||
|
||||
// > 150ms of inactivity
|
||||
jest.advanceTimersByTime(1);
|
||||
expect($.ajax.mock.calls.length).toEqual(2);
|
||||
expect(fetch.mock.calls.length).toEqual(2);
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user