epam-ai-conductor 0.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 (115) hide show
  1. package/README.md +46 -0
  2. package/bin/workshop.js +6 -0
  3. package/dist/auth-check.d.ts +1 -0
  4. package/dist/auth-check.js +45 -0
  5. package/dist/auth-check.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +156 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/content/content/module-1/task/module-1_home-task_components.md +257 -0
  10. package/dist/content/content/module-1/task/module-1_home-task_good_practices.md +69 -0
  11. package/dist/content/content/module-1/task/module-1_home-task_task.md +253 -0
  12. package/dist/content/content/module-1/tests/Button.test.tsx +22 -0
  13. package/dist/content/content/module-1/tests/CourseCard.test.tsx +64 -0
  14. package/dist/content/content/module-1/tests/CourseInfo.test.tsx +73 -0
  15. package/dist/content/content/module-1/tests/Courses.test.tsx +87 -0
  16. package/dist/content/content/module-1/tests/Header.test.tsx +23 -0
  17. package/dist/content/content/module-1/tests/Input.test.tsx +36 -0
  18. package/dist/content/content/module-1/tests/helpers.test.ts +13 -0
  19. package/dist/content/content/module-1/theory/module-1_elements-render.md +66 -0
  20. package/dist/content/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
  21. package/dist/content/content/module-1/theory/module-1_hooks_useState.md +131 -0
  22. package/dist/content/content/module-1/theory/module-1_react.md +64 -0
  23. package/dist/content/content/module-1/theory/module-1_spa.md +74 -0
  24. package/dist/content/content/module-2/task/module-2_home-task_components.md +313 -0
  25. package/dist/content/content/module-2/task/module-2_home-task_good_practices.md +35 -0
  26. package/dist/content/content/module-2/task/module-2_home-task_task.md +210 -0
  27. package/dist/content/content/module-2/tests/App.test.tsx +54 -0
  28. package/dist/content/content/module-2/tests/Login.test.tsx +73 -0
  29. package/dist/content/content/module-2/tests/Registration.test.tsx +70 -0
  30. package/dist/content/content/module-2/tests/SearchBar.test.tsx +39 -0
  31. package/dist/content/content/module-2/theory/module-2_custom-hooks.md +201 -0
  32. package/dist/content/content/module-2/theory/module-2_hooks.md +117 -0
  33. package/dist/content/content/module-2/theory/module-2_react-router.md +328 -0
  34. package/dist/content/content/module-3/task/module-3_home-task_components.md +94 -0
  35. package/dist/content/content/module-3/task/module-3_home-task_good_practices.md +26 -0
  36. package/dist/content/content/module-3/task/module-3_home-task_task.md +170 -0
  37. package/dist/content/content/module-3/tests/App.test.tsx +54 -0
  38. package/dist/content/content/module-3/tests/Courses.test.tsx +87 -0
  39. package/dist/content/content/module-3/tests/CreateAuthor.test.tsx +44 -0
  40. package/dist/content/content/module-3/tests/CreateCourse.test.tsx +122 -0
  41. package/dist/content/content/module-3/theory/module-3_redux-hooks.md +194 -0
  42. package/dist/content/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
  43. package/dist/content/content/module-4/task/module-4_home-task_components.md +187 -0
  44. package/dist/content/content/module-4/task/module-4_home-task_task.md +139 -0
  45. package/dist/content/content/module-4/tests/App.test.tsx +54 -0
  46. package/dist/content/content/module-4/tests/Courses.test.tsx +87 -0
  47. package/dist/content/content/module-4/tests/CreateCourse.test.tsx +122 -0
  48. package/dist/content/content/module-4/tests/Login.test.tsx +73 -0
  49. package/dist/content/content/module-4/theory/module-4_async-redux.md +99 -0
  50. package/dist/content/content/module-4/theory/module-4_private-routes.md +55 -0
  51. package/dist/content/content/module-5/task/module-5_home-task_instruction.md +68 -0
  52. package/dist/content/content/module-5/task/module-5_home-task_task.md +154 -0
  53. package/dist/content/content/module-5/tests/App.test.tsx +54 -0
  54. package/dist/content/content/module-5/tests/CourseCard.test.tsx +64 -0
  55. package/dist/content/content/module-5/tests/Courses.test.tsx +87 -0
  56. package/dist/content/content/module-5/tests/Header.test.tsx +23 -0
  57. package/dist/content/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
  58. package/dist/content/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
  59. package/dist/content/module-1/task/module-1_home-task_components.md +257 -0
  60. package/dist/content/module-1/task/module-1_home-task_good_practices.md +69 -0
  61. package/dist/content/module-1/task/module-1_home-task_task.md +253 -0
  62. package/dist/content/module-1/tests/Button.test.tsx +22 -0
  63. package/dist/content/module-1/tests/CourseCard.test.tsx +64 -0
  64. package/dist/content/module-1/tests/CourseInfo.test.tsx +73 -0
  65. package/dist/content/module-1/tests/Courses.test.tsx +87 -0
  66. package/dist/content/module-1/tests/Header.test.tsx +23 -0
  67. package/dist/content/module-1/tests/Input.test.tsx +36 -0
  68. package/dist/content/module-1/tests/helpers.test.ts +13 -0
  69. package/dist/content/module-1/theory/module-1_elements-render.md +66 -0
  70. package/dist/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
  71. package/dist/content/module-1/theory/module-1_hooks_useState.md +131 -0
  72. package/dist/content/module-1/theory/module-1_react.md +64 -0
  73. package/dist/content/module-1/theory/module-1_spa.md +74 -0
  74. package/dist/content/module-2/task/module-2_home-task_components.md +313 -0
  75. package/dist/content/module-2/task/module-2_home-task_good_practices.md +35 -0
  76. package/dist/content/module-2/task/module-2_home-task_task.md +210 -0
  77. package/dist/content/module-2/tests/App.test.tsx +54 -0
  78. package/dist/content/module-2/tests/Login.test.tsx +73 -0
  79. package/dist/content/module-2/tests/Registration.test.tsx +70 -0
  80. package/dist/content/module-2/tests/SearchBar.test.tsx +39 -0
  81. package/dist/content/module-2/theory/module-2_custom-hooks.md +201 -0
  82. package/dist/content/module-2/theory/module-2_hooks.md +117 -0
  83. package/dist/content/module-2/theory/module-2_react-router.md +328 -0
  84. package/dist/content/module-3/task/module-3_home-task_components.md +94 -0
  85. package/dist/content/module-3/task/module-3_home-task_good_practices.md +26 -0
  86. package/dist/content/module-3/task/module-3_home-task_task.md +170 -0
  87. package/dist/content/module-3/tests/App.test.tsx +54 -0
  88. package/dist/content/module-3/tests/Courses.test.tsx +87 -0
  89. package/dist/content/module-3/tests/CreateAuthor.test.tsx +44 -0
  90. package/dist/content/module-3/tests/CreateCourse.test.tsx +122 -0
  91. package/dist/content/module-3/theory/module-3_redux-hooks.md +194 -0
  92. package/dist/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
  93. package/dist/content/module-4/task/module-4_home-task_components.md +187 -0
  94. package/dist/content/module-4/task/module-4_home-task_task.md +139 -0
  95. package/dist/content/module-4/tests/App.test.tsx +54 -0
  96. package/dist/content/module-4/tests/Courses.test.tsx +87 -0
  97. package/dist/content/module-4/tests/CreateCourse.test.tsx +122 -0
  98. package/dist/content/module-4/tests/Login.test.tsx +73 -0
  99. package/dist/content/module-4/theory/module-4_async-redux.md +99 -0
  100. package/dist/content/module-4/theory/module-4_private-routes.md +55 -0
  101. package/dist/content/module-5/task/module-5_home-task_instruction.md +68 -0
  102. package/dist/content/module-5/task/module-5_home-task_task.md +154 -0
  103. package/dist/content/module-5/tests/App.test.tsx +54 -0
  104. package/dist/content/module-5/tests/CourseCard.test.tsx +64 -0
  105. package/dist/content/module-5/tests/Courses.test.tsx +87 -0
  106. package/dist/content/module-5/tests/Header.test.tsx +23 -0
  107. package/dist/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
  108. package/dist/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
  109. package/dist/content-loader.d.ts +7 -0
  110. package/dist/content-loader.js +26 -0
  111. package/dist/content-loader.js.map +1 -0
  112. package/dist/context-builder.d.ts +2 -0
  113. package/dist/context-builder.js +116 -0
  114. package/dist/context-builder.js.map +1 -0
  115. package/package.json +40 -0
