add some test

This commit is contained in:
Romulus21
2024-04-01 19:47:15 +02:00
parent 8fcf3dd680
commit 1065da076d
7 changed files with 102 additions and 14 deletions

View File

@@ -63,12 +63,17 @@ class TimeTrackerController extends Controller
{ {
abort_if($timeTracker->toDo->user_id !== $request->user()->id, 401, __('auth.unauthorized')); abort_if($timeTracker->toDo->user_id !== $request->user()->id, 401, __('auth.unauthorized'));
$beforeDelay = $timeTracker->end_at->diffInSeconds($timeTracker->start_at);
$data = $request->validate([ $data = $request->validate([
'start_at' => ['required', 'date'], 'start_at' => ['required', 'date'],
'end_at' => ['nullable', 'date', 'after_or_equal:start_at'], 'end_at' => ['nullable', 'date', 'after_or_equal:start_at'],
]); ]);
$timeTracker->update($data); $timeTracker->update($data);
$timeTracker->fresh();
$afterDelay = $timeTracker->end_at->diffInSeconds($timeTracker->start_at);
$timeTracker->toDo->increment('duration', $afterDelay - $beforeDelay);
return response()->json(new TimeTrackerResource($timeTracker)); return response()->json(new TimeTrackerResource($timeTracker));
} }
@@ -76,9 +81,16 @@ class TimeTrackerController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
*/ */
public function destroy(TimeTracker $timeTracker) public function destroy(Request $request, TimeTracker $timeTracker)
{ {
// abort_if($timeTracker->toDo->user_id !== $request->user()->id, 401, __('auth.unauthorized'));
$delay = $timeTracker->end_at->diffInSeconds($timeTracker->start_at);
$timeTracker->toDo->decrement('duration', $delay);
$timeTracker->delete();
return response()->noContent();
} }
public function userTimeTracker(Request $request) public function userTimeTracker(Request $request)

View File

@@ -46,7 +46,11 @@ class ToDoController extends Controller
{ {
abort_if($todo->user_id !== $request->user()->id, 401, __('auth.unauthorized')); abort_if($todo->user_id !== $request->user()->id, 401, __('auth.unauthorized'));
$todo->update($request->validated()); $data = $request->validated();
if (isset($data['checked'])) {
$data['checked'] = $data['checked'] ? now() : null;
}
$todo->update($data);
return response()->json(new ToDoResource($todo)); return response()->json(new ToDoResource($todo));
} }

View File

@@ -23,7 +23,7 @@ class ToDoRequest extends FormRequest
{ {
return [ return [
'name' => ['string', 'min:3', 'max:255'], 'name' => ['string', 'min:3', 'max:255'],
'description' => ['string', 'max:2000'], 'description' => ['nullable', 'string', 'max:2000'],
'checked' => ['nullable', 'bool'], 'checked' => ['nullable', 'bool'],
]; ];
} }

View File

@@ -64,3 +64,9 @@ export const StopSVG: FC<ComponentProps<any>> = (props) => SVGSkeleton({
paths: <path d="M8 16h8V8H8zm4 6q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22"/>, paths: <path d="M8 16h8V8H8zm4 6q-2.075 0-3.9-.788t-3.175-2.137q-1.35-1.35-2.137-3.175T2 12q0-2.075.788-3.9t2.137-3.175q1.35-1.35 3.175-2.137T12 2q2.075 0 3.9.788t3.175 2.137q1.35 1.35 2.138 3.175T22 12q0 2.075-.788 3.9t-2.137 3.175q-1.35 1.35-3.175 2.138T12 22"/>,
...props ...props
}) })
export const TrashSVG: FC<ComponentProps<any>> = (props) => SVGSkeleton({
viewBox: "0 0 448 512",
paths: <path d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z" />,
...props
})

View File

