import {describe, it} from 'node:test'; import assert from 'node:assert/strict'; import { COMPANY_REGISTRATION_TYPES, DISTRICTS, EMPLOYMENT_TYPES, JOB_CATEGORIES, POSITION_LEVELS, SALARY_TYPES, SCHEMES, SCREEN_QUESTION_RESPONSE, getScreeningQuestionResponse, pathToJobId, removeStopWords, removeWordsInBracket, removePunctuations, removeExcessWhitespaces, removeRepeatedHyphens, joinWords, processStringToUrlFormat, isJobApplicationPath, formatJobUrl, ssecFosRequired, internshipType, } from './mcf'; describe('mcf', () => { it('should have correct employment types', () => { assert.deepStrictEqual(EMPLOYMENT_TYPES, [ {id: 7, employmentType: 'Permanent'}, {id: 8, employmentType: 'Full Time'}, {id: 5, employmentType: 'Part Time'}, {id: 3, employmentType: 'Contract'}, {id: 9, employmentType: 'Flexi-work'}, {id: 2, employmentType: 'Temporary'}, {id: 6, employmentType: 'Freelance'}, {id: 10, employmentType: internshipType}, ]); }); it('should have correct position levels', () => { assert.deepStrictEqual(POSITION_LEVELS, [ {id: 1, position: 'Senior Management'}, {id: 2, position: 'Middle Management'}, {id: 3, position: 'Manager'}, {id: 7, position: 'Professional'}, {id: 8, position: 'Senior Executive'}, {id: 9, position: 'Executive'}, {id: 10, position: 'Junior Executive'}, {id: 11, position: 'Non-executive'}, {id: 12, position: 'Fresh/entry level'}, ]); }); it('should have correct job categories', () => { assert.deepStrictEqual(JOB_CATEGORIES, [ {id: 1, category: 'Accounting / Auditing / Taxation'}, {id: 2, category: 'Admin / Secretarial'}, {id: 3, category: 'Advertising / Media'}, {id: 4, category: 'Architecture / Interior Design'}, {id: 5, category: 'Banking and Finance'}, {id: 6, category: 'Building and Construction'}, {id: 7, category: 'Consulting'}, {id: 8, category: 'Customer Service'}, {id: 9, category: 'Design'}, {id: 10, category: 'Education and Training'}, {id: 11, category: 'Engineering'}, {id: 12, category: 'Entertainment'}, {id: 13, category: 'Environment / Health'}, {id: 14, category: 'Events / Promotions'}, {id: 15, category: 'F&B'}, {id: 16, category: 'General Management'}, {id: 17, category: 'General Work'}, {id: 18, category: 'Healthcare / Pharmaceutical'}, {id: 19, category: 'Hospitality'}, {id: 20, category: 'Human Resources'}, {id: 21, category: 'Information Technology'}, {id: 22, category: 'Insurance'}, {id: 23, category: 'Legal'}, {id: 24, category: 'Logistics / Supply Chain'}, {id: 25, category: 'Manufacturing'}, {id: 26, category: 'Marketing / Public Relations'}, {id: 27, category: 'Medical / Therapy Services'}, {id: 28, category: 'Personal Care / Beauty'}, {id: 43, category: 'Precision Engineering'}, {id: 29, category: 'Professional Services'}, {id: 30, category: 'Public / Civil Service'}, {id: 31, category: 'Purchasing / Merchandising'}, {id: 32, category: 'Real Estate / Property Management'}, {id: 33, category: 'Repair and Maintenance'}, {id: 34, category: 'Risk Management'}, {id: 35, category: 'Sales / Retail'}, {id: 36, category: 'Sciences / Laboratory / R&D'}, {id: 37, category: 'Security and Investigation'}, {id: 38, category: 'Social Services'}, {id: 39, category: 'Telecommunications'}, {id: 40, category: 'Travel / Tourism'}, {id: 42, category: 'Wholesale Trade'}, {id: 41, category: 'Others'}, ]); }); it('should have correct schemes', () => { assert.deepStrictEqual(SCHEMES, [ { id: 1, scheme: 'P-Max', startDate: '1977-05-25', expiryDate: '2055-05-04', link: 'http://www.swda.gov.sg/programmes-and-initiatives/p-max-employer.html', jobseekerLink: 'http://www.wsg.gov.sg/programmes-and-initiatives/p-max-employer.html', }, { id: 2, scheme: 'Career Conversion Programme', startDate: '1977-05-25', expiryDate: '2055-05-04', link: 'https://www.swda.gov.sg/home/employers-industry-partners/workforce-skills-development/career-conversion-programmes-employers', jobseekerLink: 'https://conversion.mycareersfuture.gov.sg/Portal/ProgramListing.aspx?Source=PCP', }, { id: 3, scheme: 'Career Trial', startDate: '1977-05-25', expiryDate: '2055-05-04', link: 'http://www.swda.gov.sg/programmes-and-initiatives/career-trial-employers.html', jobseekerLink: 'https://programmes.mycareersfuture.gov.sg/CareerTrialJobseekers/ProgrammeDetails.aspx', }, { id: 4, scheme: 'Career Support Programme', startDate: '1977-05-25', expiryDate: '2055-05-04', link: 'http://www.swda.gov.sg/programmes-and-initiatives/wsg-career-support-programme-employers.html', jobseekerLink: 'http://www.wsg.gov.sg/programmes-and-initiatives/wsg-career-support-programme-individuals.html', }, { id: 5, scheme: 'SGUnited Traineeships', startDate: '2020-06-01', expiryDate: '2047-06-01', link: 'https://www.swda.gov.sg/SGUnitedTraineeships-HostCompanies.html', jobseekerLink: 'https://www.wsg.gov.sg/SGUnitedTraineeships-Trainees.html', }, { id: 6, scheme: 'SGUnited Mid-Career Pathways Programme', startDate: '2020-07-01', expiryDate: '2047-07-01', link: 'https://www.swda.gov.sg/SGUnitedMidCareerPathways-HostOrganisations.html', jobseekerLink: 'https://www.wsg.gov.sg/SGUnitedMidCareerPathways-Trainees.html', }, { id: 7, scheme: 'Mid-Career Pathways Programme', startDate: '2022-03-10', expiryDate: '2052-03-10', link: 'https://www.swda.gov.sg/home/employers-industry-partners/workforce-skills-development/mid-career-pathways-programme-for-host-organisations', jobseekerLink: 'https://www.wsg.gov.sg/home/individuals/attachment-placement-programmes/mid-career-pathways-programme-for-mature-mid-career-individuals', swdaJobseekerLink: 'https://www.swda.gov.sg/home/individuals/attachment-placement-programmes/mid-career-pathways-programme-for-mature-mid-career-individuals', }, { id: 8, scheme: 'GRaduate Industry Traineeships (GRIT) Programme', startDate: '2025-09-01', expiryDate: '2026-09-30', link: '', jobseekerLink: 'https://www.wsg.gov.sg/home/individuals/attachment-placement-programmes/graduate-industry-traineeships', swdaJobseekerLink: 'https://www.swda.gov.sg/home/individuals/attachment-placement-programmes/graduate-industry-traineeships', }, ]); }); it('should have correct districts', () => { assert.deepStrictEqual(DISTRICTS, [ { id: 1, location: "D01 Marina, Raffles Place, People's Park, Cecil", region: 'Central', sectors: ['01', '02', '03', '04', '05', '06'], }, { id: 2, location: 'D02 Anson, Tanjong Pagar', region: 'Central', sectors: ['07', '08'], }, { id: 3, location: 'D03 Queenstown, Bukit Merah, Tiong Bahru', region: 'Central', sectors: ['14', '15', '16'], }, { id: 4, location: 'D04 Harbourfront, Sentosa Island, Telok Blangah', region: 'Central', sectors: ['09', '10'], }, { id: 5, location: 'D05 Pasir Panjang, Hong Leong Garden, Clementi New Town', region: 'West', sectors: ['11', '12', '13'], }, { id: 6, location: 'D06 Beach Road, High Street', region: 'Central', sectors: ['17'], }, { id: 7, location: 'D07 Middle Road, Golden Mile', region: 'Central', sectors: ['18', '19'], }, { id: 8, location: 'D08 Little India', region: 'Central', sectors: ['20', '21'], }, { id: 9, location: 'D09 Cairnhill, Orchard, River Valley', region: 'Central', sectors: ['22', '23'], }, { id: 10, location: 'D10 Tanglin, Ardmore, Bukit Timah, Holland Road', region: 'Central', sectors: ['24', '25', '26', '27'], }, { id: 11, location: 'D11 Watten Estate, Thomson, Novena', region: 'Central', sectors: ['28', '29', '30'], }, { id: 12, location: 'D12 Toa Payoh, Balestier, Serangoon', region: 'Central', sectors: ['31', '32', '33'], }, { id: 13, location: 'D13 Macpherson, Braddell', region: 'Central', sectors: ['34', '35', '36', '37'], }, { id: 14, location: 'D14 Geylang, Eunos', region: 'Central', sectors: ['38', '39', '40', '41'], }, { id: 15, location: 'D15 Joo Chiat, Katong, Amber Road', region: 'Central', sectors: ['42', '43', '44', '45'], }, { id: 16, location: 'D16 Bedok, Eastwood, Kew Drive, Upper East Coast', region: 'East', sectors: ['46', '47', '48'], }, { id: 17, location: 'D17 Changi, Loyang', region: 'East', sectors: ['49', '50', '81', '91'], }, { id: 18, location: 'D18 Pasir Ris, Tampines', region: 'East', sectors: ['51', '52'], }, { id: 19, location: 'D19 Hougang, Sengkang, Serangoon Garden, Punggol', region: 'North-East', sectors: ['53', '54', '55', '82'], }, { id: 20, location: 'D20 Ang Mo Kio, Bishan', region: 'Central', sectors: ['56', '57'], }, { id: 21, location: 'D21 Upper Bukit Timah, Clementi Park, Ulu Pandan', region: 'West', sectors: ['58', '59'], }, { id: 22, location: 'D22 Jurong, Jurong Island, Tuas', region: 'West', sectors: ['60', '61', '62', '63', '64'], }, { id: 23, location: 'D23 Hillview, Bukit Panjang, Dairy Farm, Choa Chu Kang', region: 'West', sectors: ['65', '66', '67', '68'], }, { id: 24, location: 'D24 Tengah, Lim Chu Kang', region: 'West', sectors: ['69', '70', '71'], }, { id: 25, location: 'D25 Kranji, Woodgrove, Woodlands', region: 'North', sectors: ['72', '73'], }, { id: 26, location: 'D26 Springleaf, Upper Thomson', region: 'North', sectors: ['77', '78'], }, { id: 27, location: 'D27 Sembawang, Yishun', region: 'North', sectors: ['75', '76'], }, { id: 28, location: 'D28 Seletar', region: 'North-East', sectors: ['79', '80'], }, { id: 998, location: 'Islandwide', region: 'Islandwide', sectors: [], }, { id: 999, location: 'Overseas', region: 'Overseas', sectors: [], }, ]); }); it('should have correct salary types', () => { assert.deepStrictEqual(SALARY_TYPES, [ {id: 4, salaryType: 'Monthly'}, {id: 5, salaryType: 'Annual'}, ]); }); it('should have correct company registration types', () => { assert.deepStrictEqual(COMPANY_REGISTRATION_TYPES, [ {id: 1, registrationType: 'Registry of Company'}, {id: 2, registrationType: 'Registry of Business'}, {id: 3, registrationType: 'Other Unique Establishments (UENO)'}, {id: 4, registrationType: 'Others - None of the Above'}, ]); }); it('should have correct screening question responses', () => { assert.deepStrictEqual(getScreeningQuestionResponse(SCREEN_QUESTION_RESPONSE.YES), {label: 'Yes', value: 'yes'}); assert.deepStrictEqual(getScreeningQuestionResponse(SCREEN_QUESTION_RESPONSE.NO), {label: 'No', value: 'no'}); assert.deepStrictEqual(getScreeningQuestionResponse('any other response'), { label: 'any other response', value: 'any other response', }); }); describe('ssecFosRequired', () => { it('should return false when ssecEqa does not require ssecFos', () => { ['01', '12', '22', '34', '41'].forEach((ssecEqa) => { assert.strictEqual(ssecFosRequired(ssecEqa), false, `expected ${ssecEqa} to have false but is true`); }); }); it('should return true when ssecEqa does require ssecFos', () => { ['42', '61', '83', 'N3', 'N9'].forEach((ssecEqa) => { assert.strictEqual(ssecFosRequired(ssecEqa), true, `expected ${ssecEqa} to have true but is false`); }); }); }); describe('formatJobUrl', () => { describe('pathToJobId', () => { it('should works for just jobId', () => { const path = '/job/1580bcedd5fafbcf04ee47e918cf25d2'; const jobId = pathToJobId(path); assert.strictEqual(jobId, '1580bcedd5fafbcf04ee47e918cf25d2'); }); it('should works for sample job title', () => { const path = '/job/java-software-developer-1580bcedd5fafbcf04ee47e918cf25d2'; const jobId = pathToJobId(path); assert.strictEqual(jobId, '1580bcedd5fafbcf04ee47e918cf25d2'); }); it('should works for trailing path', () => { const path = '/job/java-software-developer-1580bcedd5fafbcf04ee47e918cf25d2/apply'; const jobId = pathToJobId(path); assert.strictEqual(jobId, '1580bcedd5fafbcf04ee47e918cf25d2'); }); it('should works for path with special characters', () => { const path = '/job/-?!@#$%^,as;ld,asjnakjsndkankjnskjdnk-akjsndkjan-&*()_-----1580bcedd5fafbcf04ee47e918cf25d2'; const jobId = pathToJobId(path); assert.strictEqual(jobId, '1580bcedd5fafbcf04ee47e918cf25d2'); }); it('should works for all official language and weird characters', () => { assert.strictEqual(pathToJobId('/job/🤡软件开发人员–谷歌©-1580bcedd5fafbcf04ee47e918cf25d2'), '1580bcedd5fafbcf04ee47e918cf25d2', ); assert.strictEqual(pathToJobId('/job/🤡सॉफ्टवेयर डेवलपर–गूगल©-1580bcedd5fafbcf04ee47e918cf25d2'), '1580bcedd5fafbcf04ee47e918cf25d2', ); assert.strictEqual(pathToJobId('/job/🤡pemaju-perisian–google©-1580bcedd5fafbcf04ee47e918cf25d2'), '1580bcedd5fafbcf04ee47e918cf25d2', ); }); }); describe('isJobApplicationPath', () => { it('should return true for job path with /apply', () => { const path = '/job/1580bcedd5fafbcf04ee47e918cf25d2/apply'; assert.strictEqual(isJobApplicationPath(path), true); }); it('should return false for job path without /apply', () => { const path = '/job/1580bcedd5fafbcf04ee47e918cf25d2'; assert.strictEqual(isJobApplicationPath(path), false); }); it('should return true for descriptive job path with /apply', () => { const path = '/job/java-software-developer-1580bcedd5fafbcf04ee47e918cf25d2/apply'; assert.strictEqual(isJobApplicationPath(path), true); }); it('should return false for descriptive job path without /apply', () => { const path = '/job/java-software-developer-1580bcedd5fafbcf04ee47e918cf25d2'; assert.strictEqual(isJobApplicationPath(path), false); }); }); describe('removeStopWords', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(removeStopWords(), ''); assert.strictEqual(removeStopWords(undefined), ''); }); it('does nothing if there is no stop words', () => { const input = 'software developer needed'; assert.strictEqual(removeStopWords(input), 'software developer needed'); }); it('removes word from the list', () => { const input = 'software developer needed to make coffee'; assert.strictEqual(removeStopWords(input), 'software developer needed make coffee'); }); it('removes multiple words from the list', () => { const input = 'software developer needed to make coffee for directors'; assert.strictEqual(removeStopWords(input), 'software developer needed make coffee directors'); }); }); describe('removeWordsInBracket', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(removeWordsInBracket(), ''); assert.strictEqual(removeWordsInBracket(undefined), ''); }); it('does nothing if there is no words in bracket', () => { const input = 'software developer needed'; assert.strictEqual(removeWordsInBracket(input), 'software developer needed'); }); it('removes empty bracket', () => { const input = 'software developer needed to make () coffee'; assert.strictEqual(removeWordsInBracket(input), 'software developer needed to make coffee'); }); it('removes word in bracket', () => { const input = '(software) developer needed to make coffee'; assert.strictEqual(removeWordsInBracket(input), ' developer needed to make coffee'); }); it('removes multiple words in bracket', () => { const input = '(software) developer needed (to make coffee)'; assert.strictEqual(removeWordsInBracket(input), ' developer needed '); }); }); describe('removePunctuations', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(removePunctuations(), ''); assert.strictEqual(removePunctuations(undefined), ''); }); it('does nothing if there is no punctuations', () => { const input = 'software developer needed'; assert.strictEqual(removePunctuations(input), 'software developer needed'); }); it('removes multiple punctuations in different places', () => { const input = 'soft!w@are deve$lop^er n&eeded to make coffee'; assert.strictEqual(removePunctuations(input), 'software developer needed to make coffee'); }); }); describe('removeExcessWhitespaces', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(removeExcessWhitespaces(), ''); assert.strictEqual(removeExcessWhitespaces(undefined), ''); }); it('removes excess whitespace between words', () => { const input = 'software developer needed'; assert.strictEqual(removeExcessWhitespaces(input), 'software developer needed'); }); it('removes excess whitespace before and after sentence, except one', () => { const input = ' test '; assert.strictEqual(removeExcessWhitespaces(input), ' test '); }); }); describe('removeRepeatedHyphens', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(removeRepeatedHyphens(), ''); assert.strictEqual(removeRepeatedHyphens(undefined), ''); }); it('removes excess whitespace between words', () => { const input = 'software---developer--------needed'; assert.strictEqual(removeRepeatedHyphens(input), 'software-developer-needed'); }); it('does not remove single hyphens', () => { const input = 'software-developer-needed'; assert.strictEqual(removeRepeatedHyphens(input), 'software-developer-needed'); }); }); describe('joinWords', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(joinWords(), ''); assert.strictEqual(joinWords(undefined), ''); }); it('joins words with hypehen', () => { const input = 'software developer needed'; assert.strictEqual(joinWords(input), 'software-developer-needed'); }); it('trims whitespace before joining', () => { const input = ' test engineer '; assert.strictEqual(joinWords(input), 'test-engineer'); }); }); describe('processStringToUrlFormat', () => { it('returns empty string on empty, null or undefined string', () => { assert.strictEqual(processStringToUrlFormat(), ''); assert.strictEqual(processStringToUrlFormat(undefined), ''); }); it('removes standard phrases like "Pte", "Ltd", "Pte.", "Ltd." "Private (Limited)", "Private Limited"', () => { const expectedOutput = 'airya-crestar'; assert.strictEqual(processStringToUrlFormat('AIRYA - CRESTAR PTE. LTD.'), expectedOutput); assert.strictEqual(processStringToUrlFormat('AIRYA - CRESTAR Pte Ltd'), expectedOutput); assert.strictEqual(processStringToUrlFormat('AIRYA - CRESTAR Private (Limited)'), expectedOutput); assert.strictEqual(processStringToUrlFormat('AIRYA - CRESTAR Private Limited'), expectedOutput); }); it('removes special characters', () => { const input = "Adi's Designs (International)"; assert.strictEqual(processStringToUrlFormat(input), 'adis-designs'); }); }); describe('formatJobUrl', () => { it('works for just uuid', () => { const job = {uuid: '1580bcedd5fafbcf04ee47e918cf25d2'}; assert.strictEqual(formatJobUrl(job), '/job/1580bcedd5fafbcf04ee47e918cf25d2'); }); it('works for uuid and job title', () => { const job = { uuid: '1580bcedd5fafbcf04ee47e918cf25d2', jobTitle: 'DIRECTOR OF OPERATIONS', }; assert.strictEqual(formatJobUrl(job), '/job/director-operations-1580bcedd5fafbcf04ee47e918cf25d2'); }); it('works for uuid, job title and company name', () => { const job = { uuid: '1580bcedd5fafbcf04ee47e918cf25d2', jobTitle: 'DIRECTOR OF OPERATIONS', company: 'AIRYA CRESTAR INTERNATIONAL PTE. LTD.', }; assert.strictEqual(formatJobUrl(job), '/job/director-operations-airya-crestar-international-1580bcedd5fafbcf04ee47e918cf25d2', ); }); it('works for all official language and weird characters', () => { assert.strictEqual( formatJobUrl({ uuid: '1580bcedd5fafbcf04ee47e918cf25d2', jobTitle: '软件开发人员🤡', company: '谷歌©', }), '/job/%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E4%BA%BA%E5%91%98%F0%9F%A4%A1-%E8%B0%B7%E6%AD%8C%C2%A9-1580bcedd5fafbcf04ee47e918cf25d2', ); assert.strictEqual( formatJobUrl({ uuid: '1580bcedd5fafbcf04ee47e918cf25d2', jobTitle: '🤡सॉफ्टवेयर', company: 'वलपर–गूगल©', }), '/job/%F0%9F%A4%A1%E0%A4%B8%E0%A5%89%E0%A4%AB%E0%A5%8D%E0%A4%9F%E0%A4%B5%E0%A5%87%E0%A4%AF%E0%A4%B0-%E0%A4%B5%E0%A4%B2%E0%A4%AA%E0%A4%B0%E2%80%93%E0%A4%97%E0%A5%82%E0%A4%97%E0%A4%B2%C2%A9-1580bcedd5fafbcf04ee47e918cf25d2', ); assert.strictEqual( formatJobUrl({ uuid: '1580bcedd5fafbcf04ee47e918cf25d2', jobTitle: 'pemaju-perisian🤡', company: 'google©', }),'/job/pemaju-perisian%F0%9F%A4%A1-google%C2%A9-1580bcedd5fafbcf04ee47e918cf25d2'); }); }); }); });