Skip to content

Commit 8212f90

Browse files
authored
Merge pull request #30 from MelanieH7/MelanieH7-automated-testing
feat: url automated testing
2 parents db21b00 + c8295f9 commit 8212f90

File tree

6 files changed

+153
-51
lines changed

6 files changed

+153
-51
lines changed

.github/workflows/url.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: URL Navigation and Parameter Input CI
2+
3+
on:
4+
push:
5+
branches:
6+
- 2024_sem2
7+
pull_request:
8+
branches:
9+
- 2024_sem2
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
15+
- name: Checkout 🛎️
16+
uses: actions/[email protected]
17+
with:
18+
persist-credentials: false
19+
20+
- name: Install dependencies
21+
run:
22+
npm install
23+
npm install jest supertest --save-dev
24+
25+
- name: Run tests 🔧
26+
run:
27+
npm start
28+
npm test-url

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"start:win32": "SET NODE_OPTIONS=--openssl-legacy-provider && react-scripts start",
1616
"test": "react-scripts test",
1717
"test-uf": "npm test -- ./src/algorithms/controllers/unionFind.test.js",
18-
"test-234t": "npm test -- ./src/algorithms/controllers/TTFTree.test.js"
18+
"test-234t": "npm test -- ./src/algorithms/controllers/TTFTree.test.js",
19+
"test-url": "npm test -- ./src/algorithms/parameters/helpers/urlHelpers.test.js"
1920
},
2021
"husky": {
2122
"hooks": {
@@ -62,6 +63,7 @@
6263
"@mui/styles": "^5.14.4",
6364
"@testing-library/jest-dom": "^4.2.4",
6465
"@testing-library/react": "^12.1.2",
66+
"@testing-library/react-hooks": "^8.0.1",
6567
"@testing-library/user-event": "^14.4.3",
6668
"denque": "^2.0.1",
6769
"framer-motion": "^4.0.0",
@@ -90,9 +92,11 @@
9092
"eslint-plugin-jsx-a11y": "^6.7.1",
9193
"eslint-plugin-react": "^7.33.2",
9294
"husky": "^4.2.5",
95+
"jest": "^27.5.1",
9396
"lint-staged": "^10.1.3",
9497
"react": "^17.0.2",
9598
"react-test-renderer": "^17.0.2",
96-
"run-script-os": "^1.1.6"
99+
"run-script-os": "^1.1.6",
100+
"supertest": "^7.0.0"
97101
}
98102
}

src/algorithms/parameters/HSParam.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { withAlgorithmParams } from './helpers/urlHelpers' // Import this for UR
1010
import { URLContext } from '../../context/urlState.js';
1111
import '../../styles/Param.scss';
1212