@@ -2,7 +2,7 @@ import React, {FC, useEffect, useState} from "react"
import {useParams} from "react-router-dom" import {useParams} from "react-router-dom"
import useAxiosTools from "../../hooks/AxiosTools" import useAxiosTools from "../../hooks/AxiosTools"
import {timeTracker, toDo} from "../../utilities/types" import {timeTracker, toDo} from "../../utilities/types"
import {EditSVG} from "../../components/SVG" import {EditSVG, TrashSVG} from "../../components/SVG"
import Field, {TextArea} from "../../components/Field" import Field, {TextArea} from "../../components/Field"
import TimeTrackerEdit from "../../components/TimeTrackers/TimeTrackerEdit" import TimeTrackerEdit from "../../components/TimeTrackers/TimeTrackerEdit"
import {Modal} from "../../components/Modals" import {Modal} from "../../components/Modals"
@@ -70,7 +70,7 @@ export default ToDoShow
const ToDoTimeTrackers: FC<{toDo: toDo}> = ({toDo: toDo}) => { const ToDoTimeTrackers: FC<{toDo: toDo}> = ({toDo: toDo}) => {
const {setLoading, errorCatch, errorLabel, axiosGet} = useAxiosTools(true) const {setLoading, errorCatch, errorLabel, axiosGet, axiosDelete} = useAxiosTools(true)
const [timeTrackers, setTimeTrackers] = useState<timeTracker[]>([]) const [timeTrackers, setTimeTrackers] = useState<timeTracker[]>([])
const [showTrackers, setShowTrackers] = useState<timeTracker|null>(null) const [showTrackers, setShowTrackers] = useState<timeTracker|null>(null)
const [reload, setReload] = useState<timeTracker|null>(null) const [reload, setReload] = useState<timeTracker|null>(null)
@@ -112,6 +112,17 @@ const ToDoTimeTrackers: FC<{toDo: toDo}> = ({toDo: toDo}) => {
return (more ? '+' : '') + timer.durationify() return (more ? '+' : '') + timer.durationify()
} }
const destroyTimeTracker = async (timeTracker: timeTracker) => {
try {
await axiosDelete('/api/time-trackers/' + timeTracker.id)
await fetchTimeTrackers()
} catch (error) {
errorCatch(error)
} finally {
setLoading(false)
}
}
return <div className="p-5"> return <div className="p-5">
<div className="text-center">Temps passé : {timeSpend()}</div> <div className="text-center">Temps passé : {timeSpend()}</div>
{errorLabel()} {errorLabel()}
@@ -134,6 +145,11 @@ const ToDoTimeTrackers: FC<{toDo: toDo}> = ({toDo: toDo}) => {
<EditSVG className="w-5"/> <EditSVG className="w-5"/>
</button> </button>
</td> </td>
<td className="px-1 text-right">
<button onClick={() => destroyTimeTracker(timeTracker)}>
<TrashSVG className="w-5"/>
</button>
</td>
</tr>)} </tr>)}
</tbody> </tbody>
</table> </table>

View File

