epam-ai-conductor 0.3.0 → 0.3.2

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 (118) hide show
  1. package/dist/content/{content/module-1/tests/Button.test.tsx → module-1/tests/Button.test.js} +8 -8
  2. package/dist/content/module-1/tests/CourseCard.test.js +68 -0
  3. package/dist/content/module-1/tests/CourseInfo.test.js +136 -0
  4. package/dist/content/module-1/tests/Courses.test.js +81 -0
  5. package/dist/content/{content/module-1/tests/Header.test.tsx → module-1/tests/Header.test.js} +5 -7
  6. package/dist/content/module-1/tests/Input.test.js +42 -0
  7. package/dist/content/module-1/tests/helpers.test.js +13 -0
  8. package/dist/content/module-2/tests/App.test.js +130 -0
  9. package/dist/content/module-2/tests/Button.test.js +22 -0
  10. package/dist/content/module-2/tests/CourseCard.test.js +93 -0
  11. package/dist/content/module-2/tests/CourseInfo.test.js +125 -0
  12. package/dist/content/module-2/tests/Courses.test.js +106 -0
  13. package/dist/content/module-2/tests/CreateCourse.test.js +117 -0
  14. package/dist/content/module-2/tests/Header.test.js +45 -0
  15. package/dist/content/module-2/tests/Input.test.js +42 -0
  16. package/dist/content/module-2/tests/Login.test.js +128 -0
  17. package/dist/content/module-2/tests/Registration.test.js +119 -0
  18. package/dist/content/module-2/tests/helpers.test.js +13 -0
  19. package/dist/content/module-2/tests/services.test.js +79 -0
  20. package/dist/content/module-3/tests/App.test.js +192 -0
  21. package/dist/content/{module-1/tests/Button.test.tsx → module-3/tests/Button.test.js} +8 -8
  22. package/dist/content/module-3/tests/CourseCard.test.js +50 -0
  23. package/dist/content/module-3/tests/CourseInfo.test.js +148 -0
  24. package/dist/content/module-3/tests/Courses.test.js +107 -0
  25. package/dist/content/module-3/tests/CreateAuthor.test.js +36 -0
  26. package/dist/content/module-3/tests/CreateCourse.test.js +66 -0
  27. package/dist/content/module-3/tests/Header.test.js +76 -0
  28. package/dist/content/module-3/tests/Input.test.js +42 -0
  29. package/dist/content/module-3/tests/Login.test.js +62 -0
  30. package/dist/content/{module-2/tests/Registration.test.tsx → module-3/tests/Registration.test.js} +13 -13
  31. package/dist/content/module-3/tests/helpers.test.js +13 -0
  32. package/dist/content/module-3/tests/services.test.js +83 -0
  33. package/dist/content/module-3/tests/slices.test.js +146 -0
  34. package/dist/content/module-4/tests/App.test.js +309 -0
  35. package/dist/content/module-4/tests/Button.test.js +22 -0
  36. package/dist/content/module-4/tests/CourseCard.test.js +111 -0
  37. package/dist/content/module-4/tests/CourseForm.test.js +108 -0
  38. package/dist/content/module-4/tests/CourseInfo.test.js +146 -0
  39. package/dist/content/module-4/tests/Courses.test.js +129 -0
  40. package/dist/content/module-4/tests/CreateAuthor.test.js +37 -0
  41. package/dist/content/module-4/tests/Header.test.js +79 -0
  42. package/dist/content/{content/module-1/tests/Input.test.tsx → module-4/tests/Input.test.js} +17 -11
  43. package/dist/content/module-4/tests/Login.test.js +61 -0
  44. package/dist/content/module-4/tests/PrivateRoute.test.js +45 -0
  45. package/dist/content/{content/module-2/tests/Registration.test.tsx → module-4/tests/Registration.test.js} +14 -13
  46. package/dist/content/module-4/tests/helpers.test.js +13 -0
  47. package/dist/content/module-4/tests/services.test.js +267 -0
  48. package/dist/content/module-4/tests/slices.test.js +146 -0
  49. package/dist/content/module-4/tests/thunk.test.js +238 -0
  50. package/package.json +4 -3
  51. package/scripts/postinstall.cjs +24 -0
  52. package/dist/content/content/module-1/task/module-1_home-task_components.md +0 -257
  53. package/dist/content/content/module-1/task/module-1_home-task_good_practices.md +0 -69
  54. package/dist/content/content/module-1/task/module-1_home-task_task.md +0 -253
  55. package/dist/content/content/module-1/tests/CourseCard.test.tsx +0 -64
  56. package/dist/content/content/module-1/tests/CourseInfo.test.tsx +0 -73
  57. package/dist/content/content/module-1/tests/Courses.test.tsx +0 -87
  58. package/dist/content/content/module-1/tests/helpers.test.ts +0 -13
  59. package/dist/content/content/module-1/theory/module-1_elements-render.md +0 -66
  60. package/dist/content/content/module-1/theory/module-1_hooks_useEffect.md +0 -178
  61. package/dist/content/content/module-1/theory/module-1_hooks_useState.md +0 -131
  62. package/dist/content/content/module-1/theory/module-1_react.md +0 -64
  63. package/dist/content/content/module-1/theory/module-1_spa.md +0 -74
  64. package/dist/content/content/module-2/task/module-2_home-task_components.md +0 -313
  65. package/dist/content/content/module-2/task/module-2_home-task_good_practices.md +0 -35
  66. package/dist/content/content/module-2/task/module-2_home-task_task.md +0 -210
  67. package/dist/content/content/module-2/tests/App.test.tsx +0 -54
  68. package/dist/content/content/module-2/tests/Login.test.tsx +0 -73
  69. package/dist/content/content/module-2/tests/SearchBar.test.tsx +0 -39
  70. package/dist/content/content/module-2/theory/module-2_custom-hooks.md +0 -201
  71. package/dist/content/content/module-2/theory/module-2_hooks.md +0 -117
  72. package/dist/content/content/module-2/theory/module-2_react-router.md +0 -328
  73. package/dist/content/content/module-3/task/module-3_home-task_components.md +0 -94
  74. package/dist/content/content/module-3/task/module-3_home-task_good_practices.md +0 -26
  75. package/dist/content/content/module-3/task/module-3_home-task_task.md +0 -170
  76. package/dist/content/content/module-3/tests/App.test.tsx +0 -54
  77. package/dist/content/content/module-3/tests/Courses.test.tsx +0 -87
  78. package/dist/content/content/module-3/tests/CreateAuthor.test.tsx +0 -44
  79. package/dist/content/content/module-3/tests/CreateCourse.test.tsx +0 -122
  80. package/dist/content/content/module-3/theory/module-3_redux-hooks.md +0 -194
  81. package/dist/content/content/module-3/theory/module-3_state-actions-reducers.md +0 -445
  82. package/dist/content/content/module-4/task/module-4_home-task_components.md +0 -187
  83. package/dist/content/content/module-4/task/module-4_home-task_task.md +0 -139
  84. package/dist/content/content/module-4/tests/App.test.tsx +0 -54
  85. package/dist/content/content/module-4/tests/Courses.test.tsx +0 -87
  86. package/dist/content/content/module-4/tests/CreateCourse.test.tsx +0 -122
  87. package/dist/content/content/module-4/tests/Login.test.tsx +0 -73
  88. package/dist/content/content/module-4/theory/module-4_async-redux.md +0 -99
  89. package/dist/content/content/module-4/theory/module-4_private-routes.md +0 -55
  90. package/dist/content/content/module-5/task/module-5_home-task_instruction.md +0 -68
  91. package/dist/content/content/module-5/task/module-5_home-task_task.md +0 -154
  92. package/dist/content/content/module-5/tests/App.test.tsx +0 -54
  93. package/dist/content/content/module-5/tests/CourseCard.test.tsx +0 -64
  94. package/dist/content/content/module-5/tests/Courses.test.tsx +0 -87
  95. package/dist/content/content/module-5/tests/Header.test.tsx +0 -23
  96. package/dist/content/content/module-5/theory/module-5_react-testing-library_example.md +0 -379
  97. package/dist/content/content/module-5/theory/module-5_redux-writing-tests.md +0 -246
  98. package/dist/content/module-1/tests/CourseCard.test.tsx +0 -64
  99. package/dist/content/module-1/tests/CourseInfo.test.tsx +0 -73
  100. package/dist/content/module-1/tests/Courses.test.tsx +0 -87
  101. package/dist/content/module-1/tests/Header.test.tsx +0 -23
  102. package/dist/content/module-1/tests/Input.test.tsx +0 -36
  103. package/dist/content/module-1/tests/helpers.test.ts +0 -13
  104. package/dist/content/module-2/tests/App.test.tsx +0 -54
  105. package/dist/content/module-2/tests/Login.test.tsx +0 -73
  106. package/dist/content/module-2/tests/SearchBar.test.tsx +0 -39
  107. package/dist/content/module-3/tests/App.test.tsx +0 -54
  108. package/dist/content/module-3/tests/Courses.test.tsx +0 -87
  109. package/dist/content/module-3/tests/CreateAuthor.test.tsx +0 -44
  110. package/dist/content/module-3/tests/CreateCourse.test.tsx +0 -122
  111. package/dist/content/module-4/tests/App.test.tsx +0 -54
  112. package/dist/content/module-4/tests/Courses.test.tsx +0 -87
  113. package/dist/content/module-4/tests/CreateCourse.test.tsx +0 -122
  114. package/dist/content/module-4/tests/Login.test.tsx +0 -73
  115. package/dist/content/module-5/tests/App.test.tsx +0 -54
  116. package/dist/content/module-5/tests/CourseCard.test.tsx +0 -64
  117. package/dist/content/module-5/tests/Courses.test.tsx +0 -87
  118. package/dist/content/module-5/tests/Header.test.tsx +0 -23
