Replace Element "Message" with Bootstrap "Alert"

This commit is contained in:
Pig Fang 2019-12-01 17:52:30 +08:00
parent beec114717
commit 264369699a
46 changed files with 376 additions and 169 deletions

View File

@ -27,6 +27,7 @@
<script>
import Modal from './Modal.vue'
import { toast } from '../scripts/notify'
export default {
name: 'AddPlayerDialog',
@ -47,10 +48,10 @@ export default {
{ name: this.name },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
this.$emit('add')
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -40,6 +40,7 @@
<script>
import $ from 'jquery'
import Modal from './Modal.vue'
import { toast } from '../scripts/notify'
export default {
name: 'ApplyToPlayerDialog',
@ -66,11 +67,13 @@ export default {
},
async submit() {
if (!this.selected) {
return this.$message.info(this.$t('user.emptySelectedPlayer'))
toast.info(this.$t('user.emptySelectedPlayer'))
return
}
if (!this.skin && !this.cape) {
return this.$message.info(this.$t('user.emptySelectedTexture'))
toast.info(this.$t('user.emptySelectedTexture'))
return
}
const { code, message } = await this.$http.post(
@ -81,10 +84,10 @@ export default {
},
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
$('#modal-use-as').modal('hide')
} else {
this.$message.warning(message)
toast.error(message)
}
},
avatarUrl(player) {

View File

@ -43,7 +43,7 @@
<script>
import setAsAvatar from './mixins/setAsAvatar'
import removeClosetItem from './mixins/removeClosetItem'
import { showModal } from '../scripts/notify'
import { showModal, toast } from '../scripts/notify'
import { truthy } from '../scripts/validators'
export default {
@ -102,9 +102,9 @@ export default {
)
if (code === 0) {
this.textureName = newTextureName
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -15,6 +15,8 @@
</template>
<script>
import { toast } from '../scripts/notify'
export default {
name: 'EmailVerification',
data() {
@ -28,9 +30,9 @@ export default {
this.pending = true
const { code, message } = await this.$http.post('/user/email-verification')
if (code === 0) {
this.$message.success(message)
toast.success(message)
} else {
this.$message.error(message)
toast.error(message)
}
this.pending = false
},

View File

@ -1,5 +1,5 @@
import Vue from 'vue'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
import { truthy } from '../../scripts/validators'
export default Vue.extend<{
@ -26,10 +26,10 @@ export default Vue.extend<{
{ tid: this.tid, name: value },
)
if (code === 0) {
this.$message.success(message!)
toast.success(message)
this.$emit('like-toggled', true)
} else {
this.$message.warning(message!)
toast.error(message)
}
},
},

View File

@ -1,5 +1,5 @@
import Vue from 'vue'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default Vue.extend({
data: () => ({ plugins: [] }),
@ -29,7 +29,7 @@ export default Vue.extend({
{ action: 'enable', name },
) as { code: number, message: string, data: { reason: string[] } }
if (code === 0) {
this.$message.success(message)
toast.success(message)
this.$set(this.plugins[originalIndex], 'enabled', true)
} else {
const div = document.createElement('div')

View File

@ -1,5 +1,5 @@
import Vue from 'vue'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default Vue.extend<{
name: string
@ -19,9 +19,9 @@ export default Vue.extend<{
const { code, message } = await this.$http.post(`/user/closet/remove/${this.tid}`)
if (code === 0) {
this.$emit('item-removed')
this.$message.success(message!)
toast.success(message)
} else {
this.$message.warning(message!)
toast.error(message)
}
},
},

View File

@ -1,5 +1,5 @@
import Vue from 'vue'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default Vue.extend<{
tid: number
@ -20,7 +20,7 @@ export default Vue.extend<{
{ tid: this.tid },
)
if (code === 0) {
this.$message.success(message!)
toast.success(message)
Array
.from(
@ -28,7 +28,7 @@ export default Vue.extend<{
)
.forEach(el => (el.src += `?${new Date().getTime()}`))
} else {
this.$message.warning(message!)
toast.error(message)
}
},
},

View File

@ -1,5 +1,7 @@
import { showModal } from './modal'
import { Toast } from './toast'
Object.assign(blessing, { notify: { showModal } })
export const toast = new Toast()
Object.assign(blessing, { notify: { showModal, toast } })
export * from './modal'
export { showModal } from './modal'

View File

@ -0,0 +1,96 @@
import $ from 'jquery'
import 'bootstrap'
const toastIcons: Record<ToastType, string> = {
success: 'check',
info: 'info',
warning: 'exclamation-triangle',
error: 'times-circle',
}
export type ToastQueue = QueueElement[]
type QueueElement = { el: HTMLDivElement, height: number }
type ToastType =
| 'success'
| 'info'
| 'warning'
| 'error'
export function showToast(
queue: ToastQueue,
type: ToastType,
message = '',
): void {
const alertType = type === 'error' ? 'danger' : type
const container = document.createElement('div')
container.className = 'alert-toast'
const last = queue[queue.length - 1]
if (last) {
container.style.top = `${last.el.offsetTop + last.el.offsetHeight + 12}px`
} else {
container.style.top = '35px'
}
const toast = document.createElement('div')
toast.className = `alert alert-${alertType} d-flex justify-content-between fade`
const icon = document.createElement('i')
icon.className = `icon fas fa-${toastIcons[type]}`
const text = document.createElement('span')
text.textContent = message
const span = document.createElement('span')
span.className = 'mr-auto'
span.appendChild(icon)
span.appendChild(text)
toast.appendChild(span)
const button = document.createElement('button')
button.type = 'button'
button.className = 'ml-2 mr-1 close'
button.dataset.dismiss = 'alert'
button.textContent = '×'
toast.appendChild(button)
container.appendChild(toast)
document.body.appendChild(container)
queue.push({ el: container, height: container.offsetHeight })
setTimeout(() => toast.classList.add('show'), 100)
setTimeout(() => $(toast).alert('close'), 3000)
$(toast).on('closed.bs.alert', () => {
container.remove()
let i = queue.findIndex(({ el }) => el === container)
const distance = queue[i].height + 12
for (i += 1; i < queue.length; i += 1) {
const element = queue[i].el
element.style.top = `${element.offsetTop - distance}px`
}
})
}
export class Toast {
private queue: ToastQueue
constructor() {
this.queue = []
}
success(message = '') {
return showToast(this.queue, 'success', message)
}
info(message = '') {
return showToast(this.queue, 'info', message)
}
warning(message = '') {
return showToast(this.queue, 'warning', message)
}
error(message = '') {
return showToast(this.queue, 'error', message)
}
}

View File

@ -30,3 +30,13 @@
.user-panel .info
cursor default
.alert-toast
position fixed
right calc((100% - 350px) / 2)
width 350px
z-index 1050
transition-property top
transition-duration 0.3s
.alert
box-shadow 0 .25rem .75rem rgba(0,0,0,.1)

View File

@ -76,7 +76,7 @@ import 'vue-good-table/dist/vue-good-table.min.css'
import enablePlugin from '../../components/mixins/enablePlugin'
import tableOptions from '../../components/mixins/tableOptions'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default {
name: 'Market',
@ -139,11 +139,11 @@ export default {
{ name },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
this.plugins[originalIndex].update_available = false
this.plugins[originalIndex].installed = true
} else {
this.$message.warning(message)
toast.error(message)
}
this.installing = ''

View File

@ -95,7 +95,7 @@ import Modal from '../../components/Modal.vue'
import tableOptions from '../../components/mixins/tableOptions'
import serverTable from '../../components/mixins/serverTable'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
import { truthy } from '../../scripts/validators'
export default {
@ -167,9 +167,9 @@ export default {
)
if (code === 0) {
player[`tid_${type}`] = tid
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async changeName(player) {
@ -191,9 +191,9 @@ export default {
)
if (code === 0) {
player.name = value
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async changeOwner(player) {
@ -215,9 +215,9 @@ export default {
)
if (code === 0) {
player.uid = value
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async deletePlayer({ pid, originalIndex }) {
@ -236,9 +236,9 @@ export default {
)
if (code === 0) {
this.$delete(this.players, originalIndex)
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -80,7 +80,7 @@ import 'vue-good-table/dist/vue-good-table.min.css'
import enablePlugin from '../../components/mixins/enablePlugin'
import tableOptions from '../../components/mixins/tableOptions'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default {
name: 'Plugins',
@ -136,10 +136,10 @@ export default {
{ action: 'disable', name },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
this.plugins[originalIndex].enabled = false
} else {
this.$message.warning(message)
toast.error(message)
}
},
async deletePlugin({
@ -161,9 +161,9 @@ export default {
)
if (code === 0) {
this.$delete(this.plugins, originalIndex)
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -52,6 +52,7 @@ import 'vue-good-table/dist/vue-good-table.min.css'
import tableOptions from '../../components/mixins/tableOptions'
import serverTable from '../../components/mixins/serverTable'
import emitMounted from '../../components/mixins/emitMounted'
import { toast } from '../../scripts/notify'
export default {
name: 'ReportsManagement',
@ -132,10 +133,10 @@ export default {
{ id: report.id, action },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
report.status = data.status
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -31,7 +31,7 @@ import { VueGoodTable } from 'vue-good-table'
import 'vue-good-table/dist/vue-good-table.min.css'
import tableOptions from '../../components/mixins/tableOptions'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default {
name: 'Translations',
@ -83,9 +83,9 @@ export default {
)
if (code === 0) {
line.text = text
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async remove({ id, originalIndex }) {
@ -100,7 +100,7 @@ export default {
const { message } = await this.$http.del('/admin/i18n', { id })
this.$delete(this.lines, originalIndex)
this.$message.success(message)
toast.success(message)
},
},
}

View File

@ -128,7 +128,7 @@ import Modal from '../../components/Modal.vue'
import tableOptions from '../../components/mixins/tableOptions'
import serverTable from '../../components/mixins/serverTable'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
import { truthy } from '../../scripts/validators'
export default {
@ -224,9 +224,9 @@ export default {
)
if (code === 0) {
user.email = value
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async toggleVerification(user) {
@ -236,9 +236,9 @@ export default {
)
if (code === 0) {
user.verified = !user.verified
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async changeNickName(user) {
@ -260,9 +260,9 @@ export default {
)
if (code === 0) {
user.nickname = value
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async changePassword(user) {
@ -281,7 +281,7 @@ export default {
'/admin/users?action=password',
{ uid: user.uid, password: value },
)
code === 0 ? this.$message.success(message) : this.$message.warning(message)
code === 0 ? toast.success(message) : toast.error(message)
},
async changeScore(user) {
let value
@ -303,9 +303,9 @@ export default {
)
if (code === 0) {
user.score = score
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async changePermission() {
@ -316,9 +316,9 @@ export default {
})
if (code === 0) {
this.editingUser.permission = permission
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async deleteUser({ uid, originalIndex }) {
@ -337,9 +337,9 @@ export default {
)
if (code === 0) {
this.$delete(this.users, originalIndex)
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -110,8 +110,7 @@ export default {
},
)
if (code === 0) {
this.$message.success(message)
setTimeout(() => (window.location = redirectTo), 1000)
window.location = redirectTo
} else {
if (loginFails > 3 && !this.tooManyFails) {
if (this.recaptcha) {

View File

@ -121,6 +121,7 @@
<script>
import Captcha from '../../components/Captcha.vue'
import emitMounted from '../../components/mixins/emitMounted'
import { toast } from '../../scripts/notify'
export default {
name: 'Register',
@ -169,7 +170,7 @@ export default {
}, this.requirePlayer ? { player_name: playerName } : { nickname }),
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
setTimeout(() => {
window.location = `${blessing.base_url}/user`
}, 1000)

View File

@ -58,6 +58,7 @@
<script>
import emitMounted from '../../components/mixins/emitMounted'
import { toast } from '../../scripts/notify'
export default {
name: 'Reset',
@ -90,8 +91,10 @@ export default {
{ password },
)
if (code === 0) {
this.$message.success(message)
window.location = `${blessing.base_url}/auth/login`
toast.success(message)
setTimeout(() => {
window.location = `${blessing.base_url}/auth/login`
}, 2000)
} else {
this.infoMsg = ''
this.warningMsg = message

View File

@ -214,7 +214,7 @@ import addClosetItem from '../../components/mixins/addClosetItem'
import removeClosetItem from '../../components/mixins/removeClosetItem'
import emitMounted from '../../components/mixins/emitMounted'
import ApplyToPlayerDialog from '../../components/ApplyToPlayerDialog.vue'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
import { truthy } from '../../scripts/validators'
export default {
@ -319,9 +319,9 @@ export default {
)
if (code === 0) {
this.name = value
this.$message.success(message)
toast.success(message)
} else {
this.$message.error(message)
toast.error(message)
}
},
async changeModel() {
@ -331,9 +331,9 @@ export default {
)
if (code === 0) {
this.type = this.editingType
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async togglePrivacy() {
@ -352,10 +352,10 @@ export default {
{ tid: this.tid },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
this.public = !this.public
} else {
this.$message.warning(message)
toast.error(message)
}
},
async deleteTexture() {
@ -373,10 +373,10 @@ export default {
{ tid: this.tid },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
setTimeout(() => (window.location = `${this.baseUrl}/skinlib`), 1000)
} else {
this.$message.warning(message)
toast.error(message)
}
},
async report() {
@ -405,9 +405,9 @@ export default {
{ tid: this.tid, reason },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
fetchPlayersList() {

View File

@ -123,6 +123,7 @@
import FileUpload from 'vue-upload-component'
import { isSlimSkin } from 'skinview3d'
import emitMounted from '../../components/mixins/emitMounted'
import { toast } from '../../scripts/notify'
export default {
name: 'Upload',
@ -162,17 +163,17 @@ export default {
methods: {
async upload() {
if (!this.hasFile) {
this.$message.error(this.$t('skinlib.emptyUploadFile'))
toast.error(this.$t('skinlib.emptyUploadFile'))
return
}
if (!this.name) {
this.$message.error(this.$t('skinlib.emptyTextureName'))
toast.error(this.$t('skinlib.emptyTextureName'))
return
}
if (!/image\/(x-)?png/.test(this.files[0].type)) {
this.$message.error(this.$t('skinlib.fileExtError'))
toast.error(this.$t('skinlib.fileExtError'))
return
}
@ -187,12 +188,9 @@ export default {
code, message, data: { tid } = { tid: 0 },
} = await this.$http.post('/skinlib/upload', data)
if (code === 0) {
this.$message.success(message)
setTimeout(() => {
window.location = `${blessing.base_url}/skinlib/show/${tid}`
}, 1000)
window.location = `${blessing.base_url}/skinlib/show/${tid}`
} else {
this.$message.error(message)
toast.error(message)
this.uploading = false
}
},

View File

@ -81,6 +81,7 @@
import Tween from '@tweenjs/tween.js'
import EmailVerification from '../../components/EmailVerification.vue'
import emitMounted from '../../components/mixins/emitMounted'
import { toast } from '../../scripts/notify'
const ONE_DAY = 24 * 3600 * 1000
@ -177,13 +178,13 @@ export default {
} = await this.$http.post('/user/sign')
if (code === 0) {
this.$message.success(message)
toast.success(message)
this.score = data.score
this.lastSignAt = new Date()
this.storageUsed = data.storage.used
this.storageTotal = data.storage.total
} else {
this.$message.warning(message)
toast.warning(message)
}
this.signing = false
},

View File

@ -77,7 +77,7 @@ import Modal from '../../components/Modal.vue'
import tableOptions from '../../components/mixins/tableOptions'
import emitMounted from '../../components/mixins/emitMounted'
import { walkFetch, init } from '../../scripts/net'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default {
name: 'OAuthApps',
@ -135,7 +135,7 @@ export default {
if (client.id) {
this.clients.unshift(client)
} else {
this.$message.warning(client.message)
toast.error(client.message)
}
},
async modifyName(client) {
@ -177,7 +177,7 @@ export default {
if (result.id) {
Object.assign(client, modified)
} else {
this.$message.warning(result.message)
toast.error(result.message)
}
},
async remove(client) {

View File

@ -134,7 +134,7 @@
import Modal from '../../components/Modal.vue'
import AddPlayerDialog from '../../components/AddPlayerDialog.vue'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
import { truthy } from '../../scripts/validators'
export default {
@ -223,15 +223,16 @@ export default {
{ name: value },
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
player.name = value
} else {
this.$message.warning(message)
toast.error(message)
}
},
async clearTexture() {
if (Object.values(this.clear).every(value => !value)) {
return this.$message.warning(this.$t('user.noClearChoice'))
toast.error(this.$t('user.noClearChoice'))
return
}
const { code, message } = await this.$http.post(
@ -239,13 +240,13 @@ export default {
this.clear,
)
if (code === 0) {
this.$message.success(message)
toast.success(message)
const player = this.players.find(({ pid }) => pid === this.selected)
Object.keys(this.clear)
.filter(type => this.clear[type])
.forEach(type => (player[`tid_${type}`] = 0))
} else {
this.$message.warning(message)
toast.error(message)
}
},
async deletePlayer(player, index) {
@ -262,9 +263,9 @@ export default {
const { code, message } = await this.$http.post(`/user/player/delete/${player.pid}`)
if (code === 0) {
this.$delete(this.players, index)
this.$message.success(message)
toast.success(message)
} else {
this.$message.warning(message)
toast.error(message)
}
},
},

View File

@ -196,7 +196,7 @@
import EmailVerification from '../../components/EmailVerification.vue'
import Modal from '../../components/Modal.vue'
import emitMounted from '../../components/mixins/emitMounted'
import { showModal } from '../../scripts/notify'
import { showModal, toast } from '../../scripts/notify'
export default {
name: 'Profile',
@ -231,7 +231,7 @@ export default {
'/user/profile/avatar',
{ tid: 0 },
)
this.$message.success(message)
toast.success(message)
Array.from(document.querySelectorAll('[alt="User Image"]'))
.forEach(el => (el.src += `?${new Date().getTime()}`))
},
@ -241,7 +241,7 @@ export default {
} = this
if (newPassword !== confirmPassword) {
this.$message.error(this.$t('auth.invalidConfirmPwd'))
toast.error(this.$t('auth.invalidConfirmPwd'))
this.$refs.confirmPassword.focus()
return
}
@ -252,7 +252,7 @@ export default {
)
await showModal({ mode: 'alert', text: message })
if (code === 0) {
return (window.location = `${blessing.base_url}/auth/login`)
window.location = `${blessing.base_url}/auth/login`
}
},
async changeNickName() {
@ -266,7 +266,8 @@ export default {
Array
.from(document.querySelectorAll('[data-mark="nickname"]'))
.forEach(el => (el.textContent = nickname))
return this.$message.success(message)
toast.success(message)
return
}
showModal({ mode: 'alert', text: message })
},
@ -277,11 +278,10 @@ export default {
'/user/profile?action=email',
{ new_email: email, password: this.currentPassword },
)
await showModal({ mode: 'alert', text: message })
if (code === 0) {
await this.$message.success(message)
return (window.location = `${blessing.base_url}/auth/login`)
window.location = `${blessing.base_url}/auth/login`
}
showModal({ mode: 'alert', text: message })
},
async deleteAccount() {
const { deleteConfirm: password } = this

View File

@ -1,5 +0,0 @@
export default {
success() {},
warning() {},
info() {},
}

View File

@ -1,9 +1,12 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../utils'
import { toast } from '@/scripts/notify'
import Modal from '@/components/Modal.vue'
import AddPlayerDialog from '@/components/AddPlayerDialog.vue'
jest.mock('@/scripts/notify')
window.blessing.extra = {
rule: 'rule',
length: 'length',
@ -25,10 +28,10 @@ test('add player', async () => {
)
await flushPromises()
expect(wrapper.text()).not.toContain('the-new')
expect(Vue.prototype.$message.warning).toBeCalledWith('fail')
expect(toast.error).toBeCalledWith('fail')
modal.vm.$emit('confirm')
await flushPromises()
expect(wrapper.emitted().add).toBeDefined()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
})

View File

@ -1,10 +1,13 @@
import 'bootstrap'
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../utils'
import { toast } from '@/scripts/notify'
import ApplyToPlayerDialog from '@/components/ApplyToPlayerDialog.vue'
jest.mock('@/scripts/notify')
test('submit applying texture', async () => {
window.$ = jest.fn(() => ({ modal() {} }))
Vue.prototype.$http.get.mockResolvedValue({ data: [{ pid: 1 }] })
Vue.prototype.$http.post.mockResolvedValueOnce({ code: 1 })
.mockResolvedValue({ code: 0, message: 'ok' })
@ -12,11 +15,11 @@ test('submit applying texture', async () => {
const button = wrapper.find('[data-test=submit]')
button.trigger('click')
expect(Vue.prototype.$message.info).toBeCalledWith('user.emptySelectedPlayer')
expect(toast.info).toBeCalledWith('user.emptySelectedPlayer')
wrapper.setData({ selected: 1 })
button.trigger('click')
expect(Vue.prototype.$message.info).toBeCalledWith('user.emptySelectedTexture')
expect(toast.info).toBeCalledWith('user.emptySelectedTexture')
wrapper.setProps({ skin: 1 })
button.trigger('click')
@ -37,7 +40,7 @@ test('submit applying texture', async () => {
},
)
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
})
test('compute avatar URL', () => {

View File

@ -1,8 +1,11 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../utils'
import { toast } from '@/scripts/notify'
import EmailVerification from '@/components/EmailVerification.vue'
jest.mock('@/scripts/notify')
test('message box should not be render if verified', () => {
window.blessing.extra = { unverified: false }
const wrapper = mount(EmailVerification)
@ -19,9 +22,9 @@ test('resend email', async () => {
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$message.error).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('0')
expect(toast.success).toBeCalledWith('0')
})

View File

@ -1,7 +1,7 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../utils'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import SkinLibItem from '@/components/SkinLibItem.vue'
jest.mock('@/scripts/notify')
@ -96,7 +96,7 @@ test('add to closet', async () => {
'/user/closet/add',
{ tid: 1, name: 'name' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()

View File

@ -0,0 +1,71 @@
import {
showToast, Toast, ToastQueue,
} from '@/scripts/toast'
beforeEach(() => {
document.body.innerHTML = ''
})
test('"Toast" class', () => {
const toast = new Toast()
toast.success('success')
expect(
document.querySelector('.alert-success')!.textContent,
).toContain('success')
toast.info('info')
expect(
document.querySelector('.alert-info')!.textContent,
).toContain('info')
toast.warning('warning')
expect(
document.querySelector('.alert-warning')!.textContent,
).toContain('warning')
toast.error('error')
expect(
document.querySelector('.alert-danger')!.textContent,
).toContain('error')
// Should pass.
toast.success()
toast.info()
toast.warning()
toast.error()
})
test('top position', () => {
showToast([], 'info')
expect(
document.querySelector<HTMLDivElement>('.alert-info')!.parentElement!.style.top,
).toBe('35px')
showToast(
[{ height: 20, el: { offsetTop: 30, offsetHeight: 20 } as HTMLDivElement }],
'error',
)
expect(
document.querySelector<HTMLDivElement>('.alert-danger')!.parentElement!.style.top,
).toBe('62px')
})
test('delay show', () => {
const queue: ToastQueue = []
showToast(queue, 'info')
jest.runTimersToTime(100)
expect(document.querySelector('.fade')!.classList.contains('show')).toBeTrue()
expect(queue).toHaveLength(1)
})
test('move queue', () => {
const queue: ToastQueue = []
const fake = { offsetTop: 30, style: {} } as HTMLDivElement
showToast(queue, 'info')
queue[0].height = 10
queue.push({ height: 0, el: fake })
jest.runAllTimers()
expect(fake.style.top).toBe('8px')
})

View File

@ -1,3 +1,5 @@
import { ModalOptions, ModalResult } from '../../src/scripts/notify'
import { ModalOptions, ModalResult } from '../../src/scripts/modal'
import { Toast } from '../../src/scripts/toast'
export const showModal = {} as jest.Mock<Promise<ModalResult>, [ModalOptions | void]>
export const toast = {} as Toast

View File

@ -1,7 +1,7 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Plugins from '@/views/admin/Plugins.vue'
jest.mock('@/scripts/notify')
@ -124,7 +124,7 @@ test('disable plugin', async () => {
)
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('0')
expect(toast.success).toBeCalledWith('0')
expect(wrapper.text()).toContain('admin.enablePlugin')
})
@ -163,7 +163,7 @@ test('delete plugin', async () => {
'/admin/plugins/manage',
{ action: 'delete', name: 'a' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()

View File

@ -1,7 +1,10 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import Reports from '@/views/admin/Reports.vue'
import { flushPromises } from '../../utils'
import { toast } from '@/scripts/notify'
import Reports from '@/views/admin/Reports.vue'
jest.mock('@/scripts/notify')
test('basic render', async () => {
Vue.prototype.$http.get.mockResolvedValue({
@ -50,11 +53,11 @@ test('delete texture', async () => {
'/admin/reports',
{ id: 1, action: 'delete' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('fail')
expect(toast.error).toBeCalledWith('fail')
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
expect(wrapper.text()).toContain('report.status.1')
})
@ -74,7 +77,7 @@ test('ban uploader', async () => {
'/admin/reports',
{ id: 1, action: 'ban' },
)
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
expect(wrapper.text()).toContain('report.status.1')
})
@ -94,6 +97,6 @@ test('reject', async () => {
'/admin/reports',
{ id: 1, action: 'reject' },
)
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
expect(wrapper.text()).toContain('report.status.2')
})

View File

@ -1,7 +1,7 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Translations from '@/views/admin/Translations.vue'
jest.mock('@/scripts/notify')
@ -47,7 +47,7 @@ test('modify line', async () => {
'/admin/i18n',
{ id: 1, text: '' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('failed')
expect(toast.error).toBeCalledWith('failed')
expect(wrapper.text()).not.toContain('wanshengwei')
button.trigger('click')
@ -56,7 +56,7 @@ test('modify line', async () => {
'/admin/i18n',
{ id: 1, text: 'wanshengwei' },
)
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
expect(wrapper.text()).toContain('wanshengwei')
})
@ -82,6 +82,6 @@ test('delete line', async () => {
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$http.del).toBeCalledWith('/admin/i18n', { id: 1 })
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
expect(wrapper.text()).not.toContain('general')
})

View File

@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import '@/scripts/i18n'
import Modal from '@/components/Modal.vue'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Users from '@/views/admin/Users.vue'
jest.mock('@/scripts/i18n', () => ({
@ -345,12 +345,12 @@ test('change password', async () => {
{ uid: 1, password: 'password' },
)
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('0')
expect(toast.success).toBeCalledWith('0')
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
})
test('change score', async () => {

View File

@ -82,6 +82,4 @@ test('login', async () => {
},
)
await flushPromises()
jest.runAllTimers()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
})

View File

@ -1,7 +1,10 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import Register from '@/views/auth/Register.vue'
import { flushPromises } from '../../utils'
import { toast } from '@/scripts/notify'
import Register from '@/views/auth/Register.vue'
jest.mock('@/scripts/notify')
window.blessing.extra = { player: false }
@ -64,7 +67,7 @@ test('register', async () => {
form.trigger('submit')
await flushPromises()
jest.runAllTimers()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
})
test('register with player name', async () => {

View File

@ -1,8 +1,11 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { toast } from '@/scripts/notify'
import Reset from '@/views/auth/Reset.vue'
jest.mock('@/scripts/notify')
test('reset password', async () => {
Vue.prototype.$http.post
.mockResolvedValueOnce({ code: 1, message: 'fail' })
@ -36,5 +39,6 @@ test('reset password', async () => {
form.trigger('submit')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
jest.runAllTimers()
})

View File

@ -1,7 +1,7 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Show from '@/views/skinlib/Show.vue'
jest.mock('@/scripts/notify')
@ -267,7 +267,7 @@ test('change texture name', async () => {
'/skinlib/rename',
{ tid: 1, new_name: 'new-name' },
)
expect(Vue.prototype.$message.error).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()
@ -302,7 +302,7 @@ test('change texture model', async () => {
'/skinlib/model',
{ tid: 1, model: 'alex' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
wrapper
@ -339,7 +339,7 @@ test('toggle privacy', async () => {
'/skinlib/privacy',
{ tid: 1 },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()
@ -375,12 +375,12 @@ test('delete texture', async () => {
'/skinlib/delete',
{ tid: 1 },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()
jest.runAllTimers()
expect(Vue.prototype.$message.success).toBeCalledWith('0')
expect(toast.success).toBeCalledWith('0')
})
test('report texture', async () => {
@ -431,11 +431,11 @@ test('report texture', async () => {
'/skinlib/report',
{ tid: 1, reason: 'reason' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('duplicated')
expect(toast.error).toBeCalledWith('duplicated')
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('success')
expect(toast.success).toBeCalledWith('success')
})
test('apply texture to player', () => {

View File

@ -2,8 +2,11 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import * as skinview3d from 'skinview3d'
import Upload from '@/views/skinlib/Upload.vue'
import { flushPromises } from '../../utils'
import { toast } from '@/scripts/notify'
import Upload from '@/views/skinlib/Upload.vue'
jest.mock('@/scripts/notify')
window.blessing.extra = {
textureNameRule: 'rule',
@ -137,7 +140,7 @@ test('upload file', async () => {
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
expect(Vue.prototype.$message.error).toBeCalledWith('skinlib.emptyUploadFile')
expect(toast.error).toBeCalledWith('skinlib.emptyUploadFile')
wrapper.setData({
files: [{
@ -146,12 +149,12 @@ test('upload file', async () => {
})
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
expect(Vue.prototype.$message.error).toBeCalledWith('skinlib.emptyTextureName')
expect(toast.error).toBeCalledWith('skinlib.emptyTextureName')
wrapper.find('[type=text]').setValue('t')
button.trigger('click')
expect(Vue.prototype.$http.post).not.toBeCalled()
expect(Vue.prototype.$message.error).toBeCalledWith('skinlib.fileExtError')
expect(toast.error).toBeCalledWith('skinlib.fileExtError')
wrapper.setData({
files: [{
@ -161,12 +164,10 @@ test('upload file', async () => {
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$http.post).toBeCalledWith('/skinlib/upload', expect.any(FormData))
expect(Vue.prototype.$message.error).toBeCalledWith('1')
expect(toast.error).toBeCalledWith('1')
button.trigger('click')
await flushPromises()
jest.runAllTimers()
expect(Vue.prototype.$message.success).toBeCalledWith('0')
})
test('show notice about awarding', () => {

View File

@ -2,8 +2,11 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { toast } from '@/scripts/notify'
import Dashboard from '@/views/user/Dashboard.vue'
jest.mock('@/scripts/notify')
jest.mock('@tweenjs/tween.js', () => ({
Tween: class <T> {
data: T
@ -159,7 +162,7 @@ test('sign', async () => {
button.trigger('click')
await flushPromises()
expect(Vue.prototype.$http.post).toBeCalledWith('/user/sign')
expect(Vue.prototype.$message.warning).toBeCalledWith('1')
expect(toast.warning).toBeCalledWith('1')
button.trigger('click')
await flushPromises()

View File

@ -2,7 +2,7 @@ import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { walkFetch } from '@/scripts/net'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Modal from '@/components/Modal.vue'
import OAuth from '@/views/user/OAuth.vue'
@ -43,7 +43,7 @@ test('create app', async () => {
'/oauth/clients',
{ name: 'name', redirect: 'https://example.com/' },
)
expect(Vue.prototype.$message.warning).toBeCalledWith('fail')
expect(toast.error).toBeCalledWith('fail')
modal.vm.$emit('confirm')
await flushPromises()
@ -77,7 +77,7 @@ test('modify name', async () => {
method: 'PUT',
}),
)
expect(Vue.prototype.$message.warning).toBeCalledWith('fail')
expect(toast.error).toBeCalledWith('fail')
button.trigger('click')
await flushPromises()
@ -111,7 +111,7 @@ test('modify redirect', async () => {
method: 'PUT',
}),
)
expect(Vue.prototype.$message.warning).toBeCalledWith('fail')
expect(toast.error).toBeCalledWith('fail')
button.trigger('click')
await flushPromises()

View File

@ -1,7 +1,7 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Players from '@/views/user/Players.vue'
jest.mock('@/scripts/notify')
@ -183,5 +183,5 @@ test('clear texture', async () => {
)
modal.vm.$emit('confirm')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
})

View File

@ -1,7 +1,7 @@
import Vue from 'vue'
import { mount } from '@vue/test-utils'
import { flushPromises } from '../../utils'
import { showModal } from '@/scripts/notify'
import { showModal, toast } from '@/scripts/notify'
import Profile from '@/views/user/Profile.vue'
jest.mock('@/scripts/notify')
@ -41,7 +41,7 @@ test('reset avatar', async () => {
{ tid: 0 },
)
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('ok')
expect(toast.success).toBeCalledWith('ok')
expect(document.querySelector('img')!.src).toMatch(/\d+$/)
})
@ -56,7 +56,7 @@ test('change password', async () => {
wrapper.setData({ newPassword: '1' })
wrapper.setData({ confirmPassword: '2' })
form.trigger('submit')
expect(Vue.prototype.$message.error).toBeCalledWith('auth.invalidConfirmPwd')
expect(toast.error).toBeCalledWith('auth.invalidConfirmPwd')
expect(Vue.prototype.$http.post).not.toBeCalled()
wrapper.setData({ confirmPassword: '1' })
@ -93,7 +93,7 @@ test('change nickname', async () => {
form.trigger('submit')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('o')
expect(toast.success).toBeCalledWith('o')
expect(document.querySelector('span')!.textContent).toBe('nickname')
})
@ -116,7 +116,7 @@ test('change email', async () => {
form.trigger('submit')
await flushPromises()
expect(Vue.prototype.$message.success).toBeCalledWith('o')
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'o' })
})
test('delete account', async () => {