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,253 @@
1
+ ---
2
+ sidebar_position: 1
3
+ sidebar_label: 'TASK'
4
+ title: 'Module 1. React Components'
5
+ ---
6
+
7
+ Hello friend!
8
+ Let me say a few words what we are going to do with you.
9
+ We will write a small React application that allows users to manage a list of courses
10
+ with features like creating, deleting, and viewing course information.
11
+ Additionally, the application will have authorization functionality to ensure
12
+ secure access to the application's features.
13
+
14
+ The main goal of this task is to create app skeleton - set of
15
+ some simple components for the app.
16
+
17
+ Please, follow next steps:
18
+
19
+ ## Steps:
20
+
21
+ 1. Generate a new project:
22
+
23
+ ```http request
24
+ npx create-react-app courses-app
25
+ ```
26
+
27
+ :::note
28
+ You can use `git bash` to run the command.
29
+
30
+
31
+ `courses-app` is a name of the project. You can give any name you want.
32
+ :::
33
+
34
+ 2. Open you new project via code editor.
35
+
36
+
37
+ 3. Configure `eslint` and `prettier`.
38
+ See instruction in the [ESLINT instruction](eslint).
39
+
40
+
41
+ 4. Configure `pre-commit hook`.
42
+ See instruction in the [PRE COMMIT instruction](pre_commit).
43
+
44
+
45
+ 5. Run your project.
46
+ ```http request
47
+ npm run start
48
+ ```
49
+
50
+ Result in the browser:
51
+ ![](images/initial_react_view.jpg)
52
+
53
+ :::tip
54
+ Now it's good time to push your INITIAL COMMIT to the repo and create a new branch for the first module.
55
+ :::
56
+
57
+
58
+ ## Project structure requirements
59
+
60
+ 1. You should use **function** components for your app.
61
+
62
+
63
+ 2. Rename `App.js` to `App.jsx` / `App.tsx`. `App` - main app file.
64
+
65
+
66
+ 3. Delete unnecessary files:
67
+ - `src/App.test.js`
68
+ - `src/logo.svg`
69
+ - `src/reportWebVitals.js`
70
+ - all files in the `public` folder EXCEPT `public/index.html` and `manifest.json`
71
+
72
+ 4. Delete default code in files:
73
+
74
+ - `scr/App`
75
+ - `src/App.css`
76
+
77
+ You can do like this:
78
+ ```js
79
+ function App() {
80
+ return <div>React</div>;
81
+ }
82
+
83
+ export default App;
84
+ ```
85
+
86
+ Delete unnecessary import and function call in the `index.js` file
87
+ ```js
88
+ import reportWebVitals from './reportWebVitals';
89
+ ...
90
+ reportWebVitals();
91
+ ```
92
+
93
+ Result in the browser:
94
+ ![](images/initial_view_localhost.jpg)
95
+
96
+ :::tip
97
+ If you use `App.tsx` you need to fix its import in the `index.js` file
98
+ ```js
99
+ import App from './App.tsx';
100
+ ```
101
+ :::
102
+
103
+ 5. Create folders and files for each component. Follow the architecture below:
104
+
105
+ ```
106
+ src
107
+ |-- common
108
+ | |--Button
109
+ | | |__ Button.jsx/.tsx
110
+ | |
111
+ | |__Input
112
+ | | |__ Input.jsx/.tsx
113
+ | | |
114
+ | |__ //any common components you want to add
115
+ |
116
+ |-- components
117
+ | |-- CourseInfo
118
+ | | |__ CourseInfo.jsx/.tsx
119
+ | |
120
+ | |-- Courses
121
+ | | |__ components
122
+ | | |__ CourseCard
123
+ | | |__ CourseCard.jsx/.tsx
124
+ | | |__ SearchBar (extra task)
125
+ | | | |__ SearchBar.jsx/.tsx
126
+ | | |__ Courses.jsx/.tsx
127
+ | |
128
+ | |__ // any components you want to add
129
+ | |
130
+ | |-- EmptyCourseList
131
+ | | |__ EmptyCourseList.jsx/.tsx
132
+ | |
133
+ | |-- Header
134
+ | | |__ Header.jsx/.tsx
135
+ | | |__ components
136
+ | | |__ Logo
137
+ | | |__ Logo.jsx/.tsx
138
+ |
139
+ |-- helpers
140
+ | |
141
+ | |--getCourseDuration.js/.ts // a helper to format course duration
142
+ | |
143
+ | |--formatCreationDate.js/.ts // to format date that we will receive from server
144
+ | |
145
+ | |__ // any helpers you want to add
146
+ |
147
+ |-- constants.js/.ts // file with mocked data
148
+ |
149
+ |-- App.jsx/.tsx
150
+ |-- App.css
151
+ |-- index.js
152
+ |_ ...
153
+
154
+ ```
155
+
156
+ :::caution
157
+ The presented architecture is required for use, BUT you can add files and folders at your discretion.
158
+ :::
159
+
160
+ 7. You can use any way to add styles to components (styled components, Bootstrap, CSS modules etc). Also, you can use preprocessors like SASS [instruction.](https://create-react-app.dev/docs/adding-a-sass-stylesheet/)
161
+
162
+ :::tip
163
+ It's recommended to keep each component's style file in their appropriate folders.
164
+ :::
165
+
166
+ 8. You can choose the design at your discretion.
167
+ **It is important to keep the layout** (the arrangement of elements on the page).
168
+
169
+
170
+ ![](images/initial_view.jpg)
171
+ **App initial view**
172
+
173
+ ## Final preparations:
174
+ 1. Support browsers: Google Chrome.
175
+ 2. Type checking: you can use TypeScript (it's not required but recommended).
176
+
177
+ Please, read requirements for the first task. To find the full description of each criteria please go to
178
+ the [COMPONENTS page.](components)
179
+
180
+ ## Criteria (30 points max)
181
+
182
+ ### Common
183
+
184
+ * [1 point] - The architecture of the application **should be** the same as presented above.
185
+
186
+
187
+ * [1 point] - Components are presented as [**function components**](https://react.dev/reference/react/Component) (not class components).
188
+
189
+
190
+ * [1 point] - Use `.jsx` extensions for files with [`jsx` syntax](https://react.dev/learn/writing-markup-with-jsx).
191
+
192
+
193
+ * [1 point] - All inputs and buttons should be reusable components.
194
+
195
+
196
+ * [2 points] - `eslint`, `prettier` and `pre-commit hook` work correctly.
197
+
198
+ ### [Header component](/docs/module-1/home-task/components#header)
199
+ * [3 points] - Should display `Header` component with:
200
+ * `Logo` (any appropriate image)
201
+ * `Logout` button (without functionality)
202
+
203
+ ### [CourseCard component](/docs/module-1/home-task/components#create-coursecard-component)
204
+ * [5 points] - Should display `CourseCard` component with:
205
+ * course title;
206
+ * course description;
207
+ * authors list;
208
+ * course duration;
209
+ * creation date;
210
+ * `Show course` button.
211
+
212
+ * [2 point] Show `CourseInfo` component with current course information by clicking `Show course` button.
213
+
214
+ ### [EmptyCourseList component](/docs/module-1/home-task/components#emptycourselist-component)
215
+
216
+ * [2 points] - Show `EmptyCourseList` component when no courses.
217
+
218
+ * [2 point] - Component Should contain:
219
+ * title 'Your List Is Empty';
220
+ * subtitle 'Please use "Add New Course" button to add your first course'.
221
+ * `Add New Course` button (without functionality for current task).
222
+
223
+ ### [Courses component](/docs/module-1/home-task/components#courses)
224
+ * [2 points] - Show list of courses (use [mocked course list](/docs/module-1/home-task/components#mocked-courses-and-authors-data) for this task).
225
+
226
+ * [1 point] - Show `Add new course` button (without functionality for current task).
227
+
228
+
229
+ ### [CourseInfo Component](/docs/module-1/home-task/components#course-info)
230
+
231
+ * [5 points] - Create component that contains:
232
+ * course title
233
+ * course description
234
+ * course ID
235
+ * course duration
236
+ * creation date
237
+ * course authors
238
+ * `Back` button
239
+
240
+ * [2 point] - By clicking `Back` button `CourseInfo` component should be replaced by `Courses` component.
241
+
242
+ ## Extra Task
243
+ ### [Searching](/docs/module-1/home-task/components#search-extra-task)
244
+ * Implement searching functionality by title. Reset search result when searchbar is empty.
245
+
246
+
247
+ * Implement searching functionality by id. Reset search result when searchbar is empty.
248
+
249
+ [Full description](/docs/module-1/home-task/components#search-extra-task)
250
+
251
+ :::info
252
+ Please find a detailed description of components and functionality in the [COMPONENTS](components) section.
253
+ :::
@@ -0,0 +1,22 @@
1
+ import '@testing-library/jest-dom'
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { Button } from "../common/Button/Button";
4
+
5
+ describe('Button component', () => {
6
+ test("Should render button with provided label", () => {
7
+ const handleClickMock = jest.fn();
8
+ render(<Button buttonText='Hello' handleClick={handleClickMock}/>);
9
+ const buttonElement = screen.getByText("Hello");
10
+
11
+ expect(buttonElement).toBeInTheDocument();
12
+ });
13
+
14
+ test("Should call provided callback", () => {
15
+ const handleClickMock = jest.fn();
16
+ render(<Button handleClick={handleClickMock} buttonText='Click me'/>);
17
+ const buttonElement = screen.getByText("Click me");
18
+
19
+ fireEvent.click(buttonElement);
20
+ expect(handleClickMock).toHaveBeenCalledTimes(1);
21
+ });
22
+ })
@@ -0,0 +1,64 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { CourseCard } from "../components/Courses/components/CourseCard/CourseCard";
4
+
5
+ describe('CourseCard component', () => {
6
+ const course = {
7
+ id: "1",
8
+ title: "Course Title",
9
+ description: "Course Description",
10
+ creationDate: "08/03/2021",
11
+ duration: 60,
12
+ authors: [
13
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
14
+ "f762978b-61eb-4096-812b-ebde22838167",
15
+ ],
16
+ };
17
+
18
+ test("Should contain title", () => {
19
+ render(<CourseCard course={course} />);
20
+
21
+ const titleElement = screen.getByText("Course Title");
22
+
23
+ expect(titleElement).toBeInTheDocument();
24
+ });
25
+
26
+ test("Should contain description", () => {
27
+ render(<CourseCard course={course} />);
28
+ const descriptionElement = screen.getByText("Course Description");
29
+ expect(descriptionElement).toBeInTheDocument();
30
+ });
31
+
32
+ test("Should contain duration", () => {
33
+ render(<CourseCard course={course} />);
34
+
35
+ const durationElement = screen.getByText(/01:00 hour/);
36
+
37
+ expect(durationElement).toBeInTheDocument();
38
+ });
39
+
40
+ test("Should contain date", () => {
41
+ render(<CourseCard course={course} />);
42
+
43
+ const creationDateElement = screen.getByText(/08.03.2021/);
44
+
45
+ expect(creationDateElement).toBeInTheDocument();
46
+ });
47
+
48
+ test("Should contain authors list", () => {
49
+ render(<CourseCard course={course} />);
50
+
51
+ const creationDateElement = screen.getByText(/Vasiliy Dobkin, Nicolas Kim/);
52
+
53
+ expect(creationDateElement).toBeInTheDocument();
54
+ });
55
+
56
+ test("Should contain authors list", () => {
57
+ render(<CourseCard course={course} />);
58
+
59
+ const creationDateElement = screen.getByText(/Show course/);
60
+
61
+ expect(creationDateElement).toBeInTheDocument();
62
+ });
63
+ })
64
+
@@ -0,0 +1,73 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { CourseInfo } from "../components/CourseInfo/CourseInfo";
4
+ import { formatCreationDate, getCourseDuration } from "../helpers";
5
+
6
+ const authorsList = [
7
+ { id: "1", name: "Author 1" },
8
+ { id: "2", name: "Author 2" },
9
+ { id: "3", name: "Author 3" },
10
+ { id: "4", name: "Author 4" },
11
+ ];
12
+
13
+ const course = {
14
+ id: "1",
15
+ title: "Course Title",
16
+ description: "Course Description",
17
+ authors: ["1", "3"],
18
+ creationDate: "08/03/2021",
19
+ duration: 120,
20
+ };
21
+
22
+ describe("CourseInfo", () => {
23
+ test("renders title correctly", () => {
24
+ render(<CourseInfo course={course} authorsList={authorsList} />);
25
+
26
+ const courseTitle = screen.getByRole("heading", { level: 1 });
27
+
28
+ expect(courseTitle.textContent).toBe("Course Title");
29
+ });
30
+
31
+ test("renders description correctly", () => {
32
+ render(<CourseInfo course={course} authorsList={authorsList} />);
33
+
34
+ const courseDescription = screen.getByText("Course Description");
35
+
36
+ expect(courseDescription).toBeInTheDocument();
37
+ });
38
+
39
+ test("renders course duration correctly", () => {
40
+ render(<CourseInfo course={course} authorsList={authorsList} />);
41
+
42
+ const courseDuration = screen.getByText(getCourseDuration(120));
43
+
44
+ expect(courseDuration).toBeInTheDocument();
45
+ });
46
+
47
+ test("renders course date correctly", () => {
48
+ render(<CourseInfo course={course} authorsList={authorsList} />);
49
+
50
+ const courseCreationDate = screen.getByText(
51
+ formatCreationDate(course.creationDate)
52
+ );
53
+ expect(courseCreationDate).toBeInTheDocument();
54
+ });
55
+
56
+ test("renders course authors' names correctly", () => {
57
+ render(<CourseInfo course={course} authorsList={authorsList} />);
58
+
59
+ const authorNames = screen
60
+ .getAllByRole("listitem")
61
+ .map((li) => li.textContent);
62
+
63
+ expect(authorNames).toEqual(["Author 1", "Author 3"]);
64
+ });
65
+
66
+ test("renders Back button correctly", () => {
67
+ render(<CourseInfo course={course} authorsList={authorsList} />);
68
+
69
+ const backButton = screen.getByRole("button", { name: "Back" });
70
+
71
+ expect(backButton).toBeInTheDocument();
72
+ });
73
+ });
@@ -0,0 +1,87 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { Courses } from "../components/Courses/Courses";
4
+
5
+ describe('Courses component', () => {
6
+ const mockedCoursesList = [
7
+ {
8
+ id: "1",
9
+ title: "Course 1",
10
+ description: "Course 1 description",
11
+ creationDate: "2022-01-01",
12
+ duration: 60,
13
+ authors: [
14
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
15
+ "f762978b-61eb-4096-812b-ebde22838167",
16
+ ],
17
+ },
18
+ {
19
+ id: "2",
20
+ title: "Course 2",
21
+ description: "Course 2 description",
22
+ creationDate: "2022-02-01",
23
+ duration: 90,
24
+ authors: ["df32994e-b23d-497c-9e4d-84e4dc02882f"],
25
+ },
26
+ ];
27
+ const onAddClick = jest.fn();
28
+
29
+ test("Should render list of courses", () => {
30
+ render(<Courses courseList={mockedCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
31
+
32
+ const courseElements = screen.getAllByTestId("courseCard");
33
+
34
+ expect(courseElements[0]).toBeInTheDocument();
35
+ expect(courseElements).toHaveLength(2);
36
+ });
37
+
38
+ test("Should render 'Add new course' button", () => {
39
+ render(<Courses courseList={mockedCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
40
+
41
+ const button = screen.getByText(/Add new course/);
42
+
43
+ expect(button).toBeInTheDocument();
44
+ });
45
+
46
+ test("Should render EmptyCourseList component if no courses", () => {
47
+ const mockedEmptyCoursesList: [] = [];
48
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
49
+
50
+ const emptyContainerElement = screen.getByTestId("emptyContainer");
51
+ const addButtonElement = screen.getByTestId("addCourse");
52
+
53
+ expect(emptyContainerElement).toBeInTheDocument();
54
+ expect(addButtonElement).toBeInTheDocument();
55
+ });
56
+ })
57
+
58
+ describe('EmptyCourseList', () => {
59
+ const mockedEmptyCoursesList: [] = [];
60
+ const onAddClick = jest.fn();
61
+
62
+ test("Should render title", () => {
63
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
64
+
65
+ const title = screen.getByText(/Your List Is Empty/);
66
+
67
+ expect(title).toBeInTheDocument();
68
+ });
69
+
70
+ test("Should render subtitle", () => {
71
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
72
+
73
+ const subTitle = screen.getByText(/Please use/);
74
+
75
+ expect(subTitle).toBeInTheDocument();
76
+ });
77
+
78
+ test("Should render button", () => {
79
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
80
+
81
+ const button = screen.getByText('ADD NEW COURSE');
82
+
83
+ expect(button).toBeInTheDocument();
84
+ });
85
+ })
86
+
87
+
@@ -0,0 +1,23 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { Header } from "../components/Header/Header";
4
+
5
+ describe('Header component', () => {
6
+ test("Should render logo", () => {
7
+ render(<Header />);
8
+
9
+ const imageElement = screen.getByRole("img");
10
+
11
+ expect(imageElement).toBeInTheDocument();
12
+ });
13
+
14
+ test("Should render logout button", () => {
15
+ render(<Header />);
16
+
17
+ const logoutButtonElement = screen.getByRole("button");
18
+
19
+ expect(logoutButtonElement).toBeInTheDocument();
20
+ });
21
+ })
22
+
23
+
@@ -0,0 +1,36 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { Input } from "../common/Input/Input";
4
+
5
+ describe('Input component', () => {
6
+ const placeholderTextMock = 'Enter a value';
7
+
8
+ test("should render input with provided label text", () => {
9
+ render(<Input labelText="Test Input" placeholderText={placeholderTextMock} />);
10
+
11
+ const inputElement = screen.getByLabelText("Test Input");
12
+ expect(inputElement).toBeInTheDocument();
13
+ });
14
+
15
+ test("should render input with provided placeholder text", () => {
16
+ const { getByPlaceholderText } = render(
17
+ <Input labelText='Test Input' placeholderText={placeholderTextMock} />
18
+ );
19
+
20
+ expect(getByPlaceholderText(placeholderTextMock)).toBeInTheDocument();
21
+ });
22
+
23
+ test("Should call provided callback for onChange event", () => {
24
+ const handleChange = jest.fn();
25
+
26
+ render(<Input labelText="Test Input" onChange={handleChange} placeholderText={placeholderTextMock}/>);
27
+
28
+ const inputElement = screen.getByLabelText("Test Input") as HTMLInputElement;
29
+ fireEvent.change(inputElement, { target: { value: "Hello" } });
30
+
31
+ expect(handleChange).toHaveBeenCalledTimes(1);
32
+ expect(inputElement.value).toBe("Hello");
33
+ });
34
+ })
35
+
36
+
@@ -0,0 +1,13 @@
1
+ import { formatCreationDate, getCourseDuration } from '../helpers';
2
+
3
+ test('formatCreationDate function returns formatted date', () => {
4
+ const date = '2022/01/01';
5
+ const formattedDate = formatCreationDate(date);
6
+ expect(formattedDate).toBe('2022.01.01');
7
+ });
8
+
9
+ test('getCourseDuration function returns formatted duration', () => {
10
+ expect(getCourseDuration(60)).toBe('01:00 hour');
11
+ expect(getCourseDuration(90)).toBe('01:30 hour');
12
+ expect(getCourseDuration(120)).toBe('02:00 hours');
13
+ });
@@ -0,0 +1,66 @@
1
+ ---
2
+ sidebar_position: 4
3
+ sidebar_label: 'Element Render'
4
+ title: 'Element Render'
5
+ ---
6
+
7
+ ## What is Element?
8
+
9
+ **Elements are the smallest building blocks of React apps.**
10
+
11
+ An element describes what you want to see on the screen:
12
+
13
+ ```jsx
14
+ const element = <h1>Hello, world</h1>;
15
+ ```
16
+
17
+ Unlike browser DOM elements, React elements are plain objects, and are cheap to create.
18
+ React DOM takes care of updating the DOM to match the React elements.
19
+ :::note
20
+ One might confuse elements with a more widely known concept of "components".
21
+ We will introduce components in the [next topic](components-and-props.mdx).
22
+ Elements are what components are "made of".
23
+ :::
24
+
25
+ ## Rendering an Element into the DOM
26
+ Let's say there is a `<div>` somewhere in your HTML file:
27
+
28
+ ```js
29
+ <div id="root"></div>
30
+ ```
31
+
32
+ It's called a **"root" DOM node** because everything inside it will be managed by React DOM.
33
+
34
+ Applications built with just React usually have a single root DOM node.
35
+ If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like.
36
+
37
+ To render a React element into a root DOM node, you need to create a React root and then pass the element to `root.render()`:
38
+
39
+ ```js
40
+ const element = <h1>Hello, world</h1>;
41
+
42
+ const root = ReactDOM.createRoot(document.getElementById('root'));
43
+
44
+ root.render(element);
45
+ ```
46
+
47
+ It displays "Hello, world" on the page.
48
+
49
+ ## React Only Updates What's Necessary
50
+ React DOM compares the element and its children to the previous one,
51
+ and only applies the DOM updates necessary to bring the DOM to the desired state.
52
+
53
+ It is possible because React uses [Virtual Dom](https://legacy.reactjs.org/docs/faq-internals.html).
54
+
55
+ ## Virtual DOM
56
+
57
+ **The virtual DOM (VDOM)** is a way of doing things in programming. It means having an ideal or "virtual" version of a user interface (UI) stored in the computer's memory. This virtual version is then matched up with the "real" DOM using a library like ReactDOM, and this matching process is called reconciliation.
58
+
59
+ This method makes it possible for React to work in a declarative way: *you tell React how you want the UI to look, and it makes sure the actual DOM matches that look*. This saves you from having to mess with attributes, handle events, or manually update the DOM, which you would have to do if you were building your app differently.
60
+
61
+ Because "virtual DOM" is more like a way of doing things than a specific technology, people might have different ideas about what it means. In the world of React, we often link the term "virtual DOM" with React elements because they are the objects that show the UI. However, React also uses internal objects called ["fibers"](https://github.com/acdlite/react-fiber-architecture) to keep extra information about the component tree. So, you could think of them as part of how React does its "virtual DOM" work.
62
+
63
+
64
+
65
+ ## Materials
66
+ 1. [Rendering Elements. Documentation](https://react.dev/learn/writing-markup-with-jsx)