Transcription: OpenAgents Episode 007 - First Feature Tests

June 9, 2026 ยท View on GitHub

Source: https://twitter.com/OpenAgentsInc/status/1722313899771347362 Wiki source: https://raw.githubusercontent.com/wiki/OpenAgentsInc/openagents/Video-Series.md Media title: OpenAgents - Episode 007: First Feature Tests We review our completed unit test sui... Upload date: 20231108 Transcription model: gpt-4o-transcribe-diarize Generated at: 2026-06-01T01:12:19Z

Machine-generated transcript. Review speaker labels and wording before using this as quote-grade source material.

[00:00] Christopher David: Okay, we now have all of our data models implemented in our code base with unit tests for all of them.

[00:13] Christopher David: Agent artifact conversation step task. User, our full test suite passes.

[00:20] Christopher David: Now we can start doing cool things with this. So...

[00:27] Christopher David: We have a bunch of unit tests, and in this video I want to get like a roadmap of feature tests written and then build our first few.

[00:41] Christopher David: So basically unit tests test one model or one small granular piece of functionality, and then feature tests are testing a feature like.

[00:54] Christopher David: User can create an agent.

[01:01] Christopher David: So

[01:05] Christopher David: let's make a list of feature tests.

[01:11] Christopher David: And let's go back to our doc.

[01:31] Christopher David: A user can create an agent,

[01:35] Christopher David: a user can upload a file,

[01:46] Christopher David: A user can create a conversation,

[01:50] Christopher David: user can send a message

[01:59] Christopher David: in a conversation.

[02:03] Christopher David: Agent can

[02:12] Christopher David: Agent can send a message,

[02:14] Christopher David: or agent can reply to a user message.

[02:30] Christopher David: So maybe the

[02:32] Christopher David: features should be broken up by chat

[02:39] Christopher David: plan act and actor or agent

[02:49] Christopher David: we've got to think about how to categorize these we've got like for example we've got profile test

[03:00] Christopher David: This is a feature test that we got from our Breeze scaffolding, testing that the profile pages is displayed,

[03:06] Christopher David: profile information can be displayed, updated, email verifications, blah blah blah.

[03:10] Christopher David: Different functionality related to a profile.

[03:13] Christopher David: And if there's a lot of different things in a category, you can get its own folder like auth.

[03:19] Christopher David: So I think for now,

[03:21] Christopher David: let's delete example test.

[03:29] Christopher David: Let's make some files.

[03:34] Christopher David: Think if we do like agent test and we put user can create an agent.

[03:45] Christopher David: And then if we do chat test,

[03:50] Christopher David: plan test.

[03:59] Christopher David: We can split those up later.

[04:07] Christopher David: So user can upload a file.

[04:11] Christopher David: We have file under chat.

[04:15] Christopher David: But that might be worth putting in a separate feature test.

[04:24] Christopher David: Let's just put it here for now.

[04:30] Christopher David: So we've got, user can upload a file.

[04:36] Christopher David: User can create a conversation.

[04:41] Christopher David: User can send a message in a conversation.

[04:46] Christopher David: Agent can send a message in a conversation.

[05:02] Christopher David: might actually call this a create agent test.

[05:08] Christopher David: Or maybe we'll do everything here.

[05:10] Christopher David: The user can delete an agent.

[05:25] Christopher David: What about for planning,

[05:27] Christopher David: task and step?

[05:31] Christopher David: This is something that the agent's going to do. An agent will

[05:39] Christopher David: break up a task into steps.

[05:44] Christopher David: I don't know what the feature tests for that quite yet.

[05:54] Christopher David: And acting...

[05:57] Christopher David: I don't know what to do for that yet.

[06:05] Christopher David: But I think we we should do if we order these we should do

[06:10] Christopher David: first do user can create an agent.

[06:16] Christopher David: User can create a conversation. That'll be a conversation with an agent.

[06:24] Christopher David: User can send a message.

[06:28] Christopher David: agent can send a message.

[06:31] Christopher David: User can upload a file.

[06:36] Christopher David: And say

[06:41] Christopher David: all this is in the conversation, so I'm just going to remove this.

[06:52] Christopher David: All right, so this is a logical order.

[06:56] Christopher David: And then when we get five or maybe four of these done,

[06:59] Christopher David: then

[07:02] Christopher David: we can start building out the UI.

