Это мое первое использование Jest, и я пытаюсь протестировать функцию со многими многими значениями, такими как:
const convertConfig = require('../tools/convertNumWord/config');
const numToWordConstructor = require('../tools/convertNumWord/num2words/numToWords');
const wordToNumConstructor = require('../tools/convertNumWord/words2num/wordsToNum');
describe('EN-CONFIG', () => {
const config = convertConfig['en']; // It returns an object with configuration values for the language
const numToWord = numToWordConstructor(config); // It return a function builds with config object
const wordToNum = wordToNumConstructor(config);
for (let i = 0; i <= 4; i++) {
it(`Test for value ${i}`, () => {
expect(wordToNum(numToWord(i))).toBe(Number(i));
});
}
});
Jest возвращает эту ошибку:
● ENGLISH CONFIG › Test for value 2
expect(received).toBe(expected) // Object.is equality
Expected: 2
Received: 1
69 | for (let i = 0; i <= 4; i++) {
70 | it(`Test for value ${i}`, () => {
> 71 | expect(wordToNum(numToWord(i))).toBe(Number(i));
| ^
72 | });
73 | }
74 | });
at Object.<anonymous> (__tests__/loopConvertNum.test.js:71:39)
● ENGLISH CONFIG › Test for value 3
expect(received).toBe(expected) // Object.is equality
Expected: 3
Received: 1
69 | for (let i = 0; i <= 4; i++) {
70 | it(`Test for value ${i}`, () => {
> 71 | expect(wordToNum(numToWord(i))).toBe(Number(i));
| ^
72 | });
73 | }
74 | });
at Object.<anonymous> (__tests__/loopConvertNum.test.js:71:39)
● ENGLISH CONFIG › Test for value 4
expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 1
69 | for (let i = 0; i <= 4; i++) {
70 | it(`Test for value ${i}`, () => {
> 71 | expect(wordToNum(numToWord(i))).toBe(Number(i));
| ^
72 | });
73 | }
74 | });
at Object.<anonymous> (__tests__/loopConvertNum.test.js:71:39)
Test Suites: 1 failed, 2 passed, 3 total
Tests: 3 failed, 1 todo, 3 passed, 7 total
Snapshots: 0 total
Time: 1.773s
Ran all test suites.
Мой первый тест работал, но в течение 2 дней Jest, похоже, не выполняет мою функцию для каждого раунда l oop, как если бы он сохранял значение в памяти (часто значение второго раунда l oop) и тест toBe в конечном итоге ложно. В некоторых случаях результат моих функций полностью несовместим (ноль или какое-то приращение от предыдущего результата). Когда я запускаю свою функцию с узлом с теми же аргументами, она работает хорошо.
Я пробовал с ним каждый, и проблема не устранена. Каждый режим мне не подходит, потому что я хочу протестировать свою функцию для многих, многих значений ?.
После вашего отзыва, вот две импортированные функции и константа конфигурации. Но эти функции хорошо работают с аргументами, отправленными в моем l oop. Проблема, похоже, не связана с тем, что возвращает функции, потому что, когда я запускаю их индивидуально с помощью узла, они хорошо работают с теми же аргументами, что и для l oop моего теста Jest.
Это - это функция, импортированная в numToWordConstructor :
const config = require('../config');
const _ = require('lodash');
const numToWordsConstructor = config => {
config = _.cloneDeep(config);
const letters = {
..._.invertBy(config.oneDigits),
..._.invertBy(config.doubleDigits),
..._.invertBy(config.tripleDigits),
};
const hundredWords = config.hundredWords;
const oneDigits = config.oneDigits;
const doubleDigits = config.doubleDigits;
const tripleDigits = config.isEachHundredsWords ? config.tripleDigits : null;
const separators = config.separators;
let words = [];
// Convertion function
const num2Words = number => {
let result = '';
const numbersWords = Object.keys(letters);
const nbString = number.toString();
const nb = parseFloat(nbString.replace(/ /gi, ''));
if (nb > 999999999999)
throw new Error(
'Function numToWords for number',
number,
': Number to big',
);
if (isNaN(nb))
throw new Error(
'Function numToWords for number',
number,
'Not a valid number',
);
if (Math.ceil(nb) != nb) {
separateFloatNumbers = nbString.split('.');
return (
num2Words(separateFloatNumbers[0]) +
' virgule ' +
num2Words(separateFloatNumbers[1])
);
}
if (Number(number) === 0) return oneDigits[0][0];
// Build numByThousand object to split number to 3 digits arrays
let numByThousand = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]];
if (numbersWords.includes(nbString)) {
result = letters[nbString][0];
} else {
const nbReversedDigits = nbString
.split('')
.map(digit => parseInt(digit))
.reverse();
numByThousand = numByThousand
.map(thousand => {
if (nbReversedDigits.length >= 3) {
return (thousand = nbReversedDigits.splice(0, 3).reverse());
} else {
return (thousand = [0, 0, 0]
.map(
defaultDigit =>
nbReversedDigits.splice(0, 1)[0] || defaultDigit,
)
.reverse());
}
})
.reverse();
}
// Build array of words depending of numByThousand
const convertNumByThousandToWords = numByThousand => {
const hundred = numByThousand[0] * 100;
const ten = numByThousand[1] * 10 + numByThousand[2];
const newWords = [];
if (numByThousand[0] > 0) {
if (config.isEachHundredsWords) {
newWords.push(tripleDigits[hundred][0]);
} else if (numByThousand[0] === 1 && !config.isOneBeforeOnlyOne[0]) {
newWords.push(config.hundredWords[0]);
} else {
newWords.push(oneDigits[numByThousand[0]][0]);
newWords.push(config.hundredWords[0]);
}
}
if (ten > 0) {
if (Object.keys(doubleDigits).includes(ten.toString())) {
newWords.push(doubleDigits[ten][0]);
return newWords;
} else {
if (numByThousand[1] > 0)
newWords.push(doubleDigits[numByThousand[1] * 10][0]);
if (numByThousand[2] > 0)
newWords.push(oneDigits[numByThousand[2]][0]);
return newWords;
}
}
return newWords;
};
if (config.noMoreMillionSeparator) separators.push(config.separators[0]);
numByThousand.map((thousand, i) => {
if (thousand.reduce((acc, cur) => acc + cur) > 0) {
words = _.concat(words, convertNumByThousandToWords(thousand));
// Handle thousand separators
separators[config.separators.length - i - 1] &&
words.push(separators[config.separators.length - i - 1][0]);
}
});
//Handle specifics spelling rules
words = config.spellingRules(words, oneDigits, doubleDigits);
// console.log('words : ', words.join(' '));
return words.join(' ');
};
return num2Words;
};
module.exports = numToWordsConstructor;
Это функция, импортированная в wordToNumConstructor :
const _ = require('lodash');
const arrayAwareInvert = obj => {
return _.reduce(
obj,
(result, values, key) => {
return _.reduce(
values,
(result, value) => {
result[value] = key;
return result;
},
result,
);
},
{},
);
};
const word2numConstructor = config => {
config = _.cloneDeep(config);
const separators = config.separators;
const hundredWords = config.hundredWords;
const oneDigits = arrayAwareInvert(config.oneDigits);
const doubleDigits = arrayAwareInvert(config.doubleDigits);
const tripleDigits = config.isEachHundredsWords
? arrayAwareInvert(config.tripleDigits)
: null;
const oneDigitsWords = Object.values(config.oneDigits).reduce(
(acc, cur) => acc.concat(cur),
[],
);
const doubleDigitsWords = Object.values(config.doubleDigits).reduce(
(acc, cur) => acc.concat(cur),
[],
);
const tripleDigitsWords = Object.values(config.tripleDigits).reduce(
(acc, cur) => acc.concat(cur),
[],
);
return stringNumber => {
separators.forEach(thousandSeparators =>
thousandSeparators.forEach(separator => {
// Remove spaces from separator's word in sentence to not split it with split(' ') later
const regex = new RegExp(`${separator}`, 'gi');
stringNumber = stringNumber.replace(
regex,
separator.split(' ').join(''),
);
// Remove spaces from separator's word
return separator.split(' ').join('');
}),
);
let thousandsWords = [];
if (config.noMoreMillionSeparator) {
thousandsWords = separators[0];
} else {
thousandsWords = _.flatten(separators);
}
stringNumber.trim();
// Apply on stringNumber the rules of locale key of config object
stringNumber = config.rulesOnSentence(stringNumber);
// Apply lowerCase on stringNumber and split words at each spaces
let words = stringNumber.toLowerCase().split(' ');
// Apply on each words the rules of locale key of config object
words = config.rulesOnWords(words);
const convertWordsByThousandToNumber = wordsByThousand => {
return wordsByThousand.map(values => {
if (values.length === 0) return 0;
let thousand = null;
let temp;
// Function to handle ten and unit if temp is hundred value
const handleTen_Unit = (i, coef = 100) => {
if (!values[i] || thousandsWords.includes(values[i])) {
thousand = temp * coef;
} else if (oneDigitsWords.includes(values[i])) {
thousand = temp * coef + Number(oneDigits[values[i]]);
} else if (doubleDigitsWords.includes(values[i])) {
if (!values[i + 1] || thousandsWords.includes(values[i + 1])) {
thousand = temp * coef + Number(doubleDigits[values[i]]);
} else if (oneDigitsWords.includes(values[i + 1])) {
thousand =
temp * coef +
Number(doubleDigits[values[i]]) +
Number(oneDigits[values[i + 1]]);
}
}
};
//Convert values
if (values.length === 1 && thousandsWords.includes(values[0])) {
thousand = 1;
} else if (hundredWords.includes(values[0])) {
temp = 1;
handleTen_Unit(1);
} else if (doubleDigitsWords.includes(values[0])) {
temp = Number(doubleDigits[values[0]]);
if (!values[1] || thousandsWords.includes(values[1])) {
thousand = temp;
} else if (oneDigitsWords.includes(values[1])) {
thousand = temp + Number(oneDigits[values[1]]);
}
} else if (oneDigitsWords.includes(values[0])) {
temp = Number(oneDigits[values[0]]);
if (!values[1] || thousandsWords.includes(values[1])) {
thousand = temp;
} else if (hundredWords.includes(values[1])) {
handleTen_Unit(2);
} else {
thousand = temp;
}
} else if (tripleDigitsWords.includes(values[0])) {
temp = Number(tripleDigits[values[0]]);
if (!values[1] || thousandsWords.includes(values[1])) {
thousand = temp;
} else {
handleTen_Unit(1, 1);
}
}
return thousand;
});
};
const buildWordsByThousand = words => {
const wordsByThousand = [];
separators
.slice(0) // Make a shallow copy
.reverse()
.map(thousandSeparators => {
const index = _.findIndex(words, word =>
thousandSeparators.includes(word),
);
index > -1
? wordsByThousand.push(words.splice(0, index + 1))
: wordsByThousand.push([]);
});
wordsByThousand.push(words); // Push the rest of words for hundred's part
return wordsByThousand;
};
let results = [];
let indexOfMillionWords = -1;
words.map((word, i) => {
if (separators[1].includes(word)) indexOfMillionWords = i;
});
if (config.noMoreMillionSeparator && indexOfMillionWords >= 0) {
const wordsAboveMillion = words.splice(indexOfMillionWords + 1);
const wordsOverMillion = words.splice(0, words.length - 1);
const wordsByThousandOverMillion = buildWordsByThousand(
wordsOverMillion,
).splice(1); // Splice is necessary to remove array of million thousand part
const wordsByThousandAboveMillion = buildWordsByThousand(
wordsAboveMillion,
).splice(1); // Splice is necessary to remove array of million thousand part
results = results.concat(
convertWordsByThousandToNumber(wordsByThousandOverMillion),
);
results = results.concat(
convertWordsByThousandToNumber(wordsByThousandAboveMillion),
);
} else {
const wordsByThousand = buildWordsByThousand(words);
results = results.concat(convertWordsByThousandToNumber(wordsByThousand));
}
results;
return results
.reverse()
.reduce(
(acc, cur, i) =>
acc === null || cur === null ? null : acc + cur * Math.pow(1000, i),
0,
);
};
};
module.exports = word2numConstructor;
И вот результат of const config = convertConfig ['en'] :
{
rulesOnSentence: sentence => {
// Write your rules's function to apply on sentence before splitted it
return sentence
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/[\-]/g, ' ')
.replace(/[^a-zA-Z ]/g, '');
},
rulesOnWords: words => {
// Write your rules's function to apply on words array (after to have splitted sentence)
return words.filter(word => word !== 'and');
},
spellingRules: (words, oneDigits, doubleDigits) => {
const unit = _.flatten(Object.values(oneDigits).slice(1));
const ten = _.flatten(
[20, 30, 40, 50, 60, 70, 80, 90].map(num => doubleDigits[num]),
);
const newWords = [...words];
let j = 0;
words.forEach((word, i) => {
// Hyphenate all compound numbers
if (ten.includes(word) && unit.includes(words[i + 1])) {
newWords.splice(i - j, 2, word + '-' + words[i + 1]);
j++;
}
});
return newWords;
},
noMoreMillionSeparator: false,
separators: [
['thousand', 'thousands'],
['million', 'millions'],
['billion', 'billions'],
],
hundredWords: ['hundred', 'hundreds'],
isOneBeforeOnlyOne: [true, true, true, true],
isEachHundredsWords: false,
tripleDigits: {},
oneDigits: {
0: ['zero'],
1: ['one'],
2: ['two'],
3: ['three'],
4: ['four'],
5: ['five'],
6: ['six'],
7: ['seven'],
8: ['eight'],
9: ['nine'],
},
doubleDigits: {
10: ['ten'],
11: ['eleven'],
12: ['twelve'],
13: ['thirteen'],
14: ['fourteen'],
15: ['fifteen'],
16: ['sixteen'],
17: ['seventeen'],
18: ['eighteen'],
19: ['nineteen'],
20: ['twenty'],
30: ['thirty'],
40: ['forty'],
50: ['fifty'],
60: ['sixty'],
70: ['seventy'],
80: ['eighty'],
90: ['ninety'],
},
}
Заранее благодарим вас за ваш ценный отзыв.