test: setup Mocha and ask-sdk-test suite for Malayalam calendar skill

This commit is contained in:
2026-07-20 21:25:51 +05:30
parent 04f1d7d9d1
commit 1ac9ead1d5
8 changed files with 3518 additions and 79 deletions
+28
View File
@@ -7,3 +7,31 @@
or or
npm test npm test
``` ```
## Info
### Lunar Month
Amanta and Purnimanta are two systems of measuring lunar months.
- Amanta months begin after the new moon and end on the no moon day
- Purnimanta months start after the full moon and end on the full moon day
In Kerala, the Amanta system is followed.
- 1 Chingam (ചിങ്ങം), Aug Sep, New Year, Onam Festival
- 2 Kanni (കന്നി), Sep Oct, Mahanavami, Vijayadashami
- 3 Thulam (തുലാം), Oct Nov, Monsoon retreat (Thulavarsham)
- 4 Vrischikam (വൃശ്ചികം), Nov Dec, Sabarimala Season begins
- 5 Dhanu (ധനു), Dec Jan, Thiruvathira Festival
- 6 Makaram (മകരം), Jan Feb, Makaravilakku
- 7 Kumbham (കുംഭം), Feb Mar, Maha Shivaratri
- 8 Meenam (മീനം), Mar Apr, Temple Festivals (Pooram)
- 9 Medam (മേടം), Apr May, Vishu (Harvest Festival)
- 10 Edavam (ഇടവം), May Jun, Arrival of Monsoon
- 11 Mithunam (മിഥുനം), Jun Jul, Heavy rains
- 12 Karkidakam (കർക്കടകം), Jul Aug, Ramayana Masam, Ayurveda Season
## Reference for Comparison
https://www.drikpanchang.com/malayalam
+3399 -5
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -5,12 +5,17 @@
"main": "src/index.mjs", "main": "src/index.mjs",
"scripts": { "scripts": {
"start": "node src/index.mjs", "start": "node src/index.mjs",
"test": "node tests/test-local.mjs", "test": "mocha \"tests/**/*.spec.mjs\"",
"build": "powershell -ExecutionPolicy Bypass -File ./scripts/build.ps1", "build": "powershell -ExecutionPolicy Bypass -File ./scripts/build.ps1",
"deploy": "powershell -ExecutionPolicy Bypass -File ./scripts/deploy.ps1" "deploy": "powershell -ExecutionPolicy Bypass -File ./scripts/deploy.ps1"
}, },
"dependencies": { "dependencies": {
"ask-sdk-core": "^2.14.0", "ask-sdk-core": "^2.14.0",
"ask-sdk-model": "^1.86.0",
"kollavarsham": "^2.5.4" "kollavarsham": "^2.5.4"
},
"devDependencies": {
"ask-sdk-test": "^2.7.42",
"mocha": "^10.8.2"
} }
} }
+30
View File
@@ -0,0 +1,30 @@
import { Kollavarsham } from 'kollavarsham';
const kollavarsham = new Kollavarsham({
system: 'SuryaSiddhanta',
latitude: 10,
longitude: 76.2
});
/**
* Converts a Gregorian Date object into a Malayalam calendar format.
*
* @param {Date} gregorianDate
* @returns {{ year: number, month: string, day: number, naksatra: string }}
*/
export function getMalayalamDate(gregorianDate) {
const kollavarshamDate = kollavarsham.fromGregorianDate(gregorianDate);
// Safely extract nakshatra name (handles string or object returns safely)
const naksatraName =
kollavarshamDate.naksatraName ||
kollavarshamDate.naksatra?.enMalayalam ||
'';
return {
year: kollavarshamDate.year,
month: kollavarshamDate.masaName ? kollavarshamDate.masaName.trim() : '',
day: kollavarshamDate.date,
naksatra: naksatraName.trim()
};
}
+19 -27
View File
@@ -1,5 +1,5 @@
import Alexa from 'ask-sdk-core'; import Alexa from 'ask-sdk-core';
import { Kollavarsham } from 'kollavarsham'; import { getMalayalamDate } from './calendar.mjs';
// 1. Core Logic: Handles explicit date/star question requests // 1. Core Logic: Handles explicit date/star question requests
const GetMalayalamDateIntentHandler = { const GetMalayalamDateIntentHandler = {
@@ -88,21 +88,12 @@ function getIstDate() {
// Formats into MM/DD/YYYY in IST // Formats into MM/DD/YYYY in IST
const [{ value: month }, , { value: day }, , { value: year }] = formatter.formatToParts(now); const [{ value: month }, , { value: day }, , { value: year }] = formatter.formatToParts(now);
// Create UTC date anchored at noon for that IST date // Create UTC date anchored at 0:00:00 for that IST date
return new Date(Date.UTC(year, month - 1, day, 12, 0, 0)); // Month is 0-indexed in JavaScript Date constructor, so subtract 1.
// Year and date don't need adjustment.
return new Date(Date.UTC(year, month - 1, day, 0, 0, 0));
} }
// Kollavarsham calculation.
function getMalayalamDate(gregorianDate) {
// Initialize Kollavarsham with Surya Siddhanta system
// and default coordinates of Kollarvarsham project documentation.
const kollavarsham = new Kollavarsham({
system: 'SuryaSiddhanta',
latitude: 10,
longitude: 76.2
});
return kollavarsham.fromGregorianDate(gregorianDate);
}
/** /**
* Converts a number to its ordinal string representation (1st, 2nd, 3rd, 4th, etc.) * Converts a number to its ordinal string representation (1st, 2nd, 3rd, 4th, etc.)
@@ -110,28 +101,29 @@ function getMalayalamDate(gregorianDate) {
* @returns {string} - Ordinal string (e.g., "4th") * @returns {string} - Ordinal string (e.g., "4th")
*/ */
function getOrdinalDay(day) { function getOrdinalDay(day) {
const suffixes = ['th', 'st', 'nd', 'rd'];
const remainder = day % 100; const remainder = day % 100;
if (remainder >= 11 && remainder <= 13) return `${day}th`;
// Handles special cases 11th, 12th, 13th const lastDigit = day % 10;
const suffix = (remainder >= 11 && remainder <= 13) if (lastDigit === 1) return `${day}st`;
? 'th' if (lastDigit === 2) return `${day}nd`;
: (suffixes[day % 10] || 'th'); if (lastDigit === 3) return `${day}rd`;
return `${day}${suffix}`; return `${day}th`;
} }
// 3. Central Response Builder // 3. Central Response Builder
function generateCalendarResponse(handlerInput) { function generateCalendarResponse(handlerInput) {
const kollavarshamDate = getMalayalamDate(getIstDate()); const date = getMalayalamDate(getIstDate());
// Property mappings for kollavarsham package: // Property mappings for kollavarsham package:
const dayNum = kollavarshamDate.date; // Numeric date (e.g. 4) const dayNum = date.day; // Numeric date (e.g. 4)
const month = kollavarshamDate.masaName; // Transliterated English month (e.g. "Karkidakam") const month = date.month; // Transliterated English month (e.g. "Karkidakam")
const star = kollavarshamDate.naksatraName; // Transliterated English Nakshatra (e.g. "Uthram") const star = date.naksatra; // Transliterated English Nakshatra (e.g. "Uthram")
const year = kollavarshamDate.year; // Malayalam Year (e.g. 1201) const year = date.year; // Malayalam Year (e.g. 1201)
const speechText = `Today it is the ${getOrdinalDay(dayNum)} of ${month}. Today's nakshatra is ${star}.`; const speechText = `Today is the ${getOrdinalDay(dayNum)} of ${month}. The nakshatra is ${star}.`;
return handlerInput.responseBuilder return handlerInput.responseBuilder
.speak(speechText) .speak(speechText)
+14
View File
@@ -0,0 +1,14 @@
import { getMalayalamDate } from '../src/calendar.mjs';
import assert from 'node:assert';
describe('getMalayalamDate unit test', () => {
it('Conversion of date 2026-01-01 returns correct Malayalam date', () => {
const result = getMalayalamDate(new Date(2026, 0, 1, 0, 0, 0));
assert.deepStrictEqual(result, {
year: 1201,
month: 'Dhanu',
day: 17,
naksatra: 'Rohini'
});
});
});
+21
View File
@@ -0,0 +1,21 @@
import { AlexaTest, LaunchRequestBuilder } from 'ask-sdk-test';
import { handler as skillHandler } from '../src/index.mjs';
const skillSettings = {
appId: 'amzn1.ask.skill.fake-app-id',
userId: 'amzn1.ask.account.fake-user-id',
deviceId: 'amzn1.ask.device.fake-device-id',
locale: 'en-US',
};
const alexaTest = new AlexaTest(skillHandler, skillSettings);
describe('Alexa Malayalam Calendar Skill', () => {
alexaTest.test([
{
request: new LaunchRequestBuilder(skillSettings).build(),
saysLike: 'Today is',
repromptsNothing: true,
},
]);
});
-45
View File
@@ -1,45 +0,0 @@
import { handler } from '../src/index.mjs';
// Mock Alexa LaunchRequest Payload
const mockAlexaLaunchRequest = {
version: '1.0',
session: {
new: true,
sessionId: 'amzn1.echo-sdk-s-session-mock-id',
application: {
applicationId: 'amzn1.ask.skill.53645cde-742f-499e-83d3-07ed537bce39'
},
user: {
userId: 'amzn1.ask.account.mockUser'
}
},
context: {
System: {
application: {
applicationId: 'amzn1.ask.skill.53645cde-742f-499e-83d3-07ed537bce39'
},
user: {
userId: 'amzn1.ask.account.mockUser'
}
}
},
request: {
type: 'LaunchRequest',
requestId: 'amzn1.echo-api.request.mockRequestId',
timestamp: new Date().toISOString(),
locale: 'en-US'
}
};
async function runLocalTest() {
console.log('🚀 Running Alexa Handler Locally...\n');
try {
const response = await handler(mockAlexaLaunchRequest, {});
console.log('✅ Response Received:\n');
console.log(JSON.stringify(response, null, 2));
} catch (error) {
console.error('❌ Error executing handler locally:', error);
}
}
runLocalTest();