@@ -0,0 +1,70 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import { MemoryRouter } from "react-router-dom";
4
+ import { Registration } from "../components/Registration";
5
+ import * as services from "../../../services";
6
+
7
+ const mockedUsedNavigate = jest.fn();
8
+
9
+ beforeEach(() => {
10
+ jest
11
+ .spyOn(services, "createUser")
12
+ .mockImplementation(jest.fn(() => Promise.resolve()) as jest.Mock);
13
+
14
+ jest.spyOn(global, "fetch").mockImplementation(
15
+ jest.fn(() =>
16
+ Promise.resolve({
17
+ ok: true,
18
+ json: () => Promise.resolve(),
19
+ })
20
+ ) as jest.Mock
21
+ );
22
+
23
+ jest.mock("react-router-dom", () => ({
24
+ ...jest.requireActual("react-router-dom"),
25
+ useNavigate: () => mockedUsedNavigate,
26
+ }));
27
+ });
28
+
29
+ describe("Registration", () => {
30
+ test("renders the registration form", () => {
31
+ render(
32
+ <MemoryRouter>
33
+ <Registration />
34
+ </MemoryRouter>
35
+ );
36
+
37
+ expect(screen.getByLabelText("name")).toBeInTheDocument();
38
+ expect(screen.getByLabelText("email")).toBeInTheDocument();
39
+ expect(screen.getByLabelText("password")).toBeInTheDocument();
40
+ expect(screen.getByRole("button")).toBeInTheDocument();
41
+ expect(screen.getByRole("link")).toBeInTheDocument();
42
+ });
43
+
44
+ test("submits the form", async () => {
45
+ render(
46
+ <MemoryRouter>
47
+ <Registration />
48
+ </MemoryRouter>
49
+ );
50
+
51
+ fireEvent.change(screen.getByLabelText("name"), {
52
+ target: { value: "John Doe" },
53
+ });
54
+ fireEvent.change(screen.getByLabelText("email"), {
55
+ target: { value: "john.doe@example.com" },
56
+ });
57
+ fireEvent.change(screen.getByLabelText("password"), {
58
+ target: { value: "password123" },
59
+ });
60
+
61
+ fireEvent.click(screen.getByRole("button", { name: "registration" }));
62
+
63
+ expect(services.createUser).toHaveBeenCalledTimes(1);
64
+ await expect(services.createUser).toHaveBeenCalledWith({
65
+ name: "John Doe",
66
+ email: "john.doe@example.com",
67
+ password: "password123",
68
+ });
69
+ });
70
+ });
@@ -0,0 +1,39 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import { SearchBar } from "../components/Courses/components/SearchBar/SearchBar";
4
+
5
+ test("SearchBar renders correctly", () => {
6
+ const onAddClick = jest.fn();
7
+ render(<SearchBar onAddClick={onAddClick} />);
8
+
9
+ const inputElement = screen.getByRole("textbox");
10
+ const searchButtonElement = screen.getByText("Search");
11
+ const addButtonElement = screen.getByText("Add new courses");
12
+
13
+ expect(inputElement).toBeInTheDocument();
14
+ expect(searchButtonElement).toBeInTheDocument();
15
+ expect(addButtonElement).toBeInTheDocument();
16
+ });
17
+
18
+ test("SearchBar handles input change correctly", () => {
19
+ const onAddClick = jest.fn();
20
+ render(<SearchBar onAddClick={onAddClick} />);
21
+
22
+ const inputElement = screen.getByRole("textbox") as HTMLInputElement;
23
+
24
+ fireEvent.change(inputElement, {
25
+ target: { value: "test" },
26
+ });
27
+
28
+ expect(inputElement.value).toBe("test");
29
+ });
30
+
31
+ test("SearchBar calls onAddClick correctly", () => {
32
+ const onAddClick = jest.fn();
33
+ render(<SearchBar onAddClick={onAddClick} />);
34
+
35
+ const addButtonElement = screen.getByText("Add new courses");
36
+ fireEvent.click(addButtonElement);
37
+
38
+ expect(onAddClick).toHaveBeenCalledTimes(1);
39
+ });
@@ -0,0 +1,201 @@
1
+ ---
2
+ sidebar_position: 4
3
+ sidebar_label: 'Custom Hooks'
4
+ title: 'Extracting a Custom Hook'
5
+ ---
6
+
7
+ ## What is a Custom Hook?
8
+
9
+ In order not to duplicate code in JavaScript we create functions, which give us an opportunity to
10
+ make our code reusable.
11
+
12
+ Sometimes we may want to use the same logic (for instance, use some set of
13
+ `Hooks`) in different components in React. Usually we don't want to repeat the logic for each component,
14
+ because there may be quite a lot of components in the application. As `Hooks` are also functions we can
15
+ extract repeated logic to a `Custom Hook`.
16
+
17
+ ## Usage of Custom Hook
18
+
19
+ Let's create two similar components to understand better what `Custom Hook` is and how it works.
20
+
21
+ ```jsx
22
+ // src/App.jsx
23
+
24
+ import FirstComponent from "./FirstComponent";
25
+ import SecondComponent from "./SecondComponent";
26
+
27
+ function App() {
28
+ return (
29
+ <>
30
+ <FirstComponent />
31
+ <SecondComponent />
32
+ </>
33
+ );
34
+ }
35
+
36
+ export default App;
37
+ ```
38
+
39
+ ```jsx
40
+ // src/FirstComponent.jsx
41
+
42
+ import { useEffect, useState } from "react";
43
+
44
+ const url = 'https://api.github.com/users';
45
+
46
+ function FirstComponent() {
47
+ const [data, setData] = useState([]);
48
+
49
+ const getData = async () => {
50
+ const response = await fetch(url);
51
+ const data = await response.json();
52
+ setData(data);
53
+ };
54
+
55
+ useEffect(() => {
56
+ getData();
57
+ }, []);
58
+
59
+ return (
60
+ <>
61
+ <div>First Component</div>
62
+ // rendering data after checking if array is not empty
63
+ {data.length > 0 && data.map(element => {
64
+ return <div key={element.id}>{element.login}</div>;
65
+ })}
66
+ </>
67
+ );
68
+ }
69
+
70
+ export default FirstComponent;
71
+ ```
72
+
73
+ ```jsx
74
+ // src/SecondComponent.jsx
75
+
76
+ import { useEffect, useState } from "react";
77
+
78
+ const url = 'https://api.github.com/events';
79
+
80
+ function SecondComponent() {
81
+ const [data, setData] = useState([]);
82
+
83
+ const getData = async () => {
84
+ const response = await fetch(url);
85
+ const data = await response.json();
86
+ setData(data);
87
+ };
88
+
89
+ useEffect(() => {
90
+ getData();
91
+ }, []);
92
+
93
+ return (
94
+ <>
95
+ <div>Second Component</div>
96
+ // rendering data after checking if array is not empty
97
+ {data.length > 0 && data.map(element => {
98
+ return <div key={element.id}>{element.type}</div>;
99
+ })}
100
+ </>
101
+ );
102
+ }
103
+
104
+ export default SecondComponent;
105
+ ```
106
+
107
+ As you can see, these components are almost the same: both have local state with data and both make
108
+ request to API. The only difference is URL. So now when similarity is obvious let's create a
109
+ `Custom Hook` `useFetch` with common logic.
110
+
111
+ :::warning
112
+ Custom Hook's name should start with `use`.
113
+ :::
114
+
115
+ ```jsx
116
+ // src/useFetch.jsx
117
+
118
+ import { useEffect, useState } from "react";
119
+
120
+ function useFetch(url) {
121
+ const [data, setData] = useState([]);
122
+
123
+ const getData = async () => {
124
+ const response = await fetch(url);
125
+ const data = await response.json();
126
+ setData(data);
127
+ };
128
+
129
+ useEffect(() => {
130
+ getData();
131
+ }, [url]);
132
+
133
+ return data;
134
+ }
135
+
136
+ export default useFetch;
137
+ ```
138
+
139
+ As you can see inside the `Custom Hook` we moved our `useState` and `useEffect hooks`.
140
+ It works the same as this code worked inside components, but the difference is:
141
+ * it takes `url` as a parameter
142
+ * `useEffect` will execute every time when URL changes (dependency array is the second parameter of `useEffect`)
143
+ * returns `data` that we need.
144
+
145
+ Now we can use it inside our components.
146
+
147
+ ```jsx
148
+ // src/FirstComponent.jsx
149
+
150
+ import useFetch from "./useFetch";
151
+
152
+ const url = 'https://api.github.com/users';
153
+
154
+ function FirstComponent() {
155
+ const data = useFetch(url);
156
+
157
+ return (
158
+ <>
159
+ <div>First Component</div>
160
+ {data.length > 0 && data.map(element => {
161
+ return <div key={element.id}>{element.login}</div>;
162
+ })}
163
+ </>
164
+ );
165
+ }
166
+
167
+ export default FirstComponent;
168
+ ```
169
+
170
+ ```jsx
171
+ // src/SecondComponent.jsx
172
+
173
+ import useFetch from "./useFetch";
174
+
175
+ const url = 'https://api.github.com/events';
176
+
177
+ function SecondComponent() {
178
+ const data = useFetch(url);
179
+
180
+ return (
181
+ <>
182
+ <div>Second Component</div>
183
+ {data.map(element => {
184
+ return <div key={element.id}>{element.type}</div>;
185
+ })}
186
+ </>
187
+ );
188
+ }
189
+
190
+ export default SecondComponent;
191
+ ```
192
+ As you can see we use `Custom Hook` as a simple JS function that starts with 'use' and returns data.
193
+ So now there is no need to duplicate our code for every component.
194
+
195
+ ## Conclusion
196
+
197
+ Congratulations! Now you've learned how `Custom Hooks` work.
198
+
199
+ ---
200
+ ## Materials
201
+ 1. [React documentation. Custom Hooks](https://react.dev/learn/reusing-logic-with-custom-hooks)
@@ -0,0 +1,117 @@
1
+ ---
2
+ sidebar_position: 3
3
+ sidebar_label: 'React Router Hooks'
4
+ title: 'React Router Hooks'
5
+ ---
6
+
7
+ ## useLocation()
8
+ This hook returns the current location object. This can be useful if you'd like to perform some side effect whenever the current location changes.
9
+
10
+ ```jsx
11
+ import React, { useEffect } from 'react';
12
+ import { useLocation } from 'react-router-dom';
13
+
14
+ function App() {
15
+ const location = useLocation();
16
+
17
+ useEffect(() => {
18
+ // this block will run once location is changed
19
+ }, [location]);
20
+
21
+ return (
22
+ // ...
23
+ );
24
+ }
25
+
26
+ ```
27
+
28
+ ## useNavigate()
29
+ The `useNavigate` hook returns a function that lets you navigate programmatically, for example after a form is submitted.
30
+
31
+ ```jsx
32
+ import { useNavigate } from "react-router-dom";
33
+
34
+ function SignupForm() {
35
+ const navigate = useNavigate();
36
+
37
+ async function handleSubmit(event) {
38
+ event.preventDefault();
39
+
40
+ await submitForm(event.target);
41
+
42
+ navigate("../success", { replace: true });
43
+ }
44
+
45
+ return <form onSubmit={handleSubmit}>{/* ... */}</form>;
46
+ }
47
+
48
+ ```
49
+ The navigate function has two signatures:
50
+
51
+ * Either pass a `to` value (same type as `<Link to>`) with an optional second `{ replace, state }` arg or
52
+
53
+ * Pass the delta you want to go in the history stack. For example, `navigate(-1)` is equivalent to hitting the back button.
54
+
55
+ ## useParams()
56
+ The `useParams` hook returns an object of key/value pairs of the dynamic params from the current
57
+ URL that were matched by the `<Route path >`.
58
+ Child routes inherit all params from their parent routes.
59
+
60
+ ```jsx
61
+ import * as React from 'react';
62
+ import { Routes, Route, useParams } from 'react-router-dom';
63
+
64
+ function ProfilePage() {
65
+ // Get the userId param from the URL.
66
+ const { userId } = useParams();
67
+ // ...
68
+ }
69
+
70
+ function App() {
71
+ return (
72
+ <Routes>
73
+ <Route path="users">
74
+ <Route path=":userId" element={<ProfilePage />} />
75
+ <Route path="me" element={...} />
76
+ </Route>
77
+ </Routes>
78
+ );
79
+ }
80
+
81
+ ```
82
+
83
+ ## useRoutes()
84
+
85
+ The useRoutes hook is the functional equivalent of `<Routes>`, but it uses JavaScript objects instead of `<Route>` elements to define your routes. These objects have the same properties as normal `<Route>` elements, but they don't require JSX.
86
+
87
+ The return value of `useRoutes` is either a valid React element you can use to render the route tree, or null if nothing matched.
88
+
89
+ ```jsx
90
+ import * as React from "react";
91
+ import { useRoutes } from "react-router-dom";
92
+
93
+ function App() {
94
+ let element = useRoutes([
95
+ {
96
+ path: "/",
97
+ element: <App />,
98
+ children: [
99
+ {
100
+ path: "first-page",
101
+ element: <FirstPage />,
102
+ },
103
+ {
104
+ path: "second-page",
105
+ element: <SecondPage />,
106
+ },
107
+ ],
108
+ },
109
+ ]);
110
+
111
+ return element;
112
+ }
113
+ ```
114
+
115
+ :::info
116
+ You can find more React Router hooks in the official [documentation](https://reactrouter.com/en/6.6.2)
117
+ :::