@@ -2,11 +2,13 @@
use App\Models\ToDo; use App\Models\ToDo;
use App\Models\User; use App\Models\User;
use Carbon\Carbon;
use Laravel\Sanctum\Sanctum; use Laravel\Sanctum\Sanctum;
test('user can start a time tracker', function () { test('user can start a time tracker', function () {
$this->withoutExceptionHandling();
Sanctum::actingAs($user = User::factory()->create()); Sanctum::actingAs($user = User::factory()->create());
$toDo = ToDo::factory()->create(['user_id' => $user->id, 'checked' => false]); $toDo = ToDo::factory()->create(['user_id' => $user->id, 'checked' => null]);
$this->postJson('/api/time-trackers', ['todo_id' => $toDo->id]) $this->postJson('/api/time-trackers', ['todo_id' => $toDo->id])
->assertCreated() ->assertCreated()
@@ -25,7 +27,7 @@ test('user can start a time tracker', function () {
test('user can retrieve his current timer', function () { test('user can retrieve his current timer', function () {
Sanctum::actingAs($user = User::factory()->create()); Sanctum::actingAs($user = User::factory()->create());
$toDo = ToDo::factory()->create(['user_id' => $user->id, 'checked' => false]); $toDo = ToDo::factory()->create(['user_id' => $user->id, 'checked' => null]);
$this->postJson('/api/time-trackers', ['todo_id' => $toDo->id]) $this->postJson('/api/time-trackers', ['todo_id' => $toDo->id])
->assertCreated(); ->assertCreated();
@@ -40,7 +42,7 @@ test('user can retrieve his current timer', function () {
'id' => $toDo->id, 'id' => $toDo->id,
'user_id' => $user->id, 'user_id' => $user->id,
'name' => $toDo->name, 'name' => $toDo->name,
'checked' => false, 'checked' => null,
], ],
]); ]);
}); });
@@ -54,7 +56,7 @@ test('user has no content response if not current time tracker', function () {
test('user can stop current time tracker', function () { test('user can stop current time tracker', function () {
Sanctum::actingAs($user = User::factory()->create()); Sanctum::actingAs($user = User::factory()->create());
$toDo = ToDo::factory()->create(['user_id' => $user->id, 'checked' => false]); $toDo = ToDo::factory()->create(['user_id' => $user->id, 'checked' => null]);
$this->postJson('/api/time-trackers', ['todo_id' => $toDo->id]) $this->postJson('/api/time-trackers', ['todo_id' => $toDo->id])
->assertCreated(); ->assertCreated();
@@ -65,3 +67,51 @@ test('user can stop current time tracker', function () {
expect($toDo->timeTrackers->first()) expect($toDo->timeTrackers->first())
->end_at->format('Y-m-d H:i:s')->toBe(now()->format('Y-m-d H:i:s')); ->end_at->format('Y-m-d H:i:s')->toBe(now()->format('Y-m-d H:i:s'));
}); });
test('user can destroy one of his time tracker', function () {
Sanctum::actingAs($user = User::factory()->create());
$toDo = ToDo::factory()->create(['user_id' => $user->id, 'duration' => 600, 'checked' => null]);
$timeTracker = $toDo->timeTrackers()->create([
'start_at' => now()->subMinutes(20),
'end_at' => now()->subMinutes(10),
]);
$this->deleteJson('/api/time-trackers/'.$timeTracker->id)
->assertNoContent();
});
test('user can retrieve all his time trackers', function () {
Sanctum::actingAs($user = User::factory()->create());
$toDo = ToDo::factory()->create(['user_id' => $user->id, 'duration' => 600, 'checked' => null]);
for ($i = 10; $i > 0; $i--) {
$toDo->timeTrackers()->create([
'start_at' => now()->subMinutes(20 + $i * 10),
'end_at' => now()->subMinutes(10 + $i * 10),
]);
}
$this->get('/api/time-trackers')
->assertOk()
->assertJsonCount(10)
->assertJson([
['id' => $toDo->timeTrackers()->orderBy('start_at', 'desc')->first()->id],
]);
});
test('user can update a time tracker', function () {
Sanctum::actingAs($user = User::factory()->create());
$toDo = ToDo::factory()->create(['user_id' => $user->id, 'duration' => 600, 'checked' => null]);
$date = '2024-04-01 14:00:00';
$timeTracker = $toDo->timeTrackers()->create([
'start_at' => Carbon::parse($date)->subMinutes(20),
'end_at' => Carbon::parse($date)->subMinutes(10),
]);
$this->putJson('/api/time-trackers/'.$timeTracker->id, [
'start_at' => $timeTracker->start_at->format('Y-m-d H:i:s'),
'end_at' => Carbon::parse($date)->subMinutes(9)->format('Y-m-d H:i:s'),
]);
expect($toDo->refresh())->duration->toBe(660);
});

View File

@@ -71,7 +71,7 @@ test('an user can retrieve a to do', function () {
Sanctum::actingAs($this->user); Sanctum::actingAs($this->user);
$toDos = ToDo::factory()->count(10)->create([ $toDos = ToDo::factory()->count(10)->create([
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'checked' => false, 'checked' => null,
]); ]);
$toDo = $toDos[rand(0, 9)]; $toDo = $toDos[rand(0, 9)];
@@ -91,7 +91,7 @@ test('an user can update a to do', function () {
Sanctum::actingAs($this->user); Sanctum::actingAs($this->user);
$toDos = ToDo::factory()->count(10)->create([ $toDos = ToDo::factory()->count(10)->create([
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'checked' => false, 'checked' => null,
]); ]);
$toDo = $toDos[rand(0, 9)]; $toDo = $toDos[rand(0, 9)];
@@ -103,7 +103,7 @@ test('an user can update a to do', function () {
'id' => $toDo->id, 'id' => $toDo->id,
'user_id' => $toDo->user_id, 'user_id' => $toDo->user_id,
'name' => 'update test', 'name' => 'update test',
'checked' => false, 'checked' => null,
]); ]);
expect(ToDo::find($toDo->id)) expect(ToDo::find($toDo->id))
@@ -114,7 +114,7 @@ test('an user can delete a to do', function () {
Sanctum::actingAs($this->user); Sanctum::actingAs($this->user);
$toDos = ToDo::factory()->count(10)->create([ $toDos = ToDo::factory()->count(10)->create([
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'checked' => false, 'checked' => null,
]); ]);
$toDo = $toDos[rand(0, 9)]; $toDo = $toDos[rand(0, 9)];