|
1 | 1 | import { requestHandler } from '../index.mts'; |
2 | | -import { makeTestTempDir } from '../test-helpers/makeFileStructure.mts'; |
| 2 | +import { makeTestTempDir, makeTestTempFile } from '../test-helpers/makeFileStructure.mts'; |
3 | 3 | import { responds } from '../test-helpers/responds.mts'; |
4 | 4 | import { withServer } from '../test-helpers/withServer.mts'; |
| 5 | +import type { ConfigMount } from './config/types.mts'; |
5 | 6 | import { buildRouter, type LogInfo } from './buildRouter.mts'; |
6 | 7 | import 'lean-test'; |
7 | 8 |
|
@@ -237,6 +238,138 @@ describe('buildRouter', () => { |
237 | 238 | }); |
238 | 239 | }); |
239 | 240 |
|
| 241 | + describe('redirect-map', () => { |
| 242 | + it('adds multiple redirects', { timeout: 3000 }, async () => { |
| 243 | + const router = await buildRouter([ |
| 244 | + { |
| 245 | + type: 'redirect-map', |
| 246 | + mapping: { '/one': '/new-one', '/two': '/new-two' }, |
| 247 | + status: 307, |
| 248 | + options: { caseSensitive: false }, |
| 249 | + }, |
| 250 | + FALLBACK_200, |
| 251 | + ]); |
| 252 | + return withServer(router, async (url) => { |
| 253 | + await expect( |
| 254 | + fetch(url + '/one', { redirect: 'manual' }), |
| 255 | + responds({ status: 307, headers: { location: '/new-one' }, body: '' }), |
| 256 | + ); |
| 257 | + await expect( |
| 258 | + fetch(url + '/ONE', { redirect: 'manual' }), |
| 259 | + responds({ status: 307, headers: { location: '/new-one' }, body: '' }), |
| 260 | + ); |
| 261 | + await expect( |
| 262 | + fetch(url + '/two', { redirect: 'manual' }), |
| 263 | + responds({ status: 307, headers: { location: '/new-two' }, body: '' }), |
| 264 | + ); |
| 265 | + await expect(fetch(url + '/other', { redirect: 'manual' }), responds({ status: 200 })); |
| 266 | + }); |
| 267 | + }); |
| 268 | + |
| 269 | + it('can be case sensitive', { timeout: 3000 }, async () => { |
| 270 | + const router = await buildRouter([ |
| 271 | + { |
| 272 | + type: 'redirect-map', |
| 273 | + mapping: { '/one': '/new-one' }, |
| 274 | + status: 307, |
| 275 | + options: { caseSensitive: true }, |
| 276 | + }, |
| 277 | + FALLBACK_200, |
| 278 | + ]); |
| 279 | + return withServer(router, async (url) => { |
| 280 | + await expect( |
| 281 | + fetch(url + '/one', { redirect: 'manual' }), |
| 282 | + responds({ status: 307, headers: { location: '/new-one' }, body: '' }), |
| 283 | + ); |
| 284 | + await expect(fetch(url + '/ONE', { redirect: 'manual' }), responds({ status: 200 })); |
| 285 | + }); |
| 286 | + }); |
| 287 | + |
| 288 | + it('allows routing paths to themselves to normalise case', { timeout: 3000 }, async () => { |
| 289 | + const router = await buildRouter([ |
| 290 | + { |
| 291 | + type: 'redirect-map', |
| 292 | + mapping: { '/one': '/one' }, |
| 293 | + status: 307, |
| 294 | + options: { caseSensitive: false }, |
| 295 | + }, |
| 296 | + FALLBACK_200, |
| 297 | + ]); |
| 298 | + return withServer(router, async (url) => { |
| 299 | + await expect( |
| 300 | + fetch(url + '/ONE', { redirect: 'manual' }), |
| 301 | + responds({ status: 307, headers: { location: '/one' }, body: '' }), |
| 302 | + ); |
| 303 | + await expect( |
| 304 | + fetch(url + '/One', { redirect: 'manual' }), |
| 305 | + responds({ status: 307, headers: { location: '/one' }, body: '' }), |
| 306 | + ); |
| 307 | + await expect(fetch(url + '/one', { redirect: 'manual' }), responds({ status: 200 })); |
| 308 | + }); |
| 309 | + }); |
| 310 | + |
| 311 | + const TEST_MAPPING_FILE = makeTestTempFile( |
| 312 | + 'map-', |
| 313 | + 'redirects.map', |
| 314 | + ` |
| 315 | +/foo /new-foo; |
| 316 | +# comment |
| 317 | +/bar\t/new-bar #comment |
| 318 | +; |
| 319 | +/baz |
| 320 | +/new-baz ; |
| 321 | + /indented \t /new-indented |
| 322 | +; |
| 323 | +# /nope /new-nope; /nope /new-nope |
| 324 | +/s1 /escaped\\ space; |
| 325 | +/s2 "/quoted space"; |
| 326 | +`, |
| 327 | + ); |
| 328 | + |
| 329 | + it( |
| 330 | + 'loads mappings from an nginx-formatted mapping file', |
| 331 | + { timeout: 3000 }, |
| 332 | + async ({ getTyped }) => { |
| 333 | + const router = await buildRouter([ |
| 334 | + { |
| 335 | + type: 'redirect-map', |
| 336 | + mapping: getTyped(TEST_MAPPING_FILE), |
| 337 | + status: 307, |
| 338 | + options: { caseSensitive: false }, |
| 339 | + }, |
| 340 | + FALLBACK_200, |
| 341 | + ]); |
| 342 | + return withServer(router, async (url) => { |
| 343 | + await expect( |
| 344 | + fetch(url + '/foo', { redirect: 'manual' }), |
| 345 | + responds({ status: 307, headers: { location: '/new-foo' }, body: '' }), |
| 346 | + ); |
| 347 | + await expect( |
| 348 | + fetch(url + '/bar', { redirect: 'manual' }), |
| 349 | + responds({ status: 307, headers: { location: '/new-bar' }, body: '' }), |
| 350 | + ); |
| 351 | + await expect( |
| 352 | + fetch(url + '/baz', { redirect: 'manual' }), |
| 353 | + responds({ status: 307, headers: { location: '/new-baz' }, body: '' }), |
| 354 | + ); |
| 355 | + await expect( |
| 356 | + fetch(url + '/indented', { redirect: 'manual' }), |
| 357 | + responds({ status: 307, headers: { location: '/new-indented' }, body: '' }), |
| 358 | + ); |
| 359 | + await expect( |
| 360 | + fetch(url + '/s1', { redirect: 'manual' }), |
| 361 | + responds({ status: 307, headers: { location: '/escaped space' }, body: '' }), |
| 362 | + ); |
| 363 | + await expect( |
| 364 | + fetch(url + '/s2', { redirect: 'manual' }), |
| 365 | + responds({ status: 307, headers: { location: '/quoted space' }, body: '' }), |
| 366 | + ); |
| 367 | + await expect(fetch(url + '/nope', { redirect: 'manual' }), responds({ status: 200 })); |
| 368 | + }); |
| 369 | + }, |
| 370 | + ); |
| 371 | + }); |
| 372 | + |
240 | 373 | it('logs requests', { timeout: 3000 }, async () => { |
241 | 374 | const events: Omit<LogInfo, 'duration'>[] = []; |
242 | 375 | const router = await buildRouter( |
@@ -270,3 +403,12 @@ describe('buildRouter', () => { |
270 | 403 | }); |
271 | 404 | }); |
272 | 405 | }); |
| 406 | + |
| 407 | +const FALLBACK_200: ConfigMount = { |
| 408 | + type: 'fixture', |
| 409 | + method: 'GET', |
| 410 | + path: '/*any', |
| 411 | + body: '', |
| 412 | + status: 200, |
| 413 | + headers: {}, |
| 414 | +}; |
0 commit comments