Skip to content

Commit

Permalink
Merge pull request #669 from GSA-TTS/feature/unit-tests-two
Browse files Browse the repository at this point in the history
Feature/unit tests two
  • Loading branch information
ximekilgsa authored Nov 22, 2024
2 parents ad92ace + 228fa3c commit 301cbb7
Show file tree
Hide file tree
Showing 12 changed files with 3,000 additions and 924 deletions.
193 changes: 20 additions & 173 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const markdownItAnchor = require("markdown-it-anchor");
const yaml = require("js-yaml");
const { sassPlugin } = require("esbuild-sass-plugin");
const svgSprite = require("eleventy-plugin-svg-sprite");
const { imageShortcode, imageWithClassShortcode } = require("./config");
const {
isValidGitBranch,
isValidTwitterHandle,
Expand All @@ -20,6 +19,13 @@ const {
isValidVerificationToken,
uswdsIconWithSize,
numberWithCommas,
sortByProp,
readableDate,
getStateFromDates,
htmlDateString,
minNumber,
uswdsIcon,
imageWithClassShortcode,
} = require("./js/global.js");

require("dotenv").config();
Expand Down Expand Up @@ -90,6 +96,11 @@ module.exports = function (config) {
baseUrl = new URL(hosts.undefined).href.replace(/\/$/, "");
}

// If BASEURL env variable exists, update pathPrefix to the BASEURL
if (process.env.BASEURL) {
pathPrefix = process.env.BASEURL;
}

config.addGlobalData("baseUrl", baseUrl);
config.addGlobalData("site.baseUrl", baseUrl);

Expand Down Expand Up @@ -139,160 +150,15 @@ module.exports = function (config) {
);
}

// Template function used to sort a collection by a certain property
// Ex: {% assign sortedJobs = collection.jobs | sortByProp: "title" %}
function sortByProp(values, prop) {
let vals = [...values];
return vals.sort((a, b) => {
if (typeof a[prop] == "string" && typeof b[prop] == "string") {
return a[prop].localeCompare(b[prop]);
} else {
return Math.sign(a[prop] - b[prop]);
}
});
}

// Get Date and Time as Seconds
// Datetime format: YYYY-MM-DD HH:MM
config.addLiquidShortcode("getDateTimeinSeconds", getDateTimeinSeconds);
function getDateTimeinSeconds(datetime) {
// Split the datetime string into date and time parts
const dateParts = datetime.split(" ");
const date = dateParts[0];
const time = dateParts[1];

// Extract hours, minutes, and AM/PM
let hours = parseInt(time.slice(0, time.length - 2).split(":")[0], 10); // Adjusted to capture full hour
const minutes = time.length === 6 ? time.slice(2, 4) : time.slice(3, 5);
const amPm = time.slice(-2).toLowerCase(); // Handle AM/PM case

// Convert hours to 24-hour format
if (amPm === "pm" && hours !== 12) {
hours += 12;
} else if (amPm === "am" && hours === 12) {
hours = 0;
}

// Format the datetime string for timestamp conversion
const formattedDatetime = `${date} ${String(hours).padStart(2, "0")}:${minutes} ET`;

// Convert to timestamp (in seconds)
const timestamp = Math.floor(new Date(formattedDatetime).getTime() / 1000);

return timestamp;
}

// Get State From Dates
config.addLiquidShortcode("getStateFromDates", getStateFromDates);
function getStateFromDates(opens, closes) {
if (!opens && !closes) {
return "unknown";
}

// Get the current date in "America/New_York" timezone
let now_date = new Date(
new Date().toLocaleString("en-US", { timeZone: "America/New_York" }),
);

// Parse the 'opens' date in UTC and convert to local time
let opens_date = opens ? new Date(opens) : null;

// Parse the 'closes' date in UTC and set time to 11:59:59 PM in local time
let closes_date = null;
if (closes) {
closes_date = new Date(closes);
// Set the time to 11:59:59 PM in local time
closes_date.setHours(23, 59, 59, 999);
}

// Convert opens_date and closes_date to local time for comparison
if (opens_date) {
// Adjust opens_date to local timezone
opens_date = new Date(
opens_date.toLocaleString("en-US", { timeZone: "America/New_York" }),
);

// Adjust closes_date to local timezone
if (closes_date) {
closes_date = new Date(
closes_date.toLocaleString("en-US", { timeZone: "America/New_York" }),
);
}

// Check if it's open or closed
let isOpen = now_date >= opens_date;
let isClosed = closes_date && now_date > closes_date;

if (isOpen && !isClosed) {
return "open";
} else if (isClosed) {
return "closed";
} else {
return "upcoming";
}
}

return "unknown"; // Default fallback if no conditions are met
}

config.addFilter("stateFromDates", getStateFromDates);
config.addFilter("sortByProp", sortByProp);

config.addFilter("readableDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, { zone: "America/New_York" }).toFormat(
"dd LLL yyyy",
);
});

// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
config.addFilter("htmlDateString", (dateObj) => {
if (dateObj !== undefined && dateObj !== null) {
let dateTime = DateTime.fromJSDate(dateObj);

// If working locally, add one day to the date to match what is in the actual environments.
if (baseUrl.includes("localhost")) {
dateTime = dateTime.plus({ days: 1 });
return dateTime.toFormat("yyyy-LL-dd");
} else {
return dateTime.toFormat("yyyy-LL-dd");
}
}
});

// Get the first `n` elements of a collection.
config.addFilter("head", (array, n) => {
if (!Array.isArray(array) || array.length === 0) {
return [];
}
if (n < 0) {
return array.slice(n);
}

return array.slice(0, n);
});

