Skip to content

Commit

Permalink
Merge pull request #58 from IT-Academy-BCN/feature/Apps
Browse files Browse the repository at this point in the history
[BE] Apps Crud #54
  • Loading branch information
CloudSalander authored Jun 12, 2023
2 parents e094e07 + 4f1901f commit a71519b
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 1 deletion.
70 changes: 70 additions & 0 deletions app/Http/Controllers/api/AppController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace App\Http\Controllers\api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\App;

class AppController extends Controller
{
/**
* Display a listing of the Apps.
*/
public function index()
{
return response()->json(App::all());
}

/**
* Store a newly created App in storage.
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|max:255',
'description' => 'required',
'url' => 'required|url',
'state' => 'required|in:COMPLETED,IN PROGRESS,SOON',
]);

$app = App::create($validatedData);
return response()->json($app, 201);
}

/**
* Display the specified App.
*/
public function show($id)
{
$app = App::findOrFail($id);
return response()->json($app);
}

/**
* Update the specified App in storage.
*/
public function update(Request $request, $id)
{
$app = App::findOrFail($id);

$validatedData = $request->validate([
'title' => 'required|max:255',
'description' => 'required',
'url' => 'required|url',
'state' => 'required|in:COMPLETED,IN PROGRESS,SOON',
]);

$app->update($validatedData);
return response()->json($app, 200);
}

/**
* Remove the specified App from storage.
*/
public function destroy($id)
{
$app = App::findOrFail($id)->delete();
return response()->json(['message' => 'Deleted successfully']);
}
}
13 changes: 13 additions & 0 deletions app/Models/App.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class App extends Model
{
use HasFactory;

protected $fillable = ['title', 'description', 'url', 'state'];
}
28 changes: 28 additions & 0 deletions database/factories/AppFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\App>
*/
class AppFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [

'title' => fake()->title(),
'description' => fake()->text(),
'url' => fake()->url(),
'state' => fake()->randomElement(['COMPLETED', 'IN PROGRESS', 'SOON']),

];
}
}
2 changes: 1 addition & 1 deletion database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void
{
// \App\Models\User::factory(10)->create();
\App\Models\App::factory(10)->create();

\App\Models\User::factory(3)->create();
\App\Models\Faq::factory(3)->create();
Expand Down
11 changes: 11 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Http\Controllers\api\UserController;
use App\Http\Controllers\api\FaqController;
use App\Http\Controllers\api\AuthController;
use App\Http\Controllers\api\AppController;

/*
|--------------------------------------------------------------------------
Expand All @@ -27,3 +28,13 @@
Route::put('/{id}', [FaqController::class, 'update']);
Route::delete('/{id}', [FaqController::class, 'destroy']);
});

Route::middleware(['auth:api'])->group(function () {
Route::get('/apps', [AppController::class, 'index'])->name('app.index');
Route::get('/apps/{id}', [AppController::class, 'show'])->name('app.show');
Route::post('/apps', [AppController::class, 'store'])->name('app.store');
Route::put('/apps/{id}', [AppController::class, 'update'])->name('app.update');
Route::delete('/apps/{id}', [AppController::class, 'destroy'])->name('app.destroy');
});


220 changes: 220 additions & 0 deletions tests/Feature/AppTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Models\App;
use App\Models\User;

class AppTest extends TestCase
{
use RefreshDatabase;


public function test_can_get_all_apps(): void
{
App::factory(3)->create();

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->getJson(route('app.index'));

$response->assertStatus(200);
$response->json();
}

public function test_can_store_an_app_with_valid_data(): void
{
$app = [
'title' => fake()->title(),
'description' => fake()->text(),
'url' => fake()->url(),
'state' => fake()->randomElement(['COMPLETED', 'IN PROGRESS', 'SOON'])
];

$this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->postJson(route('app.store'), $app);

$this->assertDatabaseHas('apps', $app);
}

public function test_can_not_store_an_app_without_token(): void
{
$app = [
'title' => fake()->title(),
'description' => fake()->text(),
'url' => fake()->url(),
'state' => fake()->randomElement(['COMPLETED', 'IN PROGRESS', 'SOON'])
];

$response = $this->postJson(route('app.store'), $app);

$response->assertStatus(401);
}

public function test_can_not_store_an_app_with_a_missing_field(): void
{
$app = [
'title' => '',
'description' => fake()->text(),
'url' => fake()->url(),
'state' => fake()->randomElement(['COMPLETED', 'IN PROGRESS', 'SOON'])
];

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->postJson(route('app.store'), $app);

$response->assertStatus(422);
}

public function test_can_not_store_an_app_with_wrong_data(): void
{
$app = [
'title' => fake()->title(),
'description' => fake()->text(),
'url' => 123355, // must be text
'state' => fake()->randomElement(['COMPLETED', 'IN PROGRESS', 'SOON'])
];

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->postJson(route('app.store'), $app);

$response->assertJsonValidationErrorFor('url');

}

public function test_can_not_store_an_app_with_empty_fields(): void
{
$app = [
'title' => '',
'description' => '',
'url' => '',
'state' => [],
];

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->postJson(route('app.store'), $app);

$response->assertStatus(422);
}

public function test_can_show_an_app(): void
{
$app = App::factory()->create();

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->getJson(route('app.show', $app));

$response->assertJson([
'title' => $app->title,
'description' => $app->description,
'url' => $app->url,
'state' => $app->state,
]);
}

public function test_can_not_show_an_app_without_token(): void
{
$app = App::factory()->create();

$response = $this->getJson(route('app.show', $app));

$response->assertStatus(401);
}

public function test_can_not_show_an_app_that_it_doesnt_exists(): void
{
App::factory()->create();

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->getJson(route('app.show', ['id' => '2']));

$response->assertStatus(404);
}

public function test_can_update_an_app_with_valid_data(): void
{
$app = App::factory()->create();

$newData = [
'title' => 'Title updated',
'description' => $app->description,
'url' => $app->url,
'state' => $app->state,
];

$this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->putJson(route('app.update', $app->id), $newData);

$this->assertDatabaseHas('apps', $newData);
}

public function test_can_not_update_an_app_without_token(): void
{
$app = App::factory()->create();

$newData = [
'title' => 'Title updated',
'description' => $app->description,
'url' => $app->url,
'state' => $app->state,
];

$response = $this->putJson(route('app.update', $app->id), $newData);

$response->assertStatus(401);
}

public function test_can_not_update_an_app_with_missing_field(): void
{
$app = App::factory()->create();

$newData = [
'title' => '',
'description' => $app->description,
'url' => $app->url,
'state' => $app->state,
];

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->putJson(route('app.update', $app->id), $newData);

$response->assertStatus(422);
}

public function test_can_delete_an_app(): void
{
$app = App::factory()->create();

$this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->deleteJson(route('app.destroy', $app));

$this->assertDatabaseCount('apps', 0);
}

public function test_can_not_delete_an_app_that_it_doesnt_exists(): void
{
App::factory()->create();

$response = $this->withHeaders(['Authorization' => 'Bearer ' . $this->authCreated()])->deleteJson(route('app.destroy', ['id' => '2']));

$response->assertStatus(404);
}

public function test_can_not_delete_an_app_without_token(): void
{
$app = App::factory()->create();

$response = $this->deleteJson(route('app.destroy', $app));

$response->assertStatus(401);
}

private function authCreated()
{
\Artisan::call('passport:install');

$user = User::create([
'name' => 'Gabriela',
'email' => '[email protected]',
'dni' => '39986946S',
'password' => bcrypt('password'),
'status' => 'ACTIVE',
'role' => 'ADMIN',
]);
return $token = $user->createToken('auth_token')->accessToken;

}

}

0 comments on commit a71519b

Please sign in to comment.