我正在为浏览器开发WebExtension,并且我想启动TDD。通常,没有测试客户端JS经验的人只是谷歌搜索一个流行的框架并坚持使用它-即使不尝试在纯JS中测试功能。我不喜欢依赖项-仅当我了解它可以解决什么问题时才使用任何东西,我喜欢简单性。目前,我不知道为什么需要任何Javascript单元测试框架。现在,我看到了流行的https://mochajs.org,看不到使用它的原因。
现在我的代码如下:
function unitTests() { // eslint-disable-line no-unused-vars
(function _prepareRemoving_test() {
(function _setUp() {
_testUtils._fillDB();
})();
(async function _isUnique() {
const {itemFeed, isUniqueForUser} = await _prepareRemoving(_testUtils['id']);
console.assert(itemFeed['hashArticle'] === _testUtils['val']['hashArticle'], itemFeed);
console.assert(isUniqueForUser === true, isUniqueForUser);
})();
_testUtils._addArticleWithDuplicatedHash();
(async function _isNotUniqueWhenPreviousWithTheSameHash() {
const {itemFeed, isUniqueForUser} = await _prepareRemoving(_testUtils['id3']);
console.assert(itemFeed['hashArticle'] === _testUtils['val3']['hashArticle'], itemFeed);
console.assert(isUniqueForUser === false, isUniqueForUser);
})();
(async function _isNotUniqueWhenNextWithTheSameHash() {
const {itemFeed, isUniqueForUser} = await _prepareRemoving(_testUtils['id2']);
console.assert(itemFeed['hashArticle'] === _testUtils['val2']['hashArticle'], itemFeed);
console.assert(isUniqueForUser === false, isUniqueForUser);
})();
(function _tearDown() {
_testUtils._clearDB();
})();
})();
(function _syncHistory_test() {
// ===== setup =====
const fetchOriginal = window.fetch;
const chromeOriginal = window.chrome;
// ===== end of setup =====
(function _added() {
(function _mock() {
window.fetch = function() {
_testUtils._mock(fetch, arguments);
return fetchOriginal('unitTests/_syncHistory/mockResponses/added.json');
};
window._getArticle = function() {
_testUtils._mock(_getArticle, arguments);
return Promise.resolve();
};
window._persistItemFeed = function() {
_testUtils._mock(_persistItemFeed, arguments);
};
chrome.runtime.sendMessage = function() {
_testUtils._mock(chrome.runtime.sendMessage, arguments);
};
chrome.storage.sync.set = function() {
_testUtils._mock(chrome.storage.sync.set, arguments);
};
})();
_syncHistory(0, 'myFakeIdToken');
console.assert(fetch['hasCalls'].length === 1);
console.assert(fetch['hasCalls'][0][0] === `${stageUrlNew}history?updated=0`);
console.assert(
fetch['hasCalls'][0][1]['headers']['Authorization'] = 'myFakeIdToken'
);
setTimeout(_ => { // setTimeout for waiting all callbacks from fetch()
console.assert(_getArticle['hasCalls'].length === 1);
console.assert(_getArticle['hasCalls'][0][0] === 1537886629);
console.assert(
_persistItemFeed['hasCalls'][0][0] === '1537886629'
);
console.assert(
_persistItemFeed['hasCalls'][0][1] === 'https://example.com/favicon.ico'
);
console.assert(
_persistItemFeed['hasCalls'][0][2] === 'https://example.com/my-article'
);
console.assert(
_persistItemFeed['hasCalls'][0][3] === 'The title of article'
);
console.assert(
_persistItemFeed['hasCalls'][0][4] === false
);
console.assert(
_persistItemFeed['hasCalls'][0][5] === true
);
console.assert(
_persistItemFeed['hasCalls'][0][6] === false
);
console.assert(
_persistItemFeed['hasCalls'][0][7] === '75042f43e7ba2228934f75d96a02f7a1'
);
console.assert(
_persistItemFeed['hasCalls'][0][8] === 1
);
console.assert(chrome.runtime.sendMessage['hasCalls'].length === 1);
console.assert(
chrome.runtime.sendMessage['hasCalls'][0][0]['fromPopup'] === '_cacheSynced'
);
console.assert(
chrome.runtime.sendMessage['hasCalls'][0][0]['hashArticle'] ===
'75042f43e7ba2228934f75d96a02f7a1'
);
console.assert(
chrome.runtime.sendMessage['hasCalls'][0][0]['id'] === '1537886629'
);
console.assert(
chrome.runtime.sendMessage['hasCalls'][0][0]['lenChunks'] === '1'
);
console.assert(
chrome.runtime.sendMessage['hasCalls'][0][0]['idToken'] === 'myFakeIdToken'
);
console.assert(
chrome.storage.sync.set['hasCalls'].length === 1
);
console.assert(
typeof chrome.storage.sync.set['hasCalls'][0][0]['updated'] === 'number'
);
console.assert(
Number.isInteger(chrome.storage.sync.set['hasCalls'][0][0]['updated'])
);
console.assert(
(chrome.storage.sync.set['hasCalls'][0][0]['updated'] + '').length === 10
);
_syncHistory(1537886629, 'myFakeIdToken');
console.assert(fetch['hasCalls'].length === 2);
console.assert(
fetch['hasCalls'][1][0] === `${stageUrlNew}history?updated=1537886629`
);
console.assert(
fetch['hasCalls'][1][1]['headers']['Authorization'] = 'myFakeIdToken'
);
(function _tearDown() {
window.fetch = fetchOriginal;
window.chrome = chromeOriginal;
})();
}, 100);
})();
}
我的助手功能:
const _testUtils = { // eslint-disable-line no-unused-vars
id: 1000000,
id1: 1111111,
id2: 2222222,
id3: 3333333,
val: {'hashArticle': '75042f43e7ba2228934f75d96a02f7a0', 'cache': [new Blob(), new Blob()]},
val1: {'hashArticle': '75042f43e7ba2228934f75d96a02f7a1', 'cache': [new Blob(), new Blob()]},
val2: {'hashArticle': '75042f43e7ba2228934f75d96a02f7a2', 'cache': [new Blob(), new Blob()]},
val3: {'hashArticle': '75042f43e7ba2228934f75d96a02f7a2', 'cache': [new Blob(), new Blob()]},
_fillDB: function() {
return Promise.all([
_insertOrReplace(this.id, this.val),
_insertOrReplace(this.id1, this.val1),
_insertOrReplace(this.id2, this.val2)
]);
},
_addArticleWithDuplicatedHash: function() {
_insertOrReplace(this.id3, this.val3);
},
_clearDB: function() {
_deleteArticle(this.id);
_deleteArticle(this.id1);
_deleteArticle(this.id2);
_deleteArticle(this.id3);
},
_hasCallsify: function(obj) {
if (!obj['hasCalls']) {
obj['hasCalls'] = [];
}
},
_mock: function(obj, _arguments) {
this._hasCallsify(obj);
obj['hasCalls'].push(_arguments);
}
};