Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/code coverage #763

Merged
merged 10 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .mega-linter.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
---
# don't test the reports Mega-Linter created, docs, or test files
ADDITIONAL_EXCLUDED_DIRECTORIES:
[report, megalinter-reports, docs, node_modules, _site]
[
report,
megalinter-reports,
docs,
node_modules,
_site,
"pages/jointts/positions/archive",
]

# don't lint test files or documentation
FILTER_REGEX_EXCLUDE: (.venv/|/test/|\.test\.|_test\.|/docs/|/index.html|.github/.*\.html)
Expand Down
9 changes: 4 additions & 5 deletions _data/assetPaths.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
"admin.map": "/assets/js/admin-77FHK54G.js.map",
"app.js": "/assets/js/app-LOZVWXOU.js",
"app.map": "/assets/js/app-LOZVWXOU.js.map",
"positions.js": "/assets/js/positions-JSZISVTK.js",
"positions.map": "/assets/js/positions-JSZISVTK.js.map",
"positions.js": "/assets/js/positions-XEJGQPIN.js",
"positions.map": "/assets/js/positions-XEJGQPIN.js.map",
"subnav.js": "/assets/js/subnav-3QHQ2EX4.js",
"subnav.map": "/assets/js/subnav-3QHQ2EX4.js.map",
"uswds.js": "/assets/js/uswds-init.js",
"styles.css": "/assets/styles/styles-V3W55VXY.css",
"styles.map": "/assets/styles/styles-V3W55VXY.css.map"
"styles.css": "/assets/styles/styles-EDJMOHM2.css",
"styles.map": "/assets/styles/styles-EDJMOHM2.css.map"
}
13 changes: 6 additions & 7 deletions _data/global_info_sessions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@
- link: https://events.zoomgov.com/ev/Av-aDrwce3qkDwAXkOMWHA7bgUNqMch9qfDdQ8l2AJn7sq1DYRHP~AgHpmnTUiBfoa07XmieFdB0ynwX70cbufwR_U9pYVt1lkpD459yK1KUa8h2GNMtsmQ5D-wxuGICpWWYo7ztVs-GZXA
date: 2025-01-16
time: 12:30pm-1:30pm
# - link: https://events.zoomgov.com/ev/AjU8F2VKUOcgDvLzAnFQET5Xh_GQYdKDPGw6LdmbUGSdx8k04YYS~AmXNHn2pIW5NNym1WMc7Vc2QF3emlotWOSrDHUWArrta84tDRajgpIQ2QijwiNvtrwVXM8j4uhJmXFyvil5CsO-15g
# date: 2025-02-20
# time: 12:30pm-1:30pm

- link: https://events.zoomgov.com/ev/AjU8F2VKUOcgDvLzAnFQET5Xh_GQYdKDPGw6LdmbUGSdx8k04YYS~AmXNHn2pIW5NNym1WMc7Vc2QF3emlotWOSrDHUWArrta84tDRajgpIQ2QijwiNvtrwVXM8j4uhJmXFyvil5CsO-15g
date: 2025-02-20
time: 12:30pm-1:30pm

- link: https://events.zoomgov.com/ev/AnrQGHhOglyNdnzcy3GnwehWdQhK6TknCJRa-VJfVXQMbhIusD7A~AlRk8YiVY0s5kV1H-LBHVqZV52GnaMKpa4GuDM5x8Dq5pzhB73x9dENElndxcLMd1FBFmnPQiaiD35-N1JMk--OEXQ
date: 2025-03-20
time: 12:30pm-1:30pm
# - link: https://events.zoomgov.com/ev/AnrQGHhOglyNdnzcy3GnwehWdQhK6TknCJRa-VJfVXQMbhIusD7A~AlRk8YiVY0s5kV1H-LBHVqZV52GnaMKpa4GuDM5x8Dq5pzhB73x9dENElndxcLMd1FBFmnPQiaiD35-N1JMk--OEXQ
# date: 2025-03-20
# time: 12:30pm-1:30pm
2 changes: 0 additions & 2 deletions _includes/layouts/jointts/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,10 @@ <h2>Application process</h2>
</p>
</div>

{% comment %}
<!-- General Info Sessions -->
{% if sorted_info_sessions.size > 0 %}
{% include "layouts/jointts/info-sessions-sidebar.html" %}
{% endif %}
{% endcomment %}
</div>
</div>
</section>
2 changes: 1 addition & 1 deletion _includes/layouts/jointts/info-sessions-sidebar.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="desktop:grid-col-4 margin-top-4 desktop:margin-top-0">
<div class="usa-summary-box">
<div class="usa-summary-box" id="info-sessions-box">
<div class="usa-summary-box__body">
<h3 class="usa-summary-box__heading">Join an info session</h3>
<div class="usa-summary-box__text" id="global-info-sessions-wrapper">
Expand Down
2 changes: 0 additions & 2 deletions _includes/layouts/jointts/jobs.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ <h2 id="open-positions">Open positions</h2>
<p>We are hiring and will be sharing upcoming jobs and open positions as they are available.</p>
</section>

{% comment %}
<section class="upcoming-jobs">
<h2 id="upcoming-positions">Upcoming positions</h2>
</section>
{% endcomment %}
162 changes: 162 additions & 0 deletions _tests/addOpenJobsToDOM.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/**
* @jest-environment jsdom
*/

const { addOpenJobsToDOM } = require("../js/positions");

describe("addOpenJobsToDOM", () => {
let openJobsSection;

beforeEach(() => {
// Set up a DOM structure for testing
document.body.innerHTML = `<div class="open-jobs"></div>`;
openJobsSection = document.querySelector(".open-jobs");
});

afterEach(() => {
jest.clearAllMocks();
document.body.innerHTML = "";
});

test("should append job list with correct details when jobs are available", () => {
const openJobs = [
{
title: "Frontend Developer",
url: "/join/frontend-developer/",
external_url: "",
closes: "2025-01-31",
max_applications: 50,
info_sessions: [],
},
{
title: "Backend Developer",
url: "/join/backend-developer/",
external_url: "https://external.com/job/backend",
closes: "2025-02-15",
max_applications: 0,
info_sessions: [],
},
];

addOpenJobsToDOM(openJobs);

const jobList = openJobsSection.querySelector("ul");
expect(jobList).not.toBeNull();
expect(jobList.children.length).toBe(2);

const firstJob = jobList.children[0];
expect(firstJob.querySelector("a").textContent).toBe("Frontend Developer");
expect(firstJob.querySelector("a").href).toContain(
"/join/frontend-developer/",
);
expect(firstJob.textContent).toContain(
"Open now through Friday, January 31, 2025 at 11:59pm ET or until 50 applications have been received.",
);

const secondJob = jobList.children[1];
expect(secondJob.querySelector("a").textContent).toBe("Backend Developer");
expect(secondJob.querySelector("a").href).toBe(
"https://external.com/job/backend",
);
expect(secondJob.textContent).toContain(
"Open now through Saturday, February 15, 2025 at 11:59pm ET.",
);
expect(secondJob.querySelector("a").target).toBe("_blank"); // External link opens in new tab
});

test("should append no jobs message when no jobs are available", () => {
addOpenJobsToDOM([]);

const noJobsText = openJobsSection.querySelector("p");
expect(noJobsText).not.toBeNull();
expect(noJobsText.textContent).toContain("No open positions at this time.");
expect(noJobsText.innerHTML).toContain("Sign up for job alerts!");
});

test("should handle empty info sessions array gracefully", () => {
const openJobs = [
{
title: "Frontend Developer",
url: "/join/frontend-developer/",
external_url: "",
closes: "2025-01-31T23:59:59Z",
max_applications: 0,
info_sessions: [],
},
];

addOpenJobsToDOM(openJobs);

const jobList = openJobsSection.querySelector("ul");
expect(jobList.children.length).toBe(1);

const firstJob = jobList.children[0];
expect(firstJob.textContent).toContain("Frontend Developer");
});

test("should correctly construct URLs for pages.cloud.gov", () => {
delete global.window.location; // Clear existing location mock
global.window.location = { href: "https://pages.cloud.gov/join/" };

const openJobs = [
{
title: "Frontend Developer",
url: "/join/frontend-developer/",
external_url: "",
closes: "2025-01-31",
max_applications: 0,
info_sessions: [],
},
];

addOpenJobsToDOM(openJobs);

const jobLink = openJobsSection.querySelector("a");
expect(jobLink.href).toBe(
"https://pages.cloud.gov/join/frontend-developer/",
);
});

test("should use external URL if provided", () => {
const openJobs = [
{
title: "Backend Developer",
url: "/join/backend-developer/",
external_url: "https://external.com/job/backend",
closes: "2025-02-15",
max_applications: 0,
info_sessions: [],
},
];

addOpenJobsToDOM(openJobs);

const jobLink = openJobsSection.querySelector("a");
expect(jobLink.href).toBe("https://external.com/job/backend");
expect(jobLink.target).toBe("_blank");
});

test("should apply correct inline styles to elements", () => {
const openJobs = [
{
title: "Frontend Developer",
url: "/join/frontend-developer/",
external_url: "",
closes: "2025-01-31",
max_applications: 0,
info_sessions: [],
},
];

addOpenJobsToDOM(openJobs);

const jobList = openJobsSection.querySelector("ul");
expect(jobList.style.paddingLeft).toBe("3ch");

const listItem = jobList.children[0];
expect(listItem.style.marginBottom).toBe("0.25em");

const link = listItem.querySelector("a");
expect(link.style.color).toBe("rgb(0, 94, 162)"); // CSS color translated
});
});
103 changes: 103 additions & 0 deletions _tests/addUpcomingJobsToDOM.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* @jest-environment jsdom
*/