13-
13+
// export const DEFAULT_NODES = genRandNumList(12, 1, 50);
1414
const DEFAULT_NODES = genRandNumList(10, 1, 100);
1515
const HEAP_SORT = 'Heap Sort';
1616
const HEAP_SORT_EXAMPLE = 'Please follow the example provided: 0,1,2,3,4';
@@ -20,13 +20,13 @@ function HeapsortParam({ list }) { // add the parsing parameters for your algori
2020
// const { alg, mode, param } = useUrlParams();
2121
// const {list, value, xyCoords, edgeWeights, start, end, string, pattern, union} = parseParam(param);
2222
// const { alg, mode, list } = withAlgorithmParams(HeapsortParam);
23-
const DEFAULT_NODES = genRandNumList.bind(null, 12, 1, 50); // Define the default list of nodes
23+
// const DEFAULT_NODES = genRandNumList.bind(null, 12, 1, 50); // Define the default list of nodes
2424
const [localNodes, setLocalNodes] = useState(list || DEFAULT_NODES);
2525
const [message, setMessage] = useState(null);
2626
const { setNodes } = useContext(URLContext);
2727

2828
useEffect(() => {
29-
setNodes(localNodes);
29+
setNodes(localNodes);
3030
}, [localNodes]);
3131

3232
return (

src/algorithms/parameters/helpers/urlHelpers.js

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import DEFAULT_NODES from '../../../algorithms/parameters/HSParam.js';
21
import React, { useState, useEffect, useMemo } from 'react';
32
import algorithms from '../../../algorithms';
43

@@ -18,21 +17,31 @@ import algorithms from '../../../algorithms';
1817
// const DEFAULT_MIN = '1'
1918
// const DEFAULT_MAX = '10'
2019

21-
const DEFAULT_ALGORITHM = 'heapSort';
22-
const DEFAULT_MODE = 'sort';
23-
const DEFAULT_LIST = '';
24-
const DEFAULT_VALUE = '';
25-
const DEFAULT_XY_COORDS = '';
26-
const DEFAULT_EDGE_WEIGHTS = '';
27-
const DEFAULT_SIZE = '';
28-
const DEFAULT_START = '';
29-
const DEFAULT_END = '';
30-
const DEFAULT_STRING = '';
31-
const DEFAULT_PATTERN = '';
32-
const DEFAULT_UNION = '';
33-
const DEFAULT_HEURISTIC = '';
34-
const DEFAULT_MIN = '';
35-
const DEFAULT_MAX = '';
20+
// List of valid parameter names
21+
const VALID_PARAM_NAMES = [
22+
'alg', 'mode', 'list', 'value', 'xyCoords', 'edgeWeights',
23+
'size', 'start', 'end', 'string', 'pattern', 'union',
24+
'heuristic', 'min', 'max'
25+
];
26+
27+
// Default values for each parameter
28+
const DEFAULT_VALUES = {
29+
alg: 'heapSort',
30+
mode: 'sort',
31+
list: '',
32+
value: '',
33+
xyCoords: '',
34+
edgeWeights: '',
35+
size: '',
36+
start: '',
37+
end: '',
38+
string: '',
39+
pattern: '',
40+
union: '',
41+
heuristic: '',
42+
min: '',
43+
max: ''
44+
};
3645

3746

3847
export function useUrlParams() {
@@ -50,39 +59,30 @@ export function useUrlParams() {
5059
}, []);
5160

5261
const urlParams = useMemo(() => new URLSearchParams(search), [search]);
53-
const alg = urlParams.get('alg') || DEFAULT_ALGORITHM; // Default algorithm
54-
const mode = urlParams.get('mode') || DEFAULT_MODE; // Default mode
55-
56-
// Helper function to handle both missing and 'null' values
57-
const getParamOrDefault = (param, defaultValue) => {
58-
return param === null || param === "null" ? defaultValue : param;
59-
};
60-
61-
// Parse individual parameters directly from URL
62-
const list = getParamOrDefault(urlParams.get('list'), DEFAULT_LIST);
63-
const value = getParamOrDefault(urlParams.get('value'), DEFAULT_VALUE);
64-
const xyCoords = getParamOrDefault(urlParams.get('xyCoords'), DEFAULT_XY_COORDS);
65-
const edgeWeights = getParamOrDefault(urlParams.get('edgeWeights'), DEFAULT_EDGE_WEIGHTS);
66-
const size = getParamOrDefault(urlParams.get('size'), DEFAULT_SIZE);
67-
const start = getParamOrDefault(urlParams.get('start'), DEFAULT_START);
68-
const end = getParamOrDefault(urlParams.get('end'), DEFAULT_END);
69-
const string = urlParams.get('string') || DEFAULT_STRING
70-
const pattern = urlParams.get('pattern') || DEFAULT_PATTERN;
71-
const union = getParamOrDefault(urlParams.get('union'), DEFAULT_UNION);
72-
const heuristic = getParamOrDefault(urlParams.get('heuristic'), DEFAULT_HEURISTIC);
73-
const min = getParamOrDefault(urlParams.get('min'), DEFAULT_MIN);
74-
const max = getParamOrDefault(urlParams.get('max'), DEFAULT_MAX);
75-
76-
77-
console.log("Raw URL alg:", urlParams.get('alg'));
78-
console.log("Raw URL mode:", urlParams.get('mode'));
79-
console.log("Parsed URL Params:", { list, value, xyCoords, edgeWeights, size, start, end, string, pattern, union, heuristic, min, max });
62+
const params = {};
63+
64+
// Filter and parse valid URL parameters
65+
VALID_PARAM_NAMES.forEach((name) => {
66+
const value = urlParams.get(name);
67+
params[name] = value !== null ? value : DEFAULT_VALUES[name];
68+
});
69+
70+
// Log a warning if there are any invalid parameters in the URL
71+
urlParams.forEach((_, key) => {
72+
if (!VALID_PARAM_NAMES.includes(key)) {
73+
console.warn(`Invalid URL parameter ignored: ${key}`);
74+
}
75+
});
8076

81-
return { alg, mode, list, value, xyCoords, edgeWeights, size, start, end, string, pattern, union, heuristic, min, max };
77+
// console.log("Raw URL alg:", urlParams.get('alg'));
78+
// console.log("Raw URL mode:", urlParams.get('mode'));
79+
// console.log("Parsed URL Params:", { list, value, xyCoords, edgeWeights, size, start, end, string, pattern, union, heuristic, min, max });
8280

81+
return params;
8382
}
8483

8584

85+
8686
function extractValue(paramString, key) {
8787
const regex = new RegExp(`${key}=([^;]*)`);
8888
const match = paramString.match(regex);
@@ -98,6 +98,10 @@ export const withAlgorithmParams = (WrappedComponent) => {
9898
return <div>Invalid algorithm specified</div>;
9999
}
100100

101+
if (!mode || !(mode in algorithms[alg].pseudocode)) {
102+
return <div>Invalid mode specified</div>;
103+
}
104+
101105
return <WrappedComponent
102106
alg={alg}
103107
mode={mode}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* eslint-env jest */
2+
3+
jest.mock('../../../context/GlobalState', () => ({}));
4+
jest.mock('../../../context/actions', () => ({}));
5+
jest.mock('../../../algorithms', () => ({}));
6+
7+
import { renderHook, act } from '@testing-library/react-hooks';
8+
import { useUrlParams } from '../../../algorithms/parameters/helpers/urlHelpers';
9+
10+
// Helper function to change the URL
11+
const setMockUrl = (url) => {
12+
window.history.pushState({}, 'Test page', url);
13+
};
14+
15+
describe('useUrlParams', () => {
16+
it('should parse default values when no alg, mode, or parameters are provided', () => {
17+
setMockUrl('/');
18+
19+
const { result } = renderHook(() => useUrlParams());
20+
21+
expect(result.current).toEqual({
22+
alg: 'heapSort', // Default algorithm
23+
mode: 'sort', // Default mode
24+
list: '',
25+
value: '',
26+
xyCoords: '',
27+
edgeWeights: '',
28+
size: '',
29+
start: '',
30+
end: '',
31+
string: '',
32+
pattern: '',
33+
union: '',
34+
heuristic: '',
35+
min: '',
36+
max: '',
37+
});
38+
});
39+
40+
41+
it('should parse valid URL parameters', () => {
42+
setMockUrl('/?alg=binarySearchTree&mode=search&list=1,2,3&value=5&xyCoords=1-1,2-2&edgeWeights=1-2-3');
43+
44+
const { result } = renderHook(() => useUrlParams());
45+
46+
expect(result.current).toEqual({
47+
alg: 'binarySearchTree',
48+
mode: 'search',
49+
list: '1,2,3',
50+
value: '5',
51+
xyCoords: '1-1,2-2',
52+
edgeWeights: '1-2-3',
53+
size: '',
54+
start: '',
55+
end: '',
56+
string: '',
57+
pattern: '',
58+
union: '',
59+
heuristic: '',
60+
min: '',
61+
max: '',
62+
});
63+
});
64+
});

src/context/actions.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import React, { useState } from 'react';
1010
import { onCollapseChange } from '../algorithms/controllers/collapseChunkPlugin';
1111
import { onCollapseStateChange } from '../algorithms/controllers/transitiveClosureCollapseChunkPlugin';
1212
import { unionFindToggleRank } from '../algorithms/controllers/unionFindUnion';
13+
import { genRandNumList } from '../algorithms/parameters/helpers/ParamHelper';
1314

1415
const DEFAULT_ALGORITHM = 'heapSort';
1516
const DEFAULT_MODE = 'sort';
16-
const DEFAULT_PARAM = DEFAULT_NODES; // maybe for other algorithms
17-
import DEFAULT_NODES from '../algorithms/parameters/HSParam.js';
17+
// const DEFAULT_PARAM = DEFAULT_NODES; // maybe for other algorithms
18+
// import { DEFAULT_NODES } from '../algorithms/parameters/HSParam';
19+
const DEFAULT_NODES = genRandNumList(12, 1, 50);
1820

1921
// const DEFAULT_ALGORITHM = 'binarySearchTree';
2022
// const DEFAULT_MODE = 'insertion';

0 commit comments

Comments
 (0)