Improving cervix:

* adding tempEvalEnd value to cervix tests
* more comments in code for cervix sympto
* better description in cervix temp tests
* take out cervix.value
This commit is contained in:
emelko
2018-09-13 09:54:13 +02:00
parent 3f5c86086d
commit 76056e1db0
5 changed files with 141 additions and 56 deletions
+18 -7
View File
@@ -1,15 +1,26 @@
export default function (cycleDays, tempEvalEndIndex) {
const cervixDays = cycleDays.filter(day => day.cervix && !day.cervix.exclude)
const notDetected = { detected: false }
const cervixDays = cycleDays
.filter(day => day.cervix && !day.cervix.exclude)
.filter(day => typeof day.cervix.opening === 'number' && typeof day.cervix.firmness === 'number')
// we search for the day of cervix peak, which must:
// * have fertile cervix values
// * be followed by at least 3 days
// these 3 following days must all show infertile cervix values
// if everything applies we must check the days until the end of temperature evaluation
// during these relevantDays no fertile cervix must occur
for (let i = 0; i < cervixDays.length; i++) {
const day = cervixDays[i]
if (isClosedAndHard(day.cervix)) continue
// the three following days must be with closed and hard cervix
// AND no other cervix value may occur until temperature evaluation has
// been completed
// the three following days must be with closed and hard cervix (indicating an infertile cervix)
const threeFollowingDays = cervixDays.slice(i + 1, i + 4)
if (threeFollowingDays.length < 3) continue
// no other fertile cervix value may occur until temperature evaluation has
// been completed
const fertileCervixOccursIn3FollowingDays = threeFollowingDays.some(day => {
return !isClosedAndHard(day.cervix)
})
@@ -33,9 +44,9 @@ export default function (cycleDays, tempEvalEndIndex) {
}
}
return { detected: false }
return notDetected
}
function isClosedAndHard (cervix) {
return cervix.value.opening === 0 && cervix.value.firmness === 0
function isClosedAndHard (cervixDay) {
return cervixDay.opening === 0 && cervixDay.firmness === 0
}
+4 -4
View File
@@ -115,10 +115,10 @@ function throwIfArgsAreNotInRequiredFormat(cycles) {
if (day.mucus) assert.equal(typeof day.mucus.value, 'number', "Mucus value must be a number.")
if (day.mucus) assert.ok(day.mucus.value >= 0, "Mucus value must greater or equal to 0.")
if (day.mucus) assert.ok(day.mucus.value <= 4, "Mucus value must be below 5.")
if (day.cervix) assert.ok(day.cervix.value.opening >= 0, "Cervix opening value must be 0 or bigger")
if (day.cervix) assert.ok(day.cervix.value.opening <= 2, "Cervix opening value must be 2 or smaller")
if (day.cervix) assert.ok(day.cervix.value.firmness >= 0, "Cervix firmness value must be 0 or bigger")
if (day.cervix) assert.ok(day.cervix.value.firmness <= 1, "Cervix firmness value must be 1 or smaller")
if (day.cervix) assert.ok(day.cervix.opening >= 0, "Cervix opening value must be 0 or bigger")
if (day.cervix) assert.ok(day.cervix.opening <= 2, "Cervix opening value must be 2 or smaller")
if (day.cervix) assert.ok(day.cervix.firmness >= 0, "Cervix firmness value must be 0 or bigger")
if (day.cervix) assert.ok(day.cervix.firmness <= 1, "Cervix firmness value must be 1 or smaller")
assert.equal(typeof cycle[0].bleeding.value, 'number', "Bleeding value must be a number")
})
})
+5 -3
View File
@@ -4,8 +4,10 @@ function convertToSymptoFormat(val) {
value: val.temperature,
exclude: false
}
if (val.cervix) sympto.cervix = {
value: val.cervix,
if (val.cervix && typeof val.cervix.opening === 'number' && typeof val.cervix.firmness === 'number') sympto.cervix = {
opening: val.cervix.opening,
firmness: val.cervix.firmness,
exclude: false
}
if (val.bleeding) sympto.bleeding = {
@@ -130,7 +132,7 @@ export const tempShift3DaysAfterCervixShift = [
{ date: '2018-05-20', temperature: 36.7, cervix: { opening: 0, firmness: 0 } },
{ date: '2018-05-21', temperature: 36.6, cervix: { opening: 0, firmness: 0 } },
{ date: '2018-05-22', temperature: 36.85, cervix: { opening: 0, firmness: 0 } },
{ date: '2018-05-23', temperature: 36.8, cervix: { opening: 0, firmness: 0 } },
{ date: '2018-05-23', temperature: 36.8, cervix: { opening: 1, firmness: 0 } },
{ date: '2018-05-24', temperature: 36.85, cervix: { opening: 0, firmness: 0 } },
{ date: '2018-05-25', temperature: 36.95, cervix: { opening: 0, firmness: 0 } },
{ date: '2018-05-26', temperature: 36.85, cervix: { opening: 0, firmness: 1 } },
+7 -8
View File
@@ -48,10 +48,9 @@ describe('sympto', () => {
}
})
})
it('with temp and cervix shifts detects only peri- and post-ovulatory phases', () => {
it('with temp and cervix shifts at the same day an no previous cycle detects only peri- and post-ovulatory phases', () => {
const status = getSensiplanStatus({
cycle: cervixShiftAndFhmOnSameDay,
previousCycle: cycleWithoutFhm,
secondarySymptom: 'cervix'
})
expect(Object.keys(status.phases).length).to.eql(2)
@@ -72,7 +71,7 @@ describe('sympto', () => {
})
})
describe('with previous higher temp measurement', () => {
it('with no shifts detects only peri-ovulatory in 5-day long cycle according to 5-day rule', () => {
it('with no shifts in 5-day long cycle detects only peri-ovulatory according to 5-day rule', () => {
const status = getSensiplanStatus({
cycle: fiveDayCycle,
previousCycle: cervixShiftAndFhmOnSameDay,
@@ -85,7 +84,7 @@ describe('sympto', () => {
end: { date: '2018-08-05' }
})
})
it('with no shifts detects pre- and peri-ovulatory phase according to 5-day-rule', () => {
it('with no shifts in long cycle detects pre- and peri-ovulatory phase according to 5-day-rule', () => {
const status = getSensiplanStatus({
cycle: longCycleWithoutAnyShifts,
previousCycle: cervixShiftAndFhmOnSameDay,
@@ -105,7 +104,7 @@ describe('sympto', () => {
start: { date: '2018-07-06' }
})
})
it('with evaluation of temperature and cervix end on same day', () => {
it('with temperature and cervix evaluation end on same day detects all 3 phases', () => {
const status = getSensiplanStatus({
cycle: cervixShiftAndFhmOnSameDay,
previousCycle: cervixShiftAndFhmOnSameDay,
@@ -135,7 +134,7 @@ describe('sympto', () => {
.filter(({date}) => date >= '2018-08-15')
})
})
it('when temperature shift happens 3 days after cervix shift', () => {
it('with temperature shift 3 days after cervix shift detects all 3 phases', () => {
const status = getSensiplanStatus({
cycle: tempShift3DaysAfterCervixShift,
previousCycle: cervixShiftAndFhmOnSameDay,
@@ -167,7 +166,7 @@ describe('sympto', () => {
.filter(({date}) => date >= '2018-05-21')
})
})
it('when cervix shift happens 2 days after temperature shift', () => {
it('with cervix shift 2 days after temperature shift detects all 3 phases', () => {
const status = getSensiplanStatus({
cycle: cervixShift2DaysAfterTempShift,
previousCycle: cervixShiftAndFhmOnSameDay,
@@ -198,7 +197,7 @@ describe('sympto', () => {
start: { date: '2018-04-19', time: '18:00' }
})
})
it('when no infertile phase can be detected', () => {
it('with no shifts no ovulation is found detects only pre and peri-ovulatory phase', () => {
const status = getSensiplanStatus({
cycle: noOvulationDetected,
previousCycle: cervixShiftAndFhmOnSameDay,
+107 -34
View File
@@ -5,87 +5,160 @@ const expect = chai.expect
function turnIntoCycleDayObject(value, fakeDate) {
const hardAndClosed = {
value: { opening: 0, firmness: 0 }
opening: 0,
firmness: 0
}
const hardAndOpen = {
value: { opening: 1, firmness: 0 }
opening: 1,
firmness: 0
}
const softAndClosed = {
value: { opening: 0, firmness: 1 }
opening: 0,
firmness: 1
}
const softAndOpen = {
value: { opening: 1, firmness: 1 }
opening: 1,
firmness: 1
}
const cervixStates = [hardAndClosed, hardAndOpen, softAndClosed, softAndOpen]
return {
date: fakeDate,
cervix: cervixStates[value],
exclude: false
cervix: {
opening: cervixStates[value].opening,
firmness: cervixStates[value].firmness,
exclude: false
}
}
}
describe('sympto', () => {
describe('detects cervix shift', () => {
it('when shift happens at day 15 with consistent following days', function () {
const values = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 1, 3, 1, 0, 0, 0, 0]
it('when shift happens at day 13 with consistent following days of infertile cervix until tempEvalEnd', () => {
const values = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values)
const status = getCervixStatus(values, 16)
expect(status).to.eql({
detected: true,
cervixPeakBeforeShift: {
date: 13,
cervix: {value: { opening: 1, firmness: 0 }},
exclude: false
date: 10,
cervix: {
opening: 1,
firmness: 1,
exclude: false
}
},
evaluationCompleteDay: {
date: 16,
cervix: { value: { opening: 0, firmness: 0 }},
exclude: false
date: 13,
cervix: {
opening: 0,
firmness: 0,
exclude: false
}
}
})
})
it('at the very first day of cycle days even if later shift happens again', function () {
it('right at the start of cycle days even if later shift happens again because tempEvalEnd happened before second potential shift', () => {
const values = [2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values)
const status = getCervixStatus(values, 5)
expect(status).to.eql({
detected: true,
cervixPeakBeforeShift: {
date: 0,
cervix: { value: { opening: 0, firmness: 1 } },
exclude: false
cervix: {
opening: 0,
firmness: 1,
exclude: false
},
},
evaluationCompleteDay: {
date: 3,
cervix: { value: { opening: 0, firmness: 0 } },
exclude: false
cervix: {
opening: 0,
firmness: 0,
exclude: false
}
}
})
})
it('at day 6 although right at the start of cycle days a potential shift happened but because tempEvalEnd happens after second shift', () => {
const values = [2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values, 10)
expect(status).to.eql({
detected: true,
cervixPeakBeforeShift: {
date: 6,
cervix: {
opening: 1,
firmness: 0,
exclude: false
},
},
evaluationCompleteDay: {
date: 9,
cervix: {
opening: 0,
firmness: 0,
exclude: false
}
}
})
})
it('when the cervix shift is happening after tempEvalEnd', () => {
const values = [1,1,1,1,1,2,3,3,3,3,1,1,1,1,0,0,0,0,0,0,0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values, 10)
expect(status).to.eql({
detected: true,
cervixPeakBeforeShift: {
date: 13,
cervix: {
opening: 1,
firmness: 0,
exclude: false
}
},
evaluationCompleteDay: {
date: 16,
cervix: {
opening: 0,
firmness: 0,
exclude: false
}
}
})
})
})
describe('detects no cervix shift', () => {
it('if there are less than 3 days closed and hard cervix', function () {
const values = [0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 1, 1, 1, 0, 0, 2, 0]
it('if there are less than 3 days closed and hard cervix', () => {
const values = [0, 0, 0, 1, 1, 1, 2, 0, 3, 3, 3, 1, 1, 1, 0, 0, 2, 0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values)
const status = getCervixStatus(values, 15)
expect(status).to.eql({ detected: false })
})
it('if there are no cervix values', function () {
const values = [].map(turnIntoCycleDayObject)
const status = getCervixStatus(values)
expect(status).to.eql({ detected: false })
})
it('when the cervix values are all the same', function () {
const values = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
it('if cycleDays have not enough cervix values to detect valid cervix shift', () => {
const values = [2,0,0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values)
const status = getCervixStatus(values, 17)
expect(status).to.eql({ detected: false })
})
it('if no days of hard and closed cervix are tracked', function () {
it('if no days indicate fertile cervix which could be cervix peak', () => {
const values = [1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values)
const status = getCervixStatus(values, 12)
expect(status).to.eql({ detected: false })
})
it('if all days indicate infertile cervix values', () => {
const values = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
.map(turnIntoCycleDayObject)
const status = getCervixStatus(values, 9)
expect(status).to.eql({ detected: false })
})
it('if there are no cervix values', () => {
const values = [].map(turnIntoCycleDayObject)
const status = getCervixStatus(values, 15)
expect(status).to.eql({ detected: false })
})
})