Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions components/Author/Author.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
<template>
<div :class="{ disabled: disableLink, 'is-owner': isOwner, mask: maskUser }"
class="media hc__author"
@click="showProfile">
<div class="media-left" v-if="showAvatar">
class="media hc__author">
<div class="media-left" v-if="showAvatar" @click="showProfile">
<hc-avatar
:user="getUser"
:showOnlineStatus="true"
:imageKey="imageKey" />
</div>
<div class="media-content" v-if="showText">
<div class="media-content" @click="showProfile" v-if="showText">
<p class="title" v-if="!user">
{{ $t('component.contribution.creatorUnknown') }}
</p>
Expand All @@ -20,6 +19,8 @@
<hc-relative-date-time :dateTime="createdAt"></hc-relative-date-time>
</p>
</div>
<slot>
</slot>
</div>
</template>

Expand Down
12 changes: 9 additions & 3 deletions components/Comments/Comment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
:isAuthor="isAuthor"
:createdAt="comment.createdAt" />
</div>
<div class="comment-header-actions">
<div class="comment-header-actions" v-if="!comment.isBlacklisted">
<template v-if="isOwner">
<div class="disabled">
<small v-if="comment.upvoteCount > 0"><strong>+{{ comment.upvoteCount || 0 }}</strong></small>&nbsp;
Expand All @@ -38,7 +38,7 @@
</template>
</div>
</div>
<div v-html="getText" class="comment-text" v-if="!edit"></div>
<div v-html="getText" :class="{'comment-text': true, 'comment-blacklisted': comment.isBlacklisted}" v-if="!edit"></div>
<form class="comment-form" @submit.prevent="patchComment" v-else>
<hc-editor identifier="comment"
editorClass="autowrap"
Expand All @@ -61,7 +61,7 @@
</hc-button>
</div>
</form>
<div class="comment-footer">
<div class="comment-footer" v-if="!comment.isBlacklisted">
<div class="comment-footer-actions-left">
<hc-tooltip :label="$t('component.contribution.commentReplyThis')" type="is-black" position="is-right" v-if="!isOwner">
<a class="level-item" @click.prevent="$emit('reply', comment)">
Expand Down Expand Up @@ -143,6 +143,7 @@
user: 'auth/user'
}),
getText () {
if (this.comment.isBlacklisted) return this.$t('component.contribution.commentBlacklistPlaceholder')
return (this.fullContentShown && this.content)
? linkifyHtml(this.content)
: linkifyHtml(this.comment.contentExcerpt)
Expand Down Expand Up @@ -277,6 +278,11 @@
}
}

.comment-blacklisted {
color: $grey;
font-style: italic;
}

