Your post is failing one of the validation checks.
Try getting the response json so you can see what the error is.
dd($response->getContent());
You'll need to remove withoutExceptionHandling to see the response.
In my blog project, creating post is working. But i has problem in testing.
Here is my createblog.vue
<template>
<div>
<form @submit.prevent="Publish">
<div class="form-group">
<input
type="file"
class="form-control border-0 p-0"
@change="imageSelected"
/>
<div v-if="previewImage">
<img :src="previewImage" style="height: 200px" class="rounded" />
</div>
<span class="text-danger" v-text="errors.get('featured_image')"></span>
</div>
<div class="form-group">
<input
type="text"
placeholder="Title"
class="form-control"
v-model="title"
/>
<span class="text-danger" v-text="errors.get('title')"></span>
</div>
<div class="form-group">
<input
type="text"
placeholder="Write a excerpt for post ..."
class="form-control"
v-model="excerpt"
/>
<span class="text-danger" v-text="errors.get('excerpt')"></span>
</div>
<div class="form-group">
<vue-editor v-model="content"/>
<span class="text-danger" v-text="errors.get('content')"></span>
</div>
<div class="form-group">
<multiselect
v-model="selectedTags" :options="tagOptions"
:multiple="true" track-by="id"
label="name" placeholder="Search or add tags"
>
</multiselect>
<span class="text-danger" v-text="errors.get('tags')"></span>
</div>
<div v-if="isSchedule" class="form-group text-dark mb-3">
<label for="published_at">Schedule your publish time (* if you blank this field, post will publish with current time)</label>
<!-- <input
type="text" step="1" class="form-control"
v-model="published_at" placeholder="dd/mm/yyyy, H:i:s"
onfocus="(this.type='datetime-local')"
/> -->
<input
type="datetime-local" step="1" class="form-control"
v-model="published_at"
/>
<span class="text-danger" v-text="errors.get('published_at')"></span>
</div>
<div class="mt-3">
<button class="btn btn-sm btn-success">
Publish
</button>
<!-- for next improvement :)
<button name="draft" type="submit" class="btn btn-sm btn-outline-success">
Save as draft
</button> -->
-Or-
<a class="btn btn-sm btn-link pl-0" v-if="isSchedule" @click="isSchedule = false">
Cancel scheduling
</a>
<a v-else class="btn btn-sm btn-link pl-0" @click="isSchedule = true">
Schedule for later
</a>
</div>
</form>
</div>
</template>
<script>
// import Quill from 'quill'
import Errors from "../form";
import Multiselect from "vue-multiselect";
import { VueEditor } from "vue2-editor";
import axios from "axios";
export default {
components: {
VueEditor,
Multiselect,
},
// props: ["current"],
data() {
return {
title: "",
excerpt: "",
content: "",
featured_image: "",
published_at: "",
previewImage: "",
selectedTags: [],
tagOptions: [],
errors: new Errors(),
isSchedule: false,
};
},
methods: {
imageSelected(e) {
this.featured_image = e.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(this.featured_image);
reader.onload = (e) => {
this.previewImage = e.target.result;
};
},
Publish() {
let fd = new FormData();
fd.append("featured_image", this.featured_image);
fd.append("title", this.title);
fd.append("excerpt", this.excerpt);
fd.append("content", this.content);
fd.append("published_at", this.published_at);
fd.append("tags", JSON.stringify(this.selectedTags));
axios
.post(`/posts`, fd)
.then((response) => {
window.location.href = `https://hielo.test/posts/${response.data.postId}`;
// console.log(JSON.stringify(this.selectedTags))
})
.catch((err) => this.errors.record(err.response.data.errors));
},
fetchTag() {
axios
.get(`/api/tags`)
.then((res) => (this.tagOptions = res.data.data))
.catch((err) => this.errors.record(err.response.data));
},
},
created() {
this.fetchTag();
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style lang="scss" scoped>
</style>
postscontroller@store
public function store(StorePostRequest $request)
{
$attributes = $request->except('tags');
if ($request->hasFile('featured_image')) {
$attributes['featured_image'] = request('featured_image')->store('featured-images');
}
if (request('published_at') != null) {
$attributes['published_at'] = request('published_at');
$post = current_user()->posts()->create($attributes);
} else {
$attributes['published_at'] = date('Y-m-d\TH:i:s');
$post = current_user()->posts()->create($attributes);
}
$tags = json_decode(request('tags'));
foreach ($tags as $tag) {
$tagsId[$tag->id] = ['tag_id' => $tag->id];
}
$post->tags()->sync($tagsId);
foreach (current_user()->followers as $follower) {
$follower->notify(new PostPublished($post));
}
\Session::flash('status', 'Post created success');
return response()->json(['postId' => $post->id]);
}
StorePostRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Post;
use Illuminate\Support\Facades\Gate;
use App\Exceptions\ThrottleException;
class StorePostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Gate::allows('create_post', new Post);
}
protected function failedAuthorization()
{
throw new ThrottleException(
'Action too frequently. Not allowed'
);
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
if (is_string(request('tags'))) {
$this->merge([
'tags' => json_decode(request('tags')),
]);
}
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
'title' => 'required|string|max:255',
'excerpt' => 'required|string|max:255',
'content' => 'required|string'
];
if (request()->isMethod('post')) {
$rules['featured_image'] = 'required|image|mimes:jpeg,png,jpg';
$rules['tags'] = 'required';
} else {
$rules['featured_image'] = 'image|mimes:jpeg,png,jpg';
}
return $rules;
}
}
PostFactory
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Post;
use App\User;
use Faker\Generator as Faker;
$factory->define(Post::class, function (Faker $faker) {
return [
'author_id' => factory(User::class),
'title' => $faker->sentence,
'excerpt' => $faker->sentence,
'content' => $faker->paragraph,
'featured_image' => 'images/0aa186eb49f844476d7e2e9448f69496.jpg',
'published_at' => null,
'tags' => '[{"id":7,"name":"Makayla Wiegand IV"}]'
];
});
TestCase
public function testAuthorizedUserCanCreatePost()
{
$this->withoutExceptionHandling();
$this->signIn();
$post = make('Post');
$response = $this->post("/posts", $post->toArray());
// dd($response->headers->get('Location'));
$this->assertDatabaseHas('posts', ['title' => $post->title]);
// $response->assertRedirect($response->headers->get('Location'));
$this->get($response->headers->get('Location'))
->assertSee($post->title);
}
As you see, i has post tags and featured_image in creating blog. Validate them in post request. When i run test, it show the given data was invalid with withoutExceptionHandling in test case. I am confusing how to make test pass and my code is really messy. Please give me advice.
@aunghtetpaing__ I’m not reading through that line of text, but will say when I’m testing endpoints that deal with validation, I’ll use ->assertSessionHasNoErrors() on web requests and ->assertJsonMissingValidationErrors() on API requests.
If validation does fail when I’m not expecting it to, the rules that failed and their messages will be printed to the console in a nice manner so that I can debug the issue without having to temporarily disable exception handling or stick dd statements in my tests.
Please or to participate in this conversation.