[07:07] Christopher David: So let's commit this as - are these stubs? Test stubs comments.

[07:18] Christopher David: Okay,

[07:19] Christopher David: so let's do a test where a user can create an agent.

[07:22] Christopher David: test user can create an agent.

[07:32] Christopher David: And now this is going to be an API endpoint.

[07:44] Christopher David: On top of the,

[07:45] Christopher David: so the feature tests are usually just testing that the back end can support.

[07:49] Christopher David: That feature.

[07:51] Christopher David: Separately, we'll do like a final test, probably like a browser test where we're actually steering the browser and like stepping through the flow to hook up the full front end experience of it.

[08:03] Christopher David: But for now, we just want to have the we know that the back end can can do this.

[08:10] Christopher David: Let's say via API.

[08:11] Christopher David: Let's see if that changes what Copilot tells us.

[08:25] Christopher David: Post API agents.

[08:37] Christopher David: I think this is the syntax we want.

[09:04] Christopher David: Okay.

[09:11] Christopher David: Whether or not this is what we actually end up using, I don't know.

[09:17] Christopher David: And whether or not 201 is the correct status code for this,

[09:23] Christopher David: I don't know.

[09:23] Christopher David: That's what Copiot thinks.

[09:24] Christopher David: 201 created means that the request was successfully fulfilled and resulted in one or possibly multiple new resources being created.

[09:30] Christopher David: Yeah, I guess that sounds good.

[09:36] Christopher David: Okay, let's uh This looks not bad. Do agents even have a name? I don't know. But let's just step through this. Alright, so first of all

[09:47] Christopher David: Uh do we need to do this without exception handling here?

[09:51] Christopher David: I don't know where my auto-complete went.

[09:55] Christopher David: Okay, the post method is not supported for a route APX agents.

[10:07] Christopher David: I don't know if the API route.

[10:13] Christopher David: The API route file here attaches to middleware, and at least last time I was playing with this with inertia,

[10:19] Christopher David: like the example app I saw with inertia had the routes here for some reason. There's some like middleware thing I was having trouble with putting it in the API file,

[10:29] Christopher David: so we're just going to put them here.

[10:30] Christopher David: All right, so let's do a post handler for API.

[10:36] Christopher David: agents look at that let's

[10:44] Christopher David: just see what that is all

[10:47] Christopher David: right we can create an agent via API no because we are testing that we're getting back at 201 but that's because we're manually throwing it to one what we're gonna want to do here is

[11:01] Christopher David: put this functionality in a controller.

[11:05] Christopher David: So HTTP controller, we've got profile controller here.

[11:09] Christopher David: We're going to make an agent controller.

[11:15] Christopher David: And we're going to copy this namespace.

[11:19] Christopher David: And we're going to copy some of this stuff.

[11:35] Christopher David: And then over here, instead of just returning that there,

[11:39] Christopher David: what

[11:43] Christopher David: do we call this? Store.

[11:52] Christopher David: Instead of doing a function call,

[11:54] Christopher David: we're going to say agent controller.

[12:03] Christopher David: I should have in-line type hinting. Something's broken, I don't know why I don't use A_G_P_ control. There's agent controller,

[12:10] Christopher David: class

[12:13] Christopher David: and we usually do store for posting new things.

[12:24] Christopher David: Okay. We still got the same response.

[12:29] Christopher David: And

[12:29] Christopher David: And the next thing we need to do is say we are going to expect that there are one agents.

[12:47] Christopher David: We're going to begin by expecting that there are zero agents.

[13:00] Christopher David: Okay, so this assertion is working,

[13:03] Christopher David: there are zero agents,

[13:04] Christopher David: and then there is no new agents being created because we're not actually creating it. So let's create it.

[13:24] Christopher David: I don't know what all that stuff is.

[13:41] Christopher David: Okay, first of all, do we even have name as a thing?

[13:45] Christopher David: We don't have name as a thing.

[13:47] Christopher David: Should agents have a name?

[13:51] Christopher David: Yeah, I think agents should have a name.

[13:55] Christopher David: So first of all, this error add name to fillable property on agent.

[14:01] Christopher David: That's just like a guard against mass assignment,

[14:03] Christopher David: which I'm going to disable.

[14:07] Christopher David: Okay,

