|
1 | 1 | import { beforeAll, describe, expect, test } from 'vitest' |
2 | 2 |
|
3 | 3 | import { get } from '@/tests/helpers/e2etest' |
4 | | -import { SURROGATE_ENUMS } from '@/frame/middleware/set-fastly-surrogate-key' |
5 | | -import { latest } from '@/versions/lib/enterprise-server-releases' |
6 | | - |
7 | | -const makeURL = (pathname: string): string => |
8 | | - `/api/article/meta?${new URLSearchParams({ pathname })}` |
9 | | - |
10 | | -interface PageMetadata { |
11 | | - product: string |
12 | | - title: string |
13 | | - intro: string |
14 | | -} |
15 | | - |
16 | | -interface ErrorResponse { |
17 | | - error: string |
18 | | -} |
19 | | - |
20 | | -describe('pageinfo api', () => { |
21 | | - beforeAll(() => { |
22 | | - // If you didn't set the `ROOT` variable, the tests will fail rather |
23 | | - // cryptically. So as a warning for engineers running these tests, |
24 | | - // alert in case it was accidentally forgotten. |
25 | | - if (!process.env.ROOT) { |
26 | | - console.warn( |
27 | | - 'WARNING: The pageinfo tests require the ROOT environment variable to be set to the fixture root', |
28 | | - ) |
29 | | - } |
30 | | - // Ditto for fixture-based translations to work |
31 | | - if (!process.env.TRANSLATIONS_FIXTURE_ROOT) { |
32 | | - console.warn( |
33 | | - 'WARNING: The pageinfo tests require the TRANSLATIONS_FIXTURE_ROOT environment variable to be set', |
34 | | - ) |
35 | | - } |
36 | | - }) |
37 | | - |
38 | | - test('happy path', async () => { |
39 | | - const res = await get(makeURL('/en/get-started/start-your-journey')) |
40 | | - expect(res.statusCode).toBe(200) |
41 | | - const meta = JSON.parse(res.body) as PageMetadata |
42 | | - expect(meta.product).toBe('Get started') |
43 | | - expect(meta.title).toBe('Start your journey') |
44 | | - expect(meta.intro).toBe( |
45 | | - 'Get started using HubGit to manage Git repositories and collaborate with others.', |
46 | | - ) |
47 | | - // Check that it can be cached at the CDN |
48 | | - expect(res.headers['set-cookie']).toBeUndefined() |
49 | | - expect(res.headers['cache-control']).toContain('public') |
50 | | - expect(res.headers['cache-control']).toMatch(/max-age=[1-9]/) |
51 | | - expect(res.headers['surrogate-control']).toContain('public') |
52 | | - expect(res.headers['surrogate-control']).toMatch(/max-age=[1-9]/) |
53 | | - expect(res.headers['surrogate-key']).toBe(`${SURROGATE_ENUMS.DEFAULT} language:en`) |
54 | | - }) |
55 | | - |
56 | | - test('a pathname that does not exist', async () => { |
57 | | - const res = await get(makeURL('/en/never/heard/of')) |
58 | | - expect(res.statusCode).toBe(404) |
59 | | - const { error } = JSON.parse(res.body) as ErrorResponse |
60 | | - expect(error).toBe("No page found for '/en/never/heard/of'") |
61 | | - }) |
62 | | - |
63 | | - test("no 'pathname' query string at all", async () => { |
64 | | - const res = await get('/api/article/meta') |
65 | | - expect(res.statusCode).toBe(400) |
66 | | - const { error } = JSON.parse(res.body) as ErrorResponse |
67 | | - expect(error).toBe("No 'pathname' query") |
68 | | - }) |
69 | | - |
70 | | - test("empty 'pathname' query string", async () => { |
71 | | - const res = await get('/api/article/meta?pathname=%20') |
72 | | - expect(res.statusCode).toBe(400) |
73 | | - const { error } = JSON.parse(res.body) as ErrorResponse |
74 | | - expect(error).toBe("'pathname' query empty") |
75 | | - }) |
76 | | - |
77 | | - test('repeated pathname query string key', async () => { |
78 | | - const res = await get('/api/article/meta?pathname=a&pathname=b') |
79 | | - expect(res.statusCode).toBe(400) |
80 | | - const { error } = JSON.parse(res.body) as ErrorResponse |
81 | | - expect(error).toBe("Multiple 'pathname' keys") |
82 | | - }) |
83 | | - |
84 | | - test('redirects correct the URL', async () => { |
85 | | - // Regular redirect from `redirect_from` |
86 | | - { |
87 | | - const res = await get(makeURL('/en/olden-days')) |
88 | | - expect(res.statusCode).toBe(200) |
89 | | - const meta = JSON.parse(res.body) as PageMetadata |
90 | | - expect(meta.title).toBe('HubGit.com Fixture Documentation') |
91 | | - } |
92 | | - // Trailing slashes are always removed |
93 | | - { |
94 | | - const res = await get(makeURL('/en/olden-days/')) |
95 | | - expect(res.statusCode).toBe(200) |
96 | | - const meta = JSON.parse(res.body) as PageMetadata |
97 | | - expect(meta.title).toBe('HubGit.com Fixture Documentation') |
98 | | - } |
99 | | - // Short code for latest version |
100 | | - { |
101 | | - const res = await get(makeURL('/en/enterprise-server@latest/get-started/liquid/ifversion')) |
102 | | - expect(res.statusCode).toBe(200) |
103 | | - const meta = JSON.parse(res.body) as PageMetadata |
104 | | - expect(meta.intro).toMatch(/\(not on fpt\)/) |
105 | | - } |
106 | | - // A URL that doesn't have fpt as an available version |
107 | | - { |
108 | | - const res = await get(makeURL('/en/get-started/versioning/only-ghec-and-ghes')) |
109 | | - expect(res.statusCode).toBe(200) |
110 | | - const meta = JSON.parse(res.body) as PageMetadata |
111 | | - expect(meta.title).toBe('Only in Enterprise Cloud and Enterprise Server') |
112 | | - } |
113 | | - }) |
114 | | - |
115 | | - test('a page that uses non-trivial Liquid to render', async () => { |
116 | | - // This page uses `{% ifversion not fpt %}` in the intro. |
117 | | - |
118 | | - // First on the fpt version |
119 | | - { |
120 | | - const res = await get(makeURL('/en/get-started/liquid/ifversion')) |
121 | | - expect(res.statusCode).toBe(200) |
122 | | - const meta = JSON.parse(res.body) as PageMetadata |
123 | | - expect(meta.intro).toMatch(/\(on fpt\)/) |
124 | | - } |
125 | | - // Second on any other version |
126 | | - { |
127 | | - const res = await get(makeURL('/en/enterprise-server@latest/get-started/liquid/ifversion')) |
128 | | - expect(res.statusCode).toBe(200) |
129 | | - const meta = JSON.parse(res.body) as PageMetadata |
130 | | - expect(meta.intro).toMatch(/\(not on fpt\)/) |
131 | | - } |
132 | | - }) |
133 | | - |
134 | | - test('home pages', async () => { |
135 | | - // The home page with language specified |
136 | | - { |
137 | | - const res = await get(makeURL('/en')) |
138 | | - expect(res.statusCode).toBe(200) |
139 | | - const meta = JSON.parse(res.body) as PageMetadata |
140 | | - expect(meta.title).toMatch('HubGit.com Fixture Documentation') |
141 | | - } |
142 | | - // enterprise-server with language specified |
143 | | - // This is important because it tests that we check for a page |
144 | | - // before we bothering to see if it can be a redirect. |
145 | | - // That's how our middleware and Next router works. First we look |
146 | | - // for a page, if it can't be found, then we check if it's a redirect. |
147 | | - // This test proves something that caused a bug in production. |
148 | | - { |
149 | | - const res = await get(makeURL(`/en/enterprise-server@${latest}`)) |
150 | | - expect(res.statusCode).toBe(200) |
151 | | - const meta = JSON.parse(res.body) as PageMetadata |
152 | | - expect(meta.title).toMatch('HubGit Enterprise Server Fixture Documentation') |
153 | | - } |
154 | | - }) |
155 | | - |
156 | | - test('home pages (with redirects)', async () => { |
157 | | - // The home page for the default language *not* specified |
158 | | - { |
159 | | - const res = await get(makeURL('/')) |
160 | | - expect(res.statusCode).toBe(200) |
161 | | - const meta = JSON.parse(res.body) as PageMetadata |
162 | | - expect(meta.title).toMatch('HubGit.com Fixture Documentation') |
163 | | - } |
164 | | - // enterprise-server without language specified |
165 | | - { |
166 | | - const res = await get(makeURL('/enterprise-server@latest')) |
167 | | - expect(res.statusCode).toBe(200) |
168 | | - const meta = JSON.parse(res.body) as PageMetadata |
169 | | - expect(meta.title).toMatch('HubGit Enterprise Server Fixture Documentation') |
170 | | - } |
171 | | - }) |
172 | | - |
173 | | - test('archived enterprise versions', async () => { |
174 | | - // For example /en/[email protected] is a valid Page in the |
175 | | - // site tree, but /en/[email protected] is not. Yet we can |
176 | | - // 200 OK and serve content for that. This needs to be reflected in |
177 | | - // page info too. Even if we have to "fabricate" the title a bit. |
178 | | - |
179 | | - // At the time of writing, the latest archived version |
180 | | - { |
181 | | - const res = await get(makeURL('/en/[email protected]')) |
182 | | - expect(res.statusCode).toBe(200) |
183 | | - const meta = JSON.parse(res.body) as PageMetadata |
184 | | - expect(meta.title).toMatch('GitHub Enterprise Server 3.2 Help Documentation') |
185 | | - } |
186 | | - |
187 | | - // The oldest known archived version that we proxy |
188 | | - { |
189 | | - const res = await get(makeURL('/en/enterprise/11.10.340')) |
190 | | - expect(res.statusCode).toBe(200) |
191 | | - const meta = JSON.parse(res.body) as PageMetadata |
192 | | - expect(meta.title).toMatch('GitHub Enterprise Server 11.10.340 Help Documentation') |
193 | | - } |
194 | | - }) |
195 | | - |
196 | | - test('pathname has to start with /', async () => { |
197 | | - const res = await get(makeURL('ip')) |
198 | | - expect(res.statusCode).toBe(400) |
199 | | - const { error } = JSON.parse(res.body) as ErrorResponse |
200 | | - expect(error).toBe("'pathname' has to start with /") |
201 | | - }) |
202 | | - |
203 | | - test("pathname can't contain spaces /", async () => { |
204 | | - const res = await get(makeURL('/en foo bar')) |
205 | | - expect(res.statusCode).toBe(400) |
206 | | - const { error } = JSON.parse(res.body) as ErrorResponse |
207 | | - expect(error).toBe("'pathname' cannot contain whitespace") |
208 | | - }) |
209 | | - |
210 | | - describe('translations', () => { |
211 | | - test('Japanese page', async () => { |
212 | | - const res = await get(makeURL('/ja/get-started/start-your-journey/hello-world')) |
213 | | - expect(res.statusCode).toBe(200) |
214 | | - const meta = JSON.parse(res.body) as PageMetadata |
215 | | - expect(meta.product).toBe('はじめに') |
216 | | - expect(meta.title).toBe('こんにちは World') |
217 | | - expect(meta.intro).toBe('この Hello World 演習に従って、HubGit の使用を開始します。') |
218 | | - }) |
219 | | - |
220 | | - test('falls back to English if translation is not present', async () => { |
221 | | - const enRes = await get(makeURL('/en/get-started/start-your-journey')) |
222 | | - expect(enRes.statusCode).toBe(200) |
223 | | - // This page doesn't have a Japanese translation. I.e. it doesn't |
224 | | - // even exist on disk. So it'll fall back to English. |
225 | | - const translationRes = await get(makeURL('/ja/get-started/start-your-journey')) |
226 | | - expect(translationRes.statusCode).toBe(200) |
227 | | - const en = JSON.parse(enRes.body) as PageMetadata |
228 | | - const translation = JSON.parse(translationRes.body) as PageMetadata |
229 | | - expect(en.title).toBe(translation.title) |
230 | | - expect(en.intro).toBe(translation.intro) |
231 | | - }) |
232 | | - }) |
233 | | -}) |
| 4 | +import { SURROGATE_ENUMS } from '@/frame/middleware/set-fastly-surrogate |
0 commit comments