1
+ import { expect , test } from '@playwright/test' ;
2
+ import { TeachPage } from '../../page/teach/education' ;
3
+ import { closeExternalBanners } from '../utils' ;
4
+ import { testSelector } from '../../utils' ;
5
+ import { checkTeachCta , checkTeachMap , checkTeachNav , MAILTO_LINK , MATERIALS_LINK , SIGNUP_LINK } from './utils' ;
6
+
7
+ test . describe ( 'Education landing page content and interactions' , async ( ) => {
8
+ test . beforeEach ( async ( { context, page, baseURL } ) => {
9
+ const teachPage = new TeachPage ( page ) ;
10
+ await teachPage . init ( ) ;
11
+ await closeExternalBanners ( context , page , baseURL ) ;
12
+ } ) ;
13
+
14
+ test ( 'Should load the education page correctly' , async ( { page } ) => {
15
+ // Check if the page title is correct
16
+ expect ( await page . title ( ) ) . toBe ( 'Kotlin for Education' ) ;
17
+
18
+ // Check if the main content is visible
19
+ const mainContent = page . locator ( testSelector ( 'teach-index-page' ) ) ;
20
+ await expect ( mainContent ) . toBeVisible ( ) ;
21
+
22
+ // Check if the page heading is correct
23
+ const title = mainContent . locator ( 'h1' ) ;
24
+ await expect ( title ) . toBeVisible ( ) ;
25
+
26
+ expect ( await title . textContent ( ) ) . toBe ( 'Teach Computer Science with Kotlin' ) ;
27
+ } ) ;
28
+
29
+ test ( 'Should have working navigation buttons' , async ( { page } ) => {
30
+ await checkTeachNav ( page , 'Overview' ) ;
31
+ } ) ;
32
+
33
+ test ( 'Should display course materials download button' , async ( { page } ) => {
34
+ const block = page . locator ( '.teach-launch-course__text' ) ;
35
+
36
+ // Locate and verify the download button with the exact name match
37
+ const button = block . getByRole ( 'link' , { name : 'Download all materials →' , exact : true } ) ;
38
+ await expect ( button ) . toBeVisible ( ) ;
39
+ await expect ( button ) . toHaveAttribute ( 'href' , MATERIALS_LINK ) ;
40
+
41
+ expect ( await block . screenshot ( ) ) . toMatchSnapshot ( 'launch-course-text.png' ) ;
42
+ } ) ;
43
+
44
+ test ( 'Should display features section with features' , async ( { page } ) => {
45
+ // Check if the features section is visible
46
+ const featuresSection = page . locator ( '.teach-features' ) ;
47
+ await expect ( featuresSection ) . toBeVisible ( ) ;
48
+
49
+ // Check if there are exactly 3 features
50
+ const expectedFeatures = [ 'Academically recognized' , 'Language of the industry' , 'Multiplatform' ] ;
51
+ const features = featuresSection . locator ( '.teach-feature' ) ;
52
+ expect ( await features . count ( ) ) . toBe ( 3 ) ;
53
+
54
+ // Check each feature
55
+ for ( let i = 0 ; i < expectedFeatures . length ; i ++ ) {
56
+ const feature = features . nth ( i ) ;
57
+ await expect ( feature . locator ( '.teach-feature__icon img' ) ) . toBeVisible ( ) ;
58
+ expect ( await feature . locator ( '.ktl-h3' ) . textContent ( ) ) . toBe ( expectedFeatures [ i ] ) ;
59
+ }
60
+
61
+ expect ( await featuresSection . screenshot ( ) ) . toMatchSnapshot ( 'teach-features.png' ) ;
62
+ } ) ;
63
+
64
+ test ( 'Should display buttons in top section' , async ( { page } ) => {
65
+ // Get the top buttons block container
66
+ const block = page . locator ( '.teach-top-buttons' ) ;
67
+
68
+ // Check the "Join Educators Community" button visibility and link
69
+ const join = block . getByRole ( 'link' , { name : 'Join Educators Сommunity' , exact : true } ) ;
70
+ await expect ( join ) . toBeVisible ( ) ;
71
+ await expect ( join ) . toHaveAttribute ( 'href' , SIGNUP_LINK ) ;
72
+
73
+ // Check the "Why Teach Kotlin" button visibility and link
74
+ const why = block . getByRole ( 'link' , { name : 'Why Teach Kotlin →' , exact : true } ) ;
75
+ await expect ( why ) . toBeVisible ( ) ;
76
+ await expect ( why ) . toHaveAttribute ( 'href' , 'why-teach-kotlin.html' ) ;
77
+
78
+ expect ( await block . screenshot ( ) ) . toMatchSnapshot ( 'teach-top-mobile-buttons.png' ) ;
79
+ } ) ;
80
+
81
+ test ( 'Should display university statistics correctly' , async ( { page } ) => {
82
+ // Check if the university count is displayed
83
+ const universitiesText = page . locator ( '.universities-top__title h2' ) ;
84
+ expect ( await universitiesText . textContent ( ) ) . toBe ( 'Kotlin Courses Around the World' ) ;
85
+
86
+ // Check if the TeachNumbers component is visible
87
+ const teachNumbers = page . locator ( '.universities-top__numbers' ) ;
88
+ await expect ( teachNumbers ) . toBeVisible ( ) ;
89
+
90
+ // Check if the TeachNumbers component is visible
91
+ const subtitles = teachNumbers . locator ( '.teach-number__subtitle' ) ;
92
+ expect ( await subtitles . count ( ) ) . toBe ( 2 ) ;
93
+ expect ( await subtitles . nth ( 0 ) . textContent ( ) ) . toBe ( 'countries' ) ;
94
+ expect ( await subtitles . nth ( 1 ) . textContent ( ) ) . toBe ( 'universities' ) ;
95
+ } ) ;
96
+
97
+ test ( 'Should display university logos' , async ( { page } ) => {
98
+ // Check if the university logos are visible
99
+ const logos = page . locator ( '.teach-logos__logo' ) ;
100
+ expect ( await logos . count ( ) ) . toBe ( 5 ) ;
101
+
102
+ // Check specific universities
103
+ await expect ( page . locator ( 'img[alt="Harvard University"]' ) ) . toBeVisible ( ) ;
104
+ await expect ( page . locator ( 'img[alt="University of Cambridge"]' ) ) . toBeVisible ( ) ;
105
+ await expect ( page . locator ( 'img[alt="Stanford University"]' ) ) . toBeVisible ( ) ;
106
+ await expect ( page . locator ( 'img[alt="Imperial College London"]' ) ) . toBeVisible ( ) ;
107
+ await expect ( page . locator ( 'img[alt="The University of Chicago"]' ) ) . toBeVisible ( ) ;
108
+
109
+ expect ( await page . locator ( '.teach-logos' ) . screenshot ( ) ) . toMatchSnapshot ( 'teach-logos.png' ) ;
110
+ } ) ;
111
+
112
+ test ( 'Should have a working interactive map' , async ( { page } ) => {
113
+ // Check if the map is visible
114
+ const map = page . locator ( '.teach-map__wrapper' ) ;
115
+ await checkTeachMap ( page , map ) ;
116
+ } ) ;
117
+
118
+ test ( 'Should display navigation buttons' , async ( { page } ) => {
119
+ const bottom = page . locator ( '.teach-universities__bottom' ) ;
120
+ await expect ( bottom ) . toBeVisible ( ) ;
121
+
122
+ // Check if the mailto button is visible and working
123
+ const mailtoButton = bottom . getByRole ( 'link' , { name :
'[email protected] .' , exact :
true } ) ;
124
+ await expect ( mailtoButton ) . toBeVisible ( ) ;
125
+ await expect ( mailtoButton ) . toHaveAttribute ( 'href' , MAILTO_LINK ) ;
126
+
127
+ // Check if the "All Universities" button is visible
128
+ const allUniversitiesButton = bottom . getByRole ( 'link' , { name : 'All universities' , exact : true } ) ;
129
+ await expect ( allUniversitiesButton ) . toBeVisible ( ) ;
130
+ await expect ( allUniversitiesButton ) . toHaveAttribute ( 'href' , 'courses.html' ) ;
131
+ } ) ;
132
+
133
+ test ( 'Should have comprehensive resource links section' , async ( { page } ) => {
134
+ // Check if the resources section is visible
135
+ const resourcesSection = page . locator ( '#start-teaching-kotlin' ) ;
136
+ await expect ( resourcesSection ) . toBeVisible ( ) ;
137
+
138
+ // Check section title
139
+ const sectionTitle = resourcesSection . locator ( 'h2' ) ;
140
+ await expect ( sectionTitle ) . toHaveText ( 'Start Teaching Kotlin with These Resources' ) ;
141
+
142
+ // Check category headings
143
+ const expectedTitles = [ 'Get started' , 'Tools' , 'Online Courses' , 'Android in Kotlin' , 'Practice Kotlin' ] ;
144
+ const categoryHeadings = resourcesSection . locator ( '.ktl-h4' ) ;
145
+ await expect ( categoryHeadings ) . toHaveCount ( expectedTitles . length ) ;
146
+
147
+ // Check each category heading and its associated links
148
+ for ( let i = 0 ; i < expectedTitles . length ; i ++ ) {
149
+ const item = categoryHeadings . nth ( i ) ;
150
+ await expect ( item , `Category heading should be ${ expectedTitles [ i ] } ` ) . toHaveText ( expectedTitles [ i ] ) ;
151
+ const links = item . locator ( ':scope + .teach-list > li' ) ;
152
+ expect ( await links . count ( ) , `${ expectedTitles [ i ] } category should have at least one link` ) . toBeGreaterThan ( 0 ) ;
153
+ }
154
+ } ) ;
155
+
156
+ test ( 'Should have a working subscription form' , async ( { page } ) => {
157
+ const email = '[email protected] ' ;
158
+
159
+ await page . route ( 'https://forms-service.jetbrains.com/marketo' , route => {
160
+ if ( route . request ( ) . method ( ) !== 'POST' ) route . continue ( ) ;
161
+ route . fulfill ( {
162
+ status : 200 ,
163
+ contentType : 'application/json' ,
164
+ body : JSON . stringify ( { 'success' : true , 'cause' : [ ] } )
165
+ } ) ;
166
+ } ) ;
167
+
168
+ await page . route ( `https://account.jetbrains.com/services/acceptAgreement?email=${ encodeURIComponent ( email ) } &type=mkt.newsletter.visitor` , route => {
169
+ if ( route . request ( ) . method ( ) !== 'POST' ) route . continue ( ) ;
170
+ route . fulfill ( {
171
+ status : 200 ,
172
+ contentType : 'application/json' ,
173
+ body : JSON . stringify ( { 'status' : 'OK' } )
174
+ } ) ;
175
+ } ) ;
176
+
177
+ // Locate the subscription form
178
+ const subscriptionForm = page . locator ( '.teach-subscription-section' ) ;
179
+ await expect ( subscriptionForm ) . toBeVisible ( ) ;
180
+
181
+ // Find the form elements
182
+ await subscriptionForm . locator ( 'input[name="Email"]' ) . fill ( email ) ;
183
+
184
+ // Check the privacy checkbox by clicking its label
185
+ await subscriptionForm . locator ( '.teach-subscription-form__checkbox label' ) . click ( ) ;
186
+
187
+ // Submit the form
188
+ await subscriptionForm . locator ( 'button[type="submit"]' ) . click ( ) ;
189
+
190
+ // Verify that the form shows the submitted state (check icon appears)
191
+ await expect ( subscriptionForm . locator ( '.teach-subscription-form__submitted-icon' ) ) . toBeVisible ( ) ;
192
+
193
+ expect ( await subscriptionForm . screenshot ( ) ) . toMatchSnapshot ( 'subscription-form.png' ) ;
194
+ } ) ;
195
+
196
+ test ( 'Should have a working YouTube player' , async ( { page } ) => {
197
+ // Check if the YouTube player container is visible
198
+ const youtubePlayer = page . locator ( '.teach-video' ) ;
199
+ await expect ( youtubePlayer ) . toBeVisible ( ) ;
200
+
201
+ // Check if the player is in "show video" mode
202
+ await expect ( youtubePlayer . locator ( '[class*="ktl-youtube-player-module_preview_"]' ) ) . toBeVisible ( ) ;
203
+
204
+ // Check if the play button is visible
205
+ const playButton = youtubePlayer . locator ( '[class*="ktl-youtube-player-module_play-button_"]' ) ;
206
+ await expect ( playButton ) . toBeVisible ( ) ;
207
+
208
+ // Click the play button to start the video
209
+ await playButton . click ( ) ;
210
+
211
+ // After clicking, the play button should be hidden and the video should be playing
212
+ await expect ( playButton ) . toBeHidden ( ) ;
213
+
214
+ // Check if the iframe is loaded correctly
215
+ const iframe = youtubePlayer . locator ( 'iframe' ) ;
216
+ await expect ( iframe ) . toBeVisible ( ) ;
217
+
218
+ // Check if the iframe has the correct src attribute (YouTube embed URL)
219
+ const iframeSrc = await iframe . getAttribute ( 'src' ) ;
220
+ expect ( iframeSrc ) . toBeTruthy ( ) ;
221
+ expect ( iframeSrc ) . toContain ( 'youtube.com' ) ;
222
+ expect ( iframeSrc ) . toContain ( 'PLlFc5cFwUnmzT4cgLOGJYGnY6j0W2xoFA' ) ;
223
+ } ) ;
224
+
225
+ test ( 'Should have working quotes slider' , async ( { page } ) => {
226
+ const quotes = page . locator ( '[class*=ktl-quotes-slider-module_quotes-slider_]' ) ;
227
+
228
+ // Initial state of quotes
229
+ const defaultAuthor = quotes . getByText ( 'David Vaughn' , { exact : false } ) ;
230
+ await expect ( defaultAuthor ) . toBeVisible ( ) ;
231
+
232
+ const quoteContent = quotes . getByText ( 'Kotlin is faster to develop' , { exact : false } ) ;
233
+ await expect ( quoteContent ) . toBeVisible ( ) ;
234
+
235
+ // Controls of navigation
236
+ const controls = page . locator ( '[class*=ktl-quotes-slider-module_control_]' ) ;
237
+ await expect ( controls ) . toHaveCount ( 2 ) ;
238
+
239
+ const backButton = controls . first ( ) ;
240
+ await expect ( backButton ) . not . toHaveClass ( / k t l - q u o t e s - s l i d e r - m o d u l e _ c o n t r o l - a c t i v e _ / ) ;
241
+
242
+ const forwardButton = controls . last ( ) ;
243
+ await expect ( forwardButton ) . toHaveClass ( / k t l - q u o t e s - s l i d e r - m o d u l e _ c o n t r o l - a c t i v e _ / ) ;
244
+
245
+ await forwardButton . click ( ) ;
246
+
247
+ await expect ( quotes . getByText ( 'Sergey Bratus' ) ) . toBeVisible ( ) ;
248
+ await expect ( quotes . getByText ( 'I used Kotlin' ) ) . toBeVisible ( ) ;
249
+
250
+ await expect ( backButton ) . toHaveClass ( / k t l - q u o t e s - s l i d e r - m o d u l e _ c o n t r o l - a c t i v e _ / ) ;
251
+ } ) ;
252
+
253
+ test ( 'Should have action buttons for educators' , checkTeachCta ) ;
254
+ } ) ;
0 commit comments