// Return the smallest number argument
config.addFilter("min", (...numbers) => {
return Math.min.apply(null, numbers);
});

function filterTagList(tags) {
return (tags || []).filter(
(tag) => ["all", "nav", "post", "posts"].indexOf(tag) === -1,
);
}

config.addFilter("filterTagList", filterTagList);

// Create an array of all tags
config.addCollection("tagList", function (collection) {
let tagSet = new Set();
collection.getAll().forEach((item) => {
(item.data.tags || []).forEach((tag) => tagSet.add(tag));
});

return filterTagList([...tagSet]);
});
config.addFilter("readableDate", readableDate);
config.addFilter("htmlDateString", htmlDateString);
config.addFilter("min", minNumber);
config.addFilter("numberWithCommas", numberWithCommas);
config.addLiquidShortcode("image_with_class", imageWithClassShortcode);
config.addLiquidShortcode("uswds_icon", uswdsIcon);
config.addLiquidShortcode("uswds_icon_with_size", uswdsIconWithSize);
config.addLiquidShortcode("getStateFromDates", getStateFromDates);

let markdownLibrary = markdownIt({
html: true,
Expand Down Expand Up @@ -331,25 +197,6 @@ module.exports = function (config) {
ghostMode: false,
});

// Set image shortcodes
config.addLiquidShortcode("image", imageShortcode);
config.addLiquidShortcode("image_with_class", imageWithClassShortcode);
config.addLiquidShortcode("uswds_icon", function (name) {
return `
<svg class="usa-icon" aria-hidden="true" role="img">
<use xlink:href="#svg-${name}"></use>
</svg>`;
});

config.addLiquidShortcode("uswds_icon_with_size", uswdsIconWithSize);

config.addFilter("numberWithCommas", numberWithCommas);

// If BASEURL env variable exists, update pathPrefix to the BASEURL
if (process.env.BASEURL) {
pathPrefix = process.env.BASEURL;
}

return {
dataTemplateEngine: "liquid",

Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ See the [11ty docs](https://www.11ty.dev/docs/filters/url/)
All of your images will be stored in the `_img/` directory. To reference your
images in your templates you can use the `shortcodes` built into the template.

For referencing an image without a style class, you will pass the template
shortcode the image's source path and the alternative image name in that order, i.e.,

```NJK
{% image "_img/my-image.png" "My PNG Image Alternative Name" %}
```

For referencing an image with a style class, you will pass the template
shortcode the image's source path, class names, and the alternative image name in
that order, i.e.,
Expand All @@ -80,6 +73,11 @@ that order, i.e.,
{% image_with_class "_img/my-image.png" "img-class another-class" "My PNG Image Alternative Name" %}
```

If the image does not have a style class, simply pass an empty string, i.e.,
```NJK
{% image_with_class "_img/my-image.png" "" "My PNG Image Alternative Name" %}
```

### Referencing USWDS Sprite Icons

USWDS has sprite icons available for use. Here is the
Expand Down
2 changes: 1 addition & 1 deletion _includes/menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
>
<div class="usa-nav__inner">
<button class="usa-nav__close">
{% image "_img/close.svg" "close" %}
{% image_with_class "_img/close.svg" "" "close" %}
</button>
<ul class="usa-nav__primary usa-accordion">
{% for nav_item in primary_navigation %}
Expand Down
50 changes: 50 additions & 0 deletions _tests/getStateFromDates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const { getStateFromDates } = require("../js/global");

describe("getStateFromDates", () => {
beforeEach(() => {
// Mock the system time to ensure consistent results
jest.useFakeTimers().setSystemTime(new Date("2024-11-21T12:00:00Z")); // Mock current time: 7 AM ET
});

afterEach(() => {
jest.useRealTimers(); // Restore real timers
});

test('should return "unknown" if both opens and closes are undefined', () => {
expect(getStateFromDates(null, null)).toBe("unknown");
expect(getStateFromDates(undefined, undefined)).toBe("unknown");
});

test('should return "upcoming" if now is before opens', () => {
const opens = "2024-11-22T00:00:00Z"; // Opens tomorrow at midnight UTC
expect(getStateFromDates(opens, null)).toBe("upcoming");
});

test('should return "open" if now is after opens and before closes', () => {
const opens = "2024-11-20T00:00:00Z"; // Opened yesterday at midnight UTC
const closes = "2024-11-22T00:00:00Z"; // Closes tomorrow at midnight UTC
expect(getStateFromDates(opens, closes)).toBe("open");
});

test('should return "closed" if now is after closes', () => {
const opens = "2024-11-19T00:00:00Z"; // Opened two days ago at midnight UTC
const closes = "2024-11-20T23:59:59Z"; // Closed yesterday at 11:59:59 PM UTC
expect(getStateFromDates(opens, closes)).toBe("closed");
});

test("should handle cases with only opens defined", () => {
const opens = "2024-11-20T00:00:00Z"; // Opened yesterday at midnight UTC
expect(getStateFromDates(opens, null)).toBe("open");
});

test("should handle cases with only closes defined", () => {
const closes = "2024-11-22T00:00:00Z"; // Closes tomorrow at midnight UTC
expect(getStateFromDates(null, closes)).toBe("unknown"); // No opens means "unknown"
});

test("should handle edge cases for opens and closes on the same day", () => {
const opens = "2024-11-21T00:00:00Z"; // Opens today at midnight UTC
const closes = "2024-11-21T23:59:59Z"; // Closes today at 11:59:59 PM UTC
expect(getStateFromDates(opens, closes)).toBe("open"); // Current time is 7 AM ET
});
});
Loading

0 comments on commit 301cbb7

Please sign in to comment.