@@ -0,0 +1,125 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { CourseInfo } from "../../components/CourseInfo";
4
+ import { formatCreationDate, getCourseDuration } from "../../helpers";
5
+ import { MemoryRouter } from "react-router";
6
+
7
+ const mockedCoursesList = [
8
+ {
9
+ id: "1",
10
+ title: "Course 1",
11
+ description: "Course 1 description",
12
+ creationDate: "2022-01-01",
13
+ duration: 60,
14
+ authors: [
15
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
16
+ "f762978b-61eb-4096-812b-ebde22838167",
17
+ ],
18
+ },
19
+ {
20
+ id: "2",
21
+ title: "Course 2",
22
+ description: "Course 2 description",
23
+ creationDate: "2022-02-01",
24
+ duration: 90,
25
+ authors: ["df32994e-b23d-497c-9e4d-84e4dc02882f"],
26
+ },
27
+ ];
28
+ const authorsList = [
29
+ { id: "df32994e-b23d-497c-9e4d-84e4dc02882f", name: "name1" },
30
+ { id: "27cc3006-e93a-4748-8ca8-73d06aa93b6d", name: "name2" },
31
+ { id: "f762978b-61eb-4096-812b-ebde22838167", name: "name3" },
32
+ ];
33
+
34
+ jest.mock("react-router-dom", () => ({
35
+ ...jest.requireActual("react-router-dom"),
36
+ useParams: () => ({ courseId: "1" }),
37
+ }));
38
+
39
+ describe("CourseInfo", () => {
40
+ test("should render correct title (find correct course from coursesList based on courseId param use useParams hook)", () => {
41
+ render(
42
+ <MemoryRouter>
43
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
44
+ </MemoryRouter>
45
+ );
46
+
47
+ const courseTitle = screen.getByRole("heading", { level: 1 });
48
+
49
+ expect(courseTitle.textContent).toBe("Course 1");
50
+ });
51
+
52
+ test("should render correct description", () => {
53
+ render(
54
+ <MemoryRouter>
55
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
56
+ </MemoryRouter>
57
+ );
58
+
59
+ const courseDescription = screen.getByText("Course 1 description");
60
+
61
+ expect(courseDescription).toBeInTheDocument();
62
+ });
63
+
64
+ test("should render correct course duration (use getCourseDuration)", () => {
65
+ render(
66
+ <MemoryRouter>
67
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
68
+ </MemoryRouter>
69
+ );
70
+
71
+ const courseDuration = screen.queryByText(getCourseDuration(60));
72
+
73
+ expect(courseDuration).toBeInTheDocument();
74
+ });
75
+
76
+ test("should render correct course creation date (use formatCreationDate)", () => {
77
+ render(
78
+ <MemoryRouter>
79
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
80
+ </MemoryRouter>
81
+ );
82
+
83
+ const courseCreationDate = screen.getByText(
84
+ formatCreationDate(mockedCoursesList[0].creationDate)
85
+ );
86
+ expect(courseCreationDate).toBeInTheDocument();
87
+ });
88
+
89
+ test("should render correct course authors names (find a course in the coursesList and match data from course authors and authorsList prop)", () => {
90
+ render(
91
+ <MemoryRouter>
92
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
93
+ </MemoryRouter>
94
+ );
95
+
96
+ const authorNames = screen
97
+ .getAllByRole("listitem")
98
+ .map((li) => li.textContent);
99
+
100
+ expect(authorNames).toEqual(["name2", "name3"]);
101
+ });
102
+
103
+ test('should render "BACK" button as a Link provided by react-router-dom', () => {
104
+ render(
105
+ <MemoryRouter>
106
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
107
+ </MemoryRouter>
108
+ );
109
+
110
+ const backButton = screen.queryByText(/back/i);
111
+
112
+ expect(backButton.closest("a")).toBeInTheDocument();
113
+ });
114
+
115
+ test('should render "BACK" link to="/courses"', () => {
116
+ render(
117
+ <MemoryRouter>
118
+ <CourseInfo coursesList={mockedCoursesList} authorsList={authorsList} />
119
+ </MemoryRouter>
120
+ );
121
+
122
+ const backButton = screen.queryByText(/back/i);
123
+ expect(backButton.closest("a")).toHaveAttribute("href", "/courses");
124
+ });
125
+ });
@@ -0,0 +1,106 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { Courses } from "../../components/Courses/Courses";
4
+ import { MemoryRouter } from "react-router";
5
+
6
+ describe("Courses component", () => {
7
+ const mockedCoursesList = [
8
+ {
9
+ id: "1",
10
+ title: "Course 1",
11
+ description: "Course 1 description",
12
+ creationDate: "2022-01-01",
13
+ duration: 60,
14
+ authors: [
15
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
16
+ "f762978b-61eb-4096-812b-ebde22838167",
17
+ ],
18
+ },
19
+ {
20
+ id: "2",
21
+ title: "Course 2",
22
+ description: "Course 2 description",
23
+ creationDate: "2022-02-01",
24
+ duration: 90,
25
+ authors: ["df32994e-b23d-497c-9e4d-84e4dc02882f"],
26
+ },
27
+ ];
28
+ const authorsList = [
29
+ { id: "df32994e-b23d-497c-9e4d-84e4dc02882f", name: "name" },
30
+ { id: "27cc3006-e93a-4748-8ca8-73d06aa93b6d", name: "name" },
31
+ { id: "f762978b-61eb-4096-812b-ebde22838167", name: "name" },
32
+ ];
33
+ const onAddClick = jest.fn();
34
+
35
+ test('should render list of courses from coursesList prop with data-testid="courseCard"', () => {
36
+ render(
37
+ <MemoryRouter>
38
+ <Courses
39
+ coursesList={mockedCoursesList}
40
+ authorsList={authorsList}
41
+ onAddClick={onAddClick}
42
+ handleShowCourse={(id) => {}}
43
+ />
44
+ </MemoryRouter>
45
+ );
46
+
47
+ const courseElements = screen.getAllByTestId("courseCard");
48
+
49
+ expect(courseElements[0]).toBeInTheDocument();
50
+ expect(courseElements).toHaveLength(2);
51
+ });
52
+
53
+ test("should render 'ADD NEW COURSE' button", () => {
54
+ render(
55
+ <MemoryRouter>
56
+ <Courses
57
+ coursesList={mockedCoursesList}
58
+ authorsList={authorsList}
59
+ onAddClick={onAddClick}
60
+ handleShowCourse={(id) => {}}
61
+ />
62
+ </MemoryRouter>
63
+ );
64
+
65
+ const button = screen.getByText(/add new/i);
66
+
67
+ expect(button).toBeInTheDocument();
68
+ });
69
+
70
+ test("should render 'ADD NEW COURSE' button as a Link with provided by react-router-dom to='/courses/add'", () => {
71
+ render(
72
+ <MemoryRouter>
73
+ <Courses
74
+ coursesList={mockedCoursesList}
75
+ authorsList={authorsList}
76
+ onAddClick={onAddClick}
77
+ handleShowCourse={(id) => {}}
78
+ />
79
+ </MemoryRouter>
80
+ );
81
+
82
+ const link = screen.getByText(/add new/i).closest("a");
83
+
84
+ expect(link).toBeInTheDocument();
85
+ expect(link).toHaveAttribute("href", "/courses/add");
86
+ });
87
+
88
+ test("should render EmptyCourseList component if no courses (with 'Your List Is Empty' text and button with data-testid='addCourse')", () => {
89
+ render(
90
+ <MemoryRouter>
91
+ <Courses
92
+ coursesList={[]}
93
+ authorsList={authorsList}
94
+ onAddClick={onAddClick}
95
+ handleShowCourse={(id) => {}}
96
+ />
97
+ </MemoryRouter>
98
+ );
99
+
100
+ const emptyText = screen.queryByText(/your list is empty/i);
101
+ const addButtonElement = screen.getByTestId("addCourse");
102
+
103
+ expect(emptyText).toBeInTheDocument();
104
+ expect(addButtonElement).toBeInTheDocument();
105
+ });
106
+ });
@@ -0,0 +1,117 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { CourseForm } from "../../components/CourseForm/CourseForm";
4
+ import { MemoryRouter } from "react-router";
5
+
6
+ describe("CourseForm", () => {
7
+ const mockAuthors = [
8
+ { id: "1", name: "Author 1" },
9
+ { id: "2", name: "Author 2" },
10
+ ];
11
+
12
+ const mockCourseForm = jest.fn();
13
+ const mockCreateAuthor = jest.fn();
14
+
15
+ beforeEach(() => {
16
+ mockCourseForm.mockClear();
17
+ mockCreateAuthor.mockClear();
18
+ });
19
+
20
+ it("should create a new course with the entered data in all field`s (createCourse prop should be called on createCourseButton click)", () => {
21
+ render(
22
+ <MemoryRouter>
23
+ <CourseForm
24
+ authorsList={mockAuthors}
25
+ createCourse={mockCourseForm}
26
+ createAuthor={mockCreateAuthor}
27
+ />
28
+ </MemoryRouter>
29
+ );
30
+
31
+ const titleInput = screen.getByTestId("titleInput");
32
+ const durationInput = screen.getByTestId("durationInput");
33
+ const descriptionTextArea = screen.getByTestId("descriptionTextArea");
34
+ const addAuthorButton = screen.getAllByTestId("addAuthor")[0];
35
+ const createCourseButton = screen.getByTestId("createCourseButton");
36
+
37
+ fireEvent.change(titleInput, { target: { value: "Course Title" } });
38
+ fireEvent.change(durationInput, { target: { value: "20" } });
39
+ fireEvent.click(addAuthorButton);
40
+ fireEvent.change(descriptionTextArea, {
41
+ target: { value: "Course Description" },
42
+ });
43
+
44
+ fireEvent.click(createCourseButton);
45
+
46
+ expect(mockCourseForm).toHaveBeenCalled();
47
+ });
48
+
49
+ it("should not create a new course with the empty data (createCourse prop should NOT be called on createCourseButton click)", () => {
50
+ render(
51
+ <MemoryRouter>
52
+ <CourseForm
53
+ authorsList={mockAuthors}
54
+ createCourse={mockCourseForm}
55
+ createAuthor={mockCreateAuthor}
56
+ />
57
+ </MemoryRouter>
58
+ );
59
+
60
+ const createCourseButton = screen.getByTestId("createCourseButton");
61
+
62
+ fireEvent.click(createCourseButton);
63
+
64
+ expect(mockCourseForm).not.toHaveBeenCalled();
65
+ });
66
+
67
+ it("should add an author to the course when CreateAuthor component creates a new author (createAuthor prop should be called on createAuthorButton click)", () => {
68
+ render(
69
+ <MemoryRouter>
70
+ <CourseForm
71
+ authorsList={mockAuthors}
72
+ createCourse={mockCourseForm}
73
+ createAuthor={mockCreateAuthor}
74
+ />
75
+ </MemoryRouter>
76
+ );
77
+
78
+ const createAuthorButton = screen.getByTestId("createAuthorButton");
79
+ const nameInput = screen.getByTestId("createAuthorInput");
80
+
81
+ fireEvent.change(nameInput, { target: { value: "John" } });
82
+
83
+ fireEvent.click(createAuthorButton);
84
+
85
+ expect(mockCreateAuthor).toHaveBeenCalled();
86
+ });
87
+
88
+ it('should render the course authors with data-testid="authorItem" in the course authors list', () => {
89
+ const mockCourseAuthors = ["1", "2"];
90
+ render(
91
+ <MemoryRouter>
92
+ <CourseForm
93
+ authorsList={mockAuthors}
94
+ createCourse={mockCourseForm}
95
+ createAuthor={mockCreateAuthor}
96
+ />
97
+ </MemoryRouter>
98
+ );
99
+
100
+ const courseAuthorItems = screen.getAllByTestId("authorItem");
101
+ expect(courseAuthorItems.length).toBe(mockCourseAuthors.length);
102
+ });
103
+ it('should display the "Authors list is empty" message when there are no authors is selected for the course', () => {
104
+ render(
105
+ <MemoryRouter>
106
+ <CourseForm
107
+ authorsList={[]}
108
+ createCourse={mockCourseForm}
109
+ createAuthor={mockCreateAuthor}
110
+ />
111
+ </MemoryRouter>
112
+ );
113
+ const emptyText = screen.queryByText(/list is empty/i);
114
+
115
+ expect(emptyText).toBeInTheDocument();
116
+ });
117
+ });
@@ -0,0 +1,45 @@
1
+ import "@testing-library/jest-dom";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import { Header } from "../../components/Header/Header";
4
+ import { MemoryRouter } from "react-router";
5
+
6
+ describe("Header component", () => {
7
+ test("should render logo (<img /> tag)", () => {
8
+ render(
9
+ <MemoryRouter>
10
+ <Header />
11
+ </MemoryRouter>
12
+ );
13
+
14
+ const imageElement = screen.getByRole("img");
15
+
16
+ expect(imageElement).toBeInTheDocument();
17
+ });
18
+
19
+ test('should not render logout button without "token" in localStorage', () => {
20
+ render(
21
+ <MemoryRouter>
22
+ <Header />
23
+ </MemoryRouter>
24
+ );
25
+
26
+ const logoutButtonElement = screen.queryByText(/logout/i);
27
+
28
+ expect(logoutButtonElement).not.toBeInTheDocument();
29
+ });
30
+
31
+ test('should immediately remove "token" from localStorage on "LOGOUT" button click', () => {
32
+ localStorage.setItem("token", "token");
33
+ render(
34
+ <MemoryRouter>
35
+ <Header />
36
+ </MemoryRouter>
37
+ );
38
+
39
+ const logoutButtonElement = screen.queryByText(/logout/i);
40
+
41
+ fireEvent.click(logoutButtonElement);
42
+
43
+ expect(localStorage.getItem("token")).toBeFalsy();
44
+ });
45
+ });
@@ -0,0 +1,42 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { Input } from "../../common/Input";
4
+
5
+ describe("Input component", () => {
6
+ const placeholderTextMock = "Enter a value";
7
+
8
+ test("should render input with provided labelText prop value", () => {
9
+ render(
10
+ <Input labelText="Test Input" placeholderText={placeholderTextMock} />
11
+ );
12
+
13
+ const inputElement = screen.getByLabelText("Test Input");
14
+ expect(inputElement).toBeInTheDocument();
15
+ });
16
+
17
+ test("should render input with provided placeholderText prop value", () => {
18
+ const { getByPlaceholderText } = render(
19
+ <Input labelText="Test Input" placeholderText={placeholderTextMock} />
20
+ );
21
+
22
+ expect(getByPlaceholderText(placeholderTextMock)).toBeInTheDocument();
23
+ });
24
+
25
+ test("should call provided callback for onChange event", () => {
26
+ const handleChange = jest.fn();
27
+
28
+ render(
29
+ <Input
30
+ labelText="Test Input"
31
+ onChange={handleChange}
32
+ placeholderText={placeholderTextMock}
33
+ />
34
+ );
35
+
36
+ const inputElement = screen.getByLabelText("Test Input");
37
+ fireEvent.change(inputElement, { target: { value: "Hello" } });
38
+
39
+ expect(handleChange).toHaveBeenCalledTimes(1);
40
+ expect(inputElement.value).toBe("Hello");
41
+ });
42
+ });
@@ -0,0 +1,128 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, fireEvent, screen, waitFor } from "@testing-library/react";
3
+ import { MemoryRouter } from "react-router-dom";
4
+ import { Login } from "../../components/Login/Login";
5
+ import * as services from "../../services";
6
+
7
+ beforeEach(() => {
8
+ jest.spyOn(services, "login").mockImplementation(
9
+ jest.fn(() =>
10
+ Promise.resolve({
11
+ successful: true,
12
+ result: "token123",
13
+ user: {
14
+ name: "John Doe",
15
+ },
16
+ })
17
+ )
18
+ );
19
+
20
+ jest.spyOn(global, "fetch").mockImplementation(
21
+ jest.fn(() =>
22
+ Promise.resolve({
23
+ ok: true,
24
+ json: () =>
25
+ Promise.resolve({
26
+ result: "token",
27
+ user: {
28
+ name: "John Doe",
29
+ },
30
+ }),
31
+ })
32
+ )
33
+ );
34
+ });
35
+
36
+ describe("Login", () => {
37
+ test("should render login form with 2 inputs, registration info text and link", () => {
38
+ render(
39
+ <MemoryRouter>
40
+ <Login />
41
+ </MemoryRouter>
42
+ );
43
+
44
+ expect(screen.queryByText(/email/i)).toBeInTheDocument();
45
+ expect(screen.queryByText(/password/i)).toBeInTheDocument();
46
+ expect(screen.queryByText(/an account you/i)).toBeInTheDocument();
47
+ expect(screen.getByRole("link")).toBeInTheDocument();
48
+ });
49
+
50
+ test("should submits login form calls login service with entered email and password", async () => {
51
+ render(
52
+ <MemoryRouter>
53
+ <Login setName={jest.fn()} />
54
+ </MemoryRouter>
55
+ );
56
+
57
+ fireEvent.change(screen.queryByText(/email/i).querySelector("input"), {
58
+ target: { value: "test@example.com" },
59
+ });
60
+ fireEvent.change(screen.queryByText(/password/i).querySelector("input"), {
61
+ target: { value: "password123" },
62
+ });
63
+
64
+ fireEvent.click(screen.getByRole("button"));
65
+
66
+ expect(services.login).toHaveBeenCalledWith({
67
+ email: "test@example.com",
68
+ password: "password123",
69
+ });
70
+ await waitFor(() => expect(localStorage.getItem("token")).toBe("token123"));
71
+ });
72
+
73
+ test('should set "token" to localstorage after login submit', async () => {
74
+ render(
75
+ <MemoryRouter>
76
+ <Login setName={jest.fn()} />
77
+ </MemoryRouter>
78
+ );
79
+
80
+ fireEvent.change(screen.queryByText(/email/i).querySelector("input"), {
81
+ target: { value: "test@example.com" },
82
+ });
83
+ fireEvent.change(screen.queryByText(/password/i).querySelector("input"), {
84
+ target: { value: "password123" },
85
+ });
86
+
87
+ fireEvent.click(screen.getByRole("button"));
88
+
89
+ expect(services.login).toHaveBeenCalledWith({
90
+ email: "test@example.com",
91
+ password: "password123",
92
+ });
93
+ await waitFor(() => expect(localStorage.getItem("token")).toBe("token123"));
94
+ });
95
+
96
+ test('should render the "Password is required" validation message and NOT call login service', async () => {
97
+ render(
98
+ <MemoryRouter>
99
+ <Login setName={jest.fn()} />
100
+ </MemoryRouter>
101
+ );
102
+
103
+ fireEvent.change(screen.queryByText(/email/i).querySelector("input"), {
104
+ target: { value: "test@example.com" },
105
+ });
106
+
107
+ fireEvent.click(screen.getByRole("button"));
108
+
109
+ expect(screen.queryByText(/password is required/i)).toBeInTheDocument();
110
+ expect(services.login).not.toHaveBeenCalled();
111
+ });
112
+ test('should render the "Email is required" validation message and NOT call login service', async () => {
113
+ render(
114
+ <MemoryRouter>
115
+ <Login setName={jest.fn()} />
116
+ </MemoryRouter>
117
+ );
118
+
119
+ fireEvent.change(screen.queryByText(/password/i).querySelector("input"), {
120
+ target: { value: "password123" },
121
+ });
122
+
123
+ fireEvent.click(screen.getByRole("button"));
124
+
125
+ expect(screen.queryByText(/email is required/i)).toBeInTheDocument();
126
+ expect(services.login).not.toHaveBeenCalled();
127
+ });
128
+ });
@@ -0,0 +1,119 @@
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/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()));
13
+
14
+ jest.spyOn(global, "fetch").mockImplementation(
15
+ jest.fn(() =>
16
+ Promise.resolve({
17
+ ok: true,
18
+ json: () => Promise.resolve(),
19
+ })
20
+ )
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("should render the registration form with 3 inputs, login info text and link", () => {
31
+ render(
32
+ <MemoryRouter>
33
+ <Registration />
34
+ </MemoryRouter>
35
+ );
36
+
37
+ expect(screen.queryByText(/name/i)).toBeInTheDocument();
38
+ expect(screen.queryByText(/email/i)).toBeInTheDocument();
39
+ expect(screen.queryByText(/password/i)).toBeInTheDocument();
40
+ expect(screen.getByRole("button")).toBeInTheDocument();
41
+ expect(screen.getByRole("link")).toBeInTheDocument();
42
+ });
43
+
44
+ test('should submit the registration form, call the "createUser" service with the entered name, email and password', async () => {
45
+ render(
46
+ <MemoryRouter>
47
+ <Registration />
48
+ </MemoryRouter>
49
+ );
50
+
51
+ fireEvent.change(screen.queryByText(/name/i).querySelector("input"), {
52
+ target: { value: "John Doe" },
53
+ });
54
+ fireEvent.change(screen.queryByText(/email/i).querySelector("input"), {
55
+ target: { value: "john.doe@example.com" },
56
+ });
57
+ fireEvent.change(screen.queryByText(/password/i).querySelector("input"), {
58
+ target: { value: "password123" },
59
+ });
60
+
61
+ fireEvent.click(screen.getByRole("button"));
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
+
71
+ test('should render the "Password is required" validation message and NOT call registration service', async () => {
72
+ render(
73
+ <MemoryRouter>
74
+ <Registration setName={jest.fn()} />
75
+ </MemoryRouter>
76
+ );
77
+
78
+ fireEvent.change(screen.queryByText(/email/i).querySelector("input"), {
79
+ target: { value: "test@example.com" },
80
+ });
81
+
82
+ fireEvent.click(screen.getByRole("button"));
83
+
84
+ expect(screen.queryByText(/password is required/i)).toBeInTheDocument();
85
+ expect(services.createUser).not.toHaveBeenCalled();
86
+ });
87
+ test('should render the "Email is required" validation message and NOT call registration service', async () => {
88
+ render(
89
+ <MemoryRouter>
90
+ <Registration setName={jest.fn()} />
91
+ </MemoryRouter>
92
+ );
93
+
94
+ fireEvent.change(screen.queryByText(/password/i).querySelector("input"), {
95
+ target: { value: "password123" },
96
+ });
97
+
98
+ fireEvent.click(screen.getByRole("button"));
99
+
100
+ expect(screen.queryByText(/email is required/i)).toBeInTheDocument();
101
+ expect(services.createUser).not.toHaveBeenCalled();
102
+ });
103
+ test('should render the "Name is required" validation message and NOT call registration service', async () => {
104
+ render(
105
+ <MemoryRouter>
106
+ <Registration setName={jest.fn()} />
107
+ </MemoryRouter>
108
+ );
109
+
110
+ fireEvent.change(screen.queryByText(/password/i).querySelector("input"), {
111
+ target: { value: "password123" },
112
+ });
113
+
114
+ fireEvent.click(screen.getByRole("button"));
115
+
116
+ expect(screen.queryByText(/name is required/i)).toBeInTheDocument();
117
+ expect(services.createUser).not.toHaveBeenCalled();
118
+ });
119
+ });
@@ -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
+ });