[14:07] Christopher David: now we're saying column name on relation agents does not exist.

[14:10] Christopher David: Now when we want to make a change to how things are handled at the model level,

[14:15] Christopher David: that's where a unit test will help us.

[14:18] Christopher David: So let's go to our agent test,

[14:20] Christopher David: our unit test,

[14:21] Christopher David: and

[14:26] Christopher David: let's do, that's going to run our feature test too.

[14:31] Christopher David: Let's do this. It.

[14:34] Christopher David: Has a name.

[14:40] Christopher David: Isn't that nice?

[14:43] Christopher David: p f name.

[14:47] Christopher David: Artifact has a name. Agent does not have a name.

[14:49] Christopher David: So agents actually

[14:52] Christopher David: just take the same field from here.

[14:56] Christopher David: Should it be nullable?

[14:59] Christopher David: I don't know.

[15:01] Christopher David: Okay, agent now has a name. So we'll run the previous test.

[15:09] Christopher David: Column email, we don't actually want email. That's not doesn't belong there.

[15:14] Christopher David: No password.

[15:19] Christopher David: And user ID cannot be null. The user ID has to belong to the current user.

[15:29] Christopher David: That's something I should make a test for,

[15:31] Christopher David: actually.

[15:45] Christopher David: Okay,

[15:45] Christopher David: so it's

[15:49] Christopher David: trying to read an ID off of the authenticated user,

[15:52] Christopher David: but there is no authenticated user.

[15:54] Christopher David: So...

[15:56] Christopher David: We don't want an authenticated user to be able to hit this API endpoint at all.

[16:01] Christopher David: So unauthenticated user cannot create an agent.

[16:15] Christopher David: Let's try this.

[16:19] Christopher David: Okay, looks like that's failing properly because we don't have...

[16:27] Christopher David: out lock down let's try this let's throw this middleware off on there see if that handles it

[16:37] Christopher David: unauthenticated that's cool

[16:40] Christopher David: so what we actually want is

[16:51] Christopher David: I'm just gonna

[16:52] Christopher David: Grab the proper syntax from our heh heh heh previous code base. This post.js on assert unauthorized. Isn't that nice.

[17:22] Christopher David: Yeah, doing that the same.

[17:27] Christopher David: It's just throwing a thing oh, that's 'cause it without exception handling. Oops.

[17:33] Christopher David: Alright.

[17:42] Christopher David: I guess I gotta assert the status too.

[17:50] Christopher David: Okay, so and now an unauthenticated user cannot create an agent via the API.

[17:54] Christopher David: So now if I do this test up here, I should get the error that I'm not logged in, unauthenticated.

[18:03] Christopher David: Okay,

[18:03] Christopher David: so now I want to act as a dummy user.

[18:06] Christopher David: So I'm just going to create a user and

[18:10] Christopher David: I'm going to act as that user.

[18:17] Christopher David: Mock that user being logged in. Okay, class user not found.

[18:27] Christopher David: Okay, test passes for user can create an agent via API.

[18:33] Christopher David: This exception handling thing.

[18:39] Christopher David: Let's run all of our tests.

[18:41] Christopher David: Our test pass.

[18:43] Christopher David: Okay,

[18:44] Christopher David: so what are we actually testing here?

[18:48] Christopher David: We're testing that a user, once they're logged in, can create an agent,

[18:54] Christopher David: and we're getting back,

[18:57] Christopher David: yes, it was created and an agent has been created.

[18:59] Christopher David: What else do we want to assert?

[19:05] Christopher David: Assert that the agent...

[19:09] Christopher David: Has the correct name.

[19:16] Christopher David: Like if I change this to Jane Doe,

[19:18] Christopher David: does

[19:21] Christopher David: that still work?

[19:25] Christopher David: No, because we're hard coding John Doe here.

[19:29] Christopher David: Get name from request.

[19:44] Christopher David: I don't think that's going to work.

[19:57] Christopher David: Yeah, this that's not right.

[19:59] Speaker B: Okay.

[20:02] Christopher David: Validation is good to do. Um pretty sure it's just request

[20:09] Christopher David: name maybe.

[20:14] Christopher David: Let's do this.

[20:22] Christopher David: Okay, that works.

[20:26] Christopher David: Now what else looks weird here? Um

[20:30] Christopher David: We're returning a hard-coded ID.

[20:34] Christopher David: I could

