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

Fetch constants from api instead of having values hardcoded #2787

Merged
merged 11 commits into from
Apr 30, 2024
11 changes: 10 additions & 1 deletion src/__fixtures__/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
NewsResponse,
ReleaseAsset,
TemurinReleases,
OperatingSystem,
Architecture
} from '../hooks';

export const createRandomTemurinRelease = (installer): ReleaseAsset => ({
Expand Down Expand Up @@ -232,7 +234,6 @@ export const createMockReleaseNotesAPI = (number): ReleaseNoteAPIResponse => ({
}))
});


export const createMockTemurinFeatureReleaseAPI = (installer): MockTemurinFeatureReleaseAPI => ({
id: 'id_mock',
download_count: 0,
Expand Down Expand Up @@ -377,3 +378,11 @@ export const createMockAdoptiumContributorsApi = (): ContributorApiResponse => (
site_admin: false
}
);

export const mockOsesAPI = (): OperatingSystem[] => (
[{name: "mock_macos"}, {name: "mock_linux"}, {name: "mock_windows"}]
);

export const mockArchesAPI = (): Architecture[] => (
[{name: "mock_aarch64"}, {name: "mock_ppc64"}, {name: "mock_x64"}
]);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { act, render, fireEvent, waitFor } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest'
import { createRandomTemurinReleases } from '../../../__fixtures__/hooks';
import { createRandomTemurinReleases, mockOsesAPI, mockArchesAPI } from '../../../__fixtures__/hooks';
import DownloadDropdowns from '..';
import queryString from 'query-string';

Expand All @@ -11,6 +11,17 @@ const Table = () => {
);
};

vi.mock('../../../hooks/fetchConstants', () => {
return {
fetchOses: () => {
return mockOsesAPI();
},
fetchArches: () => {
return mockArchesAPI();
}
};
});

