@powerhousedao/academy 5.1.0-staging.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +46 -1148
  2. package/blog/BeyondCommunication-ABlueprintForDevelopment.md +1 -2
  3. package/blog/TheChallengeOfChange.md +0 -1
  4. package/docs/academy/00-EthereumArgentinaHackathon.md +207 -0
  5. package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +27 -24
  6. package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +10 -155
  7. package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +35 -122
  8. package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +155 -178
  9. package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +218 -0
  10. package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/05-VetraStudio.md +22 -62
  11. package/docs/academy/01-GetStarted/06-ReactorMCP.md +58 -0
  12. package/docs/academy/01-GetStarted/_04-BuildToDoListEditor +1 -1
  13. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +2 -2
  14. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +44 -75
  15. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +22 -28
  16. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +31 -28
  17. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +206 -211
  18. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +62 -176
  19. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +0 -21
  20. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +319 -309
  21. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +0 -4
  22. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +0 -4
  23. package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -1
  24. package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +35 -111
  25. package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +79 -195
  26. package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +241 -435
  27. package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +27 -388
  28. package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +7 -95
  29. package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
  30. package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +2 -6
  31. package/docs/academy/04-APIReferences/01-ReactHooks.md +501 -291
  32. package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +39 -7
  33. package/docs/academy/05-Architecture/02-ReferencingMonorepoPackages +65 -0
  34. package/docs/academy/05-Architecture/04-MovingBeyondCRUD +61 -0
  35. package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +24 -72
  36. package/docs/academy/08-Glossary.md +0 -7
  37. package/docusaurus.config.ts +3 -28
  38. package/package.json +1 -1
  39. package/sidebars.ts +13 -49
  40. package/src/css/custom.css +18 -26
  41. package/docs/academy/01-GetStarted/04-WriteDocumentModelTests.md +0 -425
  42. package/docs/academy/01-GetStarted/05-BuildToDoListEditor.md +0 -557
  43. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/images/Modules.png +0 -0
  44. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/images/VetraStudioDrive.png +0 -0
  45. package/docs/academy/02-MasteryTrack/05-Launch/05-DockerDeployment.md +0 -384
  46. package/docs/academy/03-ExampleUsecases/TodoList/00-GetTheStarterCode.md +0 -24
  47. package/docs/academy/03-ExampleUsecases/TodoList/01-GenerateTodoListDocumentModel.md +0 -211
  48. package/docs/academy/03-ExampleUsecases/TodoList/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +0 -171
  49. package/docs/academy/03-ExampleUsecases/TodoList/03-AddTestsForTodoListActions.md +0 -462
  50. package/docs/academy/03-ExampleUsecases/TodoList/04-GenerateTodoListDocumentEditor.md +0 -45
  51. package/docs/academy/03-ExampleUsecases/TodoList/05-ImplementTodoListDocumentEditorUIComponents.md +0 -422
  52. package/docs/academy/03-ExampleUsecases/TodoList/06-GenerateTodoDriveExplorer.md +0 -61
  53. package/docs/academy/03-ExampleUsecases/TodoList/07-AddSharedComponentForShowingTodoListStats.md +0 -384
  54. package/docs/academy/03-ExampleUsecases/TodoList/_category_.json +0 -8
  55. package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/VetraPackageLibrary.md +0 -7
  56. package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/_category_.json +0 -9
  57. package/docs/academy/04-APIReferences/06-VetraRemoteDrive.md +0 -160
  58. package/docs/academy/04-APIReferences/renown-sdk/00-Overview.md +0 -316
  59. package/docs/academy/04-APIReferences/renown-sdk/01-Authentication.md +0 -672
  60. package/docs/academy/04-APIReferences/renown-sdk/02-APIReference.md +0 -957
  61. package/docs/academy/04-APIReferences/renown-sdk/_category_.json +0 -8
  62. package/docs/academy/10-TodoListTutorial/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +0 -171
  63. package/docs/academy/10-TodoListTutorial/03-AddTestsForTodoListActions.md +0 -462
  64. package/docs/academy/10-TodoListTutorial/05-ImplementTodoListDocumentEditorUIComponents.md +0 -422
  65. package/docs/academy/10-TodoListTutorial/07-AddSharedComponentForShowingTodoListStats.md +0 -370
  66. package/static/img/Vetra-logo-dark.svg +0 -11
  67. package/static/img/vetra-logo-light.svg +0 -11
  68. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/{02-RevisionHistoryTimeline/360/237/232/247" → 02-RevisionHistoryTimeline} +0 -0
  69. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /01-WhatIsADocumentModel" → 01-WhatIsADocumentModel} +0 -0
  70. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /02-DAOandDocumentsModelsQ+A" → 02-DAOandDocumentsModelsQ+A} +0 -0
  71. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /02-domain-modeling" → 02-domain-modeling} +0 -0
  72. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /03-BenefitsOfDocumentModels" → 03-BenefitsOfDocumentModels} +0 -0
  73. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /04-UtilitiesAndTips" → 04-UtilitiesAndTips} +0 -0
  74. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /05-best-practices" → 05-best-practices} +0 -0
  75. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /_category_.json" → _category_.json} +0 -0
  76. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /three-data-layers.png" → three-data-layers.png} +0 -0
@@ -1,8 +0,0 @@
1
- {
2
- "label": "Renown SDK",
3
- "position": 6,
4
- "link": {
5
- "type": "generated-index",
6
- "description": "Complete documentation for the Renown SDK - authentication and user profile management for React applications."
7
- }
8
- }
@@ -1,171 +0,0 @@
1
- # Step 2 — Implement the `TodoList` document model reducer operation handlers
2
-
3
- ## Adding the logic for handling operations with reducers
4
-
5
- Your document model update's the state of a given document by applying a set of append-only actions. Once these have been applied to the document, we call them operations.
6
-
7
- The document model does this with a reducer — a function which takes the existing state and a given action, and then returns the new state with the action applied.
8
-
9
- ## What we have so far
10
-
11
- The operation handler logic for each module is found in `document-models/SOME-DOCUMENT-MODEL/src/reducers/SOME-MODULE-NAME.ts`.
12
-
13
- So for our todos module, we will implement our handler logic in `document-models/todo-list/src/reducers/todos.ts`
14
-
15
- When you generated your document model code, we created a boilerplate implementation of the reducer logic for each of the operations we defined in step 1. You will see that there are functions for handling each of the operations, but all they do is throw "not implemented" errors.
16
-
17
- ```ts
18
- import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
19
-
20
- export const todoListTodosOperations: TodoListTodosOperations = {
21
- addTodoItemOperation(state, action) {
22
- // TODO: Implement "addTodoItemOperation" reducer
23
- throw new Error('Reducer "addTodoItemOperation" not yet implemented');
24
- },
25
- updateTodoItemOperation(state, action) {
26
- // TODO: Implement "updateTodoItemOperation" reducer
27
- throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
28
- },
29
- deleteTodoItemOperation(state, action) {
30
- // TODO: Implement "deleteTodoItemOperation" reducer
31
- throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
32
- },
33
- };
34
- ```
35
-
36
- Let's add the handler logic for each operation in the same order we defined them in the previous step.
37
-
38
- To handle the `addTodoItemOperation`, all we need to do is create an `id` for our new operation, and then push an object with that `id` and the rest of the action input into the `items` array in our state.
39
-
40
- Update your `addTodoItemOperation` like so:
41
-
42
- ```typescript
43
- import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
44
-
45
- export const todoListTodosOperations: TodoListTodosOperations = {
46
- // removed-start
47
- addTodoItemOperation(state, action) {
48
- // TODO: Implement "addTodoItemOperation" reducer
49
- throw new Error('Reducer "addTodoItemOperation" not yet implemented');
50
- },
51
- // removed-end
52
- // added-start
53
- addTodoItemOperation(state, action) {
54
- const id = generateId();
55
- state.items.push({ ...action.input, id, checked: false });
56
- },
57
- // added-end
58
- updateTodoItemOperation(state, action) {
59
- // TODO: Implement "updateTodoItemOperation" reducer
60
- throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
61
- },
62
- deleteTodoItemOperation(state, action) {
63
- // TODO: Implement "deleteTodoItemOperation" reducer
64
- throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
65
- },
66
- };
67
- ```
68
-
69
- Under the hood, we use a library for making the functions always create and return new copies of the state, i.e. they are always _immutable_. This is why you don't actually have to return your new state, the newly created copy of the state is used automatically.
70
-
71
- The `updateTodoOperation` works in much the same way, except this time instead of creating a new `id`, we find the item in the items array which has the given id. Then we spread out the rest of the values we get from the action input, same as when creating.
72
-
73
- Update your `updateTodoOperation` to be like so:
74
-
75
- ```typescript
76
- export const todoListTodosOperations: TodoListTodosOperations = {
77
- addTodoItemOperation(state, action) {
78
- const id = generateId();
79
- state.items.push({ ...action.input, id, checked: false });
80
- },
81
- // removed-start
82
- updateTodoItemOperation(state, action) {
83
- // TODO: Implement "updateTodoItemOperation" reducer
84
- throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
85
- },
86
- // removed-end
87
- // added-start
88
- updateTodoItemOperation(state, action) {
89
- const item = state.items.find((item) => item.id === action.input.id);
90
- if (!item) return;
91
- item.text = action.input.text ?? item.text;
92
- item.checked = action.input.checked ?? item.checked;
93
- },
94
- // added-end
95
- deleteTodoItemOperation(state, action) {
96
- // TODO: Implement "deleteTodoItemOperation" reducer
97
- throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
98
- }
99
- };
100
- ```
101
-
102
- The delete operation is the simplest of the three. All we need to do is filter the items array so that it no longer contains the item with the given id.
103
-
104
- ```typescript
105
- export const todoListTodosOperations: TodoListTodosOperations = {
106
- addTodoItemOperation(state, action) {
107
- const id = generateId();
108
- state.items.push({ ...action.input, id, checked: false });
109
- },
110
- updateTodoItemOperation(state, action) {
111
- const item = state.items.find((item) => item.id === action.input.id);
112
- if (!item) return;
113
- item.text = action.input.text ?? item.text;
114
- item.checked = action.input.checked ?? item.checked;
115
- },
116
- // removed-start
117
- deleteTodoItemOperation(state, action) {
118
- // TODO: Implement "deleteTodoItemOperation" reducer
119
- throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
120
- },
121
- // removed-end
122
- // added-start
123
- deleteTodoItemOperation(state, action) {
124
- state.items = state.items.filter((item) => item.id !== action.input.id);
125
- },
126
- // added-end
127
- };
128
- ```
129
-
130
- With that all done, your final result should look like this:
131
-
132
- ```ts
133
- import { generateId } from "document-model/core";
134
- import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
135
-
136
- export const todoListTodosOperations: TodoListTodosOperations = {
137
- addTodoItemOperation(state, action) {
138
- const id = generateId();
139
- state.items.push({ ...action.input, id, checked: false });
140
- },
141
- updateTodoItemOperation(state, action) {
142
- const item = state.items.find((item) => item.id === action.input.id);
143
- if (!item) return;
144
- item.text = action.input.text ?? item.text;
145
- item.checked = action.input.checked ?? item.checked;
146
- },
147
- deleteTodoItemOperation(state, action) {
148
- state.items = state.items.filter((item) => item.id !== action.input.id);
149
- },
150
- };
151
- ```
152
-
153
- ## Check your work
154
-
155
- To make sure all works as expected, we should:
156
-
157
- - check types
158
- run: `pnpm tsc`
159
-
160
- - check linting
161
- run: `pnpm lint`
162
-
163
- - check tests
164
- run: `pnpm test`
165
-
166
- - make sure your code matches the code in the completed step branch
167
- run: `git diff your-branch-name step-2-complete-implemented-todo-list-document-model-reducer-operation-handlers`
168
-
169
- ### Up next: tests for our new operation handlers
170
-
171
- Up next, you'll implement some custom tests to check the behavior of our new code.
@@ -1,462 +0,0 @@
1
- # Step 3 — Adding our own tests for the document model actions
2
-
3
- Similarly to the operation handler logic, when you add a new module to your document model, we generate some boilerplate tests for your code.
4
-
5
- Take a look in `document-models/todo-list/src/tests/todos.test.ts`
6
-
7
- You will see that we have some basic "sanity check" style tests for you already. These make sure that your operations are at least able to result in a valid document model state. You should copy these boilerplate checks in your other tests to ensure that your outputs are valid.
8
-
9
- ```ts
10
- /**
11
- * This is a scaffold file meant for customization:
12
- * - change it by adding new tests or modifying the existing ones
13
- */
14
-
15
- import { describe, it, expect } from "vitest";
16
- import { generateMock } from "@powerhousedao/codegen";
17
- import {
18
- reducer,
19
- utils,
20
- isTodoListDocument,
21
- addTodoItem,
22
- AddTodoItemInputSchema,
23
- updateTodoItem,
24
- UpdateTodoItemInputSchema,
25
- deleteTodoItem,
26
- DeleteTodoItemInputSchema,
27
- } from "todo-tutorial/document-models/todo-list";
28
-
29
- describe("Todos Operations", () => {
30
- it("should handle addTodoItem operation", () => {
31
- // the `createDocument` utility function from your document model creates
32
- // an a new empty document, i.e. one with your default initial state
33
- const document = utils.createDocument();
34
-
35
- // the generate mock function takes one of your generated input schemas
36
- // and creates an object populated with random values for each field
37
- const input = generateMock(AddTodoItemInputSchema());
38
-
39
- // we call your document model's reducer with the new document we just created
40
- // and the action we want to test, `addTodoItem` in this case
41
- // the reducer returns a new object, which is the document with the action applied
42
- // if successful, there will be an operation which corresponds to this action
43
- // in the updated document's operations list
44
- const updatedDocument = reducer(document, addTodoItem(input));
45
-
46
- // when you generate a document model, we give you some validation utilities like
47
- // `isTodoListDocument` which confirms the document is of the correct form in a way
48
- // that typescript recognizes
49
- expect(isTodoListDocument(updatedDocument)).toBe(true);
50
-
51
- // at the start a document will have 0 operations, so after applying this action
52
- // there should now be one operation
53
- expect(updatedDocument.operations.global).toHaveLength(1);
54
-
55
- // the operation added to the list should correspond to the correct action type
56
- expect(updatedDocument.operations.global[0].action.type).toBe(
57
- "ADD_TODO_ITEM",
58
- );
59
-
60
- // the operation added should have used the correct input
61
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
62
- input,
63
- );
64
-
65
- // the index of the operation should be 0, since it is the first and only operation
66
- expect(updatedDocument.operations.global[0].index).toEqual(0);
67
- });
68
- it("should handle updateTodoItem operation", () => {
69
- // ...
70
- });
71
- it("should handle deleteTodoItem operation", () => {
72
- // ...
73
- });
74
- });
75
- ```
76
-
77
- Since testing the `addTodoItemOperation` is such a simple case, we have not added further testing here. You are welcome to add a more test cases for it if you want.
78
-
79
- ## Tests for update operations
80
-
81
- ### Test updating the todo item text
82
-
83
- Let's add some more sophisticated tests for our `updateTodoItem` operation. We want to know that we can update todos successfully, and that we we do so it only changes the values we want to change, while leaving the rest as is.
84
-
85
- Delete the existing "should handle updateTodoItem operation" test.
86
-
87
- ```typescript
88
- // removed-start
89
- it("should handle updateTodoItem operation", () => {
90
- const document = utils.createDocument();
91
- const input = generateMock(UpdateTodoItemInputSchema());
92
- const updatedDocument = reducer(document, updateTodoItem(input));
93
- expect(isTodoListDocument(updatedDocument)).toBe(true);
94
- expect(updatedDocument.operations.global).toHaveLength(1);
95
- expect(updatedDocument.operations.global[0].action.type).toBe(
96
- "UPDATE_TODO_ITEM",
97
- );
98
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
99
- input,
100
- );
101
- expect(updatedDocument.operations.global[0].index).toEqual(0);
102
- });
103
- // removed-end
104
- ```
105
-
106
- Let's test that the text of a todo item is updated correctly first. Put this code in the place where you just deleted the existing test case:
107
-
108
- ```ts
109
- it("should handle updateTodoItem operation to update text", () => {
110
- // we need there to already be a todo item in the document,
111
- // since we want to test updating an existing document
112
- const mockItem = generateMock(TodoItemSchema());
113
-
114
- // we also need to generate a mock input for the update operation we are testing
115
- const input: UpdateTodoItemInput = generateMock(
116
- UpdateTodoItemInputSchema(),
117
- );
118
-
119
- // since the mocks are generated with random values, we need to set the `id` on our mock input
120
- // to match the `id` of the existing mock input
121
- input.id = mockItem.id;
122
-
123
- // we want to easily check if the item's text was updated to be our new value,
124
- // so we assign a variable and use that for the mock input's text field
125
- const newText = "new text";
126
- input.text = newText;
127
-
128
- // we are only testing updating the text here, so we want the checked field on the input
129
- // to be undefined, i.e. it should not change anything on the existing item
130
- input.checked = undefined;
131
-
132
- // we can pass a different initial state to the `createDocument` utility,
133
- // so in this case we pass in an `items` array with our existing item already in it
134
- const document = utils.createDocument({
135
- global: {
136
- items: [mockItem],
137
- },
138
- });
139
-
140
- /* The following checks are copied from the boilerplate */
141
-
142
- // create an updated document by applying the reducer with the action and input
143
- const updatedDocument = reducer(document, updateTodoItem(input));
144
-
145
- // use our validator to check that the document conforms to the document model schema
146
- expect(isTodoListDocument(updatedDocument)).toBe(true);
147
-
148
- // there should now be one operation in the operations list
149
- expect(updatedDocument.operations.global).toHaveLength(1);
150
-
151
- // the operation applied should correspond to an action of the correct type
152
- expect(updatedDocument.operations.global[0].action.type).toBe(
153
- "UPDATE_TODO_ITEM",
154
- );
155
-
156
- // the operation applied should have used the correct input
157
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
158
- input,
159
- );
160
-
161
- // the operation applied should be the first operation in the list
162
- expect(updatedDocument.operations.global[0].index).toEqual(0);
163
-
164
- /* The following checks are unique to this test case */
165
-
166
- // find the updated item in the items list by its `id`
167
- const updatedItem = updatedDocument.state.global.items.find(
168
- (item) => item.id === input.id,
169
- );
170
-
171
- // the item's text should now be updated to be our new text
172
- expect(updatedItem?.text).toBe(newText);
173
-
174
- // the item's `checked` field should be unchanged.
175
- expect(updatedItem?.checked).toBe(mockItem.checked);
176
- });
177
- ```
178
-
179
- #### Check your work
180
-
181
- Running `pnpm tsc && pnpm lint && pnpm test` should pass
182
-
183
- ### Test updating the todo item checked state
184
-
185
- Now let's do the same thing, but for the checked state of an item. This test is essentially just the same as the above, but we update the `checked` field while leaving the `text` field `undefined`.
186
-
187
- Add this code below the test case we just added:
188
-
189
- ```ts
190
- it("should handle updateTodoItem operation to update checked", () => {
191
- // generate a mock existing item
192
- const mockItem = generateMock(TodoItemSchema());
193
-
194
- // generate a mock input
195
- const input: UpdateTodoItemInput = generateMock(
196
- UpdateTodoItemInputSchema(),
197
- );
198
-
199
- // set the mock input's `id` to the mock item's `id`
200
- input.id = mockItem.id;
201
-
202
- // we want the new `checked` field value to be the opposite of the randomly generated value from the mock
203
- const newChecked = !mockItem.checked;
204
- input.checked = newChecked;
205
-
206
- // leave the `text` field unchanged
207
- input.text = undefined;
208
-
209
- // create a document with the existing item in it
210
- const document = utils.createDocument({
211
- global: {
212
- items: [mockItem],
213
- },
214
- });
215
-
216
- // apply the reducer with the action and the mock input
217
- const updatedDocument = reducer(document, updateTodoItem(input));
218
-
219
- /* The following checks are copied from the boilerplate */
220
-
221
- // validate your document
222
- expect(isTodoListDocument(updatedDocument)).toBe(true);
223
-
224
- // check your operations
225
- expect(updatedDocument.operations.global).toHaveLength(1);
226
-
227
- // check the operation's action type
228
- expect(updatedDocument.operations.global[0].action.type).toBe(
229
- "UPDATE_TODO_ITEM",
230
- );
231
-
232
- // check the operation's input
233
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
234
- input,
235
- );
236
-
237
- // check the operation's index
238
- expect(updatedDocument.operations.global[0].index).toEqual(0);
239
-
240
- /* The following checks are unique to this test case */
241
-
242
- // get the updated item by it's `id`
243
- const updatedItem = updatedDocument.state.global.items.find(
244
- (item) => item.id === input.id,
245
- );
246
-
247
- // the item's `text` field should remain unchanged
248
- expect(updatedItem?.text).toBe(mockItem.text);
249
-
250
- // the item's `checked` field should be updated to our new checked value
251
- expect(updatedItem?.checked).toBe(newChecked);
252
- });
253
- ```
254
-
255
- #### Check your work
256
-
257
- Running `pnpm tsc && pnpm lint && pnpm test` should pass
258
-
259
- ## Test for deleting todo items
260
-
261
- You will have seen that the tests for the `deleteTodoItem` operation passed, even though we didn't set up an existing item to delete. This is because the boilerplate just checks that the operation was applied with the correct inputs, which it technically was. Checking that it actually had the _result_ we want is our job.
262
-
263
- Update the `deleteTodoItem` operation test case to also create an existing item and then check that is was actually deleted:
264
-
265
- ```typescript
266
- it("should handle deleteTodoItem operation", () => {
267
- // removed-start
268
- const document = utils.createDocument();
269
- const input = generateMock(DeleteTodoItemInputSchema());
270
- // removed-end
271
- // added-start
272
- const mockItem = generateMock(TodoItemSchema());
273
- const document = utils.createDocument({
274
- global: {
275
- items: [mockItem],
276
- },
277
- });
278
- const input: DeleteTodoItemInput = generateMock(
279
- DeleteTodoItemInputSchema(),
280
- );
281
- input.id = mockItem.id;
282
- // added-end
283
- const updatedDocument = reducer(document, deleteTodoItem(input));
284
- expect(isTodoListDocument(updatedDocument)).toBe(true);
285
-
286
- expect(updatedDocument.operations.global).toHaveLength(1);
287
- expect(updatedDocument.operations.global[0].action.type).toBe(
288
- "DELETE_TODO_ITEM",
289
- );
290
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
291
- input,
292
- );
293
- expect(updatedDocument.operations.global[0].index).toEqual(0);
294
- // added-start
295
- const updatedItems = updatedDocument.state.global.items;
296
- expect(updatedItems).toHaveLength(0);
297
- // added-end
298
- });
299
- ```
300
-
301
- #### Check your work
302
-
303
- Running `pnpm tsc && pnpm lint && pnpm test` should pass
304
-
305
- ## Final result
306
-
307
- After these updates, your `document-models/todo-list/src/tests/todos.test.ts` file should look like this:
308
-
309
- ```ts
310
- /**
311
- * This is a scaffold file meant for customization:
312
- * - change it by adding new tests or modifying the existing ones
313
- */
314
-
315
- import { describe, it, expect } from "vitest";
316
- import { generateMock } from "@powerhousedao/codegen";
317
- import type {
318
- AddTodoItemInput,
319
- DeleteTodoItemInput,
320
- UpdateTodoItemInput,
321
- } from "todo-tutorial/document-models/todo-list";
322
- import {
323
- reducer,
324
- utils,
325
- isTodoListDocument,
326
- addTodoItem,
327
- AddTodoItemInputSchema,
328
- updateTodoItem,
329
- UpdateTodoItemInputSchema,
330
- deleteTodoItem,
331
- DeleteTodoItemInputSchema,
332
- TodoItemSchema,
333
- } from "todo-tutorial/document-models/todo-list";
334
-
335
- describe("Todos Operations", () => {
336
- it("should handle addTodoItem operation", () => {
337
- const document = utils.createDocument();
338
- const input: AddTodoItemInput = generateMock(AddTodoItemInputSchema());
339
-
340
- const updatedDocument = reducer(document, addTodoItem(input));
341
- expect(isTodoListDocument(updatedDocument)).toBe(true);
342
-
343
- expect(updatedDocument.operations.global).toHaveLength(1);
344
- expect(updatedDocument.operations.global[0].action.type).toBe(
345
- "ADD_TODO_ITEM",
346
- );
347
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
348
- input,
349
- );
350
- expect(updatedDocument.operations.global[0].index).toEqual(0);
351
- });
352
- it("should handle updateTodoItem operation to update text", () => {
353
- const mockItem = generateMock(TodoItemSchema());
354
- const input: UpdateTodoItemInput = generateMock(
355
- UpdateTodoItemInputSchema(),
356
- );
357
- input.id = mockItem.id;
358
- const newText = "new text";
359
- input.text = newText;
360
- input.checked = undefined;
361
- const document = utils.createDocument({
362
- global: {
363
- items: [mockItem],
364
- },
365
- });
366
-
367
- const updatedDocument = reducer(document, updateTodoItem(input));
368
- expect(isTodoListDocument(updatedDocument)).toBe(true);
369
-
370
- expect(updatedDocument.operations.global).toHaveLength(1);
371
- expect(updatedDocument.operations.global[0].action.type).toBe(
372
- "UPDATE_TODO_ITEM",
373
- );
374
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
375
- input,
376
- );
377
- expect(updatedDocument.operations.global[0].index).toEqual(0);
378
- const updatedItem = updatedDocument.state.global.items.find(
379
- (item) => item.id === input.id,
380
- );
381
- expect(updatedItem?.text).toBe(newText);
382
- expect(updatedItem?.checked).toBe(mockItem.checked);
383
- });
384
- it("should handle updateTodoItem operation to update checked", () => {
385
- const mockItem = generateMock(TodoItemSchema());
386
- const input: UpdateTodoItemInput = generateMock(
387
- UpdateTodoItemInputSchema(),
388
- );
389
- input.id = mockItem.id;
390
- const newChecked = !mockItem.checked;
391
- input.checked = newChecked;
392
- input.text = undefined;
393
- const document = utils.createDocument({
394
- global: {
395
- items: [mockItem],
396
- },
397
- });
398
-
399
- const updatedDocument = reducer(document, updateTodoItem(input));
400
- expect(isTodoListDocument(updatedDocument)).toBe(true);
401
-
402
- expect(updatedDocument.operations.global).toHaveLength(1);
403
- expect(updatedDocument.operations.global[0].action.type).toBe(
404
- "UPDATE_TODO_ITEM",
405
- );
406
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
407
- input,
408
- );
409
- expect(updatedDocument.operations.global[0].index).toEqual(0);
410
- const updatedItem = updatedDocument.state.global.items.find(
411
- (item) => item.id === input.id,
412
- );
413
- expect(updatedItem?.text).toBe(mockItem.text);
414
- expect(updatedItem?.checked).toBe(newChecked);
415
- });
416
- it("should handle deleteTodoItem operation", () => {
417
- const mockItem = generateMock(TodoItemSchema());
418
- const document = utils.createDocument({
419
- global: {
420
- items: [mockItem],
421
- },
422
- });
423
- const input: DeleteTodoItemInput = generateMock(
424
- DeleteTodoItemInputSchema(),
425
- );
426
- input.id = mockItem.id;
427
- const updatedDocument = reducer(document, deleteTodoItem(input));
428
- expect(isTodoListDocument(updatedDocument)).toBe(true);
429
-
430
- expect(updatedDocument.operations.global).toHaveLength(1);
431
- expect(updatedDocument.operations.global[0].action.type).toBe(
432
- "DELETE_TODO_ITEM",
433
- );
434
- expect(updatedDocument.operations.global[0].action.input).toStrictEqual(
435
- input,
436
- );
437
- expect(updatedDocument.operations.global[0].index).toEqual(0);
438
- const updatedItems = updatedDocument.state.global.items;
439
- expect(updatedItems).toHaveLength(0);
440
- });
441
- });
442
- ```
443
-
444
- ## Check your work
445
-
446
- To make sure all works as expected, we should:
447
-
448
- - check types
449
- run: `pnpm tsc`
450
-
451
- - check linting
452
- run: `pnpm lint`
453
-
454
- - check tests
455
- run: `pnpm test`
456
-
457
- - make sure your code matches the code in the completed step branch
458
- run: `git diff your-branch-name step-3-complete-implemented-tests-for-todo-operations`
459
-
460
- ### Up next: generating an editor for our `TodoList` documents
461
-
462
- Up next, we'll generate a boilerplate document editor for our `TodoList` documents.