[20:38] Christopher David: Uh

[20:40] Christopher David: What do I even want to be returning?

[20:42] Christopher David: I'm just gonna remove that.

[20:48] Christopher David: Uh we're not validating that a name is required.

[20:53] Christopher David: So maybe we'll do another test.

[20:57] Christopher David: name is required to create an agent.

[21:09] Christopher David: Got this assert JSON validation errors. Let's see if that works.

[21:14] Christopher David: Expected a 422.

[21:15] Christopher David: What happens if I do this?

[21:24] Christopher David: Co-pilot is awesome as is Laravel.

[21:32] Christopher David: Okay so we are now testing that a user can create an agent via API.

[21:36] Christopher David: It creates an agent and the name is correct.

[21:41] Christopher David: Let's also assert that the agent belongs to this user.

[22:02] Christopher David: of a bit.

[22:13] Christopher David: Alright,

[22:13] Christopher David: we're

[22:18] Christopher David: asserting that the user can create an agent,

[22:20] Christopher David: it belonged to them, it has the right name. If they're not logged in they cannot and a name is required.

[22:28] Christopher David: And so if we test this for real,

[22:32] Christopher David: let's do,

[22:36] Christopher David: because we made changes to our previous migrations, I don't know the status of it, I'm just going to reset.

[22:43] Christopher David: php artisan,

[22:46] Christopher David: was it dB reset?

[22:49] Christopher David: dB migrate,

[22:52] Christopher David: migrate reset.

[22:57] Christopher David: Okay, rolling back migrations.

[23:03] Christopher David: We've run the migrations.

[23:08] Christopher David: And let's try something.

[23:09] Christopher David: Let's do php artisan tinker.

[23:15] Christopher David: Let's do user

[23:19] Christopher David: equals user factory.

[23:23] Christopher David: create.

[23:26] Christopher David: Out of curiosity, did that put that in our database?

[23:31] Christopher David: Yeah.

[23:37] Christopher David: And if I were to make a JSON post...

[23:53] Christopher David: I actually don't know how I would do that via Tinker.

[24:01] Christopher David: I wanted to make a demo API request,

[24:08] Christopher David: but being authenticated.

[24:11] Christopher David: I don't know how to mock that in Tinker.

[24:14] Christopher David: Let's ask our good friend ChatGPT.

[24:17] Christopher David: In Laravel Tinker,

[24:19] Christopher David: can we mock...

[24:22] Christopher David: A. Can we do an API call using an authenticated user to

[24:31] Christopher David: our local Laravel application?

[24:43] Christopher David: Hurry up.

[24:51] Christopher David: Alright, let's give this a try.

[24:57] Christopher David: So the user, we've already defined the user.

[25:03] Christopher David: Does this work?

[25:07] Christopher David: Yeah. And then let's do this. The local end point is

[25:17] Christopher David: localhost colon

[25:23] Christopher David: 8,000.

[25:31] Christopher David: Okay, so it's a POST request.

[25:33] Christopher David: POST, API,

[25:36] Christopher David: agents.

[25:42] Christopher David: So first of all, let's do it without passing the name and see what happens.

[26:03] Christopher David: Uh-oh.

[26:04] Christopher David: Error 419.

[26:19] Christopher David: I see.

[26:20] Christopher David: Ensure that the route you're trying to access.

[26:28] Christopher David: Out of curiosity,

[26:30] Christopher David: what if I put that in the API?

[26:32] Christopher David: API routes there. And that'll prefix that.

[26:37] Christopher David: Have to redo Tinker.

[26:42] Christopher David: User factory.

[26:48] Christopher David: Create a token.

[27:28] Christopher David: Ensure the accept application JSON.

[27:38] Christopher David: Okay,

[27:38] Christopher David: I'm actually going to not mess with that.

[27:44] Christopher David: In some cases, inertia handles things differently. There's some stuff that I just don't want to get into at this moment.

[27:56] Christopher David: um but

[28:00] Christopher David: anyway you got this cool console with php artisan tinker to be able to do cool stuff with all right so we have tests they pass um that's our first real feature test that we've written we are going to um i'll probably offline go do some chat um feature tests

[28:25] Christopher David: And then in the next video we will start building the interface for this and uh testing out these API endpoints via our new UI.

[28:37] Christopher David: See you soon.