so today I got something a little bit different for you guys I know we are working on a series right now but I wanted to take some time to do some
additional features for the coders Tape website now the very quick recap on this if you're not familiar I have this website coders tape com and what it does is basically it has the same exact
videos that we have in YouTube with the difference that there's some additional features if you register it is free let me go ahead and log in now you can mark lessons as completed for example let's
go to this first lesson here and we can simply mark this as complete it and so if you go back to this series now that one will have a little check mark and say completed additionally you could
take some notes here about the video and I figured this section here would sort of be your own sections and notes on this particular video and if we refresh of course those notes are saved what I
wanted to show you guys is I wanted to add some new features to the site and I figured it'd make a great video to show you guys sort of a behind the scenes of this actual app in production I want to
start off easy but today what I want to handle is I want to add a new link here for all new lessons so think about this if you've been watching coders tape lessons and you've been marking them as
completed say in the example of our 5.8 tutorial there's quite a bit of videos in there but if you've already marked a lot of them as completed perhaps what I want to do is just have a view of all of
the lessons you have not watched so we're gonna call those new lessons and it's just gonna be a cool real-world thing that I'm gonna implement now again if you're not registered with our
website it's free if you'd like to use it you're more than welcome to the website just gives you a little bit more of a classroom setting where you're actually taking notes instead of just
browsing through YouTube and hoping that the next lesson kind of comes up that's another nice feature here I did not show you that but if you are logged in let me go ahead and log in again then let's go
back here to this tutorial you do have this next button down here so if you hit next it goes of course to lesson two you could hit next again and we'll go to lesson three you can go to
previous and of course we'll go to lesson two and so on and so forth and you do read all the descriptions here and everything like that so I think it's a great start and it is a great
companion for all of our lessons so with that let's go ahead and jump into the source code for this site let's go to I term and of course let's start this with a test let's see PHP artisan make a test
for new lessons test all right let's go into phpstorm and let's go ahead and pull up that new lessons test and there we go all right let's go ahead and get rid of this default test here and let's
start with the new tests so the first thing that I want to test is obviously you cannot find out what lessons are new if you are not logged in so being logged in is a requirement now we don't have a
controller we don't have a route we don't really have anything just yet but we could definitely make this work through a TDD so let's say only authenticated users can access new
lessons so let's do this let's try to fetch that slash new lessons and let's see what happens what do you expect this to be well if we save the response then we can assert that we actually got
redirected so let's say response assert redirect and we redirect to slash login that's what would happen if we are not signed in all right let's go ahead and run this first test and see what we get
PHP unit - - filter and then our test name so obviously we get a 404 meaning nothing was found but this you know is not the correct error the error we have is the fact that this is not a real
address just yet so let's go ahead and run this without exception handling very quickly exception handling is just a way that levo handles
any exceptions that occur in our application what it does is it turns exceptions into correct HTTP responses in the case of this 404 it would make sense that if there is a route that
you're requesting that does not have a proper route then it's simply a 404 it was not found but the internal error is what we really want and this is the actual exception the exception is the
not found HTTP exception so when level handles the exception what it does is it turns is not found HTTP exception into a 404 which is obviously a proper HTTP response status code okay
so the get route of /nu lessons doesn't exist all right let's create that now back to phpstorm let's go to web that PHP and let's add a new route it's gonna be a get route for slash new
dash lessons and we're gonna go to a new lessons controller where should that hit well that's gonna hit an index right remember that an index just shows us a list of a resource so obviously these
new lessons we're gonna treat them as a resource and the index is the appropriate method for that let's go ahead and run the test again and this time we're probably going to get
something about the controller not existing so we'll copy that will say PHP artisan make a controller and here's the name for it let's run our test again and this time we get index does not exist we
know that we just created the controller but of course we didn't add anything to it so let's open up the new lessons controller and let's add a new method public function index alright and now
finally we get to the error part so we're getting a 200 which is just a proper response but we're really supposed to be getting a redirection so how do we make sure that somebody is
logged in remember in any controller you can add a constructor and just say this middleware off that will force the off middleware which will redirect us unless if you are
logged in let's check that out and now we get on authenticated so now we are getting the proper response but this exception in order for us to actually get the redirection then we need laravel
to go ahead and actually handle the exception so we need to turn this back on so that level can do its thing and sure enough we get green when we run it like that now one quick little side note
on that if you don't like putting it in your controller I'm going to go ahead and comment that out I'm gonna run my test again and of course we're gonna fail another approach is in your route
file you can actually say Aero middleware and then in here say off and sure enough you see that our test is back to green that is exactly the same thing the argument sometimes that comes
up when you put it in your routes is that it's a lot easier to see the overall picture of middleware when it's in your route because basically you don't have to open each controller to
find out if any middleware is being applied to that route I'm not a huge fan of it I do like having it in my controller so this is just the way that I default to it but again it may be
something that you may want to consider to put in your routes that's entirely up to you but we are green so let's move on to the next test so let's add a new test here in this next test I want to test
that the view has the correct data obviously we're gonna have to go into our database grab the correct lessons and the correct lessons are only lessons that have not
been marked as watched and we towerview to have that data so let's say only on completed lessons are passed to the view okay so let's go ahead and do something first and foremost as we proved with
this very first test we need to be logged in so level in the testing helpers we have this acting asset and to acting as you have to pass in a user now the nice thing is of course we can use
our Factory and just whip up a user right on the fly so we could save app user and then just call the create method on it if you want to clean this up of course you can import this class
as I did here so now the class is up here and that does clean it up a little bit because now you just see user in order to do that you need to have this up there well what's the next step we
need a lesson right we don't even have a lesson remember after every test we are getting a blank database so let's go ahead and use refresh database as a trait and
there it is it's this one that's up here you can actually get rid of that altogether clean it up and now let's go ahead and create a lesson so let's create lesson number one you know what
let's actually call it complete it lesson first of all let's call on our factory and I do have a lesson Factory let me show you that now very quickly so this is my lesson Factory so I can very
quickly create a lesson so let's say lesson class and let's go ahead and create one lesson now lesson is being imported up here at the top and there it is and so how do we complete a lesson
well I actually have a test just for that that I wrote in the current implementation so let's go to the features test and I have this lesson interactions test and if we look through
here I have this test that says a video can be marked as completed and it looks like all I need to do is hit a post to this route with the video ID and the video ID being simply just a lesson ID
and if I do that then that lesson gets marked as completed so I can actually reuse that so let's do a post request to slash complete slash the video ID and again the video ID is really just a
complete lesson ID it's just the ID of the lesson that we are trying to complete however if we just create one lesson and we complete it then we're not gonna have
any new lessons of course we want to be able to have new lessons so let's create another one and call this one uncompleted lesson and again we'll call to our Factory and say give me a new
lesson and let's create that ok so we have a completed lesson and we have an uncompleted lesson so what do we expect at this point well let's actually make the
request to let's say response equals this get what are we gonna get what we're gonna get / new - lessons and now what can we assert on this response well you can actually say a response like so
right and do something like assert okay for example or you can actually chain these together like so and I do like this flow a little bit better so we're gonna assert that it's okay let's go
ahead and start running our test it's not ready yet but let's go ahead and start running it so we can start getting some feedback so so far so good everything is good our code is good
syntax is good so what else can we assert so yes we are hitting this endpoint but now here's the thing we need the data that the view is receiving so let's do something let's do response
original and the original is simply just the original request not the response the actual request and that's what original gives us and there's a method in here called
get data so if I save this to maybe view data what can we ascertain how about this assert count first thing I want to do is I want to assert that there's only one lesson so even though I created two
lessons only one of them should show up so that's assert count 1 of view data and view data is actually an array so we can just request the key that we're looking for I'm gonna call that
uncompleted lessons in my view so let's go ahead and do that so we're gonna assert a count of one on that one and finally maybe just compare IDs I want the ID of the one uncompleted
lesson to be matched up to this uncompleted lesson right here so let's say this assert equals on completed lesson ID that should be the same as view data and then give me uncompleted
lessons and of that one that's actually going to be a collection so I just need the first one so we'll grab the first one and then grab its ID now to clean this up a little bit if we moved this
over to in here then we can actually get rid of it in each of these calls and I think that gets cleaned up a little bit all right so we are good to go on this test let's go ahead and give it a run
and see what kind of errors we get so right off the bat we're getting a member to a function of get data on No so that means that our view is null so we need to return a view let's go ahead and do
that here let's return a new view now I have this convention where I name my controllers and views the same way so this is my new lessons controller so I'm gonna call the
directory new - lessons and then this is the index method so I'm gonna put an index top blade that PHP file inside of there and let's go ahead and create a new directory and it's gonna be a new -
lessons and inside here let's create a new file which is gonna be index that blade that PHP and yes I do want to add them all right so inside this index top blade extends layouts dot app that's
just my layout and let's go ahead and start a new section for the content and section all right let's run our tests all right so undefined index of uncompleted lessons of course we are not
passing any data in the controller so of course that's not gonna work so let's go ahead and for now let me do uncompleted lessons I'm just gonna set that equal to an empty array now
obviously that's gonna fail but let's go ahead and pass that through to the view to uncompleted lessons run the test and now we get that we are asserting that an actual size of zero matches the size of
one so in true TDD fashion really acted literally just put anything in here and that would actually change our air which it does but now we're calling first on an array we really do know what's going
on here so let's just go ahead and start to implement what we really need so here's what I'm thinking every authenticated user has a relationship and that relationship is in
a belongs to many of completed lessons let me show you that let me go to my user that PHP file my model we have this completed relationship so I can fetch all of the complete relationships and
grab their IDs and then I could do a database query to go ahead and grab any lessons that are not in that list of IPs let's see what that would look like let's say complete it lessons not
uncompleted but completed lessons right that's what our user is gonna give us so let's just say off user meaning give me the authenticated user give me their completed and then pluck just their ID
all right let's see what we get there complete it lessons let me die and dump that and show you what that looks like just simply looks like a collection with an array and it has ID of one obviously
we created one completed lesson so that's why that ID is one armed with that information we could say lesson that is app lesson notice how it got imported up here so lesson we're not in
we're not in accepts two parameters the first one is the column that we're going to be comparing to so let's say ID and as a second parameter it accepts an array so let's go ahead and give it
completed lessons so what we're saying here is fetch me everything that is not in the completed lessons when you compare it to the ID column and go ahead and fetch me all of those records so
let's go ahead and die and dump uncompleted lessons this time and let's check out what we got and sure enough we have ID - and nothing else so we just have the single lesson
which is what we've been looking for okay let's run our test and see what we get and we are green awesome let's run the entire test not just a one test and yes we are still green okay so our back
end is set up let's switch over now and start talking about our front-end so of course our front-end is gonna have this new uncompleted lessons variable so what I'm thinking is just having rows for
each of the lessons so let's say for each uncompleted lessons as maybe just lesson to keep it nice and short and for each so for each one let's add a new row and the first thing I want is maybe
let's do a column of three and inside of there I want the image of each of the lessons now I do have this nice little helper that I put together in my lessons model let me show you that now so in my
lessons if we scroll up we have this image and what the image does is it basically just grabs the YouTube thumbnail now I do nice thumbnails for each of the videos and this is one of
the reasons why because I want to just be able to use that so I can just call this image method on each of those lessons and get an image so let's say source and then let's use the lesson
image for that lesson so for this first time we're actually gonna visit the browser notice I have not visited the browser once during this whole entire time so let's switch over to the local
version of the code escape site coders tape dot test slash new lessons and there we go so we have each of those as an image alright so obviously those
images are too large so let's give it a class of width of 100 there we go and those are still a little too big we'll play around with this a little bit there we go
that's more like what I was thinking so if we have a column of two let's add maybe a column of eight and let's just say an h2 let's try an h2 for now and let's grab the lesson title see what
that looks like alright so we have each of the titles now each of these rows do need a little bit of padding it's due padding bottom of three there we go that's a little bit
better and I would like this title to be down just a smidge just a little high so let me add a class to the h2 of padding top of two yeah like that and then underneath it let's add a
paragraph with maybe just a description so lesson description there we go so we have description of the lesson description of the lesson and so we have three plus eight that's eleven let's
just give it nine that way we can complete that so now this whole thing should be clickable so let me actually wrap all of this in an anchor tag and paste that back in and I
have another nice little helper in my lesson model let me show you that one that one is path and there it is URL path so URL path gives me the path to this lesson so all I have to do is
just say lesson give me URL path refresh and now we do have to go back and change this color a little bit but if you click on that then yes it takes you to that lesson so now let's go ahead and mess
with the color a little bit so let's say on this h2 let's say text dark and then on this one let's add a class of text dark as well okay so now we just need a title maybe for this page
and we'll say h1 of new lessons and then let's add a P tag for a little bit of a description of what we have here so here are the lessons that you have not completed yet happy coding and there we
go let's add a little bit of padding underneath this peep do padding bottom of five maybe I'll be too much let's do three and there we go so there it is that's the basic of it
the only last little bit that I have is when I click on here I do want to show this new lessons so let's tackle that now let's go to my navigation that's nav that blade what I did was I extract that
the navigation out as I typically do and let's look up for that logout that logout is right here so let's add another anchor with a class of drop drop down - item and where are we going to be
going we're gonna be going to slash new lessons and let's just call it new lessons let's check it out sure enough now we have this new lessons right here right on this drop down so I'm gonna do
a little bit more work behind the scenes getting this to look a little bit pretty and by the time you watch this video this is probably gonna be live on the actual website so go ahead and check it
out coders tape comm and of course you're gonna have to register to see this in action but that will complete today's lessons I hope you enjoyed this style of lesson as we're gonna be adding
more and more features to the coders tape website and I will continue to bring you guys along so you can see what we're doing behind the scenes so with that don't forget to subscribe and on
the next lesson we'll move on to something else
-
add videos
carbon laravel
embed youtube video
feature testing laravel
github
laravel
laravel 5.8
laravel carbon
laravel feature test
laravel feature testing
laravel phpunit
laravel phpunit testing
laravel tdd
laravel tdd tutorial
laravel test driven development
laravel test workflow
laravel testing
laravel testing controllers
laravel testing tutorial
laravel unit testing controllers
laravel vue
laravel vue js tutorial
laravel vue tutorial
learn laravel
phpunit
phpunit laravel
phpunit testing
test driven laravel
unit testing
unit testing laravel
vue events
vue laravel
vue laravel api
vue laravel crud
vue laravel tutorial
vue portal
vue video player
youtube video vue js