Add more tests

This commit is contained in:
Pig Fang 2018-09-07 23:58:00 +08:00
parent 544b30c830
commit 47207476ff
6 changed files with 151 additions and 9 deletions

View File

@ -107,9 +107,8 @@
"setupTestFrameworkScriptFile": "<rootDir>/resources/assets/tests/setup.js",
"coveragePathIgnorePatterns": [
"/node_modules/",
"setup",
"utils",
"assets/src/js"
"<rootDir>/resources/assets/tests/setup",
"<rootDir>/resources/assets/tests/utils"
],
"testRegex": "resources/assets/tests/.*\\.(spec|test)\\.js"
},

View File

@ -1,9 +1,8 @@
import Vue from 'vue';
import { emit } from './event';
import { queryStringify } from './utils';
import { showAjaxError } from './notify';
const csrfField = document.querySelector('meta[name="csrf-token"]');
const empty = Object.create(null);
/** @type Request */
export const init = {
@ -11,11 +10,19 @@ export const init = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfField && csrfField.content
}
};
function retrieveToken() {
const csrfField = document.querySelector('meta[name="csrf-token"]');
return csrfField && csrfField.content;
}
export async function walkFetch(request) {
request.headers['X-CSRF-TOKEN'] = retrieveToken();
emit('beforeFetch', request);
try {
const response = await fetch(request);
if (response.ok) {

View File

@ -11,7 +11,7 @@ import { trans } from './i18n';
* @return {void}
*/
export function showMsg(msg, type = 'info') {
$('[id=msg]')
$('#msg')
.removeClass()
.addClass('callout')
.addClass(`callout-${type}`)
@ -30,7 +30,7 @@ export function showAjaxError(error) {
}
const message = typeof error === 'string' ? error : error.message;
showModal(message.replace(/\n/g, '<br />'), trans('general.fatalError'), 'danger');
showModal(message.replace(/\n/g, '<br>'), trans('general.fatalError'), 'danger');
}
/**
@ -68,7 +68,7 @@ export function showModal(msg, title = 'Message', type = 'default', options = {}
</div>
</div>`;
$(dom).on('hidden.bs.modal', function () {
$(dom).on('hidden.bs.modal', /* istanbul ignore next */ function () {
destroyOnClose && $(this).remove();
}).modal(options);
}

View File

@ -0,0 +1,78 @@
import * as net from '@/js/net';
import { on } from '@/js/event';
import { showAjaxError } from '@/js/notify';
jest.mock('@/js/notify');
test('the GET method', async () => {
const json = jest.fn().mockResolvedValue({});
window.fetch = jest.fn().mockResolvedValue({
ok: true,
json
});
window.Request = jest.fn(function (url, init) {
this.url = url;
Object.keys(init).forEach(key => this[key] = init[key]);
});
await net.get('/abc', { a: 'b' });
expect(window.fetch.mock.calls[0][0].url).toBe('/abc?a=b');
expect(json).toBeCalled();
await net.get('/abc');
expect(window.fetch.mock.calls[1][0].url).toBe('/abc');
});
test('the POST method', async () => {
window.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({})
});
window.Request = jest.fn(function (url, init) {
this.url = url;
Object.keys(init).forEach(key => this[key] = init[key]);
});
const meta = document.createElement('meta');
meta.name = 'csrf-token';
meta.content = 'token';
document.head.appendChild(meta);
await net.post('/abc', { a: 'b' });
const request = window.fetch.mock.calls[0][0];
expect(request.url).toBe('/abc');
expect(request.method).toBe('POST');
expect(request.body).toBe(JSON.stringify({ a: 'b' }));
expect(request.headers['X-CSRF-TOKEN']).toBe('token');
await net.post('/abc');
expect(window.fetch.mock.calls[1][0].body).toBe('{}');
});
test('low level fetch', async () => {
const json = jest.fn().mockResolvedValue({});
window.fetch = jest.fn()
.mockRejectedValueOnce(new Error)
.mockResolvedValueOnce({
ok: false,
text: () => Promise.resolve('404')
})
.mockResolvedValueOnce({
ok: true,
json
});
const stub = jest.fn();
on('beforeFetch', stub);
const request = { headers: {} };
await net.walkFetch(request);
expect(showAjaxError.mock.calls[0][0]).toBeInstanceOf(Error);
expect(stub).toBeCalledWith(request);
await net.walkFetch(request);
expect(showAjaxError).toBeCalledWith('404');
await net.walkFetch(request);
expect(json).toBeCalled();
});

View File

@ -0,0 +1,35 @@
import $ from 'jquery';
import * as notify from '@/js/notify';
test('show message', () => {
document.body.innerHTML = '<div id=msg class="callout-x"></div>';
notify.showMsg('hi');
const element = $('#msg');
expect(element.hasClass('callout')).toBeTrue();
expect(element.hasClass('callout-info')).toBeTrue();
expect(element.html()).toBe('hi');
});
test('show AJAX error', () => {
notify.showAjaxError(); // Can be no arguments
$.fn.modal = function () {
document.body.innerHTML = this.html();
};
notify.showAjaxError('error\nerror');
expect(document.body.innerHTML).toContain('error<br>error');
notify.showAjaxError(new Error('an-error'));
expect(document.body.innerHTML).toContain('an-error');
});
test('show modal', () => {
notify.showModal('message');
expect($('.modal-title').html()).toBe('Message');
notify.showModal('message', '', 'default', {
callback: () => undefined,
destroyOnClose: false
});
});

View File

@ -0,0 +1,23 @@
import * as utils from '@/js/utils';
test('debounce', () => {
const stub = jest.fn();
const debounced = utils.debounce(stub, 2000);
debounced();
debounced();
expect(stub).not.toBeCalled();
jest.runAllTimers();
expect(stub).toBeCalledTimes(1);
});
test('queryString', () => {
history.pushState({}, 'page', 'about:blank?key=value');
expect(utils.queryString('key')).toBe('value');
expect(utils.queryString('a')).toBeUndefined();
expect(utils.queryString('a', 'b')).toBe('b');
});
test('queryStringify', () => {
expect(utils.queryStringify({ a: 'b', c: 'd' })).toBe('a=b&c=d');
});