Skip to content

Commit

Permalink
test(browser integration): patch upstream @open-draft/test-server t…
Browse files Browse the repository at this point in the history
…o fix IPv6 issue

- Fix bug in IPv6 URL serialization that isn't available upstream
- Source is not available, so waiting on new release

Same reasoning as: mswjs/interceptors#283
  • Loading branch information
milesrichardson committed Sep 2, 2022
1 parent a129a2f commit 7ccba4f
Show file tree
Hide file tree
Showing 23 changed files with 141 additions and 22 deletions.
2 changes: 1 addition & 1 deletion test/graphql-api/mutation.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as path from 'path'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'
import { pageWith } from 'page-with'
import { executeGraphQLQuery } from './utils/executeGraphQLQuery'
import { gql } from '../support/graphql'
Expand Down
2 changes: 1 addition & 1 deletion test/graphql-api/query.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as path from 'path'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'
import { pageWith } from 'page-with'
import { executeGraphQLQuery } from './utils/executeGraphQLQuery'
import { gql } from '../support/graphql'
Expand Down
2 changes: 1 addition & 1 deletion test/graphql-api/response-patching.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { setupServer } from 'msw/node'
import fetch from 'cross-fetch'
import { graphql as executeGraphql } from 'graphql'
import { buildSchema } from 'graphql/utilities'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'
import { createGraphQLClient, gql } from '../support/graphql'

let httpServer: HttpServer
Expand Down
2 changes: 1 addition & 1 deletion test/graphql-api/response-patching.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as path from 'path'
import { pageWith } from 'page-with'
import { ExecutionResult, buildSchema, graphql } from 'graphql'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'
import { SetupWorkerApi } from 'msw'
import { gql } from '../support/graphql'

