Test failing with Session is missing expected key [errors]
I have this test that checks that the active
field is either 0
or 1
:
it('requires valid data', function ($active) {
// Arrange
Belt::factory()->create([
'min_xp' => 0,
]);
$character = Character::factory()->create();
$this->actingAs($character->user)
->put(route('characters.update', ['character' => $character]), ['active' => $active])
->assertInvalid('active');
})->with([
null,
1,
1.5,
str_repeat('a', 2),
]);
However it is failing with Session is missing expected key [errors].. Here is my Vue:
<template>
<AppLayout title="My Characters">
<div class="grid row mt-5">
<div class="col-span-6 m-auto">
<div class="block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700">
<h1 class="text-center mb-3">
<i aria-hidden="true"></i> Characters
</h1>
<div v-if="characters.length === 0">
<p>You have no characters, why not create a new character?</p>
<Link :href="route('characters.create')" class="inline-block border border-blue-500 rounded py-1 px-3 bg-blue-500 text-white" role="link" title="Create a new character">Create a new character</Link>
</div>
<table v-else class="table-auto border-spacing-2 text-center">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Active</th>
<th scope="col">Options</th>
</tr>
</thead>
<tbody>
<tr v-for="character in characters" :key="character.id">
<th scope="row">{{ character.name }}</th>
<td><span v-if="character.active">X</span></td>
<td>
<Link :href="route('characters.show', {character: character})" class="text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Show</Link>
<Link v-if="!character.active" @click="switchCharacter(character.id)" class="text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Make active</Link></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</AppLayout>
</template>
<script setup>
import AppLayout from "@/Layouts/AppLayout.vue";
import {Link} from "@inertiajs/vue3";
defineProps(['characters']);
const switchCharacter = (characterId) => {
fetch(`/characters/${characterId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({})
})
.then(response => {
console.log(response); // Log the response for debugging
if (response.ok) {
// Handle success, maybe update the UI
alert('Character switched successfully!');
window.location.reload(); // Reload the page to reflect changes
} else {
// Handle error
alert('Failed to switch character.');
}
})
.catch(error => {
console.error('Error:', error);
alert('Failed to switch character.');
});
}
</script>
And here is my route action:
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Character $character)
{
// if the character is already the active
if ($character->active) {
// then redirect to the characters index
return redirect('characters');
}
// get the player's active character if any
$activecharacter = Character::where('user_id', auth()->user()->id)
->where('active', 1)
->first(['id', 'active']);
// if the play has an active character
if ($activecharacter) {
// mark the previous character as not active
$activecharacter->update(['active' => 0]);
}
// set the selected character as the active one
$character->update(['active' => 1]);
// then redirect to the characters index
return response(200);
}
I am using this as my base. It was suggested here that I add validation to my route action. However as per my response to the ai:
@LaryAI Unfortunately, the issue persists. If I add validation the route no longer works. Additionally, there is no actual input to validate because there is no actual input required by the user besides clicking on a link/button which already has the character id baked in.
Any ideas?
Hey!
What I would try to do here is to dd
the character and see if it actually has all of the required properties after being created by the Character::factory
.
That way you will be able to isolate if the problem is with the character itself or something in the vue component.
Also, if you don't need actual validation, you can modify the test to assert the expected behavior directly.
it('sets active character and redirects', function () {
$character = Character::factory()->create();
$this->actingAs($character->user)
->put(route('characters.update', ['character' => $character]), ['active' => 1])
->assertRedirect('characters'); // Assert redirect to characters route
});
But your best bet would be to just use a debugging tools like dd
or logging to inspect the request data and validation errors during test execution and take it from there.
Let me know how it goes!
- Bobby
I changed the last part to ->assertRedirect('characters');
and am now getting the following error:
Expected response status code [201, 301, 302, 303, 307, 308] but received 200.
Failed asserting that false is true.
Also here is out output of dd
:
App\Models\Character {#6756
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
+preventsLazyLoading: false
#perPage: 15
+exists: true
+wasRecentlyCreated: true
#escapeWhenCastingToString: false
#attributes: array:10 [
"user_id" => 23
"name" => "B"
"xp" => 543
"belt_id" => 18
"wins" => 11
"loses" => 83
"draws" => 78
"updated_at" => "2024-05-28 18:42:44"
"created_at" => "2024-05-28 18:42:44"
"id" => 10
]
#original: array:10 [
"user_id" => 23
"name" => "B"
"xp" => 543
"belt_id" => 18
"wins" => 11
"loses" => 83
"draws" => 78
"updated_at" => "2024-05-28 18:42:44"
"created_at" => "2024-05-28 18:42:44"
"id" => 10
]
#changes: []
#casts: array:1 [
"deleted_at" => "datetime"
]
#classCastCache: []
#attributeCastCache: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
+usesUniqueIds: false
#hidden: []
#visible: []
#fillable: array:4 [
0 => "user_id"
1 => "active"
2 => "name"
3 => "belt_id"
]
#guarded: array:1 [
0 => "*"
]
#forceDeleting: false
} // tests\Feature\Controllers\CharacterController\UpdateTest.php:77
Seems I forgot to update my factory, one second...
Hey!
Ok so it looks like that you are not hitting the redirect, so you should assert that the response is 200 rather than the redirect. How do things look after that?