diff --git a/app/assets/javascripts/initializePage.js b/app/assets/javascripts/initializePage.js index 6060097f3..8d69cd0db 100644 --- a/app/assets/javascripts/initializePage.js +++ b/app/assets/javascripts/initializePage.js @@ -3,7 +3,7 @@ initializeAllTagEditButtons, initializeUserFollowButts, initializeCommentsPage, initializeSettings, initializeRuntimeBanner, - initializeTimeFixer, initializeCreditsPage, + initializeCreditsPage, initializeOnboardingTaskCard, initScrolling, nextPage:writable, fetching:writable, done:writable, initializePaymentPointers, @@ -14,7 +14,6 @@ function callInitializers() { initializePaymentPointers(); initializeCommentsPage(); initializeSettings(); - initializeTimeFixer(); initializeCreditsPage(); initializeOnboardingTaskCard(); } diff --git a/app/javascript/packs/baseInitializers.js b/app/javascript/packs/baseInitializers.js index 47c117354..eff57ad3a 100644 --- a/app/javascript/packs/baseInitializers.js +++ b/app/javascript/packs/baseInitializers.js @@ -1,5 +1,6 @@ import { initializeCommentDate } from './initializers/initializeCommentDate'; import { initializeCommentPreview } from './initializers/initializeCommentPreview'; +import { initializeTimeFixer } from './initializers/initializeTimeFixer'; import { initializeNotifications } from './initializers/initializeNotifications'; import { initializeDateHelpers } from './initializers/initializeDateTimeHelpers'; import { @@ -10,6 +11,7 @@ import { initializeCommentDate(); initializeCommentPreview(); initializeNotifications(); +initializeTimeFixer(); initializeDateHelpers(); InstantClick.on('change', () => { diff --git a/app/javascript/packs/initializers/__tests__/initializeTimeFixer.test.js b/app/javascript/packs/initializers/__tests__/initializeTimeFixer.test.js new file mode 100644 index 000000000..ed1c1e7e8 --- /dev/null +++ b/app/javascript/packs/initializers/__tests__/initializeTimeFixer.test.js @@ -0,0 +1,209 @@ +import { + initializeTimeFixer, + convertUtcDate, + convertUtcTime, + formatDateTime, + updateLocalDateTime, + convertCalEvent, +} from '../initializeTimeFixer'; + +describe('initializeTimeFixer', () => { + beforeEach(() => { + const utcTimeClassDiv = document.createElement('div'); + const utcDateClassDiv = document.createElement('div'); + const utcDiv = document.createElement('div'); + + utcTimeClassDiv.classList.add('utc-time'); + utcDateClassDiv.classList.add('utc-date'); + utcDiv.classList.add('utc'); + + utcTimeClassDiv.dataset.datetime = 823230245000; + }); + + test('should call event listener when preview button exist', async () => { + const button = document.createElement('button'); + button.classList.add('preview-toggle'); + button.addEventListener = jest.fn(); + initializeTimeFixer(); + + expect(button.addEventListener).not.toHaveBeenCalled(); + }); + + test('should call updateLocalDateTime', async () => { + const updateLocalDateTime = jest.fn(); + initializeTimeFixer(); + + expect(updateLocalDateTime).not.toHaveBeenCalled(); + }); + + test('should call convertUtcDate', async () => { + const convertUtcDate = jest.fn(); + initializeTimeFixer(); + + expect(convertUtcDate).not.toHaveBeenCalled(); + }); + + test('should convert Utc Dates', async () => { + const utcDate = Date.UTC(96, 1, 2, 3, 4, 5); + const dateConversion = await convertUtcDate(utcDate); + // const formatDateTime = jest.fn(); + + expect(dateConversion).toContain('Feb 2'); + }); + + test('convertUtcDate function with different options', () => { + const utcDate = 917924645000; + + const options1 = { + month: 'short', + day: 'numeric', + }; + expect(convertUtcDate(utcDate, options1)).toBe('Feb 2'); + + const options2 = { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + timeZoneName: 'short', + }; + expect(convertUtcDate(utcDate, options2)).toBe('Feb 2'); + }); + + test('convertUtcTime function with different options', () => { + const utcTime = 917924645000; + + const options1 = { + hour: 'numeric', + minute: 'numeric', + timeZoneName: 'short', + }; + expect(convertUtcTime(utcTime, options1)).toBe('3:04 AM UTC'); + + const options2 = { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + timeZoneName: 'short', + }; + expect(convertUtcTime(utcTime, options2)).toBe('3:04 AM UTC'); + }); + + test('formatDateTime function with different options and values', () => { + const options1 = { + hour: 'numeric', + minute: 'numeric', + timeZoneName: 'short', + }; + const value1 = new Date(917924645000); + expect(formatDateTime(options1, value1)).toBe('3:04 AM UTC'); + + const options2 = { + year: 'numeric', + month: 'short', + day: 'numeric', + }; + const value2 = new Date(917924645000); + expect(formatDateTime(options2, value2)).toBe('Feb 2, 1999'); + }); +}); + +describe('formatDateTime', () => { + it('formats the date time with given options', () => { + const options = { + month: 'short', + day: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + }; + const value = new Date('2022-04-13T12:34:56Z'); + const expected = 'Apr 13, 2022, 12:34 PM'; + + expect(formatDateTime(options, value)).toEqual(expected); + }); +}); + +describe('convertUtcTime', () => { + it('converts the UTC time to local time with proper format', () => { + const utcTime = 917924645000; + const expected = '3:04 AM UTC'; + + expect(convertUtcTime(utcTime)).toEqual(expected); + }); +}); + +describe('convertUtcDate', () => { + it('converts the UTC date to local date with proper format', () => { + const utcDate = 917924645000; + const expected = expect.stringMatching(/^\w{3} \d{1,2}$/); + + expect(convertUtcDate(utcDate)).toEqual(expected); + }); +}); + +describe('updateLocalDateTime', () => { + it('updates the innerHTML of given elements with local time', () => { + document.body.innerHTML = ` +
+ + + 917924645000 +
+ `; + + const utcTimeElements = document.querySelectorAll('.utc-time'); + const utcDateElements = document.querySelectorAll('.utc-date'); + const utcElements = document.querySelectorAll('.utc'); + + updateLocalDateTime( + utcTimeElements, + convertUtcTime, + (element) => element.dataset.datetime, + ); + updateLocalDateTime( + utcDateElements, + convertUtcDate, + (element) => element.dataset.datetime, + ); + updateLocalDateTime( + utcElements, + convertCalEvent, + (element) => element.innerHTML, + ); + + expect(utcTimeElements[0].innerHTML).toEqual('3:04 AM UTC'); + expect(utcDateElements[0].innerHTML).toEqual( + expect.stringMatching(/^\w{3} \d{1,2}$/), + ); + expect(utcElements[0].innerHTML).toEqual('Tuesday, February 2 at 3:04 AM'); + }); +}); + +// eslint-disable-next-line jest/no-identical-title +describe('formatDateTime', () => { + it('should format a date and time using the specified options', () => { + const options = { + weekday: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + hour12: true, + }; + const value = new Date(1682636630); + const expected = 'Tue, Jan 20, 1970, 11:23 AM'; + expect(formatDateTime(options, value)).toBe(expected); + }); +}); + +describe('convertCalEvent', () => { + it('should convert UTC to a formatted date and time string', () => { + const utc = 1682636630; + const expected = 'Tuesday, January 20 at 11:23 AM'; + expect(convertCalEvent(utc)).toBe(expected); + }); +}); diff --git a/app/assets/javascripts/initializers/initializeTimeFixer.js b/app/javascript/packs/initializers/initializeTimeFixer.js similarity index 67% rename from app/assets/javascripts/initializers/initializeTimeFixer.js rename to app/javascript/packs/initializers/initializeTimeFixer.js index d34b7b319..6edeb61ae 100644 --- a/app/assets/javascripts/initializers/initializeTimeFixer.js +++ b/app/javascript/packs/initializers/initializeTimeFixer.js @@ -1,12 +1,10 @@ -'use strict'; - function formatDateTime(options, value) { return new Intl.DateTimeFormat('en-US', options).format(value); } function convertUtcTime(utcTime) { - var time = new Date(utcTime); - var options = { + const time = new Date(Number(utcTime)); + const options = { hour: 'numeric', minute: 'numeric', timeZoneName: 'short', @@ -15,8 +13,8 @@ function convertUtcTime(utcTime) { } function convertUtcDate(utcDate) { - var date = new Date(utcDate); - var options = { + const date = new Date(Number(utcDate)); + const options = { month: 'short', day: 'numeric', }; @@ -24,8 +22,8 @@ function convertUtcDate(utcDate) { } function convertCalEvent(utc) { - var date = new Date(utc); - var options = { + const date = new Date(Number(utc)); + const options = { weekday: 'long', month: 'long', day: 'numeric', @@ -37,8 +35,8 @@ function convertCalEvent(utc) { } function updateLocalDateTime(elements, convertCallback, getUtcDateTime) { - var local; - for (var i = 0; i < elements.length; i += 1) { + let local; + for (let i = 0; i < elements.length; i += 1) { local = convertCallback(getUtcDateTime(elements[i])); // eslint-disable-next-line no-param-reassign elements[i].innerHTML = local; @@ -46,9 +44,9 @@ function updateLocalDateTime(elements, convertCallback, getUtcDateTime) { } function initializeTimeFixer() { - var utcTime = document.getElementsByClassName('utc-time'); - var utcDate = document.getElementsByClassName('utc-date'); - var utc = document.getElementsByClassName('utc'); + const utcTime = document.getElementsByClassName('utc-time'); + const utcDate = document.getElementsByClassName('utc-date'); + const utc = document.getElementsByClassName('utc'); if (!utc) { return; @@ -66,3 +64,12 @@ function initializeTimeFixer() { ); updateLocalDateTime(utc, convertCalEvent, (element) => element.innerHTML); } + +export { + initializeTimeFixer, + updateLocalDateTime, + convertUtcDate, + convertUtcTime, + formatDateTime, + convertCalEvent, +}; diff --git a/cypress/e2e/seededFlows/homeFeedFlows/timeFixer.spec.js b/cypress/e2e/seededFlows/homeFeedFlows/timeFixer.spec.js new file mode 100644 index 000000000..7c2bd98a0 --- /dev/null +++ b/cypress/e2e/seededFlows/homeFeedFlows/timeFixer.spec.js @@ -0,0 +1,45 @@ +const timeHtml = ` +
+

This is a test campaign

+ +
+
+
823230245000
+
+`; + +describe('Time Fixer', () => { + beforeEach(() => { + cy.testSetup(); + cy.fixture('users/adminUser.json').as('user'); + + cy.get('@user').then((user) => { + cy.loginUser(user).then(() => { + cy.createHtmlVariant({ + name: 'TestTimeHtml', + html: timeHtml, + approved: true, + }).then(() => { + cy.setCampaign({ + display_name: 'Test Time Campaign', + hero_html_variant_name: 'TestTimeHtml', + }).then(() => { + cy.visit('/'); + }); + }); + }); + }); + }); + + afterEach(() => { + // Dismissing a banner sets a flag in local storage that we want to ensure is removed after each test + // cy.visit('/404'); + cy.clearLocalStorage(); + }); + + context('when utc exist on the page', () => { + it('displays proper time', () => { + cy.get('.utc').as('utcTime').should('exist'); + }); + }); +});