diff --git a/static/script.js b/static/script.js index b896e356..992df224 100644 --- a/static/script.js +++ b/static/script.js @@ -915,9 +915,6 @@ if (resetProgressBtn) { if (!skillsHidden) { var skillsHidden = document.getElementById("skills"); } - // Keep the hidden in sync for form serialisation - // The API expects a comma-separated string, so join the array that way - skillsHidden.value = selectedSkills.join(", "); } updateQuickPickState(); diff --git a/tests/test_basic.py b/tests/test_basic.py index d3a637c0..9148e42f 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -196,6 +196,32 @@ def test_parse_skills_single_entry(): assert parse_skills("JavaScript") == ["javascript"] +def test_parse_skills_valid_json_array(): + """parse_skills should parse a valid JSON array of skills.""" + result = parse_skills('["Python","React"]') + assert result == ["python", "react"] + + +def test_parse_skills_malformed_json_handling(): + """parse_skills should handle malformed JSON gracefully using fallback.""" + # Should not crash, and parses via fallback comma-splitting behavior + result = parse_skills('["Python",]') + assert isinstance(result, list) + assert len(result) > 0 + + +def test_parse_skills_legacy_fallback(): + """parse_skills should parse a legacy comma-separated string.""" + result = parse_skills("Python,React") + assert result == ["python", "react"] + + +def test_parse_skills_containing_commas(): + """parse_skills should preserve skill names containing commas when using JSON.""" + result = parse_skills('["HTML, CSS","JavaScript"]') + assert result == ["html, css", "javascript"] + + def test_score_single_project_full_match(): """A project that matches all four criteria should receive the maximum score.""" project = { diff --git a/utils/recommender.py b/utils/recommender.py index 74b29883..cb6e4893 100644 --- a/utils/recommender.py +++ b/utils/recommender.py @@ -45,18 +45,34 @@ def parse_skills(skills_string): """ - Convert a raw comma-separated skills string into - a normalized lowercase list. + Convert a skills string into a normalized lowercase list. - Example: - "JS, HTML5, CSS3" -> ["javascript", "html", "css"] - """ + Accepts two formats: + 1. JSON array (preferred): '["HTML, CSS", "JavaScript"]' + Handles skill names that contain commas without mis-splitting. + 2. Comma-separated string (legacy fallback): "HTML, CSS, JavaScript" - raw_skills = [ - s.strip().lower() - for s in skills_string.split(",") - if s.strip() - ] + Example: + '["JS", "HTML5", "CSS3"]' -> ["javascript", "html", "css"] + """ + import json + + # Skills are serialized as JSON arrays. + # Legacy comma-separated values remain supported for compatibility. + try: + # Preferred path: frontend sends a JSON-serialized array + parsed = json.loads(skills_string) + if isinstance(parsed, list): + raw_skills = [s.strip().lower() for s in parsed if isinstance(s, str) and s.strip()] + else: + raise ValueError("Parsed JSON is not a list") + except (json.JSONDecodeError, ValueError, TypeError): + # Fallback: handle plain comma-separated strings + raw_skills = [ + s.strip().lower() + for s in skills_string.split(",") + if s.strip() + ] normalized_skills = [] for skill in raw_skills: