Skip to content

Commit 8cbc9b2

Browse files
committed
Add tests for ai helper functions
1 parent e2e16dc commit 8cbc9b2

File tree

6 files changed

+389
-127
lines changed

6 files changed

+389
-127
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { analyzeQuery } from "../src/utils/analyzeQuery";
2+
import { describe, test, expect, jest } from "@jest/globals";
3+
import {
4+
NAMESPACE_KEYWORDS,
5+
ASSISTANT_TERMS,
6+
DEPARTMENT_CODES,
7+
} from "../src/constants/promptKeywords";
8+
9+
// Mock the constants if needed
10+
jest.mock("../src/constants/promptKeywords", () => ({
11+
NAMESPACE_KEYWORDS: {
12+
courses_v3: ["course", "class", "description"],
13+
offerings: ["offering", "schedule", "timetable"],
14+
prerequisites: ["prerequisite", "prereq"],
15+
corequisites: ["corequisite", "coreq"],
16+
departments: ["department", "faculty"],
17+
programs: ["program", "major", "minor"],
18+
},
19+
ASSISTANT_TERMS: ["you", "your", "morpheus", "assistant"],
20+
DEPARTMENT_CODES: ["cs", "math", "eng"],
21+
GENERAL_ACADEMIC_TERMS: ["academic", "study", "education"],
22+
}));
23+
24+
describe("analyzeQuery", () => {
25+
test("should return no search required for assistant-related queries", () => {
26+
const result = analyzeQuery("Can you help me with something?");
27+
expect(result).toEqual({
28+
requiresSearch: false,
29+
relevantNamespaces: [],
30+
});
31+
});
32+
33+
test("should detect course-related keywords and return appropriate namespaces", () => {
34+
const result = analyzeQuery("Tell me about this course");
35+
expect(result.requiresSearch).toBe(true);
36+
expect(result.relevantNamespaces).toContain("courses_v3");
37+
});
38+
39+
test("should detect course codes and include relevant namespaces", () => {
40+
const result = analyzeQuery("What is CSC108 about?");
41+
expect(result.requiresSearch).toBe(true);
42+
expect(result.relevantNamespaces).toContain("courses_v3");
43+
expect(result.relevantNamespaces).toContain("offerings");
44+
expect(result.relevantNamespaces).toContain("prerequisites");
45+
});
46+
47+
test("should detect department codes and include relevant namespaces", () => {
48+
const result = analyzeQuery("What math courses are available?");
49+
expect(result.requiresSearch).toBe(true);
50+
expect(result.relevantNamespaces).toContain("departments");
51+
expect(result.relevantNamespaces).toContain("courses_v3");
52+
});
53+
54+
test("should detect offering-related keywords", () => {
55+
const result = analyzeQuery("What is the schedule for winter semester?");
56+
expect(result.requiresSearch).toBe(true);
57+
expect(result.relevantNamespaces).toContain("offerings");
58+
});
59+
60+
test("should detect prerequisite-related keywords", () => {
61+
const result = analyzeQuery("What are the prerequisites for this class?");
62+
expect(result.requiresSearch).toBe(true);
63+
expect(result.relevantNamespaces).toContain("prerequisites");
64+
});
65+
66+
test("should detect corequisite-related keywords", () => {
67+
const result = analyzeQuery("Are there any corequisites for this course?");
68+
expect(result.requiresSearch).toBe(true);
69+
expect(result.relevantNamespaces).toContain("corequisites");
70+
});
71+
72+
test("should return all namespaces when search is required but no specific namespaces identified", () => {
73+
// Assuming GENERAL_ACADEMIC_TERMS includes 'academic'
74+
const result = analyzeQuery("I need academic information");
75+
expect(result.requiresSearch).toBe(true);
76+
expect(result.relevantNamespaces).toEqual([
77+
"courses_v3",
78+
"offerings",
79+
"prerequisites",
80+
"corequisites",
81+
"departments",
82+
"programs",
83+
]);
84+
});
85+
86+
test("should be case insensitive", () => {
87+
const result = analyzeQuery("TELL ME ABOUT THIS COURSE");
88+
expect(result.requiresSearch).toBe(true);
89+
expect(result.relevantNamespaces).toContain("courses_v3");
90+
});
91+
92+
test("should detect multiple namespaces in a single query", () => {
93+
const result = analyzeQuery(
94+
"What are the prerequisites and schedule for CSC108?"
95+
);
96+
expect(result.requiresSearch).toBe(true);
97+
expect(result.relevantNamespaces).toContain("prerequisites");
98+
expect(result.relevantNamespaces).toContain("offerings");
99+
expect(result.relevantNamespaces).toContain("courses_v3");
100+
});
101+
102+
test("should correctly identify course codes with different formats", () => {
103+
const formats = [
104+
"CSC108", // Standard format
105+
"CSC108H", // With suffix
106+
"CSCA08", // Four letters
107+
"MAT224", // Different department
108+
"ECO100Y", // Another format
109+
];
110+
111+
formats.forEach((code) => {
112+
const result = analyzeQuery(`Tell me about ${code}`);
113+
expect(result.requiresSearch).toBe(true);
114+
expect(result.relevantNamespaces).toContain("courses_v3");
115+
expect(result.relevantNamespaces).toContain("offerings");
116+
expect(result.relevantNamespaces).toContain("prerequisites");
117+
});
118+
});
119+
});
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import {
2+
BREADTH_REQUIREMENT_KEYWORDS,
3+
YEAR_LEVEL_KEYWORDS
4+
} from '../src/constants/promptKeywords';
5+
import { includeFilters } from '../src/utils/includeFilters';
6+
import { describe, test, expect, jest, beforeEach } from "@jest/globals";
7+
import * as ModuleType from '../src/utils/convert-breadth-requirement';
8+
import * as ModuleType0 from '../src/utils/convert-year-level';
9+
10+
// Create mock functions
11+
const mockConvertBreadthRequirement = jest.fn((namespace) => `converted_${namespace}`);
12+
const mockConvertYearLevel = jest.fn((namespace) => `converted_${namespace}`);
13+
14+
// Mock the modules
15+
jest.mock('../src/utils/convert-breadth-requirement', () => ({
16+
convertBreadthRequirement: (namespace: string) => mockConvertBreadthRequirement(namespace)
17+
}));
18+
19+
jest.mock('../src/utils/convert-year-level', () => ({
20+
convertYearLevel: (namespace: string) => mockConvertYearLevel(namespace)
21+
}));
22+
23+
describe('includeFilters', () => {
24+
beforeEach(() => {
25+
// Clear mock data before each test
26+
mockConvertBreadthRequirement.mockClear();
27+
mockConvertYearLevel.mockClear();
28+
});
29+
30+
test('should return empty object when no filters match', () => {
31+
const query = 'something random';
32+
const result = includeFilters(query);
33+
expect(result).toEqual({});
34+
});
35+
36+
test('should match breadth requirement keywords case-insensitively', () => {
37+
const query = 'I want to study ART Literature';
38+
const result = includeFilters(query);
39+
expect(result).toEqual({
40+
$or: [
41+
{ breadth_requirement: { $eq: 'converted_ART_LIT_LANG' } }
42+
]
43+
});
44+
});
45+
46+
test('should match year level keywords case-insensitively', () => {
47+
const query = 'Looking for A-level courses';
48+
const result = includeFilters(query);
49+
expect(result).toEqual({
50+
$or: [
51+
{ year_level: { $eq: 'converted_first_year' } }
52+
]
53+
});
54+
});
55+
56+
test('should combine both breadth and year level filters with $and when both are present', () => {
57+
const query = 'Natural Science First-Year courses';
58+
const result = includeFilters(query);
59+
expect(result).toEqual({
60+
$and: [
61+
{
62+
$or: [
63+
{ breadth_requirement: { $eq: 'converted_NAT_SCI' } }
64+
]
65+
},
66+
{
67+
$or: [
68+
{ year_level: { $eq: 'converted_first_year' } }
69+
]
70+
}
71+
]
72+
});
73+
});
74+
75+
test('should handle multiple breadth requirements', () => {
76+
const query = 'social science or quantitative reasoning';
77+
const result = includeFilters(query);
78+
expect(result).toEqual({
79+
$or: [
80+
{ breadth_requirement: { $eq: 'converted_SOCIAL_SCI' } },
81+
{ breadth_requirement: { $eq: 'converted_QUANT' } }
82+
]
83+
});
84+
});
85+
86+
test('should handle multiple year levels', () => {
87+
const query = 'third year or fourth-year courses';
88+
const result = includeFilters(query);
89+
expect(result).toEqual({
90+
$or: [
91+
{ year_level: { $eq: 'converted_third_year' } },
92+
{ year_level: { $eq: 'converted_fourth_year' } }
93+
]
94+
});
95+
});
96+
97+
test('should handle multiple breadth requirements and year levels', () => {
98+
const query = 'history philosophy B-level or C-level';
99+
const result = includeFilters(query);
100+
console.log(result)
101+
expect(result).toEqual({
102+
$and: [
103+
{
104+
$or: [
105+
{ breadth_requirement: { $eq: 'converted_HIS_PHIL_CUL' } }
106+
]
107+
},
108+
{
109+
$or: [
110+
{ year_level: { $eq: 'converted_second_year' } },
111+
{ year_level: { $eq: 'converted_third_year' } }
112+
]
113+
}
114+
]
115+
});
116+
});
117+
118+
test('should ignore partial keyword matches', () => {
119+
// "art" alone shouldn't match "art literature language"
120+
const query = 'art courses';
121+
const result = includeFilters(query);
122+
// This should not match any specific filter since "art" alone isn't in the keywords
123+
expect(result).toEqual({});
124+
});
125+
126+
test('should handle edge case with empty query', () => {
127+
const query = '';
128+
const result = includeFilters(query);
129+
expect(result).toEqual({});
130+
});
131+
});

course-matrix/backend/src/constants/promptKeywords.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const NAMESPACE_KEYWORDS = {
6363

6464
export const BREADTH_REQUIREMENT_KEYWORDS = {
6565
ART_LIT_LANG: [
66-
"ART_LIT_LANG",
66+
"art_lit_lang",
6767
"art literature",
6868
"arts literature",
6969
"art language",
@@ -73,7 +73,7 @@ export const BREADTH_REQUIREMENT_KEYWORDS = {
7373
"arts literature language",
7474
],
7575
HIS_PHIL_CUL: [
76-
"HIS_PHIL_CUL",
76+
"his_phil_cul",
7777
"history philosophy culture",
7878
"history, philosophy, culture",
7979
"history, philosophy, and culture",
@@ -84,16 +84,16 @@ export const BREADTH_REQUIREMENT_KEYWORDS = {
8484
"history culture",
8585
"History, Philosophy and Cultural Studies",
8686
],
87-
SOCIAL_SCI: ["SOCIAL_SCI", "social science", "social sciences"],
88-
NAT_SCI: ["NAT_SCI", "natural science", "natural sciences"],
89-
QUANT: ["QUANT", "quantitative reasoning"],
87+
SOCIAL_SCI: ["social_sci", "social science", "social sciences"],
88+
NAT_SCI: ["nat_sci", "natural science", "natural sciences"],
89+
QUANT: ["quant", "quantitative reasoning", "quantitative"],
9090
};
9191

9292
export const YEAR_LEVEL_KEYWORDS = {
93-
first_year: ["first year", "first-year", "A-level", "A level", "1st year"],
94-
second_year: ["second year", "second-year", "B-level", "B level", "2nd year"],
95-
third_year: ["third year", "third-year", "C-level", "C level", "3rd year"],
96-
fourth_year: ["fourth year", "fourth-year", "D-level", "D level", "4th year"],
93+
first_year: ["first year", "first-year", "a-level", "a level", "1st year"],
94+
second_year: ["second year", "second-year", "b-level", "b level", "2nd year"],
95+
third_year: ["third year", "third-year", "c-level", "c level", "3rd year"],
96+
fourth_year: ["fourth year", "fourth-year", "d-level", "d level", "4th year"],
9797
};
9898

9999
// General academic terms that might indicate a search is needed

0 commit comments

Comments
 (0)