const { addUpcomingJobsToDOM } = require("../js/positions");

describe("addUpcomingJobsToDOM", () => {
let upcomingJobsSection;

beforeEach(() => {
// Set up the mock DOM for testing
upcomingJobsSection = document.createElement("div");
upcomingJobsSection.className = "upcoming-jobs";
document.body.appendChild(upcomingJobsSection);
});

afterEach(() => {
// Clean up the DOM after each test
document.body.innerHTML = "";
});

it("removes the upcoming-jobs section if the jobs list is empty", () => {
addUpcomingJobsToDOM([]);

// Verify the section is removed
expect(document.querySelector(".upcoming-jobs")).toBeNull();
});

it("renders a list of jobs with correct links and styles", () => {
const upcomingJobs = [
{
title: "Job 1",
url: "/join/job1",
external_url: "",
info_sessions: [],
},
{
title: "Job 2",
url: "/join/job2",
external_url: "http://external.com/job2",
info_sessions: [],
},
];

// Mock window.location.href for internal URL handling
Object.defineProperty(window, "location", {
value: { href: "https://example.pages.cloud.gov/" },
writable: true,
});

addUpcomingJobsToDOM(upcomingJobs);

const jobList = document.querySelector(".upcoming-jobs ul");
expect(jobList).not.toBeNull();
expect(jobList.children.length).toBe(2);

const [job1, job2] = jobList.children;

// Check Job 1
const job1Link = job1.querySelector("a");
expect(job1Link.textContent).toBe("Job 1");
expect(job1Link.href).toBe("https://example.pages.cloud.gov/job1");
expect(job1Link.style.color).toBe("rgb(0, 94, 162)");

// Check Job 2
const job2Link = job2.querySelector("a");
expect(job2Link.textContent).toBe("Job 2");
expect(job2Link.href).toBe("http://external.com/job2");
expect(job2Link.style.color).toBe("rgb(0, 94, 162)");
expect(job2Link.target).toBe("_blank");
});

it("does not append the list if there are no upcoming jobs", () => {
addUpcomingJobsToDOM([]);

const jobList = document.querySelector(".upcoming-jobs ul");
expect(jobList).toBeNull();
});

it("handles internal URLs correctly when not on pages.cloud.gov", () => {
const upcomingJobs = [
{
title: "Job 1",
url: "/join/job1",
external_url: "",
info_sessions: [],
},
];

// Mock window.location to simulate the test environment
Object.defineProperty(window, "location", {
value: {
href: "https://localhost:8000/",
},
writable: true,
});

addUpcomingJobsToDOM(upcomingJobs);

const job1Link = document.querySelector(".upcoming-jobs ul li a");
expect(job1Link.href).toContain("/join/job1");
});
});
5 changes: 5 additions & 0 deletions _tests/convertTimeToZone.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ describe("convertTimeToZone", () => {
const result = convertTimeToZone("12:30pm", "America/Los_Angeles");
expect(result).toBe("9:30 AM");
});

it("should show midnight as 00:00 AM", () => {
const result = convertTimeToZone("12:00am", "America/New_York");
expect(result).toBe("0:00 AM");
});
});
33 changes: 33 additions & 0 deletions _tests/htmlDateString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { htmlDateString } = require("../js/global");

describe("htmlDateString", () => {
beforeAll(() => {
global.baseUrl = ""; // Mocking `baseUrl` for testing
});

test("should format a valid Date object to yyyy-LL-dd", () => {
const input = new Date(2024, 10, 21); // November 21, 2024
const result = htmlDateString(input);
expect(result).toBe("2024-11-21");
});

test("should add one day for local environment (`localhost` in baseUrl)", () => {
global.baseUrl = "http://localhost";
const input = new Date(2024, 10, 21); // November 21, 2024
const result = htmlDateString(input);
expect(result).toBe("2024-11-22");
});

test("should not add a day for production environment", () => {
global.baseUrl = "https://production.com";
const input = new Date(2024, 10, 21); // November 21, 2024
const result = htmlDateString(input);
expect(result).toBe("2024-11-21");
});

test("should throw an error if input is not a valid Date object", () => {
expect(() => htmlDateString("invalid-date")).toThrow();
expect(() => htmlDateString(12345)).toThrow();
expect(() => htmlDateString({})).toThrow();
});
});
Loading
Loading