diff --git a/resources/assets/src/js/__tests__/admin.test.js b/resources/assets/src/js/__tests__/admin.test.js index a425cbe1..5f9b1358 100644 --- a/resources/assets/src/js/__tests__/admin.test.js +++ b/resources/assets/src/js/__tests__/admin.test.js @@ -548,16 +548,30 @@ describe('tests for "update" module', () => { file_size: 5000 }); }) - .mockImplementationOnce(() => Promise.resolve()); + .mockImplementationOnce(() => Promise.resolve()) + .mockImplementationOnce(() => Promise.resolve({ msg: 'ok' })) + .mockImplementationOnce(() => Promise.reject()) + .mockImplementationOnce(({ beforeSend }) => { + beforeSend && beforeSend(); + return Promise.resolve({ + file_size: 5000 + }); + }) + .mockImplementationOnce(() => Promise.resolve()) + .mockImplementationOnce(() => Promise.resolve({ msg: 'ok' })); const url = jest.fn(path => path); const toastr = { success: jest.fn(), warning: jest.fn() }; const modal = jest.fn(); + const swal = jest.fn() + .mockReturnValueOnce(Promise.resolve()) + .mockReturnValueOnce(Promise.reject()); window.fetch = fetch; window.url = url; window.toastr = toastr; + window.swal = swal; window.showAjaxError = jest.fn(); $.fn.modal = modal; @@ -565,6 +579,8 @@ describe('tests for "update" module', () => {
+ + `; const downloadUpdates = require(modulePath).downloadUpdates; @@ -586,6 +602,38 @@ describe('tests for "update" module', () => { type: 'POST', dataType: 'json' }); + expect($('.modal-title').html().includes('admin.extracting')).toBe(true); + expect($('.modal-body').html().includes('admin.downloadCompleted')).toBe(true); + expect(swal).toBeCalledWith({ type: 'success', html: 'ok' }); + expect(url).toBeCalledWith('/'); + + await downloadUpdates(); + expect(window.showAjaxError).toBeCalled(); + + await downloadUpdates(); + expect(url).toBeCalledWith('/'); + }); + + it('download progress polling', async () => { + const fetch = jest.fn().mockReturnValueOnce(Promise.resolve({ size: 50 })); + const url = jest.fn(path => path); + window.fetch = fetch; + window.url = url; + + document.body.innerHTML = ` +
+
+ `; + + const { progressPolling } = require(modulePath); + await progressPolling(100)(); + expect(fetch).toBeCalledWith({ + url: 'admin/update/download?action=get-file-size', + type: 'GET' + }); + expect($('#imported-progress').html()).toBe('50.00'); + expect($('.progress-bar').css('width')).toBe('50%'); + expect($('.progress-bar').attr('aria-valuenow')).toBe('50.00'); }); it('check for updates', async () => { diff --git a/resources/assets/src/js/__tests__/skinlib.test.js b/resources/assets/src/js/__tests__/skinlib.test.js index 9d48cc19..3c29e767 100644 --- a/resources/assets/src/js/__tests__/skinlib.test.js +++ b/resources/assets/src/js/__tests__/skinlib.test.js @@ -1,6 +1,5 @@ /* eslint no-unused-vars: "off" */ -jest.dontMock('jquery'); const $ = require('jquery'); window.$ = window.jQuery = $; @@ -9,6 +8,30 @@ window.getQueryString = jest.fn((key, defaultValue) => defaultValue); describe('tests for "index" module', () => { const modulePath = '../skinlib/index'; + it('initialize skin library', () => { + const fetch = jest.fn().mockReturnValue(Promise.resolve({ items: [] })); + const url = jest.fn(path => path); + const trans = jest.fn(key => key); + const showAjaxError = jest.fn(); + window.fetch = fetch; + window.url = url; + window.trans = trans; + window.showAjaxError = showAjaxError; + $.fn.jqPaginator = jest.fn(); + const { initSkinlib } = require(modulePath); + + initSkinlib(); + expect(fetch).not.toBeCalled(); + + document.body.innerHTML = ` +
+
+
+ `; + initSkinlib(); + expect(fetch).toBeCalled(); + }); + it('render skin library', () => { const trans = jest.fn(key => key); const url = jest.fn(path => path); @@ -216,12 +239,16 @@ describe('tests for "index" module', () => { it('change page', () => { document.body.innerHTML = ` + `; const { onPageChange } = require(modulePath); onPageChange(1, 'init'); expect($.skinlib.page).toBe(1); - onPageChange(2); + //onPageChange(2); + $('select').trigger('change'); expect($('div').css('display')).not.toBe('none'); expect($.skinlib.page).toBe(2); }); @@ -238,11 +265,65 @@ describe('tests for "index" module', () => { updateFilter.call($('div'), new Event('click')); expect($.skinlib.uploader).toBe(4); }); + + it('change sort type', () => { + const fetch = jest.fn().mockReturnValue(Promise.resolve()); + window.fetch = fetch; + document.body.innerHTML = ` + + `; + + require(modulePath); + $('a').click(); + expect(fetch).toBeCalled(); + expect($.skinlib.sort).toBe('likes'); + }); + + it('search texture', async () => { + const fetch = jest.fn().mockReturnValue(Promise.resolve()); + window.fetch = fetch; + document.body.innerHTML = ` +
+ +
+ `; + + $('#search-form').trigger('submit'); + expect(fetch).toBeCalled(); + expect($.skinlib.keyword).toBe('keyword'); + }); }); describe('tests for "operations" module', () => { const modulePath = '../skinlib/operations'; + it('toggle liked', async () => { + const fetch = jest.fn().mockReturnValue(Promise.resolve()); + const swal = jest.fn().mockReturnValue(Promise.resolve()); + const url = jest.fn(path => path); + window.fetch = fetch; + window.swal = swal; + window.url = url; + document.body.innerHTML = ` + + `; + const { toggleLiked } = require(modulePath); + + await toggleLiked.call($('a')); + expect(fetch).not.toBeCalled(); + + $('a').removeClass('anonymous'); + const originGetJson = $.getJSON; + $.getJSON = jest.fn(); + await toggleLiked.call($('a')); + expect($.getJSON).toBeCalled(); + $.getJSON = originGetJson; + + $('a').addClass('liked'); + await toggleLiked.call($('a')); + expect(fetch).toBeCalled(); + }); + it('add to closet', async () => { const url = jest.fn(path => path); window.url = url; diff --git a/resources/assets/src/js/admin/update.js b/resources/assets/src/js/admin/update.js index 844fce6d..6c7193b3 100644 --- a/resources/assets/src/js/admin/update.js +++ b/resources/assets/src/js/admin/update.js @@ -1,24 +1,22 @@ 'use strict'; -function downloadUpdates() { - var fileSize = 0; - var progress = 0; +async function downloadUpdates() { + console.log('Prepare trno download'); - console.log('Prepare to download'); + try { + const preparation = await fetch({ + url: url('admin/update/download?action=prepare-download'), + type: 'GET', + dataType: 'json', + beforeSend: function() { + $('#update-button').html( + ' ' + trans('admin.preparing') + ).prop('disabled', 'disabled'); + } + }); + console.log(preparation); - fetch({ - url: url('admin/update/download?action=prepare-download'), - type: 'GET', - dataType: 'json', - beforeSend: function() { - $('#update-button').html( - ' ' + trans('admin.preparing') - ).prop('disabled', 'disabled'); - } - }).then(json => { - console.log(json); - - fileSize = json.file_size; + const { file_size: fileSize } = preparation; $('#file-size').html(fileSize); @@ -29,63 +27,65 @@ function downloadUpdates() { console.log('Start downloading'); - fetch({ + // Downloading progress polling + const interval_id = setInterval(progressPolling(fileSize), 300); + + const download = await fetch({ url: url('admin/update/download?action=start-download'), type: 'POST', dataType: 'json' - }).then(json => { - // Set progress to 100 when got the response - progress = 100; + }); - console.log('Downloading finished'); - console.log(json); - }).catch(showAjaxError); + clearInterval(interval_id); - // Downloading progress polling - let interval_id = setInterval(() => { + console.log('Downloading finished'); + console.log(download); + + $('.modal-title').html(' ' + trans('admin.extracting')); + $('.modal-body').append(`

${trans('admin.downloadCompleted')}

`); + + console.log('Start extracting'); + + const extract = await fetch({ + url: url('admin/update/download?action=extract'), + type: 'POST', + dataType: 'json' + }); + + console.log('Package extracted and files are covered'); + $('#modal-start-download').modal('toggle'); + + swal({ + type: 'success', + html: extract.msg + }).then(function () { + window.location = url('/'); + }, function () { + window.location = url('/'); + }); + } catch (error) { + showAjaxError(error); + } +} + +function progressPolling(fileSize) { + return async () => { + try { + const { size } = await fetch({ + url: url('admin/update/download?action=get-file-size'), + type: 'GET' + }); + + const progress = (size / fileSize * 100).toFixed(2); + $('#imported-progress').html(progress); - $('.progress-bar').css('width', progress+'%').attr('aria-valuenow', progress); - - if (progress == 100) { - clearInterval(interval_id); - - $('.modal-title').html(' ' + trans('admin.extracting')); - $('.modal-body').append(`

${ trans('admin.downloadCompleted') }

`); - - console.log('Start extracting'); - - fetch({ - url: url('admin/update/download?action=extract'), - type: 'POST', - dataType: 'json' - }).then(json => { - console.log('Package extracted and files are covered'); - $('#modal-start-download').modal('toggle'); - - swal({ - type: 'success', - html: json.msg - }).then(function() { - window.location = url('/'); - }, function() { - window.location = url('/'); - }); - }).catch(showAjaxError); - - } else { - fetch({ - url: url('admin/update/download?action=get-file-size'), - type: 'GET' - }).then(json => { - progress = (json.size / fileSize * 100).toFixed(2); - - console.log('Progress: ' + progress); - }).catch(showAjaxError); - } - - }, 300); - }).catch(showAjaxError); - + $('.progress-bar') + .css('width', progress + '%') + .attr('aria-valuenow', progress); + } catch (error) { + // No need to show error if failed to get size + } + }; } async function checkForUpdates() { @@ -104,6 +104,7 @@ async function checkForUpdates() { if (typeof require !== 'undefined' && typeof module !== 'undefined') { module.exports = { checkForUpdates, + progressPolling, downloadUpdates, }; } diff --git a/resources/assets/src/js/skinlib/index.js b/resources/assets/src/js/skinlib/index.js index 341cc52d..10db1633 100644 --- a/resources/assets/src/js/skinlib/index.js +++ b/resources/assets/src/js/skinlib/index.js @@ -8,7 +8,31 @@ $.skinlib = { keyword: decodeURI(getQueryString('keyword', '')) }; -$(document).ready(() => { +$(document).ready(initSkinlib); + +$('body').on('change', 'select.pagination', function () { + onPageChange(parseInt($(this).val())); +}); + +$('.filter').click(updateFilter); + +$('body').on('click', '.sort', function (e) { + e.preventDefault(); + $.skinlib.sort = $(this).data('sort'); + + console.log('Sort by ' + $.skinlib.sort); + reloadSkinlib(); +}); + +$('body').on('submit', '#search-form', function (e) { + e.preventDefault(); + $.skinlib.keyword = $('#navbar-search-input').val(); + + console.log('Search keyword: ' + $.skinlib.keyword); + reloadSkinlib(); +}); + +function initSkinlib() { if ($('#skinlib-container').length != 0) { // Initially render skinlib requestSkinlibData().then(result => { @@ -20,29 +44,7 @@ $(document).ready(() => { ); }); } -}); - -$('select.pagination').on('change', function () { - onPageChange(parseInt($(this).val())); -}); - -$('.filter').click(updateFilter); - -$('.sort').click(function (e) { - e.preventDefault(); - $.skinlib.sort = $(this).data('sort'); - - console.log('Sort by ' + $.skinlib.sort); - reloadSkinlib(); -}); - -$('#search-form').submit(function (e) { - e.preventDefault(); - $.skinlib.keyword = $('#navbar-search-input').val(); - - console.log('Search keyword: ' + $.skinlib.keyword); - reloadSkinlib(); -}); +} function renderSkinlib(items) { let container = $('#skinlib-container').html(''); @@ -228,6 +230,7 @@ function updateBreadCrumb() { if (typeof require !== 'undefined' && typeof module !== 'undefined') { module.exports = { + initSkinlib, renderSkinlib, reloadSkinlib, updatePaginator, diff --git a/resources/assets/src/js/skinlib/operations.js b/resources/assets/src/js/skinlib/operations.js index 32b8aa16..4aa41b9e 100644 --- a/resources/assets/src/js/skinlib/operations.js +++ b/resources/assets/src/js/skinlib/operations.js @@ -1,6 +1,8 @@ 'use strict'; -$(document).on('click', '.more.like', function () { +$(document).on('click', '.more.like', toggleLiked); + +function toggleLiked() { let tid = $(this).attr('tid'); if ($(this).hasClass('anonymous')) @@ -11,7 +13,7 @@ $(document).on('click', '.more.like', function () { } else { addToCloset(tid); } -}); +} function addToCloset(tid) { $.getJSON(url(`skinlib/info/${tid}`), async ({ name }) => { @@ -222,6 +224,7 @@ async function deleteTexture(tid) { if (typeof require !== 'undefined' && typeof module !== 'undefined') { module.exports = { + toggleLiked, addToCloset, changePrivacy, deleteTexture, diff --git a/resources/assets/src/js/skinlib/upload.js b/resources/assets/src/js/skinlib/upload.js index 15d92823..9977ba95 100644 --- a/resources/assets/src/js/skinlib/upload.js +++ b/resources/assets/src/js/skinlib/upload.js @@ -1,5 +1,7 @@ /* global MSP */ +// TODO: Help wanted. This file needs to be tested. + 'use strict'; $('body')