diff --git a/lib/sympto/index.js b/lib/sympto/index.js index 3fd0102..b468f36 100644 --- a/lib/sympto/index.js +++ b/lib/sympto/index.js @@ -1,12 +1,19 @@ -import getTemperatureStatus from './temperature' -import getMucusStatus from './mucus' +import getTemperatureShift from './temperature' +import getMucusShift from './mucus' export default function (cycleDays) { - const temperatureStatus = getTemperatureStatus(cycleDays) - const mucusStatus = getMucusStatus(cycleDays) + const assumeFertile = { assumeFertility: true } + + const temperatureShift = getTemperatureShift(cycleDays) + if (!temperatureShift.detected) return assumeFertile + + const tempEvalEndIndex = cycleDays.indexOf(temperatureShift.evaluationCompleteDay) + const mucusShift = getMucusShift(cycleDays, tempEvalEndIndex) + if (!mucusShift.detected) return assumeFertile + return { - assumeFertility: true, - temperatureStatus, - mucusStatus + assumeFertility: false, + temperatureShift, + mucusShift } } \ No newline at end of file diff --git a/lib/sympto/mucus.js b/lib/sympto/mucus.js index 0931ad6..ada8127 100644 --- a/lib/sympto/mucus.js +++ b/lib/sympto/mucus.js @@ -1,13 +1,25 @@ -export default function (cycleDays) { +export default function (cycleDays, tempEvalEndIndex) { const mucusDays = cycleDays.filter(day => day.mucus && !day.mucus.exclude) const bestQuality = Math.max(...mucusDays.map(day => day.mucus.value)) - const mucusPeak = mucusDays.find((day, i) => { - if (day.mucus.value !== bestQuality) return false - const threeFollowingDays = mucusDays.slice(i + 1, i + 4) + const mucusPeak = cycleDays.find((day, i) => { + if (!mucusDays.includes(day) || day.mucus.value !== bestQuality) return false + + // sensiplan says the three following days must be of lower quality + // AND no best quality day may occur until temperature evaluation has + // been completed + const mucusDaysIndex = mucusDays.indexOf(day) + const threeFollowingDays = mucusDays.slice(mucusDaysIndex + 1, mucusDaysIndex + 4) if (threeFollowingDays.length < 3) return false - return threeFollowingDays.every(day => day.mucus.value < bestQuality) + const bestQualityOccurringIn3FollowingDays = threeFollowingDays.some(day => day.mucus.value >= bestQuality) + if (bestQualityOccurringIn3FollowingDays) return false + + const relevantDays = cycleDays + .slice(i + 1, tempEvalEndIndex + 1) + .filter(day => day.mucus && !day.mucus.exclude) + + return relevantDays.every(day => day.mucus.value < bestQuality) }) if (!mucusPeak) return { detected: false } @@ -17,3 +29,4 @@ export default function (cycleDays) { mucusPeak } } + diff --git a/lib/sympto/temperature.js b/lib/sympto/temperature.js index 4779bc0..af90282 100644 --- a/lib/sympto/temperature.js +++ b/lib/sympto/temperature.js @@ -1,4 +1,4 @@ -export default function getTemperatureStatus(cycleDays) { +export default function (cycleDays) { const temperatureDays = cycleDays .filter(day => day.temperature && !day.temperature.exclude) .map(day => { diff --git a/test/sympto/index.spec.js b/test/sympto/index.spec.js new file mode 100644 index 0000000..bbea1ae --- /dev/null +++ b/test/sympto/index.spec.js @@ -0,0 +1,77 @@ +import chai from 'chai' +import getSensiplanStatus from '../../lib/sympto' + +const expect = chai.expect + +function convertToSymptoFormat(val, i) { + return { + date: i, + temperature: val.temperature ? { value: val.temperature } : null, + mucus: val.mucus ? { value: val.mucus } : null + } +} + +describe('sympto', () => { + describe('evaluating mucus and temperature shift together', () => { + it('reports fertile when mucus reaches best quality again within temperature evaluation phase', function () { + const values = [ + { temperature: 36.6 }, + { temperature: 36.65 }, + { temperature: 36.5 }, + { temperature: 36.6 }, + { temperature: 36.55 }, + { temperature: 36.7, mucus: 0 }, + { temperature: 36.75, mucus: 0 }, + { temperature: 36.45, mucus: 1 }, + { temperature: 36.5, mucus: 4 }, + { temperature: 36.4, mucus: 2 }, + { temperature: 36.5, mucus: 3 }, + { temperature: 36.55, mucus: 3 }, + { temperature: 36.45, mucus: 3 }, + { temperature: 36.5, mucus: 4 }, + { temperature: 36.55, mucus: 4 }, + { temperature: 36.7, mucus: 3 }, + { temperature: 36.65, mucus: 3 }, + { temperature: 36.75, mucus: 4 }, + { temperature: 36.8, mucus: 1 }, + { temperature: 36.85, mucus: 2 }, + { temperature: 36.8, mucus: 2 }, + { temperature: 36.9, mucus: 2 }, + { temperature: 36.9, mucus: 1 }, + { temperature: 36.85, mucus: 1 }, + { temperature: 36.9, mucus: 1 }, + { temperature: 36.8, mucus: 1 }, + { temperature: 36.9, mucus: 1 } + ] + + const temperatures = values.map(convertToSymptoFormat) + const status = getSensiplanStatus(temperatures) + expect(status).to.eql({ + assumeFertility: false, + temperatureShift: { + detected: true, + ltl: 36.55, + rule: 0, + firstHighMeasurementDay: { + date: 15, + temperature: { value: 36.7 }, + mucus: { value: 3 } + }, + evaluationCompleteDay: { + date: 17, + temperature: { value: 36.75 }, + mucus: { value: 4 } + } + }, + mucusShift: { + detected: true, + mucusPeak: { + date: 17, + mucus: { value: 4 }, + temperature: { value: 36.75 } + } + } + }) + }) + }) +}) \ No newline at end of file diff --git a/test/sympto/mucus.spec.js b/test/sympto/mucus.spec.js index c0fd2da..7e9b704 100644 --- a/test/sympto/mucus.spec.js +++ b/test/sympto/mucus.spec.js @@ -16,7 +16,7 @@ describe('sympto', () => { it('detects mucus shift correctly', function () { const values = [0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0] .map(turnIntoCycleDayObject) - const status = getMucusStatus(values) + const status = getMucusStatus(values, 30) expect(status).to.eql({ detected: true, mucusPeak: { @@ -29,7 +29,7 @@ describe('sympto', () => { it('detects no mucus shift when there are less than 3 days of lower quality', function () { const values = [0, 1, 1, 2, 0, 0, 1, 2, 3, 2, 3, 3, 3, 2, 2] .map(turnIntoCycleDayObject) - const status = getMucusStatus(values) + const status = getMucusStatus(values, 30) expect(status).to.eql({ detected: false }) }) @@ -41,7 +41,7 @@ describe('sympto', () => { it('detects no mucus shift when the mucus values are all the same', function () { const values = [2, 2, 2, 2, 2, 2, 2, 2] .map(turnIntoCycleDayObject) - const status = getMucusStatus(values) + const status = getMucusStatus(values, 30) expect(status).to.eql({ detected: false }) }) })