1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
- /* global page, browser */
- const sleep = require('await-sleep')
- const { latest } = require('../../lib/enterprise-server-releases')
- const languages = require('../../lib/languages')
- describe('homepage', () => {
- jest.setTimeout(60 * 1000)
- test('should be titled "GitHub Documentation"', async () => {
- await page.goto('http://localhost:4001')
- await expect(page.title()).resolves.toMatch('GitHub Documentation')
- })
- })
- describe('browser search', () => {
- jest.setTimeout(60 * 1000)
- it('works on the homepage', async () => {
- await page.goto('http://localhost:4001/en')
- await page.click('#search-input-container input[type="search"]')
- await page.type('#search-input-container input[type="search"]', 'actions')
- await page.waitForSelector('.ais-Hits')
- const hits = await page.$$('.ais-Hits-item')
- expect(hits.length).toBeGreaterThan(5)
- })
- it('works on article pages', async () => {
- await page.goto('http://localhost:4001/en/actions')
- await page.click('#search-input-container input[type="search"]')
- await page.type('#search-input-container input[type="search"]', 'workflows')
- await page.waitForSelector('.ais-Hits')
- const hits = await page.$$('.ais-Hits-item')
- expect(hits.length).toBeGreaterThan(5)
- })
- it('works on 404 error page', async () => {
- await page.goto('http://localhost:4001/en/404')
- await page.click('#search-input-container input[type="search"]')
- await page.type('#search-input-container input[type="search"]', 'actions')
- await page.waitForSelector('.ais-Hits')
- const hits = await page.$$('.ais-Hits-item')
- expect(hits.length).toBeGreaterThan(5)
- })
- it('sends the correct data to search for Enterprise Server', async () => {
- expect.assertions(2)
- const newPage = await browser.newPage()
- await newPage.goto('http://localhost:4001/ja/enterprise-server@2.22/admin/installation')
- await newPage.setRequestInterception(true)
- newPage.on('request', interceptedRequest => {
- if (interceptedRequest.method() === 'GET' && /search\?/i.test(interceptedRequest.url())) {
- const { searchParams } = new URL(interceptedRequest.url())
- expect(searchParams.get('version')).toBe('2.22')
- expect(searchParams.get('language')).toBe('ja')
- }
- interceptedRequest.continue()
- })
- await newPage.click('#search-input-container input[type="search"]')
- await newPage.type('#search-input-container input[type="search"]', 'test')
- await newPage.waitForSelector('.search-result')
- })
- it('sends the correct data to search for GHAE', async () => {
- expect.assertions(2)
- const newPage = await browser.newPage()
- await newPage.goto('http://localhost:4001/en/github-ae@latest/admin/overview')
- await newPage.setRequestInterception(true)
- newPage.on('request', interceptedRequest => {
- if (interceptedRequest.method() === 'GET' && /search\?/i.test(interceptedRequest.url())) {
- const { searchParams } = new URL(interceptedRequest.url())
- expect(searchParams.get('version')).toBe('ghae')
- expect(searchParams.get('language')).toBe('en')
- }
- interceptedRequest.continue()
- })
- await newPage.click('#search-input-container input[type="search"]')
- await newPage.type('#search-input-container input[type="search"]', 'test')
- await newPage.waitForSelector('.search-result')
- })
- })
- describe('helpfulness', () => {
- it('sends an event to /events when submitting form', async () => {
- // Visit a page that displays the prompt
- await page.goto('http://localhost:4001/en/actions/getting-started-with-github-actions/about-github-actions')
- // Track network requests
- await page.setRequestInterception(true)
- page.on('request', request => {
- // Ignore GET requests
- if (!/\/events$/.test(request.url())) return request.continue()
- expect(request.method()).toMatch(/POST|PUT/)
- request.respond({
- contentType: 'application/json',
- body: JSON.stringify({ id: 'abcd1234' }),
- status: 200
- })
- })
- // When I click the "Yes" button
- await page.click('.js-helpfulness [for=helpfulness-yes]')
- // (sent a POST request to /events)
- // I see the request for my email
- await page.waitForSelector('.js-helpfulness [type="email"]')
- // When I fill in my email and submit the form
- await page.type('.js-helpfulness [type="email"]', 'test@example.com')
- await sleep(1000)
- await page.click('.js-helpfulness [type="submit"]')
- // (sent a PUT request to /events/{id})
- // I see the feedback
- await page.waitForSelector('.js-helpfulness [data-help-end]')
- })
- })
- describe('csrf meta', () => {
- it('should have a csrf-token meta tag on the page', async () => {
- await page.goto('http://localhost:4001/en/actions/getting-started-with-github-actions/about-github-actions')
- await page.waitForSelector('meta[name="csrf-token"]')
- })
- })
- describe('platform specific content', () => {
- // from tests/javascripts/user-agent.js
- const userAgents = [
- { name: 'Mac', id: 'mac', ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9' },
- { name: 'Windows', id: 'windows', ua: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36' },
- { name: 'Linux', id: 'linux', ua: 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1' }
- ]
- const linuxUserAgent = userAgents[2]
- const pageWithSwitcher = 'http://localhost:4001/en/github/using-git/configuring-git-to-handle-line-endings'
- const pageWithoutSwitcher = 'http://localhost:4001/en/github/using-git'
- const pageWithDefaultPlatform = 'http://localhost:4001/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service'
- it('should have a platform switcher', async () => {
- await page.goto(pageWithSwitcher)
- const nav = await page.$$('nav.UnderlineNav')
- const switches = await page.$$('a.platform-switcher')
- const selectedSwitch = await page.$$('a.platform-switcher.selected')
- expect(nav).toHaveLength(1)
- expect(switches.length).toBeGreaterThan(1)
- expect(selectedSwitch).toHaveLength(1)
- })
- it('should NOT have a platform switcher', async () => {
- await page.goto(pageWithoutSwitcher)
- const nav = await page.$$('nav.UnderlineNav')
- const switches = await page.$$('a.platform-switcher')
- const selectedSwitch = await page.$$('a.platform-switcher.selected')
- expect(nav).toHaveLength(0)
- expect(switches).toHaveLength(0)
- expect(selectedSwitch).toHaveLength(0)
- })
- it('should detect platform from user agent', async () => {
- for (const agent of userAgents) {
- await page.setUserAgent(agent.ua)
- await page.goto(pageWithSwitcher)
- const selectedPlatformElement = await page.waitForSelector('a.platform-switcher.selected')
- const selectedPlatform = await page.evaluate(el => el.textContent, selectedPlatformElement)
- expect(selectedPlatform).toBe(agent.name)
- }
- })
- it('should prefer defaultPlatform from frontmatter', async () => {
- for (const agent of userAgents) {
- await page.setUserAgent(agent.ua)
- await page.goto(pageWithDefaultPlatform)
- const defaultPlatform = await page.$eval('[data-default-platform]', el => el.dataset.defaultPlatform)
- const selectedPlatformElement = await page.waitForSelector('a.platform-switcher.selected')
- const selectedPlatform = await page.evaluate(el => el.textContent, selectedPlatformElement)
- expect(defaultPlatform).toBe(linuxUserAgent.id)
- expect(selectedPlatform).toBe(linuxUserAgent.name)
- }
- })
- it('should show the content for the selected platform only', async () => {
- await page.goto(pageWithSwitcher)
- const platforms = ['mac', 'windows', 'linux']
- for (const platform of platforms) {
- await page.click(`.platform-switcher[data-platform="${platform}"]`)
- // content for selected platform is expected to become visible
- await page.waitForSelector(`.extended-markdown.${platform}`, { visible: true, timeout: 3000 })
- // only a single tab should be selected
- const selectedSwitch = await page.$$('a.platform-switcher.selected')
- expect(selectedSwitch).toHaveLength(1)
- // content for NOT selected platforms is expected to become hidden
- const otherPlatforms = platforms.filter(e => e !== platform)
- for (const other of otherPlatforms) {
- await page.waitForSelector(`.extended-markdown.${other}`, { hidden: true, timeout: 3000 })
- }
- }
- })
- })
- describe('card filters', () => {
- it('loads correctly', async () => {
- await page.goto('http://localhost:4001/en/actions')
- const shownCards = await page.$$('.js-filter-card:not(.d-none)')
- const shownNoResult = await page.$('.js-filter-card-no-results:not(.d-none)')
- const maxCards = await page.$eval('.js-filter-card-show-more', btn => parseInt(btn.dataset.jsFilterCardMax))
- expect(shownCards.length).toBe(maxCards)
- expect(shownNoResult).toBeNull()
- })
- it('filters cards', async () => {
- await page.goto('http://localhost:4001/en/actions')
- await page.click('input.js-filter-card-filter')
- await page.type('input.js-filter-card-filter', 'issues')
- const shownCards = await page.$$('.js-filter-card:not(.d-none)')
- const showMoreClasses = await page.$eval('.js-filter-card-show-more', btn => Object.values(btn.classList))
- expect(showMoreClasses).toContain('d-none')
- expect(shownCards.length).toBeGreaterThan(1)
- })
- it('works with select input', async () => {
- await page.goto('http://localhost:4001/en/actions/guides')
- await page.select('.js-filter-card-filter-dropdown[name="type"]', 'overview')
- const shownCards = await page.$$('.js-filter-card:not(.d-none)')
- const shownCardsAttrib = await page.$$eval('.js-filter-card:not(.d-none)', cards =>
- cards.map(card => card.dataset.type)
- )
- shownCardsAttrib.map(attrib => expect(attrib).toBe('overview'))
- expect(shownCards.length).toBeGreaterThan(0)
- })
- it('works with select input on an Enterprise version', async () => {
- await page.goto(`http://localhost:4001/en/enterprise-server@${latest}/actions/guides`)
- await page.select('.js-filter-card-filter-dropdown[name="type"]', 'overview')
- const shownCards = await page.$$('.js-filter-card:not(.d-none)')
- const shownCardsAttrib = await page.$$eval('.js-filter-card:not(.d-none)', cards =>
- cards.map(card => card.dataset.type)
- )
- shownCardsAttrib.map(attrib => expect(attrib).toBe('overview'))
- expect(shownCards.length).toBeGreaterThan(0)
- })
- it('shows more cards', async () => {
- await page.goto('http://localhost:4001/en/actions')
- const maxCards = await page.$eval('.js-filter-card-show-more', btn => parseInt(btn.dataset.jsFilterCardMax))
- await page.click('.js-filter-card-show-more')
- const shownCards = await page.$$('.js-filter-card:not(.d-none)')
- expect(shownCards.length).toBe(maxCards * 2)
- })
- it('displays no result message', async () => {
- await page.goto('http://localhost:4001/en/actions')
- await page.click('input.js-filter-card-filter')
- await page.type('input.js-filter-card-filter', 'this should not work')
- const shownCards = await page.$$('.js-filter-card:not(.d-none)')
- expect(shownCards.length).toBe(0)
- const noResultsClasses = await page.$eval('.js-filter-card-no-results', elem => Object.values(elem.classList))
- expect(noResultsClasses).not.toContain('d-none')
- })
- })
- describe('language banner', () => {
- it('directs user to the English version of the article', async () => {
- const wipLanguageKey = Object.keys(languages).find(key => languages[key].wip)
- // This kinda sucks, but if we don't have a WIP language, we currently can't
- // run a reliable test. But hey, on the bright side, if we don't have a WIP
- // language then this code will never run anyway!
- if (wipLanguageKey) {
- const res = await page.goto(`http://localhost:4001/${wipLanguageKey}/actions`)
- expect(res.ok()).toBe(true)
- const href = await page.$eval('a#to-english-doc', el => el.href)
- expect(href.endsWith('/en/actions')).toBe(true)
- }
- })
- })
- // The Explorer in the iFrame will not be accessible on localhost, but we can still
- // test the query param handling
- describe('GraphQL Explorer', () => {
- it('preserves query strings on the Explorer page without opening search', async () => {
- const queryString = `query {
- viewer {
- foo
- }
- }`
- // Encoded as: query%20%7B%0A%20%20viewer%20%7B%0A%20%20%20%20foo%0A%20%20%7D%0A%7D
- const encodedString = encodeURIComponent(queryString)
- const explorerUrl = 'http://localhost:4001/en/graphql/overview/explorer'
- await page.goto(`${explorerUrl}?query=${encodedString}`)
- // On non-Explorer pages, query params handled by search JS get form-encoded using `+` instead of `%20`.
- // So on these pages, the following test will be false; but on the Explorer page, it should be true.
- expect(page.url().endsWith(encodedString)).toBe(true)
- // On non-Explorer pages, query params handled by search JS will populate in the search box and the `js-open`
- // class is added. On these pages, the following test will NOT be null; but on the Explorer page, it should be null.
- await page.waitForSelector('#search-results-container')
- const searchResult = await page.$('#search-results-container.js-open')
- expect(searchResult).toBeNull()
- })
- })
|