@conorheffron/ironoc-frontend 9.1.3 → 9.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conorheffron/ironoc-frontend",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"dependencies": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@graphiql/plugin-explorer": "^5.1.1",
|
|
14
14
|
"@graphiql/react": "^0.37.1",
|
|
15
15
|
"@testing-library/user-event": "^14.6.1",
|
|
16
|
-
"axios": "^1.
|
|
16
|
+
"axios": "^1.15.2",
|
|
17
17
|
"bootstrap": "5.3",
|
|
18
18
|
"graphql": "^16.11.0",
|
|
19
19
|
"history": "^5.3.0",
|
package/src/App.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom';
|
|
4
4
|
import Home from './components/Home';
|
|
5
5
|
import App from './App';
|
|
@@ -65,6 +65,20 @@ describe('AppNavBar', () => {
|
|
|
65
65
|
expect(homeLink).toBeInTheDocument();
|
|
66
66
|
expect(homeLink.closest('a')).toHaveAttribute('href', '/');
|
|
67
67
|
});
|
|
68
|
+
|
|
69
|
+
test('toggles collapsed navbar state when toggler is clicked', async () => {
|
|
70
|
+
const { container } = render(<AppNavBar />);
|
|
71
|
+
const toggler = container.querySelector('.navbar-toggler');
|
|
72
|
+
const collapse = container.querySelector('.navbar-collapse');
|
|
73
|
+
|
|
74
|
+
expect(toggler).toBeInTheDocument();
|
|
75
|
+
expect(collapse).toBeInTheDocument();
|
|
76
|
+
expect(collapse).not.toHaveClass('show');
|
|
77
|
+
fireEvent.click(toggler);
|
|
78
|
+
await waitFor(() => expect(collapse).toHaveClass('show'));
|
|
79
|
+
fireEvent.click(toggler);
|
|
80
|
+
await waitFor(() => expect(collapse).not.toHaveClass('show'));
|
|
81
|
+
});
|
|
68
82
|
});
|
|
69
83
|
|
|
70
84
|
describe('Footer Component', () => {
|
|
@@ -109,4 +123,21 @@ describe('Footer Component', () => {
|
|
|
109
123
|
await waitFor(() => expect(fetch).toHaveBeenCalledTimes(1));
|
|
110
124
|
await waitFor(() => expect(screen.getByText('© 2025 by Conor Heffron |')).toBeInTheDocument());
|
|
111
125
|
});
|
|
126
|
+
|
|
127
|
+
test('handles non-ok fetch responses', async () => {
|
|
128
|
+
const textMock = jest.fn(() => Promise.resolve('unexpected-version'));
|
|
129
|
+
fetch.mockImplementationOnce(() =>
|
|
130
|
+
Promise.resolve({
|
|
131
|
+
ok: false,
|
|
132
|
+
text: textMock,
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
render(<Footer />);
|
|
137
|
+
await waitFor(() => expect(fetch).toHaveBeenCalledTimes(1));
|
|
138
|
+
await waitFor(() => {
|
|
139
|
+
expect(textMock).not.toHaveBeenCalled();
|
|
140
|
+
expect(screen.queryByText('unexpected-version')).not.toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
112
143
|
});
|
|
@@ -57,7 +57,7 @@ const errorMocks = [
|
|
|
57
57
|
describe('Donate Component', () => {
|
|
58
58
|
it('renders loading spinner initially', () => {
|
|
59
59
|
render(
|
|
60
|
-
<MockedProvider mocks={mocks}
|
|
60
|
+
<MockedProvider mocks={mocks}>
|
|
61
61
|
<Donate />
|
|
62
62
|
</MockedProvider>
|
|
63
63
|
);
|
|
@@ -68,7 +68,7 @@ describe('Donate Component', () => {
|
|
|
68
68
|
|
|
69
69
|
it('renders error message when GraphQL query fails', async () => {
|
|
70
70
|
render(
|
|
71
|
-
<MockedProvider mocks={errorMocks}
|
|
71
|
+
<MockedProvider mocks={errorMocks}>
|
|
72
72
|
<Donate />
|
|
73
73
|
</MockedProvider>
|
|
74
74
|
);
|
|
@@ -81,7 +81,7 @@ describe('Donate Component', () => {
|
|
|
81
81
|
|
|
82
82
|
it('renders donate items after successful fetch', async () => {
|
|
83
83
|
render(
|
|
84
|
-
<MockedProvider mocks={mocks}
|
|
84
|
+
<MockedProvider mocks={mocks}>
|
|
85
85
|
<Donate />
|
|
86
86
|
</MockedProvider>
|
|
87
87
|
);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const mockRender = jest.fn();
|
|
2
|
+
const mockCreateRoot = jest.fn(() => ({
|
|
3
|
+
render: mockRender,
|
|
4
|
+
}));
|
|
5
|
+
|
|
6
|
+
const elementContainsClassName = (node, className) => {
|
|
7
|
+
if (!node) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (Array.isArray(node)) {
|
|
12
|
+
return node.some((child) => elementContainsClassName(child, className));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof node !== 'object') {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const nodeClassName = node.props && typeof node.props.className === 'string'
|
|
20
|
+
? node.props.className.split(/\s+/)
|
|
21
|
+
: [];
|
|
22
|
+
|
|
23
|
+
if (nodeClassName.includes(className)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return elementContainsClassName(node.props && node.props.children, className);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('index entrypoint', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
jest.resetModules();
|
|
33
|
+
mockCreateRoot.mockReset();
|
|
34
|
+
mockCreateRoot.mockImplementation(() => ({ render: mockRender }));
|
|
35
|
+
mockRender.mockReset();
|
|
36
|
+
document.body.innerHTML = '<div id="root"></div>';
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('renders application wrapper into root element', () => {
|
|
40
|
+
jest.isolateModules(() => {
|
|
41
|
+
jest.doMock('react-dom/client', () => ({
|
|
42
|
+
createRoot: mockCreateRoot,
|
|
43
|
+
}));
|
|
44
|
+
jest.doMock('./App', () => () => null);
|
|
45
|
+
jest.doMock('./AppNavbar', () => () => null);
|
|
46
|
+
jest.doMock('./Footer', () => () => null);
|
|
47
|
+
require('./index');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(mockCreateRoot).toHaveBeenCalledWith(document.getElementById('root'));
|
|
51
|
+
expect(mockRender).toHaveBeenCalledTimes(1);
|
|
52
|
+
expect(elementContainsClassName(mockRender.mock.calls[0][0], 'app-wrapper')).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
describe('reportWebVitals', () => {
|
|
2
|
+
test('does nothing when callback is not provided', async () => {
|
|
3
|
+
const getCLSMock = jest.fn();
|
|
4
|
+
const getFIDMock = jest.fn();
|
|
5
|
+
const getFCPMock = jest.fn();
|
|
6
|
+
const getLCPMock = jest.fn();
|
|
7
|
+
const getTTFBMock = jest.fn();
|
|
8
|
+
|
|
9
|
+
jest.resetModules();
|
|
10
|
+
jest.isolateModules(() => {
|
|
11
|
+
jest.doMock('web-vitals', () => ({
|
|
12
|
+
getCLS: getCLSMock,
|
|
13
|
+
getFID: getFIDMock,
|
|
14
|
+
getFCP: getFCPMock,
|
|
15
|
+
getLCP: getLCPMock,
|
|
16
|
+
getTTFB: getTTFBMock,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const reportWebVitals = require('./reportWebVitals').default;
|
|
20
|
+
reportWebVitals();
|
|
21
|
+
});
|
|
22
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
23
|
+
|
|
24
|
+
expect(getCLSMock).not.toHaveBeenCalled();
|
|
25
|
+
expect(getFIDMock).not.toHaveBeenCalled();
|
|
26
|
+
expect(getFCPMock).not.toHaveBeenCalled();
|
|
27
|
+
expect(getLCPMock).not.toHaveBeenCalled();
|
|
28
|
+
expect(getTTFBMock).not.toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('forwards callback to web-vitals metrics', async () => {
|
|
32
|
+
const getCLSMock = jest.fn();
|
|
33
|
+
const getFIDMock = jest.fn();
|
|
34
|
+
const getFCPMock = jest.fn();
|
|
35
|
+
const getLCPMock = jest.fn();
|
|
36
|
+
const getTTFBMock = jest.fn();
|
|
37
|
+
const onPerfEntry = function onPerfEntry() {};
|
|
38
|
+
|
|
39
|
+
jest.resetModules();
|
|
40
|
+
jest.isolateModules(() => {
|
|
41
|
+
jest.doMock('web-vitals', () => ({
|
|
42
|
+
getCLS: getCLSMock,
|
|
43
|
+
getFID: getFIDMock,
|
|
44
|
+
getFCP: getFCPMock,
|
|
45
|
+
getLCP: getLCPMock,
|
|
46
|
+
getTTFB: getTTFBMock,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
const reportWebVitals = require('./reportWebVitals').default;
|
|
50
|
+
reportWebVitals(onPerfEntry);
|
|
51
|
+
});
|
|
52
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
53
|
+
|
|
54
|
+
expect(getCLSMock).toHaveBeenCalledWith(onPerfEntry);
|
|
55
|
+
expect(getFIDMock).toHaveBeenCalledWith(onPerfEntry);
|
|
56
|
+
expect(getFCPMock).toHaveBeenCalledWith(onPerfEntry);
|
|
57
|
+
expect(getLCPMock).toHaveBeenCalledWith(onPerfEntry);
|
|
58
|
+
expect(getTTFBMock).toHaveBeenCalledWith(onPerfEntry);
|
|
59
|
+
});
|
|
60
|
+
});
|