Merge remote-tracking branch 'origin/2119_Create_Post_consistent_form_input_validation' into 2119_Create_Post_consistent_form_input_validation-improvements

This commit is contained in:
roschaefer 2019-11-08 16:28:54 +01:00
commit 4108bb7d71
5 changed files with 133 additions and 109 deletions

View File

@ -22,37 +22,36 @@ config.stubs['v-popover'] = '<span><slot /></span>'
const categories = [
{
"id": "cat3",
"slug": "health-wellbeing",
"icon": "medkit"
id: 'cat3',
slug: 'health-wellbeing',
icon: 'medkit',
},
{
"id": "cat12",
"slug": "it-internet-data-privacy",
"icon": "mouse-pointer"
id: 'cat12',
slug: 'it-internet-data-privacy',
icon: 'mouse-pointer',
},
{
"id": "cat9",
"slug": "democracy-politics",
"icon": "university"
id: 'cat9',
slug: 'democracy-politics',
icon: 'university',
},
{
"id": "cat15",
"slug": "consumption-sustainability",
"icon": "shopping-cart"
id: 'cat15',
slug: 'consumption-sustainability',
icon: 'shopping-cart',
},
{
"id": "cat4",
"slug": "environment-nature",
"icon": "tree"
}
id: 'cat4',
slug: 'environment-nature',
icon: 'tree',
},
]
describe('ContributionForm.vue', () => {
let wrapper
let postTitleInput
let expectedParams
let deutschOption
let cancelBtn
let mocks
let propsData
@ -137,21 +136,13 @@ describe('ContributionForm.vue', () => {
beforeEach(() => {
wrapper = Wrapper()
wrapper.setData({
form: {
languageOptions: [
{
label: 'Deutsch',
value: 'de',
},
],
},
})
})
describe('CreatePost', () => {
describe('language placeholder', () => {
it("displays the name that corresponds with the user's location code", () => {
it.skip("displays the name that corresponds with the user's location code", () => {
// Well not anymore right? We want the user to save the language
// excplicitly. I'll keep this test if we change our minds
expect(wrapper.find('.ds-select-placeholder').text()).toEqual('English')
})
})
@ -242,8 +233,16 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent)
wrapper.find(CategoriesSelect).setData({categories})
await wrapper.find(CategoriesSelect).findAll('button').at(1).trigger('click')
wrapper.find(CategoriesSelect).setData({ categories })
wrapper
.findAll('li')
.at(1)
.trigger('click') // language
await wrapper
.find(CategoriesSelect)
.findAll('button')
.at(1)
.trigger('click')
})
it('creates a post with valid title, content, and at least one category', async () => {
@ -251,15 +250,12 @@ describe('ContributionForm.vue', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it("sends a fallback language based on a user's locale", () => {
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('supports changing the language', async () => {
expectedParams.variables.language = 'de'
deutschOption = wrapper.findAll('li').at(0)
deutschOption.trigger('click')
wrapper
.findAll('li')
.at(0)
.trigger('click') // choose German as language
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
@ -303,8 +299,16 @@ describe('ContributionForm.vue', () => {
postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent)
categoryIds = ['cat12']
wrapper.find(CategoriesSelect).setData({categories})
await wrapper.find(CategoriesSelect).findAll('button').at(1).trigger('click')
wrapper.find(CategoriesSelect).setData({ categories })
wrapper
.findAll('li')
.at(1)
.trigger('click') // language
await wrapper
.find(CategoriesSelect)
.findAll('button')
.at(1)
.trigger('click')
})
it('shows an error toaster when apollo mutation rejects', async () => {
@ -385,6 +389,10 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
wrapper.vm.updateEditorContent(postContent)
wrapper
.findAll('li')
.at(0)
.trigger('click') // language
await wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
@ -394,10 +402,26 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
wrapper.vm.updateEditorContent(postContent)
wrapper.find(CategoriesSelect).setData({categories})
await wrapper.find(CategoriesSelect).findAll('button').at(0).trigger('click')
await wrapper.find(CategoriesSelect).findAll('button').at(3).trigger('click')
await wrapper.find(CategoriesSelect).findAll('button').at(4).trigger('click')
wrapper
.findAll('li')
.at(0)
.trigger('click') // language
wrapper.find(CategoriesSelect).setData({ categories })
await wrapper
.find(CategoriesSelect)
.findAll('button')
.at(0)
.trigger('click')
await wrapper
.find(CategoriesSelect)
.findAll('button')
.at(3)
.trigger('click')
await wrapper
.find(CategoriesSelect)
.findAll('button')
.at(4)
.trigger('click')
await wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})

View File

@ -50,23 +50,27 @@
<ds-text align="right">
<ds-chip v-if="errors && errors.categoryIds" color="danger" size="base">
{{ form.categoryIds.length }} / 3
<ds-icon name="warning"></ds-icon>
<ds-icon name="warning" class="colorRed"></ds-icon>
</ds-chip>
<ds-chip v-else size="base">{{ form.categoryIds.length }} / 3</ds-chip>
</ds-text>
<ds-flex class="contribution-form-footer">
<ds-flex-item :width="{ base: '10%', sm: '10%', md: '10%', lg: '15%' }" />
<ds-flex-item :width="{ base: '80%', sm: '30%', md: '30%', lg: '20%' }">
<ds-flex-item>
<ds-space margin-bottom="small" />
<ds-select
model="language"
:options="form.languageOptions"
:options="languageOptions"
icon="globe"
:placeholder="locale"
:placeholder="$t('contribution.languageSelectText')"
:label="$t('contribution.languageSelectLabel')"
/>
</ds-flex-item>
</ds-flex>
<ds-text align="right">
<ds-chip v-if="errors && errors.language" size="base" color="danger">
<ds-icon name="warning"></ds-icon>
</ds-chip>
</ds-text>
<ds-space />
<div slot="footer" style="text-align: right">
<ds-button
@ -77,13 +81,7 @@
>
{{ $t('actions.cancel') }}
</ds-button>
<ds-button
type="submit"
icon="check"
:loading="loading"
:disabled="errors"
primary
>
<ds-button type="submit" icon="check" :loading="loading" :disabled="errors" primary>
{{ $t('actions.save') }}
</ds-button>
</div>
@ -115,16 +113,35 @@ export default {
contribution: { type: Object, default: () => {} },
},
data() {
const languageOptions = orderBy(locales, 'name').map(locale => {
return { label: locale.name, value: locale.code }
})
const formDefaults = {
title: '',
content: '',
teaserImage: null,
image: null,
language: null,
categoryIds: [],
}
let id = null
let slug = null
const form = { ...formDefaults }
if (this.contribution && this.contribution.id) {
id = this.contribution.id
slug = this.contribution.slug
form.title = this.contribution.title
form.content = this.contribution.content
form.image = this.contribution.image
form.language =
this.contribution && this.contribution.language
? languageOptions.find(o => this.contribution.language === o.value)
: null
form.categoryIds = this.categoryIds(this.contribution.categories)
}
return {
form: {
title: '',
content: '',
categoryIds: [],
teaserImage: null,
image: null,
language: null,
languageOptions: [],
},
form,
formSchema: {
title: { required: true, min: 3, max: 100 },
content: {
@ -139,66 +156,41 @@ export default {
required: true,
validator: (rule, value) => {
const errors = []
if (!(value && 1 <= value.length && value.length <= 3)) {
if (!(value && value.length >= 1 && value.length <= 3)) {
errors.push(new Error(this.$t('common.validations.categories')))
}
return errors
},
},
language: { required: true },
},
id: null,
languageOptions,
id,
slug,
loading: false,
slug: null,
users: [],
contentMin: 3,
hashtags: [],
}
},
watch: {
contribution: {
immediate: true,
handler: function(contribution) {
if (!contribution || !contribution.id) {
return
}
this.id = contribution.id
this.slug = contribution.slug
this.form.title = contribution.title
this.form.content = contribution.content
this.form.image = contribution.image
this.form.categoryIds = this.categoryIds(contribution.categories)
},
},
},
computed: {
contentLength() {
return this.$filters.removeHtml(this.form.content).length
},
locale() {
const locale =
this.contribution && this.contribution.language
? locales.find(loc => this.contribution.language === loc.code)
: locales.find(loc => this.$i18n.locale() === loc.code)
return locale.name
},
...mapGetters({
currentUser: 'auth/user',
}),
},
mounted() {
this.availableLocales()
},
methods: {
submit() {
const { title, content, image, teaserImage, categoryIds } = this.form
let language
if (this.form.language) {
language = this.form.language.value
} else if (this.contribution && this.contribution.language) {
language = this.contribution.language
} else {
language = this.$i18n.locale()
}
const {
language: { value: language },
title,
content,
image,
teaserImage,
categoryIds,
} = this.form
this.loading = true
this.$apollo
.mutate({
@ -231,11 +223,6 @@ export default {
updateEditorContent(value) {
this.$refs.contributionForm.update('content', value)
},
availableLocales() {
orderBy(locales, 'name').map(locale => {
this.form.languageOptions.push({ label: locale.name, value: locale.code })
})
},
addTeaserImage(file) {
this.form.teaserImage = file
},
@ -295,4 +282,14 @@ export default {
padding-right: 0;
}
}
.checkicon {
cursor: default;
top: -18px;
}
.checkicon_cat {
top: -58px;
}
.colorRed {
color: red;
}
</style>

View File

@ -45,6 +45,7 @@ export const postFragment = lang => gql`
deleted
slug
image
language
author {
...user
}

View File

@ -580,7 +580,8 @@
"filterFollow": "Beiträge filtern von Usern denen ich folge",
"filterALL": "Alle Beiträge anzeigen",
"success": "Gespeichert!",
"languageSelectLabel": "Sprache",
"languageSelectLabel": "Sprache deines Beitrags",
"languageSelectText": "Sprache wählen",
"categories": {
"infoSelectedNoOfMaxCategories": "{chosen} von {max} Kategorien ausgewählt"
},

View File

@ -581,7 +581,8 @@
"filterFollow": "Filter contributions from users I follow",
"filterALL": "View all contributions",
"success": "Saved!",
"languageSelectLabel": "Language",
"languageSelectLabel": "Language of your contribution",
"languageSelectText": "Select Language",
"categories": {
"infoSelectedNoOfMaxCategories": "{chosen} of {max} categories selected"
},