vi.mock('../../VendorSelector', () => {
return {
default: () => <div>vendor-selector</div>,
Expand All @@ -19,8 +30,6 @@ vi.mock('../../VendorSelector', () => {

vi.mock('../../../util/defaults', () => {
return {
oses: ['mock_os'],
arches: ['mock_arch'],
packageTypes: ['mock_pkg'],
defaultPackageType: 'mock_pkg',
defaultArchitecture: 'mock_arch',
Expand Down Expand Up @@ -71,14 +80,14 @@ describe('DownloadDropdowns component', () => {
// Simulate a user using dropdowns
select = getByTestId('os-filter');
await act(async () => {
fireEvent.change(select, { target: { value: 'mock_os' } });
fireEvent.change(select, { target: { value: 'mock_linux' } });
});

expect(updater).toHaveBeenCalledTimes(2);

select = getByTestId('arch-filter');
await act(async () => {
fireEvent.change(select, { target: { value: 'mock_arch' } });
fireEvent.change(select, { target: { value: 'mock_x64' } });
});

expect(updater).toHaveBeenCalledTimes(3);
Expand All @@ -100,7 +109,7 @@ describe('DownloadDropdowns component', () => {
});

it('renders correctly - use URL param os=mock_os', async () => {
queryString.parse = vi.fn().mockReturnValue({'os': "mock_os"});
queryString.parse = vi.fn().mockReturnValue({'os': "mock_linux"});

let getByRole;
await act(async () => {
Expand All @@ -113,11 +122,11 @@ describe('DownloadDropdowns component', () => {
));
});

expect(getByRole('option', { name: 'Mock_os' }).selected).toBeTruthy()
expect(getByRole('option', { name: 'Mock_linux' }).selected).toBeTruthy()
});

it('renders correctly - use URL param arch=mock_arch', async () => {
queryString.parse = vi.fn().mockReturnValue({'arch': "mock_arch"});
queryString.parse = vi.fn().mockReturnValue({'arch': "mock_x64"});

let getByRole;
await act(async () => {
Expand All @@ -130,7 +139,7 @@ describe('DownloadDropdowns component', () => {
));
});

expect(getByRole('option', { name: 'mock_arch' }).selected).toBeTruthy()
expect(getByRole('option', { name: 'mock_x64' }).selected).toBeTruthy()
});

it('renders correctly - use URL param package=mock_pkg', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,19 @@ exports[`DownloadDropdowns component > renders correctly - marketplace 1`] = `
Text
</option>
<option
value="mock_os"
value="mock_linux"
>
Mock_os
Mock_linux
</option>
<option
value="mock_macos"
>
Mock_macos
</option>
<option
value="mock_windows"
>
Mock_windows
</option>
</select>
</div>
Expand All @@ -56,9 +66,19 @@ exports[`DownloadDropdowns component > renders correctly - marketplace 1`] = `
Text
</option>
<option
value="mock_arch"
value="mock_aarch64"
>
mock_aarch64
</option>
<option
value="mock_ppc64"
>
mock_ppc64
</option>
<option
value="mock_x64"
>
mock_arch
mock_x64
</option>
</select>
</div>
Expand Down Expand Up @@ -144,9 +164,19 @@ exports[`DownloadDropdowns component > renders correctly 1`] = `
Text
</option>
<option
value="mock_os"
value="mock_linux"
>
Mock_os
Mock_linux
</option>
<option
value="mock_macos"
>
Mock_macos
</option>
<option
value="mock_windows"
>
Mock_windows
</option>
</select>
</div>
Expand All @@ -171,9 +201,19 @@ exports[`DownloadDropdowns component > renders correctly 1`] = `
Text
</option>
<option
value="mock_arch"
value="mock_aarch64"
>
mock_aarch64
</option>
<option
value="mock_ppc64"
>
mock_ppc64
</option>
<option
value="mock_x64"
>
mock_arch
mock_x64
</option>
</select>
</div>
Expand Down
15 changes: 8 additions & 7 deletions src/components/DownloadDropdowns/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import VendorSelector from '../VendorSelector'
import { detectOS, UserOS } from '../../util/detectOS';
import { setURLParam } from '../../util/setURLParam';
import { capitalize } from '../../util/capitalize';
import { oses, arches, packageTypes, defaultArchitecture, defaultPackageType} from '../../util/defaults';
import { packageTypes, defaultArchitecture, defaultPackageType} from '../../util/defaults';
import { fetchOses, fetchArches} from '../../hooks/fetchConstants';

const DownloadDropdowns = ({updaterAction, marketplace, Table}) => {

Expand Down Expand Up @@ -42,7 +43,7 @@ const DownloadDropdowns = ({updaterAction, marketplace, Table}) => {
const osParam = queryStringParams.os;
if (osParam) {
let sop = osParam.toString().toLowerCase();
if(oses.findIndex(os => os.toLowerCase() === sop) >= 0)
if(fetchOses(true).findIndex(os => os.name.toLowerCase() === sop) >= 0)
defaultSelectedOS = sop;
}

Expand All @@ -51,7 +52,7 @@ const DownloadDropdowns = ({updaterAction, marketplace, Table}) => {
const archParam = queryStringParams.arch;
if (archParam) {
let sap = archParam.toString().toLowerCase();
if(arches.findIndex(a => a.toLowerCase() === sap) >= 0)
if(fetchArches(true).findIndex(a => a.name.toLowerCase() === sap) >= 0)
defaultSelectedArch = sap;
}

Expand Down Expand Up @@ -182,9 +183,9 @@ const DownloadDropdowns = ({updaterAction, marketplace, Table}) => {
<label className="px-2 fw-bold" htmlFor="os"><Trans>Operating System</Trans></label>
<select id="os-filter" aria-label="OS Filter" data-testid="os-filter" onChange={(e) => setOS(e.target.value)} value={os} className="form-select form-select-sm">
<option key="any" value="any"><Trans>Any</Trans></option>
{oses.sort((os1, os2) => os1.localeCompare(os2)).map(
{fetchOses(true).sort((os1, os2) => os1.name.localeCompare(os2.name)).map(
(os, i): string | JSX.Element => os && (
<option key={`os-${i}`} value={os.toLowerCase()}>{capitalize(os)}</option>
<option key={`os-${i}`} value={os.name.toLowerCase()}>{capitalize(os.name)}</option>
)
)}
</select>
Expand All @@ -193,9 +194,9 @@ const DownloadDropdowns = ({updaterAction, marketplace, Table}) => {
<label className="px-2 fw-bold" htmlFor="arch"><Trans>Architecture</Trans></label>
<select id="arch-filter" aria-label="Architecture Filter" data-testid="arch-filter" onChange={(e) => setArch(e.target.value)} value={arch} className="form-select form-select-sm">
<option key="any" value="any"><Trans>Any</Trans></option>
{arches.sort((arch1, arch2) => arch1.localeCompare(arch2)).map(
{fetchArches(true).sort((arch1, arch2) => arch1.name.localeCompare(arch2.name)).map(
(arch, i): string | JSX.Element => arch && (
<option key={`arch-${i}`} value={arch.toLowerCase()}>{arch}</option>
<option key={`arch-${i}`} value={arch.name.toLowerCase()}>{arch.name}</option>
)
)}
</select>
Expand Down
37 changes: 37 additions & 0 deletions src/hooks/__tests__/__snapshots__/fetchConstants.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`fetchArches > URL is set correctly 1`] = `
[
{
"name": [
{
"name": "mock_aarch64",
},
{
"name": "mock_ppc64",
},
{
"name": "mock_x64",
},
],
},
]
`;

exports[`fetchOses > URL is set correctly 1`] = `
[
{
"name": [
{
"name": "mock_macos",
},
{
"name": "mock_linux",
},
{
"name": "mock_windows",
},
],
},
]
`;
79 changes: 79 additions & 0 deletions src/hooks/__tests__/fetchConstants.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { renderHook, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { fetchArches, fetchOses } from '../fetchConstants';
import { mockArchesAPI, mockOsesAPI } from '../../__fixtures__/hooks';
import axios from 'axios'
import MockAdapter from 'axios-mock-adapter';

const mock = new MockAdapter(axios);

afterEach(() => {
vi.clearAllMocks();
mock.reset();
});

afterAll(() => {
mock.restore();
});

describe('fetchArches', () => {
it('URL is set correctly', async () => {
const mockResponse = [mockArchesAPI()];

mock.onGet().reply(200, mockResponse);
let spy = vi.spyOn(axios, "get");

const { result } = renderHook(() => fetchArches(true));

await waitFor(() => {
expect(result.current.length).toBeGreaterThan(0)
}, { interval: 1 });
expect(spy).toHaveBeenCalledTimes(1)
expect(spy).toHaveBeenCalledWith(
"https://api.adoptium.net/v3/types/architectures"
);
expect(result.current).toMatchSnapshot()
})

it('Result is empty on error', async() => {
mock.onGet().reply(500);
let spy = vi.spyOn(axios, "get");

const { result } = renderHook(() => fetchArches(true));
await waitFor(() => {
expect(result.current.length).toBe(0)
}, { interval: 1 });
expect(spy).toHaveBeenCalledTimes(1)
})
});

describe('fetchOses', () => {
it('URL is set correctly', async () => {
const mockResponse = [mockOsesAPI()];

mock.onGet().reply(200, mockResponse);
let spy = vi.spyOn(axios, "get");

const { result } = renderHook(() => fetchOses(true));

await waitFor(() => {
expect(result.current.length).toBeGreaterThan(0)
}, { interval: 1 });
expect(spy).toHaveBeenCalledTimes(1)
expect(spy).toHaveBeenCalledWith(
"https://api.adoptium.net/v3/types/operating_systems"
);
expect(result.current).toMatchSnapshot()
})

it('Result is empty on error', async() => {
mock.onGet().reply(500);
let spy = vi.spyOn(axios, "get");

const { result } = renderHook(() => fetchOses(true));
await waitFor(() => {
expect(result.current.length).toBe(0)
}, { interval: 1 });
expect(spy).toHaveBeenCalledTimes(1)
})
});
Loading
Loading