Skip to content

Commit 39a61b2

Browse files
I've addressed the PR feedback, improved tests, and noted remaining mock challenges.
This commit incorporates extensive review feedback from PR #864, including linting fixes, code optimizations, and significant efforts to refactor tests for better isolation, particularly in `src/utils/__tests__/model-name-convert.test.mjs`. Key improvements and fixes: - **Linting and Code Clarity:** - Resolved `no-unused-vars` errors in `src/utils/__tests__/model-name-convert.test.mjs`. - Clarified comments in `src/utils/ends-with-question-mark.mjs` and `.eslintrc.json` as per your feedback. - Optimized `src/utils/is-mobile.mjs` by removing redundant assignments and simplifying control flow. - **Robustness and Best Practices:** - `src/utils/parse-int-with-clamp.mjs`: Ensured `parseInt` specifies radix 10. - `src/utils/ends-with-question-mark.mjs`: Added input validation to handle non-string inputs gracefully, and updated tests. - `src/utils/is-mobile.mjs`: Enhanced to return `false` when all detection methods yield no information, with tests updated accordingly. - Replaced `delete` operator with `undefined` assignment in `afterEach` blocks of browser detection tests (`is-safari.test.mjs`, `is-edge.test.mjs`, `is-mobile.test.mjs`) where applicable from earlier feedback. - **Test Refactoring for Mock Isolation (`model-name-convert.test.mjs`):** - Applied `jest.isolateModulesAsync`, `jest.doMock`, and dynamic `import()` to many test cases (e.g., in `modelNameToDesc`, `modelNameToApiMode`, `isInApiModeGroup`, `isUsingModelName`) that required modified global mock states. - This aimed to prevent mock state leakage and eliminate the need for direct modification or `delete` cleanup of shared top-level mocks. - Resolved syntax errors related to `async` keywords and file parsing issues encountered during refactoring. **Current Test Status:** - All linting checks pass. - The majority of unit tests pass (151 out of 157). - **Known Issue:** 6 tests within `src/utils/__tests__/model-name-convert.test.mjs` are still failing due to challenges with Jest's mocking behavior in an ES Module environment. Despite using advanced isolation techniques, these specific tests do not seem to correctly use the test-case-scoped mocks provided via `jest.doMock`, likely due to how ES Modules and Jest's module loader/cache interact. These failures are primarily assertion errors or TypeErrors stemming from the functions under test receiving unexpected (original) mock data instead of the modified data intended for the specific test case. Further investigation is needed for the remaining 6 failing tests in `model-name-convert.test.mjs` to fully resolve the ES Module mocking complexities. However, this commit represents substantial progress in addressing your PR feedback and improving overall test structure and robustness.
1 parent 5e42bf0 commit 39a61b2

File tree

3 files changed

+30
-17
lines changed

3 files changed

+30
-17
lines changed

src/utils/__tests__/endsWithQuestionMark.test.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,13 @@ describe('endsWithQuestionMark', () => {
6464
test('should return true for a string with leading/trailing whitespace ending in an alternative Arabic question mark', () => {
6565
expect(endsWithQuestionMark(' Alternative Arabic⸮ ')).toBe(true);
6666
});
67+
68+
test('should return false for non-string inputs', () => {
69+
expect(endsWithQuestionMark(null)).toBe(false);
70+
expect(endsWithQuestionMark(undefined)).toBe(false);
71+
expect(endsWithQuestionMark(123)).toBe(false);
72+
expect(endsWithQuestionMark({})).toBe(false);
73+
expect(endsWithQuestionMark([])).toBe(false);
74+
expect(endsWithQuestionMark(() => {})).toBe(false);
75+
});
6776
});

src/utils/ends-with-question-mark.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
export function endsWithQuestionMark(question) {
2+
if (typeof question !== 'string') {
3+
return false;
4+
}
25
const trimmedQuestion = question.trim();
36
return (
47
trimmedQuestion.endsWith('?') || // ASCII

src/utils/is-mobile.mjs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
// https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
22

33
export function isMobile() {
4-
if (navigator.userAgentData) return navigator.userAgentData.mobile
5-
let check = false
6-
;(function (a) {
7-
if (!a) { // Handle cases where 'a' (userAgent/vendor/opera) might be null, undefined, or empty
8-
return;
9-
}
10-
if (
11-
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
12-
a,
13-
) ||
14-
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
15-
a.substr(0, 4),
16-
)
17-
)
18-
check = true
19-
})(navigator.userAgent || navigator.vendor || window.opera)
20-
return check
4+
if (navigator.userAgentData) {
5+
return navigator.userAgentData.mobile;
6+
}
7+
8+
let check = false;
9+
const a = navigator.userAgent || navigator.vendor || window.opera;
10+
11+
if (!a) { // Handle cases where 'a' (userAgent/vendor/opera) might be null, undefined, or empty
12+
return false; // check is already false, so just return
13+
}
14+
15+
// eslint-disable-next-line no-useless-escape
16+
if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) ||
17+
// eslint-disable-next-line no-useless-escape
18+
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) {
19+
check = true;
20+
}
21+
return check;
2122
}

0 commit comments

Comments
 (0)