diff --git a/content/blog/slsabuild3-temurin/index.md b/content/blog/slsabuild3-temurin/index.md index 23dfd160..76d9366d 100644 --- a/content/blog/slsabuild3-temurin/index.md +++ b/content/blog/slsabuild3-temurin/index.md @@ -12,19 +12,19 @@ tags: Supply-chain Levels for Software Artifacts, or [SLSA](https://slsa.dev), is a framework with individual levels that software producers can work towards to make their software more secure, and consumers -can use to make decisions based on the software package’s security posture. The +can use to make decisions based on the software package’s security posture. The Adoptium project has worked closely with the Eclipse Foundation security team to work towards making the Eclipse Temurin compliant with the SLSA specification's build requirements. [At the end](https://adoptium.net/blog/2022/11/slsa2-temurin/) [of 2022](https://newsroom.eclipse.org/eclipse-newsletter/2022/december/eclipse-temurin-slsa-level-two-compliant) -we achieved compliance with level 2 of the SLSA v0.1 specification. In +we achieved compliance with level 2 of the SLSA v0.1 specification. In April 2023 SLSA version 1.0 was released and split the specification into multiple "tracks", of which the build track is the only one currently -published. If you're not familiar with the changes, check out +published. If you're not familiar with the changes, check out [this lightning talk](https://youtu.be/uLXzyutZEmQ?si=XjD9H6uO_GEjJVBG) from one -of my colleagues. We have been able to build on our work done previously to +of my colleagues. We have been able to build on our work done previously to meet build level 3 for Linux and macOS for Eclipse Temurin's build and distribution. @@ -54,16 +54,16 @@ claiming SLSA build level 3 for those builds. We have introduced a build verification step which can take the Software Bill of Materials (SBoM) produced as part of the build output and verify its -contents as far as is practical. This will do some checks to ensure that +contents as far as is practical. This will do some checks to ensure that the fields are valid and match expectations about how the product has been -built. This job is stored in +built. This job is stored in https://github.com/adoptium/temurin-build/blob/master/tooling as release_download_test.sh which performs SHA and GPG checks as well as -running some basic checks on the downloads. It also calls +running some basic checks on the downloads. It also calls validateSBOMcontent.sh to check the SBoM contents to make sure the -dependencies, including compilers, listed in there match expectations. The +dependencies, including compilers, listed in there match expectations. The SBoM contents now also includes the SHA256 checksums of all of the build -artifacts in the `components` section. There is information on +artifacts in the `components` section. There is information on programatically verifying the GPG signatures in [an earlier blog](https://adoptium.net/blog/2022/07/gpg-signed-releases/) @@ -78,7 +78,7 @@ then these will be trapped early on. We expect that all of these checks will be enhanced over time, particularly as we add more details into the SBoM. -The current SBoM can be downloaded via the adoptium API. If you are already +The current SBoM can be downloaded via the adoptium API. If you are already familiar with the API for downloading JDKs, then replacing `jdk` with `sbom` in the URL will let you download the SBoM. For example, this will download the latest GA SBoM for Temurin 21 on Linux/x64: @@ -87,7 +87,7 @@ the latest GA SBoM for Temurin 21 on Linux/x64: Note that there is an enhanced version of the SBoM which includes more details on the artifacts that is already in the nightly builds and will be -included for the January 2024 GA releases and beyond. We will not (and +included for the January 2024 GA releases and beyond. We will not (and should not) regenerate the SBoM for older releases. ### Prevent secret material used to sign the provenance from being accessible to user-defined build steps @@ -107,6 +107,6 @@ source code. We are also continuing to work on our [reproducible builds](https://adoptium.net/blog/2023/09/Reproducible-Comparison-Builds/) which gives an extra layer of confidence that any customers of Temurin are able to rebuild from source code in order to independently verify that nothing in our build -systems have been tampered with or introduced any unexpected code. Anyone +systems have been tampered with or introduced any unexpected code. Anyone (yes, even you!) can use our fully open-source setup and build scripts to rebuild the Temurin JDK, and we encourage you to give it a try! diff --git a/src/components/TemurinDownloadTable/index.tsx b/src/components/TemurinDownloadTable/index.tsx index f83bbe8c..9d9ba44e 100644 --- a/src/components/TemurinDownloadTable/index.tsx +++ b/src/components/TemurinDownloadTable/index.tsx @@ -1,137 +1,185 @@ import * as React from "react" -import { Link, Trans, useI18next } from 'gatsby-plugin-react-i18next'; -import { FaDownload } from 'react-icons/fa'; -import { MdNotes } from 'react-icons/md'; -import { MdVerifiedUser } from 'react-icons/md'; -import { capitalize } from '../../util/capitalize'; -import { localeDate } from '../../util/localeDate'; -import { IoMdHelpBuoy } from 'react-icons/io'; -import { PiFiles } from 'react-icons/pi'; -import LinkText from '../LinkText' +import { Link, Trans, useI18next } from "gatsby-plugin-react-i18next" +import { FaDownload } from "react-icons/fa" +import { MdNotes } from "react-icons/md" +import { MdVerifiedUser } from "react-icons/md" +import { capitalize } from "../../util/capitalize" +import { localeDate } from "../../util/localeDate" +import { IoMdHelpBuoy } from "react-icons/io" +import { PiFiles } from "react-icons/pi" +import LinkText from "../LinkText" -const TemurinDownloadTable = ({results}) => { - const { language } = useI18next(); +const TemurinDownloadTable = ({ results }) => { + const { language } = useI18next() - let source - if (results && results.source) { - source = results.source - } + let source + if (results && results.source) { + source = results.source + } - return ( + return ( <> - {source && -

- Release Notes - Installation Guide - Source Code -

- } - - - {results ? ( - results.map( - (pkg, i): string | JSX.Element => - pkg && ( - - - - - - - ) - ) - ) : - - } - -
- - {pkg.release_name} - - - Temurin - - AQAvit logo - - - {localeDate(pkg.release_date, language)} - {capitalize(pkg.os)}{pkg.architecture === 'x32' ? 'x86' : pkg.architecture} - - {pkg.binaries.map( - (binary, i): string | JSX.Element => - binary && ( - - {binary.installer_link && ( - - )} - - - ) - )} -
-
- - ); -}; - -export default TemurinDownloadTable; - -const BinaryTable = ({ checksum, link, extension, type, size, os, arch, version }) => { - return ( - - - - -
- {`${type} - ${size} MB`} + {source && ( +

+ + + Release Notes + + + + Installation Guide + + + + Source Code + +

+ )} + + + {results ? ( + results.map( + (pkg, i): string | JSX.Element => + pkg && ( + + - - - + - + + + ), + ) + ) : ( + + )} + +
+ + {pkg.release_name} + + + Temurin{" "} + + + AQAvit logo + + + + {localeDate(pkg.release_date, language)} +
- - - Checksum - - + {capitalize(pkg.os)} + {pkg.architecture === "x32" ? "x86" : pkg.architecture}
+ + {pkg.binaries.map( + (binary, i): string | JSX.Element => + binary && ( + + {binary.installer_link && ( + + )} + + + ), + )} +
+
+ + ) +} -
- - - - {extension} - - - - ) -} \ No newline at end of file +export default TemurinDownloadTable + +const BinaryTable = ({ + checksum, + link, + extension, + type, + size, + os, + arch, + version, +}) => { + return ( + + + + + + + + + + + +
{`${type} - ${size} MB`}
+ + + + Checksum + + + +
+ + + + {extension} + + + + ) +} diff --git a/src/hooks/__tests__/fetchLatestTemurin.test.tsx b/src/hooks/__tests__/fetchLatestTemurin.test.tsx index 2bd32be3..60f772a4 100644 --- a/src/hooks/__tests__/fetchLatestTemurin.test.tsx +++ b/src/hooks/__tests__/fetchLatestTemurin.test.tsx @@ -1,61 +1,76 @@ -import { renderHook, waitFor } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import { fetchLatestForOS } from '../fetchLatestTemurin'; -import { mockLatestTemurin } from '../../__fixtures__/hooks'; -import axios from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import { renderHook, waitFor } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { fetchLatestForOS } from "../fetchLatestTemurin" +import { mockLatestTemurin } from "../../__fixtures__/hooks" +import axios from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(axios); +const mock = new MockAdapter(axios) afterEach(() => { - vi.clearAllMocks(); - mock.reset(); -}); + vi.clearAllMocks() + mock.reset() +}) afterAll(() => { - mock.restore(); -}); + mock.restore() +}) -describe('fetchLatestForOS', () => { - it('binary URL is set correctly', async () => { - const mockResponse = [mockLatestTemurin(false)]; +describe("fetchLatestForOS", () => { + it("binary URL is set correctly", async () => { + const mockResponse = [mockLatestTemurin(false)] - mock.onGet().reply(200, mockResponse); - let spy = vi.spyOn(axios, "get"); + mock.onGet().reply(200, mockResponse) + let spy = vi.spyOn(axios, "get") - const { result } = renderHook(() => fetchLatestForOS(true, 11, 'linux', 'x64')); - await waitFor(() => { - expect(result.current?.release_name).toBe('release_name_mock') - }, { interval: 1 }); + const { result } = renderHook(() => + fetchLatestForOS(true, 11, "linux", "x64"), + ) + await waitFor( + () => { + expect(result.current?.release_name).toBe("release_name_mock") + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(1) expect(spy).toHaveBeenCalledWith( - "https://api.adoptium.net/v3/assets/feature_releases/11/ga?os=linux&architecture=x64&image_type=jdk&jvm_impl=hotspot&page_size=1&vendor=eclipse" - ); + "https://api.adoptium.net/v3/assets/feature_releases/11/ga?os=linux&architecture=x64&image_type=jdk&jvm_impl=hotspot&page_size=1&vendor=eclipse", + ) expect(result.current).toMatchSnapshot() }) - it('installer is returned if available', async () => { - const mockResponse = [mockLatestTemurin(true)]; + it("installer is returned if available", async () => { + const mockResponse = [mockLatestTemurin(true)] - mock.onGet().reply(200, mockResponse); - let spy = vi.spyOn(axios, "get"); + mock.onGet().reply(200, mockResponse) + let spy = vi.spyOn(axios, "get") - const { result } = renderHook(() => fetchLatestForOS(true, 11, 'linux', 'x64')); - await waitFor(() => { - expect(result.current?.release_name).toBe('release_name_mock') - }, { interval: 1 }); + const { result } = renderHook(() => + fetchLatestForOS(true, 11, "linux", "x64"), + ) + await waitFor( + () => { + expect(result.current?.release_name).toBe("release_name_mock") + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(1) expect(result.current).toMatchSnapshot() }) - it('binary to be null on error', async() => { - mock.onGet().reply(500); - let spy = vi.spyOn(axios, "get"); + it("binary to be null on error", async () => { + mock.onGet().reply(500) + let spy = vi.spyOn(axios, "get") - const { result } = renderHook(() => fetchLatestForOS(true, 11, 'linux', 'x64')); - await waitFor(() => { - expect(result).toBeNull - }, { interval: 1 }); + const { result } = renderHook(() => + fetchLatestForOS(true, 11, "linux", "x64"), + ) + await waitFor( + () => { + expect(result).toBeNull + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(1) }) -}); +}) diff --git a/src/hooks/__tests__/fetchMarketplace.test.tsx b/src/hooks/__tests__/fetchMarketplace.test.tsx index 27e6086a..e246bd93 100644 --- a/src/hooks/__tests__/fetchMarketplace.test.tsx +++ b/src/hooks/__tests__/fetchMarketplace.test.tsx @@ -1,69 +1,98 @@ -import { renderHook } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import { getAllPkgsForVersion, getImageForDistribution } from '../fetchMarketplace'; -import { createMockTemurinFeatureReleaseAPI } from '../../__fixtures__/hooks'; -import vendors from '../../json/marketplace.json'; -import getVendorIdentifier from '../../util/vendors'; -import AxiosInstance from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import { renderHook } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { + getAllPkgsForVersion, + getImageForDistribution, +} from "../fetchMarketplace" +import { createMockTemurinFeatureReleaseAPI } from "../../__fixtures__/hooks" +import vendors from "../../json/marketplace.json" +import getVendorIdentifier from "../../util/vendors" +import AxiosInstance from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(AxiosInstance); -let mockResponse = [createMockTemurinFeatureReleaseAPI(false)]; -let selectedVendorIdentifiers = vendors.map(v => getVendorIdentifier(v)); +const mock = new MockAdapter(AxiosInstance) +let mockResponse = [createMockTemurinFeatureReleaseAPI(false)] +let selectedVendorIdentifiers = vendors.map(v => getVendorIdentifier(v)) afterEach(() => { vi.clearAllMocks() }) -describe('getAllPkgsForVersion', () => { - it('returns valid JSON', async() => { - mock.onGet().reply(200, mockResponse); +describe("getAllPkgsForVersion", () => { + it("returns valid JSON", async () => { + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await getAllPkgsForVersion(8, 'linux', 'x64', 'jdk', selectedVendorIdentifiers).then((data) => { + renderHook(async () => { + await getAllPkgsForVersion( + 8, + "linux", + "x64", + "jdk", + selectedVendorIdentifiers, + ).then(data => { expect(data).toMatchSnapshot() }) }) }) - it('returns valid JSON - Alpine Linux', async() => { - mock.onGet().reply(200, mockResponse); + it("returns valid JSON - Alpine Linux", async () => { + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await getAllPkgsForVersion(8, 'alpine-linux', 'x64', 'any', selectedVendorIdentifiers).then((data) => { + renderHook(async () => { + await getAllPkgsForVersion( + 8, + "alpine-linux", + "x64", + "any", + selectedVendorIdentifiers, + ).then(data => { expect(data).toMatchSnapshot() }) }) }) - it('returns valid JSON - installer', async() => { - mockResponse = [createMockTemurinFeatureReleaseAPI(true)]; + it("returns valid JSON - installer", async () => { + mockResponse = [createMockTemurinFeatureReleaseAPI(true)] - mock.onGet().reply(200, mockResponse); + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await getAllPkgsForVersion(8, 'linux', 'x64', 'jdk', selectedVendorIdentifiers).then((data) => { + renderHook(async () => { + await getAllPkgsForVersion( + 8, + "linux", + "x64", + "jdk", + selectedVendorIdentifiers, + ).then(data => { expect(data).toMatchSnapshot() }) }) }) - it('getImageForDistribution tests', () => { - expect(getImageForDistribution('microsoft')).toBe('/images/microsoft-logo.png'); - expect(getImageForDistribution('temurin')).toBe('/images/adoptium-logo.png'); - expect(getImageForDistribution('redhat')).toBe('/images/redhat.svg'); - expect(getImageForDistribution('bisheng')).toBe('/images/huawei.svg'); - expect(getImageForDistribution('zulu')).toBe('/images/azul-logo.png'); - expect(getImageForDistribution('semeru')).toBe('/images/ibm-logo.png'); - }); + it("getImageForDistribution tests", () => { + expect(getImageForDistribution("microsoft")).toBe( + "/images/microsoft-logo.png", + ) + expect(getImageForDistribution("temurin")).toBe("/images/adoptium-logo.png") + expect(getImageForDistribution("redhat")).toBe("/images/redhat.svg") + expect(getImageForDistribution("bisheng")).toBe("/images/huawei.svg") + expect(getImageForDistribution("zulu")).toBe("/images/azul-logo.png") + expect(getImageForDistribution("semeru")).toBe("/images/ibm-logo.png") + }) - it('MarketplaceReleases to be null on error', async() => { - mock.onGet().reply(500); + it("MarketplaceReleases to be null on error", async () => { + mock.onGet().reply(500) - renderHook(async() => { - await getAllPkgsForVersion(8, 'linux', 'x64', 'jdk', selectedVendorIdentifiers).then((data) => { + renderHook(async () => { + await getAllPkgsForVersion( + 8, + "linux", + "x64", + "jdk", + selectedVendorIdentifiers, + ).then(data => { expect(data).toBeNull }) - }); + }) }) -}); +}) diff --git a/src/hooks/__tests__/fetchNews.test.tsx b/src/hooks/__tests__/fetchNews.test.tsx index 01855e89..4fc1541a 100644 --- a/src/hooks/__tests__/fetchNews.test.tsx +++ b/src/hooks/__tests__/fetchNews.test.tsx @@ -1,46 +1,52 @@ -import { renderHook, waitFor } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import { fetchNewsItems } from '../fetchNews'; -import { mockNewsAPI, mockEventsAPI } from '../../__fixtures__/hooks'; -import axios from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import { renderHook, waitFor } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { fetchNewsItems } from "../fetchNews" +import { mockNewsAPI, mockEventsAPI } from "../../__fixtures__/hooks" +import axios from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(axios); +const mock = new MockAdapter(axios) afterEach(() => { - vi.clearAllMocks(); - mock.reset(); -}); + vi.clearAllMocks() + mock.reset() +}) afterAll(() => { - mock.restore(); -}); - -describe('fetchNewsItems', () => { - it('returns valid news and events object', async () => { - mock.onGet(/.*\/api\/news.*/).reply(200, mockNewsAPI()); - mock.onGet(/.*\/api\/events.*/).reply(200, mockEventsAPI()); - let spy = vi.spyOn(axios, "get"); - - const { result } = renderHook(() => fetchNewsItems(true, 1)); - await waitFor(() => { - expect(result.current?.news.news[0].title).toBe('news_title_mock') - expect(result.current?.events[0].title).toBe('events_title_mock') - }, { interval: 1 }); + mock.restore() +}) + +describe("fetchNewsItems", () => { + it("returns valid news and events object", async () => { + mock.onGet(/.*\/api\/news.*/).reply(200, mockNewsAPI()) + mock.onGet(/.*\/api\/events.*/).reply(200, mockEventsAPI()) + let spy = vi.spyOn(axios, "get") + + const { result } = renderHook(() => fetchNewsItems(true, 1)) + await waitFor( + () => { + expect(result.current?.news.news[0].title).toBe("news_title_mock") + expect(result.current?.events[0].title).toBe("events_title_mock") + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(2) expect(result.current).toMatchSnapshot() }) - it('newsAndEvents to be empty on error', async() => { - mock.onGet().reply(500); - let spy = vi.spyOn(axios, "get"); + it("newsAndEvents to be empty on error", async () => { + mock.onGet().reply(500) + let spy = vi.spyOn(axios, "get") - const { result } = renderHook(() => fetchNewsItems(true, 1)); - await waitFor(() => { - expect(result.current?.news.news).toStrictEqual([]) - expect(result.current?.events).toStrictEqual([]) - }, { interval: 1 }); + const { result } = renderHook(() => fetchNewsItems(true, 1)) + await waitFor( + () => { + expect(result.current?.news.news).toStrictEqual([]) + expect(result.current?.events).toStrictEqual([]) + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(2) }) -}); +}) diff --git a/src/hooks/__tests__/fetchReleaseNotes.test.tsx b/src/hooks/__tests__/fetchReleaseNotes.test.tsx index 00506666..64abe59a 100644 --- a/src/hooks/__tests__/fetchReleaseNotes.test.tsx +++ b/src/hooks/__tests__/fetchReleaseNotes.test.tsx @@ -1,87 +1,126 @@ -import { renderHook, waitFor } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import { fetchReleaseNotesForVersion } from '../fetchReleaseNotes'; -import { createMockReleaseNotesAPI } from '../../__fixtures__/hooks'; -import axios from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import { renderHook, waitFor } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { fetchReleaseNotesForVersion } from "../fetchReleaseNotes" +import { createMockReleaseNotesAPI } from "../../__fixtures__/hooks" +import axios from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(axios); -let mockResponse = createMockReleaseNotesAPI(1); +const mock = new MockAdapter(axios) +let mockResponse = createMockReleaseNotesAPI(1) afterEach(() => { - vi.clearAllMocks(); - mock.reset(); -}); + vi.clearAllMocks() + mock.reset() +}) afterAll(() => { - mock.restore(); -}); + mock.restore() +}) let sortReleaseNotesByCallback = vi.fn() -describe('fetchReleaseNotesForVersion', () => { - it('returns valid JSON', async () => { - mock.onGet().reply(200, mockResponse); - let spy = vi.spyOn(axios, "get"); - - const { result } = renderHook(() => fetchReleaseNotesForVersion(true, 'sample_version', sortReleaseNotesByCallback)); - await waitFor(() => { - expect(result.current?.release_name).toBe('release_name_mock') - }, { interval: 1 }); +describe("fetchReleaseNotesForVersion", () => { + it("returns valid JSON", async () => { + mock.onGet().reply(200, mockResponse) + let spy = vi.spyOn(axios, "get") + + const { result } = renderHook(() => + fetchReleaseNotesForVersion( + true, + "sample_version", + sortReleaseNotesByCallback, + ), + ) + await waitFor( + () => { + expect(result.current?.release_name).toBe("release_name_mock") + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(1) expect(spy).toHaveBeenCalledWith( - "https://api.adoptium.net/v3/info/release_notes/sample_version" - ); + "https://api.adoptium.net/v3/info/release_notes/sample_version", + ) expect(result.current).toMatchSnapshot() }) - it('returns null if error is caught in fetch', async () => { - mock.onGet().reply(200, mockResponse); - let spy = vi.spyOn(axios, "get"); - - const { result } = renderHook(() => fetchReleaseNotesForVersion(true, 'sample_version', sortReleaseNotesByCallback)); - await waitFor(() => { - expect(result.current).toBe(null) - }, { interval: 1 }); + it("returns null if error is caught in fetch", async () => { + mock.onGet().reply(200, mockResponse) + let spy = vi.spyOn(axios, "get") + + const { result } = renderHook(() => + fetchReleaseNotesForVersion( + true, + "sample_version", + sortReleaseNotesByCallback, + ), + ) + await waitFor( + () => { + expect(result.current).toBe(null) + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(1) expect(spy).toHaveBeenCalledWith( - "https://api.adoptium.net/v3/info/release_notes/sample_version" - ); - }); + "https://api.adoptium.net/v3/info/release_notes/sample_version", + ) + }) - it('returns null if version is not defined', async () => { - mock.onGet().reply(200, mockResponse); + it("returns null if version is not defined", async () => { + mock.onGet().reply(200, mockResponse) - const { result } = renderHook(() => fetchReleaseNotesForVersion(true, null, sortReleaseNotesByCallback)); + const { result } = renderHook(() => + fetchReleaseNotesForVersion(true, null, sortReleaseNotesByCallback), + ) expect(result.current).toBe(null) }) - it('checks sortReleaseNotesByCallback to be called', async () => { - mock.onGet().reply(200, mockResponse); - - const { result } = renderHook(() => fetchReleaseNotesForVersion(true, 'sample_version', sortReleaseNotesByCallback)); - await waitFor(() => { - expect(sortReleaseNotesByCallback).toHaveBeenCalledTimes(1) - }, { interval: 1 }); - }); - - it('checks sortReleaseNotesByCallback NOT to be called', async () => { - mock.onGet().reply(200, mockResponse); - - const { result } = renderHook(() => fetchReleaseNotesForVersion(true, 'sample_version')); - await waitFor(() => { - expect(sortReleaseNotesByCallback).toHaveBeenCalledTimes(0); - }, { interval: 1 }); - }); + it("checks sortReleaseNotesByCallback to be called", async () => { + mock.onGet().reply(200, mockResponse) + + const { result } = renderHook(() => + fetchReleaseNotesForVersion( + true, + "sample_version", + sortReleaseNotesByCallback, + ), + ) + await waitFor( + () => { + expect(sortReleaseNotesByCallback).toHaveBeenCalledTimes(1) + }, + { interval: 1 }, + ) + }) - it('releaseNotes to be null on error', async() => { - mock.onGet().reply(500); - let spy = vi.spyOn(axios, "get"); + it("checks sortReleaseNotesByCallback NOT to be called", async () => { + mock.onGet().reply(200, mockResponse) + + const { result } = renderHook(() => + fetchReleaseNotesForVersion(true, "sample_version"), + ) + await waitFor( + () => { + expect(sortReleaseNotesByCallback).toHaveBeenCalledTimes(0) + }, + { interval: 1 }, + ) + }) - const { result } = renderHook(() => fetchReleaseNotesForVersion(true, 'sample_version')); - await waitFor(() => { - expect(result).toBeNull - }, { interval: 1 }); + it("releaseNotes to be null on error", async () => { + mock.onGet().reply(500) + let spy = vi.spyOn(axios, "get") + + const { result } = renderHook(() => + fetchReleaseNotesForVersion(true, "sample_version"), + ) + await waitFor( + () => { + expect(result).toBeNull + }, + { interval: 1 }, + ) expect(spy).toHaveBeenCalledTimes(1) }) -}); +}) diff --git a/src/hooks/__tests__/fetchTemurinReleases.test.tsx b/src/hooks/__tests__/fetchTemurinReleases.test.tsx index d1bc41e1..63be5201 100644 --- a/src/hooks/__tests__/fetchTemurinReleases.test.tsx +++ b/src/hooks/__tests__/fetchTemurinReleases.test.tsx @@ -1,24 +1,24 @@ -import { renderHook } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' -import { loadLatestAssets } from '../fetchTemurinReleases'; -import { createMockTemurinReleaseAPI } from '../../__fixtures__/hooks'; -import AxiosInstance from 'axios' -import MockAdapter from 'axios-mock-adapter'; -import {getVersionAsString} from '../index' +import { renderHook } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { loadLatestAssets } from "../fetchTemurinReleases" +import { createMockTemurinReleaseAPI } from "../../__fixtures__/hooks" +import AxiosInstance from "axios" +import MockAdapter from "axios-mock-adapter" +import { getVersionAsString } from "../index" -const mock = new MockAdapter(AxiosInstance); -let mockResponse = [createMockTemurinReleaseAPI(false, 'jdk')]; +const mock = new MockAdapter(AxiosInstance) +let mockResponse = [createMockTemurinReleaseAPI(false, "jdk")] afterEach(() => { vi.clearAllMocks() }) -describe('loadLatestAssets', () => { - it('returns valid JSON', async() => { - mock.onGet().reply(200, mockResponse); +describe("loadLatestAssets", () => { + it("returns valid JSON", async () => { + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'jdk').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "jdk").then(data => { expect(data).toMatchSnapshot() }) }) @@ -26,143 +26,143 @@ describe('loadLatestAssets', () => { it("source image is processed correctly", async () => { mockResponse = [ - createMockTemurinReleaseAPI(false, 'sources'), - createMockTemurinReleaseAPI(false, 'jdk') - ]; + createMockTemurinReleaseAPI(false, "sources"), + createMockTemurinReleaseAPI(false, "jdk"), + ] - mock.onGet().reply(200, mockResponse); + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'any').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "any").then(data => { expect(data).toMatchSnapshot() }) - }); - }); + }) + }) - it('returns valid JSON + installer', async() => { + it("returns valid JSON + installer", async () => { mockResponse = [ - createMockTemurinReleaseAPI(true, 'jdk'), - createMockTemurinReleaseAPI(true, 'jre') + createMockTemurinReleaseAPI(true, "jdk"), + createMockTemurinReleaseAPI(true, "jre"), ] - mock.onGet().reply(200, mockResponse); + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'jre').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "jre").then(data => { expect(data).toMatchSnapshot() }) - }); - }); + }) + }) - it('verify update the release date if this asset is newer', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - const r2 = createMockTemurinReleaseAPI(true, 'jdk'); - r2.binary.updated_at.setDate(r2.binary.updated_at.getDate() + 1); + it("verify update the release date if this asset is newer", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + const r2 = createMockTemurinReleaseAPI(true, "jdk") + r2.binary.updated_at.setDate(r2.binary.updated_at.getDate() + 1) mockResponse = [r1, r2] - mock.onGet().reply(200, mockResponse); + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'jdk').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "jdk").then(data => { expect(data).toMatchSnapshot() }) - }); - }); - - it('verify update the version if this asset is newer', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - r1.version.major = 17; - r1.version.minor = 0; - r1.version.security = 9; - r1.version.build = 9; - r1.version.adopt_build_number = 1; - const r2 = createMockTemurinReleaseAPI(true, 'jdk'); - r2.version.major = 17; - r2.version.minor = 0; - r2.version.security = 9; - r2.version.build = 9; - r2.version.adopt_build_number = 2; + }) + }) + + it("verify update the version if this asset is newer", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + r1.version.major = 17 + r1.version.minor = 0 + r1.version.security = 9 + r1.version.build = 9 + r1.version.adopt_build_number = 1 + const r2 = createMockTemurinReleaseAPI(true, "jdk") + r2.version.major = 17 + r2.version.minor = 0 + r2.version.security = 9 + r2.version.build = 9 + r2.version.adopt_build_number = 2 mockResponse = [r1, r2] - mock.onGet().reply(200, mockResponse); + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'jdk').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "jdk").then(data => { expect(data).toMatchSnapshot() }) - }); - }); - - it('verify that releases are well sorted', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - r1.binary.architecture = 'x32'; - const r2 = createMockTemurinReleaseAPI(true, 'jdk'); - r2.binary.architecture = 'x64'; - const r3 = createMockTemurinReleaseAPI(true, 'jdk'); - r3.binary.architecture = 'aarch64'; - const r4 = createMockTemurinReleaseAPI(true, 'jdk'); - r4.binary.architecture = 'ppc64le'; + }) + }) + + it("verify that releases are well sorted", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + r1.binary.architecture = "x32" + const r2 = createMockTemurinReleaseAPI(true, "jdk") + r2.binary.architecture = "x64" + const r3 = createMockTemurinReleaseAPI(true, "jdk") + r3.binary.architecture = "aarch64" + const r4 = createMockTemurinReleaseAPI(true, "jdk") + r4.binary.architecture = "ppc64le" mockResponse = [r1, r2, r3, r4] - mock.onGet().reply(200, mockResponse); + mock.onGet().reply(200, mockResponse) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'jdk').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "jdk").then(data => { expect(data).toMatchSnapshot() }) - }); - }); + }) + }) - it('pkgsFound to be empty on error', async() => { - mock.onGet().reply(500); + it("pkgsFound to be empty on error", async () => { + mock.onGet().reply(500) - renderHook(async() => { - await loadLatestAssets(8, 'linux', 'x64', 'jdk').then((data) => { + renderHook(async () => { + await loadLatestAssets(8, "linux", "x64", "jdk").then(data => { expect(data).toStrictEqual([]) }) - }); + }) }) - it('Test that getVersionAsString() works correclty', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - r1.version.major = 17; - r1.version.minor = 0; - r1.version.security = 9; - r1.version.build = 9; - r1.version.adopt_build_number = 1; - expect(getVersionAsString(r1.version)).equals('17.0.9+9.1'); + it("Test that getVersionAsString() works correclty", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + r1.version.major = 17 + r1.version.minor = 0 + r1.version.security = 9 + r1.version.build = 9 + r1.version.adopt_build_number = 1 + expect(getVersionAsString(r1.version)).equals("17.0.9+9.1") }) - it('Test that getVersionAsString() works correclty with short not allowed', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - r1.version.major = 20; - r1.version.minor = 0; - r1.version.security = 0; - r1.version.build = 36; - r1.version.patch = 0; - expect(getVersionAsString(r1.version)).equals('20.0.0+36'); + it("Test that getVersionAsString() works correclty with short not allowed", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + r1.version.major = 20 + r1.version.minor = 0 + r1.version.security = 0 + r1.version.build = 36 + r1.version.patch = 0 + expect(getVersionAsString(r1.version)).equals("20.0.0+36") }) - it('Test that getVersionAsString() works correclty with short allowed', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - r1.version.major = 20; - r1.version.minor = 0; - r1.version.security = 0; - r1.version.build = 36; - r1.version.patch = 0; - expect(getVersionAsString(r1.version, true)).equals('20+36'); + it("Test that getVersionAsString() works correclty with short allowed", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + r1.version.major = 20 + r1.version.minor = 0 + r1.version.security = 0 + r1.version.build = 36 + r1.version.patch = 0 + expect(getVersionAsString(r1.version, true)).equals("20+36") }) - it('Test that getVersionAsString() works correclty with patch', async() => { - const r1 = createMockTemurinReleaseAPI(true, 'jdk'); - r1.version.major = 18; - r1.version.minor = 0; - r1.version.security = 2; - r1.version.build = 1; - r1.version.patch = 1; - expect(getVersionAsString(r1.version)).equals('18.0.2.1+1'); + it("Test that getVersionAsString() works correclty with patch", async () => { + const r1 = createMockTemurinReleaseAPI(true, "jdk") + r1.version.major = 18 + r1.version.minor = 0 + r1.version.security = 2 + r1.version.build = 1 + r1.version.patch = 1 + expect(getVersionAsString(r1.version)).equals("18.0.2.1+1") }) -}); +}) diff --git a/src/hooks/fetchLatestTemurin.tsx b/src/hooks/fetchLatestTemurin.tsx index 0410d31c..3ecabb9f 100644 --- a/src/hooks/fetchLatestTemurin.tsx +++ b/src/hooks/fetchLatestTemurin.tsx @@ -1,6 +1,6 @@ -import { useEffect, useState } from 'react'; -import { VersionMetaData } from "."; -import axios from 'axios'; +import { useEffect, useState } from "react" +import { VersionMetaData } from "." +import axios from "axios" const baseUrl = "https://api.adoptium.net/v3" @@ -10,43 +10,43 @@ export function fetchLatestForOS( os: string, arch: string, ): Binary | null { + if (!os) { + return null + } - if (!os) { - return null - } - - const [binary, setBinary] = useState(null); + const [binary, setBinary] = useState(null) - useEffect(() => { - if (isVisible) { - (async () => { - const url = `${baseUrl}/assets/feature_releases/${version}/ga?os=${os}&architecture=${arch}&image_type=jdk&jvm_impl=hotspot&page_size=1&vendor=eclipse`; + useEffect(() => { + if (isVisible) { + ;(async () => { + const url = `${baseUrl}/assets/feature_releases/${version}/ga?os=${os}&architecture=${arch}&image_type=jdk&jvm_impl=hotspot&page_size=1&vendor=eclipse` - axios.get(url) - .then(function (response) { - const json: LatestTemurin = response.data[0]; + axios + .get(url) + .then(function (response) { + const json: LatestTemurin = response.data[0] - let binary_link = json.binaries[0].package.link - let binary_checksum = json.binaries[0].package.checksum + let binary_link = json.binaries[0].package.link + let binary_checksum = json.binaries[0].package.checksum - if (json.binaries[0].installer) { - binary_link = json.binaries[0].installer.link, - binary_checksum = json.binaries[0].installer.checksum - } + if (json.binaries[0].installer) { + ;(binary_link = json.binaries[0].installer.link), + (binary_checksum = json.binaries[0].installer.checksum) + } - const binary = { - release_name: json.release_name, - link: binary_link, - checksum: binary_checksum, - }; - setBinary(binary); - }) - .catch(function (error) { - setBinary(null); - }); - })(); - } - }, [isVisible, version, os, arch]); + const binary = { + release_name: json.release_name, + link: binary_link, + checksum: binary_checksum, + } + setBinary(binary) + }) + .catch(function (error) { + setBinary(null) + }) + })() + } + }, [isVisible, version, os, arch]) return binary } diff --git a/src/hooks/fetchMarketplace.tsx b/src/hooks/fetchMarketplace.tsx index eb2fc581..21af9bd4 100644 --- a/src/hooks/fetchMarketplace.tsx +++ b/src/hooks/fetchMarketplace.tsx @@ -1,7 +1,7 @@ -import { VersionMetaData } from "."; -import axios from 'axios'; +import { VersionMetaData } from "." +import axios from "axios" -const baseUrl = 'https://marketplace-api.adoptium.net'; +const baseUrl = "https://marketplace-api.adoptium.net" export async function getAllPkgsForVersion( version: number, @@ -25,16 +25,17 @@ export async function getAllPkgsForVersion( params += "&architecture=" + architecture } - const url = baseUrl + '/v1/assets/latestForVendors' + params; - const data = await axios.get(url) - .then(function (response) { - return response.data; - }) - .catch(function (error) { - return null; - }); + const url = baseUrl + "/v1/assets/latestForVendors" + params + const data = await axios + .get(url) + .then(function (response) { + return response.data + }) + .catch(function (error) { + return null + }) - return data + return data } export function getImageForDistribution(distribution: string) { diff --git a/src/hooks/fetchNews.tsx b/src/hooks/fetchNews.tsx index 3ea1bd90..d8f23f61 100644 --- a/src/hooks/fetchNews.tsx +++ b/src/hooks/fetchNews.tsx @@ -1,93 +1,91 @@ -import { useEffect, useState } from 'react'; -import axios from 'axios'; +import { useEffect, useState } from "react" +import axios from "axios" -const baseUrl = 'https://newsroom.eclipse.org/api'; +const baseUrl = "https://newsroom.eclipse.org/api" -export function fetchNewsItems( - isVisible: boolean, - page: number, -): News | null { +export function fetchNewsItems(isVisible: boolean, page: number): News | null { + const [news, setNews] = useState({ news: [], pagination: null }) + const [events, setEvents] = useState([]) - const [news, setNews] = useState({news: [], pagination: null}); - const [events, setEvents] = useState([]); - - useEffect(() => { - if (isVisible) { - (async () => { - setNews(await fetchLatestNews(page)); - setEvents(await fetchLatestEvents()); - })(); - } - }, [isVisible, page]); - - const newsAndEvents: News = { - news: news, - events: events + useEffect(() => { + if (isVisible) { + ;(async () => { + setNews(await fetchLatestNews(page)) + setEvents(await fetchLatestEvents()) + })() } + }, [isVisible, page]) - return newsAndEvents; + const newsAndEvents: News = { + news: news, + events: events, + } + + return newsAndEvents } async function fetchLatestNews(page) { - const url = new URL(`${baseUrl}/news`); - url.searchParams.append('parameters[publish_to]', 'adoptium'); - url.searchParams.append('page', page); - url.searchParams.append('pagesize', '5'); + const url = new URL(`${baseUrl}/news`) + url.searchParams.append("parameters[publish_to]", "adoptium") + url.searchParams.append("page", page) + url.searchParams.append("pagesize", "5") - return axios.get(url.toString()) - .then(function (response) { - return response.data; - }) - .catch(function (error) { - return [] - }); + return axios + .get(url.toString()) + .then(function (response) { + return response.data + }) + .catch(function (error) { + return [] + }) } async function fetchLatestEvents() { - const url = new URL(`${baseUrl}/events`); - url.searchParams.append('parameters[publish_to]', 'adoptium'); + const url = new URL(`${baseUrl}/events`) + url.searchParams.append("parameters[publish_to]", "adoptium") - return axios.get(url.toString()) - .then(function (response) { - return response.data.events; - }) - .catch(function (error) { - return [] - }); + return axios + .get(url.toString()) + .then(function (response) { + return response.data.events + }) + .catch(function (error) { + return [] + }) } export interface News { - news: NewsResponse; - events: EventItem[]; + news: NewsResponse + events: EventItem[] } export interface NewsResponse { - news: NewsItem[]; - pagination: { - page: number; - pagesize: number; - result_start: number; - result_end: number; - result_size: number; - total_result_size: number; - } | null; + news: NewsItem[] + pagination: { + page: number + pagesize: number + result_start: number + result_end: number + result_size: number + total_result_size: number + } | null } export interface NewsItem { - id: string; - title: string; - body: string; - date: Date; - link: URL; + id: string + title: string + body: string + date: Date + link: URL } export interface EventItem { - id: string; - title: string; - infoLink: URL; - date: Date; + id: string + title: string + infoLink: URL + date: Date } export interface EventAPI { - events: EventItem[]; -} \ No newline at end of file + events: EventItem[] +} diff --git a/src/hooks/fetchReleaseNotes.tsx b/src/hooks/fetchReleaseNotes.tsx index ea73f895..13154447 100644 --- a/src/hooks/fetchReleaseNotes.tsx +++ b/src/hooks/fetchReleaseNotes.tsx @@ -1,6 +1,6 @@ -import { VersionMetaData } from '.'; -import { useEffect, useState } from 'react'; -import axios from 'axios'; +import { VersionMetaData } from "." +import { useEffect, useState } from "react" +import axios from "axios" const baseUrl = "https://api.adoptium.net/v3/info/release_notes" @@ -13,27 +13,29 @@ export function fetchReleaseNotesForVersion( return null } - const [releaseNotes, setReleaseNotes] = useState(null); - - useEffect(() => { - if (isVisible) { - (async () => { - const url = `${baseUrl}/${version}`; - - await axios.get(url.toString()) - .then(function (response) { - let result = response.data - if(sortReleaseNotesByCallback) sortReleaseNotesByCallback(result); - setReleaseNotes(result) - }) - .catch(function (error) { - setReleaseNotes(null) - }); - })(); - } - }, [isVisible, version]); - - return releaseNotes; + const [releaseNotes, setReleaseNotes] = + useState(null) + + useEffect(() => { + if (isVisible) { + ;(async () => { + const url = `${baseUrl}/${version}` + + await axios + .get(url.toString()) + .then(function (response) { + let result = response.data + if (sortReleaseNotesByCallback) sortReleaseNotesByCallback(result) + setReleaseNotes(result) + }) + .catch(function (error) { + setReleaseNotes(null) + }) + })() + } + }, [isVisible, version]) + + return releaseNotes } export interface ReleaseNoteAPIResponse { diff --git a/src/hooks/fetchTemurinArchive.tsx b/src/hooks/fetchTemurinArchive.tsx index 536c15b7..86b56606 100644 --- a/src/hooks/fetchTemurinArchive.tsx +++ b/src/hooks/fetchTemurinArchive.tsx @@ -1,9 +1,9 @@ -import moment from 'moment'; -import { VersionMetaData } from '.'; -import { fetchExtension } from '../util/fetchExtension'; -import axios from 'axios'; +import moment from "moment" +import { VersionMetaData } from "." +import { fetchExtension } from "../util/fetchExtension" +import axios from "axios" -const baseUrl = 'https://api.adoptium.net/v3'; +const baseUrl = "https://api.adoptium.net/v3" let releases: TemurinReleases[] = [] @@ -12,173 +12,185 @@ export async function getAssetsForVersion( releaseType: ReleaseType, numBuilds: number, buildDate: Date, - page: number + page: number, ): Promise { - let url = new URL(`${baseUrl}/assets/feature_releases/${version}/${releaseType}?vendor=eclipse`); - url.searchParams.append('page', page.toString()); + let url = new URL( + `${baseUrl}/assets/feature_releases/${version}/${releaseType}?vendor=eclipse`, + ) + url.searchParams.append("page", page.toString()) if (numBuilds) { - url.searchParams.append('page_size', numBuilds.toString()); + url.searchParams.append("page_size", numBuilds.toString()) } if (buildDate) { - url.searchParams.append('before', moment(buildDate).format('Y-MM-DD')); + url.searchParams.append("before", moment(buildDate).format("Y-MM-DD")) } // Expose total page count in header for pagination - if (releaseType == 'ga') { - url.searchParams.append('show_page_count', 'true'); + if (releaseType == "ga") { + url.searchParams.append("show_page_count", "true") } releases = [] - let pagecount = 0; + let pagecount = 0 let pkgsFound: TemurinReleases[] = [] - await axios.get(url.toString()) + await axios + .get(url.toString()) .then(function (response) { for (let pkg of response.data) { - pkgsFound.push(pkg); + pkgsFound.push(pkg) } - pagecount = Number(response.headers.get('pagecount')) + pagecount = Number(response.headers.get("pagecount")) }) .catch(function (error) { - pagecount = 0; - pkgsFound = []; - }); + pagecount = 0 + pkgsFound = [] + }) - return renderReleases(pkgsFound, pagecount, releaseType); + return renderReleases(pkgsFound, pagecount, releaseType) } function renderReleases(pkgs, pagecount, releaseType) { - pkgs.forEach((aRelease) => { + pkgs.forEach(aRelease => { const release: TemurinReleases = { - release_name: aRelease.release_name, - release_link: aRelease.release_link, - timestamp: aRelease.timestamp, - platforms: {}, - }; - - aRelease.binaries.forEach(( - aReleaseAsset: APIResponse) => { - const platform = `${aReleaseAsset.os}-${aReleaseAsset.architecture}` - - // Skip this asset if it's not a binary type we're interested in displaying - const binary_type = aReleaseAsset.image_type.toUpperCase(); - if (aRelease.source) { - release.source_url = new URL(aRelease.source.link); - } - if (aRelease.release_notes) { - release.release_notes = true; - } + release_name: aRelease.release_name, + release_link: aRelease.release_link, + timestamp: aRelease.timestamp, + platforms: {}, + } + + aRelease.binaries.forEach((aReleaseAsset: APIResponse) => { + const platform = `${aReleaseAsset.os}-${aReleaseAsset.architecture}` + + // Skip this asset if it's not a binary type we're interested in displaying + const binary_type = aReleaseAsset.image_type.toUpperCase() + if (aRelease.source) { + release.source_url = new URL(aRelease.source.link) + } + if (aRelease.release_notes) { + release.release_notes = true + } - if (releaseType === 'ga' && !['INSTALLER', 'JDK', 'JRE'].includes(binary_type)) { - return; - } + if ( + releaseType === "ga" && + !["INSTALLER", "JDK", "JRE"].includes(binary_type) + ) { + return + } - // Choose which ea binary types to display - if (releaseType === 'ea' && !['INSTALLER', 'JDK', 'JRE', 'DEBUGIMAGE'].includes(binary_type)) { - return; - } - - if (!release.platforms[platform]) { - release.platforms[platform] = { - assets: [], - }; - } - - let binary_constructor: ReleaseAsset = { - os: aReleaseAsset.os, - architecture: aReleaseAsset.architecture, - type: binary_type, - link: aReleaseAsset.package.link, - checksum: aReleaseAsset.package.checksum, - size: Math.floor(aReleaseAsset.package.size / 1000 / 1000), - extension: fetchExtension(aReleaseAsset.package.name) - }; - - if (aReleaseAsset.installer) { - binary_constructor.installer_link = aReleaseAsset.installer.link; - binary_constructor.installer_checksum = aReleaseAsset.installer.checksum; - binary_constructor.installer_size = Math.floor(aReleaseAsset.installer.size / 1000 / 1000); - binary_constructor.installer_extension = fetchExtension(aReleaseAsset.installer.name) + // Choose which ea binary types to display + if ( + releaseType === "ea" && + !["INSTALLER", "JDK", "JRE", "DEBUGIMAGE"].includes(binary_type) + ) { + return + } + + if (!release.platforms[platform]) { + release.platforms[platform] = { + assets: [], } - - // Add the new binary to the release asset - release.platforms[platform].assets.push(binary_constructor); - }); - releases.push(release); + } + + let binary_constructor: ReleaseAsset = { + os: aReleaseAsset.os, + architecture: aReleaseAsset.architecture, + type: binary_type, + link: aReleaseAsset.package.link, + checksum: aReleaseAsset.package.checksum, + size: Math.floor(aReleaseAsset.package.size / 1000 / 1000), + extension: fetchExtension(aReleaseAsset.package.name), + } + + if (aReleaseAsset.installer) { + binary_constructor.installer_link = aReleaseAsset.installer.link + binary_constructor.installer_checksum = aReleaseAsset.installer.checksum + binary_constructor.installer_size = Math.floor( + aReleaseAsset.installer.size / 1000 / 1000, + ) + binary_constructor.installer_extension = fetchExtension( + aReleaseAsset.installer.name, + ) + } + + // Add the new binary to the release asset + release.platforms[platform].assets.push(binary_constructor) + }) + releases.push(release) }) - return {releases, pagecount} + return { releases, pagecount } } -type ReleaseType = 'ea' | 'ga'; +type ReleaseType = "ea" | "ga" export interface ReturnedReleases { - releases: TemurinReleases[]; - pagecount: number; + releases: TemurinReleases[] + pagecount: number } export interface TemurinReleases { - release_name: string; - release_link: URL; - source_url?: URL; - timestamp: Date; + release_name: string + release_link: URL + source_url?: URL + timestamp: Date platforms: { [key: string]: { - assets: ReleaseAsset[]; - }; - }; - release_notes?: boolean; + assets: ReleaseAsset[] + } + } + release_notes?: boolean } interface ReleaseAsset { - os: string; - architecture: string; - type: string; - link: URL; - checksum: string; - size: number; - extension: string; - installer_link?: URL; - installer_checksum?: string; - installer_size?: number; - installer_extension?: string; + os: string + architecture: string + type: string + link: URL + checksum: string + size: number + extension: string + installer_link?: URL + installer_checksum?: string + installer_size?: number + installer_extension?: string } interface APIResponse { - os: string; - architecture: string; - image_type: string; + os: string + architecture: string + image_type: string package: { - name: string; - link: URL; - checksum: string; - size: number; - }; + name: string + link: URL + checksum: string + size: number + } installer?: { - link: URL; - name: string; - checksum: string; - size: number; - }; + link: URL + name: string + checksum: string + size: number + } } export interface MockTemurinFeatureReleaseAPI { - id: string; - download_count: number; - release_name: string; - release_type: string; - release_link: URL; + id: string + download_count: number + release_name: string + release_type: string + release_link: URL source?: { - link: URL; - name: string; - size: number; - }; - binaries: APIResponse[]; + link: URL + name: string + size: number + } + binaries: APIResponse[] release_notes?: { - link: URL; - name: string; - size: number; - }; - timestamp: Date; - updated_at: Date; - vendor: string; - version_data: VersionMetaData; -} \ No newline at end of file + link: URL + name: string + size: number + } + timestamp: Date + updated_at: Date + vendor: string + version_data: VersionMetaData +} diff --git a/src/hooks/fetchTemurinReleases.tsx b/src/hooks/fetchTemurinReleases.tsx index 9226303f..f79ab263 100644 --- a/src/hooks/fetchTemurinReleases.tsx +++ b/src/hooks/fetchTemurinReleases.tsx @@ -1,6 +1,6 @@ -import { VersionMetaData, compareVersions, getVersionAsString } from '.'; -import { fetchExtension } from '../util/fetchExtension'; -import axios from 'axios'; +import { VersionMetaData, compareVersions, getVersionAsString } from "." +import { fetchExtension } from "../util/fetchExtension" +import axios from "axios" const baseUrl = "https://api.adoptium.net/v3" @@ -10,75 +10,82 @@ export async function loadLatestAssets( architecture: string, packageType: string, ): Promise { - let url = new URL(`${baseUrl}/assets/latest/${version}/hotspot?`); + let url = new URL(`${baseUrl}/assets/latest/${version}/hotspot?`) - if (os !== 'any') { - url.searchParams.append('os', os); - } - if (architecture !== 'any') { - url.searchParams.append('architecture', architecture); - } + if (os !== "any") { + url.searchParams.append("os", os) + } + if (architecture !== "any") { + url.searchParams.append("architecture", architecture) + } - // NOTE: Do not filter the query by 'image_type' because we need to have 'sources - // to display the Release Notes and source download (cf src/components/TemurinDownloadTable/index.tsx) - - let pkgsFound: TemurinRelease[] = await axios.get(url.toString()) - .then(function (response) { - return response.data; - }) - .catch(function (error) { - return [] - }); - - // Filter JDK/JRE if necessary - if (packageType === 'jdk') { - pkgsFound = pkgsFound.filter((pkg: TemurinRelease) => pkg.binary.image_type !== 'jre'); - } else if (packageType === 'jre') { - pkgsFound = pkgsFound.filter((pkg: TemurinRelease) => pkg.binary.image_type !== 'jdk'); - } + // NOTE: Do not filter the query by 'image_type' because we need to have 'sources + // to display the Release Notes and source download (cf src/components/TemurinDownloadTable/index.tsx) + + let pkgsFound: TemurinRelease[] = await axios + .get(url.toString()) + .then(function (response) { + return response.data + }) + .catch(function (error) { + return [] + }) + + // Filter JDK/JRE if necessary + if (packageType === "jdk") { + pkgsFound = pkgsFound.filter( + (pkg: TemurinRelease) => pkg.binary.image_type !== "jre", + ) + } else if (packageType === "jre") { + pkgsFound = pkgsFound.filter( + (pkg: TemurinRelease) => pkg.binary.image_type !== "jdk", + ) + } - return renderReleases(pkgsFound); + return renderReleases(pkgsFound) } function renderReleases(pkgs: Array): ReleaseAsset[] { - let releases: ReleaseAsset[] = [] + let releases: ReleaseAsset[] = [] - pkgs.forEach((releaseAsset: TemurinRelease) => { - const platform = `${releaseAsset.binary.os}-${releaseAsset.binary.architecture}` + pkgs.forEach((releaseAsset: TemurinRelease) => { + const platform = `${releaseAsset.binary.os}-${releaseAsset.binary.architecture}` - // Skip this asset if it's not a binary type we're interested in displaying - const binary_type = releaseAsset.binary.image_type.toUpperCase(); - if (binary_type === 'SOURCES') { - releases['source'] = releaseAsset; - } - if (!['INSTALLER', 'JDK', 'JRE'].includes(binary_type)) { - return; - } - // Get the existing release asset (passed to the template) or define a new one - let release: ReleaseAsset | undefined = releases.find((release: ReleaseAsset) => release.platform_name === platform); - if (!release) { - release = { - platform_name: `${releaseAsset.binary.os}-${releaseAsset.binary.architecture}`, - os: releaseAsset.binary.os, - architecture: releaseAsset.binary.architecture, - release_name: getVersionAsString(releaseAsset.version), - release_link: new URL(releaseAsset.release_link), - release_date: new Date(releaseAsset.binary.updated_at), - version: releaseAsset.version, - binaries: [], - }; - } else { - // update the release date if this asset is newer - const rabua = new Date(releaseAsset.binary.updated_at); - if (release.release_date < rabua) { - release.release_date = rabua; - } - // update the version if this asset is newer - if(compareVersions(releaseAsset.version, release.version) === 1) { - release.version = releaseAsset.version; - release.release_name = getVersionAsString(releaseAsset.version); - } - } + // Skip this asset if it's not a binary type we're interested in displaying + const binary_type = releaseAsset.binary.image_type.toUpperCase() + if (binary_type === "SOURCES") { + releases["source"] = releaseAsset + } + if (!["INSTALLER", "JDK", "JRE"].includes(binary_type)) { + return + } + // Get the existing release asset (passed to the template) or define a new one + let release: ReleaseAsset | undefined = releases.find( + (release: ReleaseAsset) => release.platform_name === platform, + ) + if (!release) { + release = { + platform_name: `${releaseAsset.binary.os}-${releaseAsset.binary.architecture}`, + os: releaseAsset.binary.os, + architecture: releaseAsset.binary.architecture, + release_name: getVersionAsString(releaseAsset.version), + release_link: new URL(releaseAsset.release_link), + release_date: new Date(releaseAsset.binary.updated_at), + version: releaseAsset.version, + binaries: [], + } + } else { + // update the release date if this asset is newer + const rabua = new Date(releaseAsset.binary.updated_at) + if (release.release_date < rabua) { + release.release_date = rabua + } + // update the version if this asset is newer + if (compareVersions(releaseAsset.version, release.version) === 1) { + release.version = releaseAsset.version + release.release_name = getVersionAsString(releaseAsset.version) + } + } let binary_constructor: Binary = { type: binary_type, @@ -103,92 +110,94 @@ function renderReleases(pkgs: Array): ReleaseAsset[] { // Add the new binary to the release asset release.binaries.push(binary_constructor) - // We have the first binary, so add the release asset. - if (release.binaries.length === 1) { - releases.push(release); - } - }) + // We have the first binary, so add the release asset. + if (release.binaries.length === 1) { + releases.push(release) + } + }) + + // well sort releases + releases.sort((pkg1: ReleaseAsset, pkg2: ReleaseAsset) => { + // order by version DESC + let comparison = compareVersions(pkg2.version, pkg1.version) + // let comparison = 0; + + if (comparison === 0) { + // NOTE: Ordering by date DESC is disabled because it's less intuitive than by version done previously + // order by date DESC + // const releaseDateUTCInMillis1 = Date.UTC(pkg1.release_date.getUTCFullYear(), pkg1.release_date.getUTCMonth(), pkg1.release_date.getUTCDate(), 0, 0, 0, 0); + // const releaseDateUTCInMillis2 = Date.UTC(pkg2.release_date.getUTCFullYear(), pkg2.release_date.getUTCMonth(), pkg2.release_date.getUTCDate(), 0, 0, 0, 0); + // comparison = releaseDateUTCInMillis2 - releaseDateUTCInMillis1; - // well sort releases - releases.sort((pkg1: ReleaseAsset, pkg2: ReleaseAsset) => { - // order by version DESC - let comparison = compareVersions(pkg2.version, pkg1.version); - // let comparison = 0; + if (comparison === 0) { + // for the same date, sort by OS ASC + comparison = pkg1.os.localeCompare(pkg2.os) if (comparison === 0) { - // NOTE: Ordering by date DESC is disabled because it's less intuitive than by version done previously - // order by date DESC - // const releaseDateUTCInMillis1 = Date.UTC(pkg1.release_date.getUTCFullYear(), pkg1.release_date.getUTCMonth(), pkg1.release_date.getUTCDate(), 0, 0, 0, 0); - // const releaseDateUTCInMillis2 = Date.UTC(pkg2.release_date.getUTCFullYear(), pkg2.release_date.getUTCMonth(), pkg2.release_date.getUTCDate(), 0, 0, 0, 0); - // comparison = releaseDateUTCInMillis2 - releaseDateUTCInMillis1; - - if (comparison === 0) { - // for the same date, sort by OS ASC - comparison = pkg1.os.localeCompare(pkg2.os); - - if (comparison === 0) { - // for the same OS, sort by architecture ASC - const arch1 = pkg1.architecture === 'x32' ? 'x86' : pkg1.architecture; - const arch2 = pkg2.architecture === 'x32' ? 'x86' : pkg2.architecture; - comparison = arch1.localeCompare(arch2); - } - } + // for the same OS, sort by architecture ASC + const arch1 = pkg1.architecture === "x32" ? "x86" : pkg1.architecture + const arch2 = pkg2.architecture === "x32" ? "x86" : pkg2.architecture + comparison = arch1.localeCompare(arch2) } - return comparison; - }); + } + } + return comparison + }) - // sort binaries inside releases - releases.forEach((release) => { - release.binaries.sort((binaryA, binaryB) => binaryA.type > binaryB.type ? 1 : binaryA.type < binaryB.type ? -1 : 0); - }); + // sort binaries inside releases + releases.forEach(release => { + release.binaries.sort((binaryA, binaryB) => + binaryA.type > binaryB.type ? 1 : binaryA.type < binaryB.type ? -1 : 0, + ) + }) - return releases + return releases } export interface ReleaseAsset { - platform_name: string; - os: string; - architecture: string; - release_name: string; - release_link: URL; - release_date: Date; - version: VersionMetaData; - binaries: Array; + platform_name: string + os: string + architecture: string + release_name: string + release_link: URL + release_date: Date + version: VersionMetaData + binaries: Array } interface TemurinRelease { - release_link: URL; - os: string; - architecture: string; - platform_name: string; - release_name: string; - release_date: Date; - version: VersionMetaData; - binary: { - updated_at: Date; - os: string; - architecture: string; - image_type: string; - jvm_impl: string; - package: { - name: string; - link: URL; - checksum: string; - checksum_link: URL; - signature_link: URL; - metadata_link: URL; - size: number; - } - installer?: { - name: string; - link: URL; - checksum: string; - checksum_link: URL; - signature_link: URL; - metadata_link: URL; - size: number; - } - }; + release_link: URL + os: string + architecture: string + platform_name: string + release_name: string + release_date: Date + version: VersionMetaData + binary: { + updated_at: Date + os: string + architecture: string + image_type: string + jvm_impl: string + package: { + name: string + link: URL + checksum: string + checksum_link: URL + signature_link: URL + metadata_link: URL + size: number + } + installer?: { + name: string + link: URL + checksum: string + checksum_link: URL + signature_link: URL + metadata_link: URL + size: number + } + } } interface Binary { diff --git a/src/hooks/index.tsx b/src/hooks/index.tsx index f6a3ee2c..b802342c 100644 --- a/src/hooks/index.tsx +++ b/src/hooks/index.tsx @@ -8,57 +8,70 @@ export * from "./fetchNews" export * from "./fetchReleaseNotes" export interface VersionMetaData { - major: number; - minor: number; - security: number; - pre?: string; - patch?: number; - build: number; - optional?: string; - adopt_build_number?: number; - openjdk_version: string; - semver: string; -}; + major: number + minor: number + security: number + pre?: string + patch?: number + build: number + optional?: string + adopt_build_number?: number + openjdk_version: string + semver: string +} /** * This method compares two versions and returns: * -> 0 if versions are equals * -> -1 if versionA is lower than versionB * -> 1 if versionA is highter than versionB - * - * @param versionA - * @param versionB - * @returns + * + * @param versionA + * @param versionB + * @returns */ -export function compareVersions(versionA: VersionMetaData, versionB: VersionMetaData) : number { - let comparison = versionA.major - versionB.major; +export function compareVersions( + versionA: VersionMetaData, + versionB: VersionMetaData, +): number { + let comparison = versionA.major - versionB.major + if (comparison === 0) { + comparison = versionA.minor - versionB.minor if (comparison === 0) { - comparison = versionA.minor - versionB.minor; + comparison = versionA.security - versionB.security + if (comparison === 0) { + comparison = versionA.build - versionB.build if (comparison === 0) { - comparison = versionA.security - versionB.security; - if (comparison === 0) { - comparison = versionA.build - versionB.build; - if (comparison === 0) { - comparison = (versionA.adopt_build_number ? versionA.adopt_build_number : 0) - (versionB.adopt_build_number? versionB.adopt_build_number : 0); - } - } + comparison = + (versionA.adopt_build_number ? versionA.adopt_build_number : 0) - + (versionB.adopt_build_number ? versionB.adopt_build_number : 0) } + } } - return comparison; + } + return comparison } -export function getVersionAsString(version: VersionMetaData, allowShortNotation: boolean = false) : string { - let result = `${version.major}.${version.minor}.${version.security}`; - if(allowShortNotation && !version.minor && !version.security && !version.patch) { - // when minor, security & patch are 0 => do not print .0.0.0 - result = `${version.major}`; - } - if(version.patch) { - result += `.${version.patch}`; - } - if(version.build) { - result += `+${version.build}`; - if(version.adopt_build_number) result += `.${version.adopt_build_number}`; - } - return result; +export function getVersionAsString( + version: VersionMetaData, + allowShortNotation: boolean = false, +): string { + let result = `${version.major}.${version.minor}.${version.security}` + if ( + allowShortNotation && + !version.minor && + !version.security && + !version.patch + ) { + // when minor, security & patch are 0 => do not print .0.0.0 + result = `${version.major}` + } + if (version.patch) { + result += `.${version.patch}` + } + if (version.build) { + result += `+${version.build}` + if (version.adopt_build_number) result += `.${version.adopt_build_number}` + } + return result } diff --git a/src/hooks/useAdoptiumContributorsApi.tsx b/src/hooks/useAdoptiumContributorsApi.tsx index a2918023..b0ae5380 100644 --- a/src/hooks/useAdoptiumContributorsApi.tsx +++ b/src/hooks/useAdoptiumContributorsApi.tsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from 'react'; -import axios from 'axios'; +import { useEffect, useState } from "react" +import axios from "axios" // List of repos that will be checked for contributions const repositories = [ @@ -72,13 +72,14 @@ function linkParser(linkHeader: string): { async function getMaxContributors(): Promise<[number, number]> { // this call is used to know how many contributors there are in this repo // check the Link header to compute first and last - const linksHeaderValue = await axios.get(CONTRIBUTORS_API_URI) + const linksHeaderValue = await axios + .get(CONTRIBUTORS_API_URI) .then(function (response) { - return response.headers.get('Link') + return response.headers.get("Link") }) .catch(function (error) { - return undefined - }); + return undefined + }) if (linksHeaderValue) { const links = linkParser(linksHeaderValue) @@ -98,16 +99,17 @@ async function getMaxContributors(): Promise<[number, number]> { * @param randomPage */ async function getContributor(randomPage: number): Promise { - const contributor = await axios.get(`${CONTRIBUTORS_API_URI}&page=${randomPage}`) + const contributor = await axios + .get(`${CONTRIBUTORS_API_URI}&page=${randomPage}`) .then(function (response) { - return response.data[0] as ContributorApiResponse; + return response.data[0] as ContributorApiResponse }) .catch(function (error) { - return undefined - }); + return undefined + }) - if(!contributor) { - return null; + if (!contributor) { + return null } return { @@ -138,8 +140,10 @@ async function fetchRandomContributor() { window.localStorage.getItem(wlsMaxContributors) const fetchDateStored = window.localStorage.getItem(wlsFetchDate) - maxContributors = maxContributorsStored ? parseInt(maxContributorsStored, 10) : null; - fetchDate = fetchDateStored ? parseInt(fetchDateStored, 10) : null; + maxContributors = maxContributorsStored + ? parseInt(maxContributorsStored, 10) + : null + fetchDate = fetchDateStored ? parseInt(fetchDateStored, 10) : null } if (fetchDate && Date.now() - fetchDate >= ONE_MONTH_MS) { diff --git a/src/pages/__tests__/marketplace.test.tsx b/src/pages/__tests__/marketplace.test.tsx index a7c6d144..465c6052 100644 --- a/src/pages/__tests__/marketplace.test.tsx +++ b/src/pages/__tests__/marketplace.test.tsx @@ -1,12 +1,12 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest' -import { axe } from 'vitest-axe'; -import Marketplace, { Head } from '../marketplace'; -import AxiosInstance from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import React from "react" +import { render } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { axe } from "vitest-axe" +import Marketplace, { Head } from "../marketplace" +import AxiosInstance from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(AxiosInstance); +const mock = new MockAdapter(AxiosInstance) vi.mock("../../util/shuffle", () => { return { @@ -27,30 +27,30 @@ afterEach(() => { vi.clearAllMocks() }) -describe('Marketplace page', () => { - it('renders correctly', () => { - mock.onGet().reply(200, []); +describe("Marketplace page", () => { + it("renders correctly", () => { + mock.onGet().reply(200, []) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const pageContent = container.querySelector("main") expect(pageContent).toMatchSnapshot() }) - it('head renders correctly', () => { - mock.onGet().reply(200, []); + it("head renders correctly", () => { + mock.onGet().reply(200, []) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const title = container.querySelector("title") expect(title?.textContent).toEqual("Marketplace | Adoptium") }) - it('has no accessibility violations', async () => { - mock.onGet().reply(200, []); + it("has no accessibility violations", async () => { + mock.onGet().reply(200, []) - const { container } = render(); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); -}); + const { container } = render() + const results = await axe(container) + expect(results).toHaveNoViolations() + }) +}) diff --git a/src/pages/supporters.tsx b/src/pages/supporters.tsx index de954ce5..878160d6 100644 --- a/src/pages/supporters.tsx +++ b/src/pages/supporters.tsx @@ -66,7 +66,7 @@ const Supporters = () => { title="Participant Members" description="Companies that use Eclipse Temurin in production." /> -
+

Are you interested in becoming a member?

diff --git a/src/pages/temurin/__tests__/archive.test.tsx b/src/pages/temurin/__tests__/archive.test.tsx index 569a5a52..287615b8 100644 --- a/src/pages/temurin/__tests__/archive.test.tsx +++ b/src/pages/temurin/__tests__/archive.test.tsx @@ -1,42 +1,42 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest' -import { axe } from 'vitest-axe'; -import Archive, { Head } from '../archive'; -import AxiosInstance from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import React from "react" +import { render } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { axe } from "vitest-axe" +import Archive, { Head } from "../archive" +import AxiosInstance from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(AxiosInstance); +const mock = new MockAdapter(AxiosInstance) afterEach(() => { - vi.clearAllMocks(); -}); + vi.clearAllMocks() +}) -describe('Temurin Archive page', () => { - it('renders correctly', () => { - mock.onGet().reply(200, [], {'pagecount': 0}); +describe("Temurin Archive page", () => { + it("renders correctly", () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const pageContent = container.querySelector("main") expect(pageContent).toMatchSnapshot() }) - it('head renders correctly', () => { - mock.onGet().reply(200, [], {'pagecount': 0}); + it("head renders correctly", () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const title = container.querySelector("title") expect(title).toHaveTextContent("Archive | Adoptium") }) - it('has no accessibility violations', async () => { - mock.onGet().reply(200, [], {'pagecount': 0}); + it("has no accessibility violations", async () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); -}); + const { container } = render() + const results = await axe(container) + expect(results).toHaveNoViolations() + }) +}) diff --git a/src/pages/temurin/__tests__/nightly.test.tsx b/src/pages/temurin/__tests__/nightly.test.tsx index bb4715ac..1f355325 100644 --- a/src/pages/temurin/__tests__/nightly.test.tsx +++ b/src/pages/temurin/__tests__/nightly.test.tsx @@ -1,23 +1,23 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { act, screen, fireEvent } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest' -import { axe } from 'vitest-axe'; -import Nightly, { Head } from '../nightly'; -import AxiosInstance from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import React from "react" +import { render } from "@testing-library/react" +import { act, screen, fireEvent } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { axe } from "vitest-axe" +import Nightly, { Head } from "../nightly" +import AxiosInstance from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(AxiosInstance); +const mock = new MockAdapter(AxiosInstance) afterEach(() => { - vi.clearAllMocks(); -}); + vi.clearAllMocks() +}) -describe('Temurin Nightly page', () => { - it('renders correctly', async () => { - mock.onGet().reply(200, [], {'pagecount': 0}); +describe("Temurin Nightly page", () => { + it("renders correctly", async () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const pageContent = container.querySelector("main") @@ -30,20 +30,20 @@ describe('Temurin Nightly page', () => { expect(pageContent).toMatchSnapshot() }) - it('head renders correctly', () => { - mock.onGet().reply(200, [], {'pagecount': 0}); + it("head renders correctly", () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const title = container.querySelector("title") expect(title).toHaveTextContent("Nightly Builds | Adoptium") }) - it('has no accessibility violations', async () => { - mock.onGet().reply(200, [], {'pagecount': 0}); + it("has no accessibility violations", async () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); -}); + const { container } = render() + const results = await axe(container) + expect(results).toHaveNoViolations() + }) +}) diff --git a/src/pages/temurin/__tests__/releases.test.tsx b/src/pages/temurin/__tests__/releases.test.tsx index dcef9fed..0a9f44c8 100644 --- a/src/pages/temurin/__tests__/releases.test.tsx +++ b/src/pages/temurin/__tests__/releases.test.tsx @@ -1,42 +1,42 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { describe, expect, it, vi } from 'vitest' -import { axe } from 'vitest-axe'; -import Releases, { Head } from '../releases'; -import AxiosInstance from 'axios' -import MockAdapter from 'axios-mock-adapter'; +import React from "react" +import { render } from "@testing-library/react" +import { describe, expect, it, vi } from "vitest" +import { axe } from "vitest-axe" +import Releases, { Head } from "../releases" +import AxiosInstance from "axios" +import MockAdapter from "axios-mock-adapter" -const mock = new MockAdapter(AxiosInstance); +const mock = new MockAdapter(AxiosInstance) afterEach(() => { - vi.clearAllMocks(); -}); + vi.clearAllMocks() +}) -describe('Releases page', () => { - it('renders correctly', () => { - mock.onGet().reply(200, [], {'pagecount': 0}); +describe("Releases page", () => { + it("renders correctly", () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const pageContent = container.querySelector("main") expect(pageContent).toMatchSnapshot() }) - it('head renders correctly', () => { - mock.onGet().reply(200, [], {'pagecount': 0}); + it("head renders correctly", () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); + const { container } = render() // eslint-disable-next-line const title = container.querySelector("title") expect(title?.textContent).toEqual("Latest Releases | Adoptium") }) - it('has no accessibility violations', async () => { - mock.onGet().reply(200, [], {'pagecount': 0}); + it("has no accessibility violations", async () => { + mock.onGet().reply(200, [], { pagecount: 0 }) - const { container } = render(); - const results = await axe(container); - expect(results).toHaveNoViolations(); - }); -}); + const { container } = render() + const results = await axe(container) + expect(results).toHaveNoViolations() + }) +}) diff --git a/tsconfig.json b/tsconfig.json index 2d59eb29..4cb668ce 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,13 +18,13 @@ "esModuleInterop": true, "downlevelIteration": true, "resolveJsonModule": true, - "plugins": [] + "plugins": [], }, "include": [ "**/*.{ts,tsx,mdx}", "gatsby-node.ts", "gatsby-config.ts", "vitest.config.ts", - "vitest-setup.tsx" - ] + "vitest-setup.tsx", + ], } diff --git a/vitest-setup.ts b/vitest-setup.ts index f28c09b1..968a3804 100644 --- a/vitest-setup.ts +++ b/vitest-setup.ts @@ -1,23 +1,23 @@ -import { expect, vi } from 'vitest' -import * as axeMatchers from 'vitest-axe/matchers' -import React from 'react' -import 'vitest-axe/extend-expect' -import '@testing-library/jest-dom' -import 'vitest-canvas-mock' -import 'jest-canvas-mock'; +import { expect, vi } from "vitest" +import * as axeMatchers from "vitest-axe/matchers" +import React from "react" +import "vitest-axe/extend-expect" +import "@testing-library/jest-dom" +import "vitest-canvas-mock" +import "jest-canvas-mock" -expect.extend(axeMatchers); +expect.extend(axeMatchers) -vi.mock('gatsby', async () => { - const gatsby = await vi.importActual('gatsby') +vi.mock("gatsby", async () => { + const gatsby = await vi.importActual("gatsby") const mockUseStaticQuery = { site: { siteMetadata: { - title: 'Sample Title', - description: 'Sample Description', - siteUrl: 'https://sample.com', - } + title: "Sample Title", + description: "Sample Description", + siteUrl: "https://sample.com", + }, }, mostRecentLts: { version: 1, @@ -29,46 +29,46 @@ vi.mock('gatsby', async () => { edges: [ { node: { - id: 'mock-id-1', + id: "mock-id-1", version: 1, - label: '1 - LTS', + label: "1 - LTS", lts: true, - } + }, }, { node: { - id: 'mock-id-2', + id: "mock-id-2", version: 2, - label: '2', + label: "2", lts: false, - } + }, }, - ] + ], }, avatar: { edges: [ { node: { - name: 'pmc', + name: "pmc", childImageSharp: { gatsbyImageData: { - layout: 'fixed', + layout: "fixed", images: { fallback: { - src: 'https://sample-images.com/pmc.png', - } - } - } - } - } - } - ] + src: "https://sample-images.com/pmc.png", + }, + }, + }, + }, + }, + }, + ], }, mdx: { frontmatter: { - author: 'pmc', - } - } + author: "pmc", + }, + }, } return { @@ -76,22 +76,25 @@ vi.mock('gatsby', async () => { graphql: vi.fn(), StaticQuery: vi.fn(), useStaticQuery: vi.fn().mockImplementation(() => mockUseStaticQuery), - Slice: vi.fn() - .mockImplementation(({ alias }) => - React.createElement('div', { className: `slice--${alias}` }) - ), + Slice: vi + .fn() + .mockImplementation(({ alias }) => + React.createElement("div", { className: `slice--${alias}` }), + ), navigate: vi.fn(), } }) -vi.mock('gatsby-plugin-image', async () => { - const plugin = await vi.importActual('gatsby-plugin-image') +vi.mock("gatsby-plugin-image", async () => { + const plugin = await vi.importActual( + "gatsby-plugin-image", + ) - const mockImage = ({imgClassName, imgStyle, ...props}: any) => { - return React.createElement('img', { + const mockImage = ({ imgClassName, imgStyle, ...props }: any) => { + return React.createElement("img", { className: imgClassName, stlye: imgStyle, - ...props + ...props, }) } @@ -104,40 +107,40 @@ vi.mock('gatsby-plugin-image', async () => { return mockPlugin }) -vi.mock('@gatsbyjs/reach-router', async () => { +vi.mock("@gatsbyjs/reach-router", async () => { return { useLocation: () => ({ - pathname: '/' - }) + pathname: "/", + }), } }) -vi.mock('react-world-flags', async () => { +vi.mock("react-world-flags", async () => { return { - default: () => 'Flag' + default: () => "Flag", } }) -vi.mock('gatsby-plugin-react-i18next', async () => { +vi.mock("gatsby-plugin-react-i18next", async () => { return { Link: vi.fn().mockImplementation(({ to, getProps, ...rest }) => - React.createElement('a', { + React.createElement("a", { ...rest, - href: to - }) + href: to, + }), ), useTranslation: () => ({ t: (key: string) => key, i18n: { - changeLanguage: async () => await new Promise(() => {}) - } + changeLanguage: async () => await new Promise(() => {}), + }, }), useI18next: () => ({ - language: 'en', - languages: ['en', 'en-GB', 'es', 'de', 'zh-CN'], - changeLanguage: async () => await new Promise(() => {}) + language: "en", + languages: ["en", "en-GB", "es", "de", "zh-CN"], + changeLanguage: async () => await new Promise(() => {}), }), - Trans: () => 'Text' + Trans: () => "Text", } }) @@ -145,7 +148,7 @@ const IntersectionObserverMock = vi.fn(() => ({ disconnect: vi.fn(), observe: vi.fn(), takeRecords: vi.fn(), - unobserve: vi.fn() + unobserve: vi.fn(), })) -vi.stubGlobal('IntersectionObserver', IntersectionObserverMock) +vi.stubGlobal("IntersectionObserver", IntersectionObserverMock) diff --git a/vitest.config.ts b/vitest.config.ts index 06f814c3..22573ad6 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -15,26 +15,26 @@ export default defineConfig({ ], test: { globals: true, - setupFiles: './vitest-setup.ts', - environment: 'jsdom', + setupFiles: "./vitest-setup.ts", + environment: "jsdom", deps: { // >= 0.34 optimizer: { web: { - include: ['vitest-canvas-mock'] - } - } + include: ["vitest-canvas-mock"], + }, + }, }, coverage: { all: true, - include: ['src/**/*.{ts,tsx}'], - exclude: ['src/types/**', 'src/**/__tests__/**', 'src/**/__mocks__/**'], - reporter: ['text', 'json', 'html'] + include: ["src/**/*.{ts,tsx}"], + exclude: ["src/types/**", "src/**/__tests__/**", "src/**/__mocks__/**"], + reporter: ["text", "json", "html"], }, environmentOptions: { jsdom: { - resources: 'usable', + resources: "usable", }, - }, - } + }, + }, })