├── resources
├── assets
│ ├── css
│ │ └── app.css
│ └── js
│ │ └── app.js
└── views
│ └── posts
│ ├── show.blade.php
│ └── index.blade.php
├── .gitignore
├── config
└── config.php
├── src
├── Traits
│ └── HasPosts.php
├── Facades
│ └── Calculator.php
├── Events
│ └── PostWasCreated.php
├── Http
│ ├── Middleware
│ │ └── CapitalizeTitle.php
│ └── Controllers
│ │ ├── Controller.php
│ │ └── PostController.php
├── Listeners
│ └── UpdatePostTitle.php
├── Models
│ └── Post.php
├── Providers
│ └── EventServiceProvider.php
├── Calculator.php
├── Console
│ └── InstallBlogPackage.php
└── BlogPackageServiceProvider.php
├── routes
└── web.php
├── database
├── factories
│ └── PostFactory.php
└── migrations
│ ├── create_posts_table.php.stub
│ └── create_users_table.php.stub
├── tests
├── User.php
├── UserFactory.php
├── Unit
│ ├── CapitalizeTitleMiddlewareTest.php
│ ├── PostTest.php
│ └── InstallBlogPackageTest.php
├── TestCase.php
└── Feature
│ └── CreatePostTest.php
├── composer.json
├── phpunit.xml
└── README.md
/resources/assets/css/app.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/assets/js/app.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | vendor
3 | .idea
4 | .phpunit.result.cache
--------------------------------------------------------------------------------
/resources/views/posts/show.blade.php:
--------------------------------------------------------------------------------
1 |
{{ $post->title }}
2 |
3 | {{ $post->body }}
--------------------------------------------------------------------------------
/config/config.php:
--------------------------------------------------------------------------------
1 | 'posts',
5 | 'prefix' => 'blogpackage',
6 | 'middleware' => ['web'], // you probably want to include 'web' here
7 | ];
--------------------------------------------------------------------------------
/resources/views/posts/index.blade.php:
--------------------------------------------------------------------------------
1 | Showing all Posts
2 |
3 | @forelse ($posts as $post)
4 | {{ $post->title }}
5 | @empty
6 | 'No posts yet'
7 | @endforelse
8 |
--------------------------------------------------------------------------------
/src/Traits/HasPosts.php:
--------------------------------------------------------------------------------
1 | morphMany(Post::class, 'author');
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Facades/Calculator.php:
--------------------------------------------------------------------------------
1 | name('posts.index');
7 | Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
8 | Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
9 |
10 |
--------------------------------------------------------------------------------
/src/Events/PostWasCreated.php:
--------------------------------------------------------------------------------
1 | post = $post;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Http/Middleware/CapitalizeTitle.php:
--------------------------------------------------------------------------------
1 | has('title')) {
12 | $request->merge([
13 | 'title' => ucfirst($request->title)
14 | ]);
15 | }
16 |
17 | return $next($request);
18 | }
19 | }
--------------------------------------------------------------------------------
/src/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | post->update([
18 | 'title' => 'New: ' . $event->post->title
19 | ]);
20 | }
21 | }
--------------------------------------------------------------------------------
/src/Models/Post.php:
--------------------------------------------------------------------------------
1 | morphTo();
17 | }
18 |
19 | protected static function newFactory()
20 | {
21 | return \JohnDoe\BlogPackage\Database\Factories\PostFactory::new();
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
14 | UpdatePostTitle::class,
15 | ]
16 | ];
17 |
18 | /**
19 | * Register any events for your application.
20 | *
21 | * @return void
22 | */
23 | public function boot()
24 | {
25 | parent::boot();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/factories/PostFactory.php:
--------------------------------------------------------------------------------
1 | $this->faker->title,
26 | 'body' => $this->faker->paragraph,
27 | 'author_id' => 999,
28 | 'author_type' => 'Fake\Author',
29 | ];
30 | }
31 | }
--------------------------------------------------------------------------------
/tests/User.php:
--------------------------------------------------------------------------------
1 | $this->faker->name,
25 | 'email' => $this->faker->unique()->safeEmail,
26 | 'email_verified_at' => now(),
27 | 'password' => bcrypt('password'),
28 | 'remember_token' => \Illuminate\Support\Str::random(10),
29 | ];
30 | }
31 | }
--------------------------------------------------------------------------------
/tests/Unit/CapitalizeTitleMiddlewareTest.php:
--------------------------------------------------------------------------------
1 | merge(['title' => 'some title']);
19 |
20 | // when we pass the request to this middleware,
21 | // it should've capitalized the title
22 | (new CapitalizeTitle())->handle($request, function ($request) {
23 | $this->assertEquals('Some title', $request->title);
24 | });
25 | }
26 | }
--------------------------------------------------------------------------------
/database/migrations/create_posts_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->string('title');
19 | $table->text('body');
20 | $table->unsignedBigInteger('author_id');
21 | $table->string('author_type');
22 | $table->timestamps();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::dropIfExists('posts');
34 | }
35 | }
--------------------------------------------------------------------------------
/src/Calculator.php:
--------------------------------------------------------------------------------
1 | result = 0;
12 | }
13 |
14 | public function add(int $value)
15 | {
16 | $this->result += $value;
17 |
18 | return $this;
19 | }
20 |
21 | public function subtract(int $value)
22 | {
23 | $this->result -= $value;
24 |
25 | return $this;
26 | }
27 |
28 | public function multiplyBy(int $value)
29 | {
30 | $this->result *= $value;
31 |
32 | return $this;
33 | }
34 |
35 | public function divideBy(int $value)
36 | {
37 | $this->result /= $value;
38 |
39 | return $this;
40 | }
41 |
42 | public function result()
43 | {
44 | return $this->result;
45 | }
46 |
47 | public function __toString()
48 | {
49 | return "{$this->result}";
50 | }
51 | }
--------------------------------------------------------------------------------
/database/migrations/create_users_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->string('name');
19 | $table->string('email')->unique();
20 | $table->timestamp('email_verified_at')->nullable();
21 | $table->string('password');
22 | $table->rememberToken();
23 | $table->boolean('is_admin')->default(false);
24 | $table->timestamps();
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | *
31 | * @return void
32 | */
33 | public function down()
34 | {
35 | Schema::dropIfExists('users');
36 | }
37 | }
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | set('database.default', 'testbench');
17 | $app['config']->set('database.connections.testbench', [
18 | 'driver' => 'sqlite',
19 | 'database' => ':memory:',
20 | 'prefix' => '',
21 | ]);
22 |
23 | include_once __DIR__ . '/../database/migrations/create_posts_table.php.stub';
24 | include_once __DIR__ . '/../database/migrations/create_users_table.php.stub';
25 |
26 | // run the migration's up() method
27 | (new \CreatePostsTable)->up();
28 | (new \CreateUsersTable)->up();
29 | }
30 |
31 | protected function getPackageProviders($app)
32 | {
33 | return [
34 | BlogPackageServiceProvider::class,
35 | ];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "johndoe/blog-package",
3 | "description": "A demo package",
4 | "type": "library",
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "John Braun",
9 | "email": "johnbraun@pm.me"
10 | }
11 | ],
12 | "require": {},
13 | "autoload": {
14 | "psr-4":
15 | {
16 | "JohnDoe\\BlogPackage\\": "src"
17 | }
18 | },
19 | "autoload-dev": {
20 | "psr-4": {
21 | "JohnDoe\\BlogPackage\\Tests\\": "tests",
22 | "JohnDoe\\BlogPackage\\Database\\Factories\\": "database/factories"
23 | }
24 | },
25 | "require-dev": {
26 | "orchestra/testbench": "^6.0",
27 | "phpunit/phpunit": "^9.0"
28 | },
29 | "scripts": {
30 | "test": "vendor/bin/phpunit",
31 | "test-f": "vendor/bin/phpunit --filter"
32 | },
33 | "extra": {
34 | "laravel": {
35 | "providers": [
36 | "JohnDoe\\BlogPackage\\BlogPackageServiceProvider"
37 | ],
38 | "aliases": {
39 | "Calculator": "JohnDoe\\BlogPackage\\Facades\\Calculator"
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | src/
19 |
20 |
21 |
22 |
23 | ./tests/Unit
24 |
25 |
26 | ./tests/Feature
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/Http/Controllers/PostController.php:
--------------------------------------------------------------------------------
1 | middleware('capitalize');
13 | // }
14 |
15 | public function index()
16 | {
17 | $posts = Post::all();
18 |
19 | return view('blogpackage::posts.index', compact('posts'));
20 | }
21 |
22 | public function show()
23 | {
24 | $post = Post::findOrFail(request('post'));
25 |
26 | return view('blogpackage::posts.show', compact('post'));
27 | }
28 |
29 | public function store()
30 | {
31 | // Let's assume we need to be authenticated
32 | // to create a new post
33 | if (! auth()->check()) {
34 | abort (403, 'Only authenticated users can create new posts.');
35 | }
36 |
37 | request()->validate([
38 | 'title' => 'required',
39 | 'body' => 'required',
40 | ]);
41 |
42 | // Assume the authenticated user is the post's author
43 | $author = auth()->user();
44 |
45 | $post = $author->posts()->create([
46 | 'title' => request('title'),
47 | 'body' => request('body'),
48 | ]);
49 |
50 | event(new PostWasCreated($post));
51 |
52 | return redirect(route('posts.show', $post));
53 | }
54 | }
--------------------------------------------------------------------------------
/src/Console/InstallBlogPackage.php:
--------------------------------------------------------------------------------
1 | info('Installing BlogPackage...');
17 |
18 | $this->info('Publishing configuration...');
19 |
20 | if (! $this->configExists('blogpackage.php')) {
21 | $this->publishConfiguration();
22 | $this->info('Published configuration');
23 | } else {
24 | if ($this->shouldOverwriteConfig()) {
25 | $this->info('Overwriting configuration file...');
26 | $this->publishConfiguration($force = true);
27 | } else {
28 | $this->info('Existing configuration was not overwritten');
29 | }
30 | }
31 |
32 | $this->info('Installed BlogPackage');
33 | }
34 |
35 | private function configExists($fileName)
36 | {
37 | return File::exists(config_path($fileName));
38 | }
39 |
40 | private function shouldOverwriteConfig()
41 | {
42 | return $this->confirm(
43 | 'Config file already exists. Do you want to overwrite it?',
44 | false
45 | );
46 | }
47 |
48 | private function publishConfiguration($forcePublish = false)
49 | {
50 | $params = [
51 | '--provider' => "JohnDoe\BlogPackage\BlogPackageServiceProvider",
52 | '--tag' => "config"
53 | ];
54 |
55 | if ($forcePublish === true) {
56 | $params['--force'] = true;
57 | }
58 |
59 | $this->call('vendor:publish', $params);
60 | }
61 | }
--------------------------------------------------------------------------------
/tests/Unit/PostTest.php:
--------------------------------------------------------------------------------
1 | create(['title' => 'Fake Title']);
18 | $this->assertEquals('Fake Title', $post->title);
19 | }
20 |
21 | /** @test */
22 | function a_post_has_a_body()
23 | {
24 | $post = Post::factory()->create(['body' => 'Fake Body']);
25 | $this->assertEquals('Fake Body', $post->body);
26 | }
27 |
28 | /** @test */
29 | function a_post_has_an_author_id()
30 | {
31 | $post = Post::factory()->create(['author_id' => 999]);
32 | $this->assertEquals(999, $post->author_id);
33 | }
34 |
35 | /** @test */
36 | function a_post_has_an_author_type()
37 | {
38 | $post = Post::factory()->create(['author_type' => 'Fake\User']);
39 | $this->assertEquals('Fake\User', $post->author_type);
40 | }
41 |
42 |
43 | /** @test */
44 | function a_post_belongs_to_an_author()
45 | {
46 | // Given we have an author
47 | $author = User::factory()->create();
48 | // And this author has a Post
49 | $author->posts()->create([
50 | 'title' => 'My first fake post',
51 | 'body' => 'The body of this fake post',
52 | ]);
53 |
54 | $this->assertCount(1, Post::all());
55 | $this->assertCount(1, $author->posts);
56 |
57 | tap($author->posts()->first(), function ($post) use ($author) {
58 | $this->assertEquals('My first fake post', $post->title);
59 | $this->assertEquals('The body of this fake post', $post->body);
60 | $this->assertTrue($post->author->is($author));
61 | });
62 | }
63 | }
--------------------------------------------------------------------------------
/src/BlogPackageServiceProvider.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__.'/../config/config.php', 'blogpackage');
18 |
19 | $this->app->register(EventServiceProvider::class);
20 | }
21 |
22 | public function boot()
23 | {
24 | // Register a Facade
25 | // $this->app->bind('calculator', function ($app) {
26 | // return new Calculator();
27 | // });
28 |
29 | $this->registerRoutes();
30 |
31 | $this->loadViewsFrom(__DIR__.'/../resources/views', 'blogpackage');
32 |
33 | // // Register a global middleware
34 | $kernel = $this->app->make(Kernel::class);
35 | $kernel->pushMiddleware(CapitalizeTitle::class);
36 | //
37 | // // Register a route specific middleware
38 | // $router = $this->app->make(Router::class);
39 | // $router->aliasMiddleware('capitalize', CapitalizeTitle::class);
40 | // $router->pushMiddlewareToGroup('web', CapitalizeTitle::class);
41 |
42 |
43 | if ($this->app->runningInConsole()) {
44 | $this->publishes([
45 | __DIR__.'/../config/config.php' => config_path('blogpackage.php'),
46 | ], 'config');
47 |
48 | $this->commands([
49 | InstallBlogPackage::class,
50 | ]);
51 |
52 | if (! class_exists('CreatePostsTable')) {
53 | $this->publishes([
54 | __DIR__ . '/../database/migrations/create_posts_table.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_create_posts_table.php'),
55 | // you can add any number of migrations here
56 | ], 'migrations');
57 | }
58 |
59 | $this->publishes([
60 | __DIR__.'/../resources/views' => resource_path('views/vendor/blogpackage'),
61 | ], 'views');
62 |
63 | $this->publishes([
64 | __DIR__.'/../resources/assets' => public_path('blogpackage'),
65 | ], 'assets');
66 | }
67 | }
68 |
69 | public function registerRoutes()
70 | {
71 | Route::group($this->routeConfiguration(), function () {
72 | $this->loadRoutesFrom(__DIR__.'../../routes/web.php');
73 | });
74 | }
75 |
76 | public function routeConfiguration()
77 | {
78 | return [
79 | 'prefix' => config('blogpackage.prefix'),
80 | 'middleware' => config('blogpackage.middleware'),
81 | ];
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/tests/Unit/InstallBlogPackageTest.php:
--------------------------------------------------------------------------------
1 | cleanUp();
17 | }
18 |
19 | public function tearDown(): void
20 | {
21 | parent::tearDown();
22 |
23 | $this->cleanUp();
24 | }
25 |
26 | /** @test */
27 | public function the_install_command_copies_a_the_configuration()
28 | {
29 | $this->assertFalse(File::exists(config_path('blogpackage.php')));
30 |
31 | Artisan::call('blogpackage:install');
32 |
33 | $this->assertTrue(File::exists(config_path('blogpackage.php')));
34 | }
35 |
36 | /** @test */
37 | public function when_a_config_file_is_present_users_can_choose_to_not_overwrite_it()
38 | {
39 | // Given we have already have an existing config file
40 | File::put(config_path('blogpackage.php'), 'test contents');
41 | $this->assertTrue(File::exists(config_path('blogpackage.php')));
42 |
43 | // When we run the install command
44 | $command = $this->artisan('blogpackage:install');
45 |
46 | // We expect a warning that our configuration file exists
47 | $command->expectsConfirmation(
48 | 'Config file already exists. Do you want to overwrite it?',
49 | // When answered with "no"
50 | 'no'
51 | );
52 |
53 | // We should see a message that our file was not overwritten
54 | $command->expectsOutput('Existing configuration was not overwritten');
55 |
56 | // Assert that the original contents of the config file remain
57 | $this->assertEquals('test contents', file_get_contents(config_path('blogpackage.php')));
58 | }
59 |
60 | /** @test */
61 | public function when_a_config_file_is_present_users_can_choose_to_do_overwrite_it()
62 | {
63 | // Given we have already have an existing config file
64 | File::put(config_path('blogpackage.php'), 'test contents');
65 | $this->assertTrue(File::exists(config_path('blogpackage.php')));
66 |
67 | // When we run the install command
68 | $command = $this->artisan('blogpackage:install');
69 |
70 | // We expect a warning that our configuration file exists
71 | $command->expectsConfirmation(
72 | 'Config file already exists. Do you want to overwrite it?',
73 | // When answered with "yes"
74 | 'yes'
75 | );
76 |
77 | $command->execute();
78 |
79 | $command->expectsOutput('Overwriting configuration file...');
80 |
81 | // Assert that the original contents are overwritten
82 | $this->assertEquals(
83 | file_get_contents(__DIR__.'/../../config/config.php'),
84 | file_get_contents(config_path('blogpackage.php'))
85 | );
86 | }
87 |
88 | private function cleanUp()
89 | {
90 | if (File::exists(config_path('blogpackage.php'))) {
91 | unlink(config_path('blogpackage.php'));
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 | This package is meant to provide a reference when you're following along with the documentation on [LaravelPackage.com](https://laravelpackage.com). Along the way, we'll build a demo package (called "BlogPackage") by introducing the functionalities (as listed below) one-by-one. When something doesn't work as expected in your own package, you might use this repository to quickly find out if the bug is in your package or in the documentation (by running this package's test suite).
3 |
4 | ## Package contents
5 | The demo package features the following components:
6 | - [Package Service Provider](https://laravelpackage.com/03-service-providers.html)
7 | - [Database migrations](https://laravelpackage.com/08-models-and-migrations.html#migrations)
8 | - [Commands](https://laravelpackage.com/06-artisan-commands.html)
9 | - [Configuration (config file)](https://laravelpackage.com/07-configuration-files.html)
10 | - [Models](https://laravelpackage.com/08-models-and-migrations.html#models)
11 | - [Routes](https://laravelpackage.com/09-routing.html#routes)
12 | - [Views](https://laravelpackage.com/09-routing.html#views)
13 | - [Assets](https://laravelpackage.com/09-routing.html#assets)
14 | - [Controllers](https://laravelpackage.com/09-routing.html#controllers)
15 | - [Events & Listeners](https://laravelpackage.com/10-events-and-listeners.html)
16 | - [Facades](https://laravelpackage.com/05-facades.html#how-a-facade-works)
17 | - [Middleware](https://laravelpackage.com/11-middleware.html)
18 | - [Mailables](https://laravelpackage.com/12-mail.html)
19 | - [Traits](https://laravelpackage.com/08-models-and-migrations.html#providing-a-trait)
20 | - [Database Factories](https://laravelpackage.com/08-models-and-migrations.html#creating-a-model-factory) (for testing purposes)
21 |
22 | ## Installation and Usage
23 | - Clone this repository: `git clone git@github.com:Jhnbrn90/BlogPackage.git`
24 | - Install the dependencies: `composer install`
25 | - Confirm by running all tests: `composer test`
26 |
27 | Now you're free to use this demo package to your advantage. You can also include the demo package in a Laravel project if you wish, check the section below.
28 |
29 | ### Using this package in a Laravel project
30 | You can easily use this packge in a local Laravel project, after cloning:
31 |
32 | 1. Specify a new repository in your composer.json file of the Laravel project (not this package!):
33 | ```
34 | // composer.json
35 |
36 | {
37 | "repositories": [
38 | {
39 | "type": "path",
40 | "url": "../../blogpackage" // the relative path to your package
41 | }
42 | ]
43 | }
44 | ```
45 |
46 | 2. Require the package in the local Laravel project:
47 | ```
48 | composer require johndoe/blogpackage
49 | ```
50 |
51 | 3. Optionally publish the package assets:
52 |
53 | ```
54 | php artisan vendor:publish --provider="JohnDoe\BlogPackage\BlogPackageServiceProvider" --tag="config"
55 |
56 | php artisan vendor:publish --provider="JohnDoe\BlogPackage\BlogPackageServiceProvider" --tag="migrations"
57 |
58 | php artisan vendor:publish --provider="JohnDoe\BlogPackage\BlogPackageServiceProvider" --tag="views"
59 |
60 | php artisan vendor:publish --provider="JohnDoe\BlogPackage\BlogPackageServiceProvider" --tag="assets"
61 | ```
62 |
63 | ## Testing
64 | This package includes a Unit and Feature [test suite](https://laravelpackage.com/04-testing.html) covering all mentioned components. You can easily run all tests for this package using `composer test`, or a specific test using `composer test-f test-name-here`.
65 |
--------------------------------------------------------------------------------
/tests/Feature/CreatePostTest.php:
--------------------------------------------------------------------------------
1 | assertCount(0, Post::all());
23 |
24 | $author = User::factory()->create();
25 |
26 | $response = $this->actingAs($author)->post(route('posts.store'), [
27 | 'title' => 'My first fake title',
28 | 'body' => 'My first fake body',
29 | ]);
30 |
31 | $this->assertCount(1, Post::all());
32 |
33 | tap(Post::first(), function ($post) use ($response, $author) {
34 | $this->assertEquals('My first fake title', $post->title);
35 | $this->assertEquals('My first fake body', $post->body);
36 | $this->assertTrue($post->author->is($author));
37 | $response->assertRedirect(route('posts.show', $post));
38 | });
39 | }
40 |
41 | /** @test */
42 | function a_post_requires_a_title_and_a_body()
43 | {
44 | $author = User::factory()->create();
45 |
46 | $this->actingAs($author)->post(route('posts.store'), [
47 | 'title' => '',
48 | 'body' => 'Some valid body',
49 | ])->assertSessionHasErrors('title');
50 |
51 | $this->actingAs($author)->post(route('posts.store'), [
52 | 'title' => 'Some valid title',
53 | 'body' => '',
54 | ])->assertSessionHasErrors('body');
55 | }
56 |
57 | /** @test */
58 | function guests_can_not_create_posts()
59 | {
60 | // We're starting from an unauthenticated state
61 | $this->assertFalse(auth()->check());
62 |
63 | $this->post(route('posts.store'), [
64 | 'title' => 'A valid title',
65 | 'body' => 'A valid body',
66 | ])->assertForbidden();
67 | }
68 |
69 | /** @test */
70 | function all_posts_are_shown_on_the_index_route()
71 | {
72 | // Given we have a couple of Posts
73 | Post::factory()->create([
74 | 'title' => 'Post number 1'
75 | ]);
76 | Post::factory()->create([
77 | 'title' => 'Post number 2'
78 | ]);
79 | Post::factory()->create([
80 | 'title' => 'Post number 3'
81 | ]);
82 |
83 | // We expect them to all show up
84 | // with their title on the index route
85 | $this->get(route('posts.index'))
86 | ->assertSee('Post number 1')
87 | ->assertSee('Post number 2')
88 | ->assertSee('Post number 3')
89 | ->assertDontSee('Post number 4');
90 | }
91 |
92 | /** @test */
93 | function a_single_post_can_be_viewed_on_the_show_route()
94 | {
95 | $post = Post::factory()->create([
96 | 'title' => 'The single post title',
97 | 'body' => 'The single post body',
98 | ]);
99 |
100 | $this->get(route('posts.show', $post))
101 | ->assertSee('The single post title')
102 | ->assertSee('The single post body');
103 | }
104 |
105 | /** @test */
106 | function an_event_is_emitted_when_a_new_post_is_created()
107 | {
108 | Event::fake();
109 |
110 | $author = User::factory()->create();
111 |
112 | $this->actingAs($author)->post(route('posts.store'), [
113 | 'title' => 'A valid title',
114 | 'body' => 'A valid body',
115 | ]);
116 |
117 | $post = Post::first();
118 |
119 | Event::assertDispatched(PostWasCreated::class, function ($event) use ($post) {
120 | return $event->post->id === $post->id;
121 | });
122 | }
123 |
124 | /** @test */
125 | function a_newly_created_posts_title_will_be_changed()
126 | {
127 | $post = Post::factory()->create([
128 | 'title' => 'Initial title',
129 | ]);
130 |
131 | $this->assertEquals('Initial title', $post->title);
132 |
133 | (new UpdatePostTitle())->handle(
134 | new PostWasCreated($post)
135 | );
136 |
137 | $this->assertEquals('New: ' . 'Initial title', $post->fresh()->title);
138 | }
139 |
140 | /** @test */
141 | function the_title_of_a_post_is_updated_whenever_a_post_is_created()
142 | {
143 | $author = User::factory()->create();
144 |
145 | $this->actingAs($author)->post(route('posts.store'), [
146 | 'title' => 'A valid title',
147 | 'body' => 'A valid body',
148 | ]);
149 |
150 | $post = Post::first();
151 |
152 | $this->assertEquals('New: ' . 'A valid title', $post->title);
153 | }
154 |
155 | /** @test */
156 | function creating_a_post_will_capitalize_the_title()
157 | {
158 | $author = User::factory()->create();
159 |
160 | $this->actingAs($author)->post(route('posts.store'), [
161 | 'title' => 'some title that was not capitalized',
162 | 'body' => 'A valid body',
163 | ]);
164 |
165 | $post = Post::first();
166 |
167 | // 'New: ' was added by our even listener
168 | $this->assertEquals('New: Some title that was not capitalized', $post->title);
169 | }
170 | }
--------------------------------------------------------------------------------