.comment-deleted {
display: flex;
align-items: center;
Expand Down
127 changes: 127 additions & 0 deletions components/Global/Elements/BlockButton/BlockButton.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { shallowMount, mount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import BlockButton from './BlockButton'

const localVue = createLocalVue()

localVue.use(Vuex)

const propsData = {
foreignEntity: {
_id: 4711,
name: 'author'
},
isFollowing: false
}

const mocks = { $t: () => {} }

describe('BlockButton.vue', () => {
let actions
let getters
let store
let wrapper

beforeEach(() => {
getters = {
'feathers-vuex-usersettings/isBlacklisted': () => () => false,
'feathers-vuex-usersettings/isPending': () => false,
'feathers-vuex-usersettings/current': () => { return { blacklist: [] } }
}
actions = {
'feathers-vuex-usersettings/toggleBlacklist': jest.fn()
}
store = new Vuex.Store({
state: {}, getters, actions
})
})

test('renders', () => {
wrapper = shallowMount(BlockButton, { store, localVue, propsData, mocks })
expect(wrapper.is('hc-button-stub')).toBeTruthy()
})

describe('request pending', () => {
beforeEach(() => {
getters['feathers-vuex-usersettings/isPending'] = () => true
store = new Vuex.Store({state: {}, getters, actions})
wrapper = shallowMount(BlockButton, { store, localVue, propsData, mocks })
})

test('shows a loading spinner', () => {
expect(wrapper.find('hc-button-stub').attributes().isloading).toBeTruthy()
})

test('is disabled', () => {
expect(wrapper.find('hc-button-stub').attributes().disabled).toBeTruthy()
})
})

describe('no request pending', () => {
test('is enabled', () => {
wrapper = shallowMount(BlockButton, { store, localVue, propsData, mocks })
expect(wrapper.findAll('hc-button-stub')).toHaveLength(1)
expect(wrapper.find('hc-button-stub').attributes()).toEqual(expect.not.objectContaining({isloading: 'true'}))
})

describe('not blacklisted', () => {
test('shows a neutral ban icon', () => {
expect(wrapper.find('hc-icon-stub').classes()).not.toContain('is-danger')
})
})

describe('is blacklisted', () => {
beforeEach(() => {
getters['feathers-vuex-usersettings/isBlacklisted'] = () => () => true
store = new Vuex.Store({state: {}, getters, actions})
wrapper = shallowMount(BlockButton, { store, localVue, propsData, mocks })
})

test('gives visual feedback with a red colour', () => {
expect(wrapper.find('hc-icon-stub').classes()).toContain('is-danger')
})
})

test('dispatches feathers-vuex-usersettings/toggleBlacklist on click', () => {
wrapper = mount(BlockButton, {
store,
localVue,
mocks: {
$t: () => {},
$snackbar: {
open () { }
}
},
propsData
})
wrapper.find('button').trigger('click')
expect(actions['feathers-vuex-usersettings/toggleBlacklist']).toHaveBeenCalled()
})

describe('isFollowed === true', () => {
beforeEach(() => {
const props = Object.assign({}, propsData, {
isFollowing: true
})
wrapper = shallowMount(BlockButton, { store, localVue, propsData: props, mocks })
})

test('is disabled', () => {
expect(wrapper.find('hc-button-stub').attributes().disabled).toEqual('true')
})
})

describe('isFollowed === false', () => {
beforeEach(() => {
const props = Object.assign({}, propsData, {
isFollowing: false
})
wrapper = shallowMount(BlockButton, { store, localVue, propsData: props, mocks })
})

test('is disabled', () => {
expect(wrapper.find('hc-button-stub').attributes().disabled).toEqual(undefined)
})
})
})
})
65 changes: 65 additions & 0 deletions components/Global/Elements/BlockButton/BlockButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<hc-button color="button"
:disabled="isPending || isFollowing"
:isLoading="isPending"
@click="toggleBlacklist">
<template v-if="isBlacklisted">
<hc-icon icon="ban" :class="['icon-left', 'is-danger']" /> {{ $t('component.blacklist.buttonLabelUnblock') }}
</template>
<template v-else>
<hc-icon icon="ban" class="icon-left" /> {{ $t('component.blacklist.buttonLabelBlock') }}
</template>
</hc-button>
</template>

<script>
import Icon from '~/components/Global/Elements/Icon/Icon.vue'
import Button from '~/components/Global/Elements/Button/Button.vue'
import { mapGetters } from 'vuex'

export default {
name: 'hc-block-button',
components: {
'hc-button': Button,
'hc-icon': Icon
},
props: {
foreignEntity: {
type: Object,
required: true
},
isFollowing: {
required: true
}
},
computed: {
...mapGetters({
isPending: 'feathers-vuex-usersettings/isPending',
}),
isBlacklisted () {
return this.$store.getters['feathers-vuex-usersettings/isBlacklisted'](this.foreignEntity)
}
},
methods: {
async toggleBlacklist() {
let message
try {
await this.$store.dispatch('feathers-vuex-usersettings/toggleBlacklist', this.foreignEntity)
const translationKey = `component.blacklist.${this.isBlacklisted ? 'blockSuccess' : 'unblockSuccess'}`
message = this.$t(translationKey, {
name: this.foreignEntity.name || this.$t('component.contribution.creatorUnknown')
})
} catch (error) {
message = this.$t('component.error.general')
throw (error)
} finally {
this.$snackbar.open({ message })
}
}
}
}
</script>

<style lang="scss" scoped>
@import "assets/styles/utilities";
</style>
85 changes: 85 additions & 0 deletions components/Global/Elements/Follow/FollowButtons.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import FollowButtons from './FollowButtons'

const localVue = createLocalVue()

localVue.use(Vuex)

let propsData

const mocks = { $t: () => {} }

describe('FollowButtons.vue', () => {
let wrapper
let actions
let getters
let store
let currentUser

beforeEach(() => {
propsData = {
entity: {
_id: 4711,
name: 'author'
}
}
currentUser = {
_id: 42
}
getters = {
'connections/follow': () => {
return { isPending: false, isFollowing: false }
},
'feathers-vuex-usersettings/current': () => { return {} },
'feathers-vuex-usersettings/isPending': () => false,
'auth/user': () => { return currentUser }
}
actions = {
'connections/syncFollow': () => {
}
}
store = new Vuex.Store({
state: {}, getters, actions
})
})

test('renders', () => {
wrapper = shallowMount(FollowButtons, { store, localVue, propsData, mocks })
expect(wrapper.is('div')).toBeTruthy()
})

describe('showButtons === true', () => {
beforeEach(() => {
propsData.showButtons = true
})

describe('entity is not blacklisted', () => {
beforeEach(() => {
getters['feathers-vuex-usersettings/isBlacklisted'] = () => () => false
store = new Vuex.Store({
state: {}, getters, actions
})
})

test('follow button is enabled', () => {
wrapper = shallowMount(FollowButtons, { store, localVue, propsData, mocks })
expect(wrapper.find('hc-button-stub').attributes().disabled).toEqual(undefined)
})
})

describe('entity is blacklisted', () => {
beforeEach(() => {
getters['feathers-vuex-usersettings/isBlacklisted'] = () => () => true
store = new Vuex.Store({
state: {}, getters, actions
})
})

test('follow button is disabled', () => {
wrapper = shallowMount(FollowButtons, { store, localVue, propsData, mocks })
expect(wrapper.find('hc-button-stub').attributes().disabled).toEqual('true')
})
})
})
})
Loading