Expand Down
2 changes: 1 addition & 1 deletion test/jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as fs from 'fs'
import * as path from 'path'
import { invariant } from 'outvariant'
import { CreateBrowserApi, createBrowser, server } from 'page-with'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from 'patched/OpenDraftTestServer'
import { SERVICE_WORKER_BUILD_PATH } from '../config/constants'
import {
createWorkerConsoleServer,
Expand Down
2 changes: 1 addition & 1 deletion test/msw-api/req/passthrough.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fetch from 'node-fetch'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../patched/OpenDraftTestServer'

let httpServer: HttpServer
const server = setupServer()
Expand Down
2 changes: 1 addition & 1 deletion test/msw-api/req/passthrough.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import * as path from 'path'
import { pageWith } from 'page-with'
import { rest, SetupWorkerApi } from 'msw'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../patched/OpenDraftTestServer'

declare namespace window {
export const msw: {
Expand Down
2 changes: 1 addition & 1 deletion test/msw-api/setup-server/life-cycle-events/on.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fetch from 'node-fetch'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'
import { waitFor } from '../../../support/waitFor'

let httpServer: HttpServer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fetch from 'node-fetch'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'

let httpServer: HttpServer
const server = setupServer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fetch from 'node-fetch'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'

let httpServer: HttpServer
const server = setupServer()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as https from 'https'
import { rest } from 'msw'
import { setupServer, SetupServerApi } from 'msw/node'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'

let httpServer: HttpServer
let server: SetupServerApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment node
*/
import fetch from 'node-fetch'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../../patched/OpenDraftTestServer'
import { setupServer } from 'msw/node'
import { rest } from 'msw'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment node
*/
import fetch from 'node-fetch'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../../patched/OpenDraftTestServer'
import { rest } from 'msw'
import { setupServer } from 'msw/node'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment node
*/
import fetch from 'node-fetch'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'
import { rest } from 'msw'
import { setupServer } from 'msw/node'

Expand Down
2 changes: 1 addition & 1 deletion test/msw-api/setup-server/use.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import fetch from 'node-fetch'
import { rest } from 'msw'
import { setupServer, SetupServerApi } from 'msw/node'
import { RequestHandler as ExpressRequestHandler } from 'express'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../patched/OpenDraftTestServer'

let httpServer: HttpServer
let server: SetupServerApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { pageWith } from 'page-with'
import { until } from '@open-draft/until'
import { workerConsoleSpy } from '../../../../support/workerConsole'
import { waitFor } from '../../../../support/waitFor'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../../patched/OpenDraftTestServer'

let httpServer: HttpServer

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path'
import { pageWith } from 'page-with'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'
import { sleep } from '../../../support/utils'
import { waitFor } from '../../../support/waitFor'

Expand Down
119 changes: 119 additions & 0 deletions test/patched/OpenDraftTestServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {
HttpServer as OrigHttpServer,
httpsAgent,
} from '@open-draft/test-server/http'

export const HttpServer: typeof OrigHttpServer = OrigHttpServer

export type HttpServer = OrigHttpServer

const PATCHED_IPV6: unique symbol = Symbol('isPatchedIPv6Compat')

type PatchedForIPv6Compat<Method> = Method & {
[PATCHED_IPV6]?: true
}

type PatchedGetServerAddress = PatchedForIPv6Compat<
typeof OrigHttpServer.getServerAddress
>
type PatchedBuildHttpServerApi = PatchedForIPv6Compat<
typeof OrigHttpServer.prototype['buildHttpServerApi']
>

/**
* Patch `HttpServer` from `../patched/OpenDraftTestServer`, to fix bug in URL
* serialization of IPv6 addresses, by surrounding the host with brackets, e.g.:
*
* correct: { port: 37007, host: '::1', url: 'http://[::1]:37007' }
* incorrect: { port: 37007, host: '::1', url: 'http://::1:37007' }
* ^^^^^ missing [ ]
*
* This bug appears in Node v18 due to new behavior of inheriting operating system
* DNS resolution order, so some dual-stack hosts will resolve addresses including
* `localhost` to `::1`, causing `HttpServer` to bind to `::1` instead of `127.0.0.1`.
*
* This patch is a work-around until the upstream bug is fixed in the
* `../patched/OpenDraftTestServer` package.
*
* To use this patch, change every import of `HttpServer` and `httpsAgent` to
* import from this file, instead of upstream `../patched/OpenDraftTestServer`
*
* To deprecate this patch once the upstream bug is fixed, revert all the
* imports to use `../patched/OpenDraftTestServer`, and delete this file.
*/
const applyPatchFixingIPv6URISerialization = (
HttpServer: typeof OrigHttpServer,
): void => {
if ((HttpServer.getServerAddress as PatchedGetServerAddress)[PATCHED_IPV6]) {
console.log('DUPLICATE PATCH: HttpServer.getServerAddress')
}

// eslint-disable-next-line no-var
var origGetServerAddress = HttpServer.getServerAddress
/**
* Patch `static HttpServer.getServer` to fix URI serialization of IPv6 hosts,
* by calling the original method and then modifying the return value.
*
* @see HttpServer.getServerAddress
*/
HttpServer.getServerAddress = function () {
const address = origGetServerAddress.apply(
{}, // we're patching a static method so we expect no valid `this` binding
// eslint-disable-next-line prefer-rest-params
arguments as unknown as Parameters<typeof HttpServer.getServerAddress>,
)

// Copy the same behavior of the original function, but fix the ternary
Object.defineProperty(address, 'href', {
get() {
// assume: host with `:` is definitely not valid IPv4, likely valid IPv6
return new URL(
`${this.protocol}//${
this.host.includes(':') &&
!this.host.startsWith('[') &&
!this.host.endsWith(']')
? `[${this.host}]`
: this.host
}:${this.port}`,
).href
},
enumerable: true,
})

return address
} as PatchedGetServerAddress
;(HttpServer.getServerAddress as PatchedGetServerAddress)[PATCHED_IPV6] = true

if (
// @ts-ignore accessing private method .buildHttpServerApi
HttpServer.prototype.buildHttpServerApi[PATCHED_IPV6]
) {
console.log('DUPLICATE PATCH: HttpServer.prototype.buildHttpServerApi')
}

/**
* Patch `HttpServer.buildHttpServerApi` (private) class method, to fix
* URI serialization of IPv6 hosts.
*
* This patch re-implements the original behavior of the function, but it's necessary
* so that `buildHttpServerApi` can call the newly patched `HttpServer.getServerAddress`
*/
// @ts-ignore patching a private method
HttpServer.prototype.buildHttpServerApi = ((
server: Parameters<typeof HttpServer.getServerAddress>[0],
) => {
const address = HttpServer.getServerAddress(server)

return {
address,
url(path = '/') {
return new URL(path, address.href).href
},
}
}) as PatchedBuildHttpServerApi
HttpServer.prototype['buildHttpServerApi'][PATCHED_IPV6] = true
}

applyPatchFixingIPv6URISerialization(HttpServer)

export { httpsAgent }
2 changes: 1 addition & 1 deletion test/rest-api/204-response.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path'
import { pageWith } from 'page-with'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'

let server: HttpServer

Expand Down
2 changes: 1 addition & 1 deletion test/rest-api/cookies-inheritance.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fetch from 'node-fetch'
import { rest } from 'msw'
import { setupServer, SetupServerApi } from 'msw/node'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'
import { RequestHandler as ExpressRequestHandler } from 'express'

let httpServer: HttpServer
Expand Down
2 changes: 1 addition & 1 deletion test/rest-api/cors.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path'
import { pageWith } from 'page-with'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'

let server: HttpServer

Expand Down
2 changes: 1 addition & 1 deletion test/rest-api/request/matching/all.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment node
*/
import fetch, { Response } from 'node-fetch'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../../../patched/OpenDraftTestServer'
import { RESTMethods, rest } from 'msw'
import { setupServer } from 'msw/node'

Expand Down
2 changes: 1 addition & 1 deletion test/support/workerConsole.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ConsoleMessageType } from 'page-with/lib/utils/spyOnConsole'
import { HttpServer } from '@open-draft/test-server/http'
import { HttpServer } from '../patched/OpenDraftTestServer'
import { format } from 'outvariant'

let workerConsoleServer: HttpServer
Expand Down

0 comments on commit 7ccba4f

Please sign in to comment.