diff --git a/config/copyServiceWorker.ts b/config/copyServiceWorker.ts index b447f298e..264ed4da2 100644 --- a/config/copyServiceWorker.ts +++ b/config/copyServiceWorker.ts @@ -3,6 +3,8 @@ import * as path from 'path' import chalk from 'chalk' import { until } from '@open-draft/until' +const { cyan } = chalk + /** * Copies the given Service Worker source file into the destination. * Injects the integrity checksum into the destination file. @@ -46,5 +48,5 @@ export default async function copyServiceWorker( throw new Error(`Failed to write file.\n${writeFileError.message}`) } - console.log('Service Worker copied to: %s', chalk.cyan(destFilePath)) + console.log('Service Worker copied to: %s', cyan(destFilePath)) } diff --git a/test/jest.config.js b/test/jest.config.js index c5bb2cd68..5221364db 100644 --- a/test/jest.config.js +++ b/test/jest.config.js @@ -2,7 +2,7 @@ module.exports = { transform: { '^.+\\.tsx?$': '@swc/jest', }, - testTimeout: 15000, + testTimeout: 10000, moduleNameMapper: { '^msw(.*)': '/..$1', }, diff --git a/test/msw-api/setup-server/scenarios/cookies-request.test.ts b/test/msw-api/setup-server/scenarios/cookies-request.test.ts index 6ae1dfe33..229aaa559 100644 --- a/test/msw-api/setup-server/scenarios/cookies-request.test.ts +++ b/test/msw-api/setup-server/scenarios/cookies-request.test.ts @@ -1,10 +1,14 @@ -import * as https from 'https' +/** + * @jest-environment node + */ +import https from 'https' import { rest } from 'msw' -import { setupServer, SetupServerApi } from 'msw/node' +import { setupServer } from 'msw/node' import { ServerApi, createServer } from '@open-draft/test-server' +import { waitForClientRequest } from '../../../support/utils' let httpServer: ServerApi -let server: SetupServerApi +const server = setupServer() beforeAll(async () => { httpServer = await createServer((app) => { @@ -13,12 +17,6 @@ beforeAll(async () => { }) }) - server = setupServer( - rest.get(httpServer.https.makeUrl('/user'), (req, res, ctx) => { - return res(ctx.json({ cookies: req.cookies })) - }), - ) - server.listen() }) @@ -27,34 +25,24 @@ afterAll(async () => { await httpServer.close() }) -test('has access to request cookies', (done) => { - let responseBody = '' +test('has access to request cookies', async () => { + server.use( + rest.get(httpServer.https.makeUrl('/user'), (req, res, ctx) => { + return res(ctx.json({ cookies: req.cookies })) + }), + ) + const url = new URL(httpServer.https.makeUrl('/user')) - https.get( - { - method: 'GET', - protocol: url.protocol, - host: url.host, - path: url.pathname, - headers: { - Cookie: 'auth-token=abc-123', - }, - }, - (res) => { - res.setEncoding('utf8') - res.on('error', done) - res.on('data', (chunk) => (responseBody += chunk)) - res.on('end', () => { - const json = JSON.parse(responseBody) - expect(json).toEqual({ - cookies: { - 'auth-token': 'abc-123', - }, - }) - - done() - }) + const request = https.get({ + protocol: url.protocol, + host: url.host, + path: url.pathname, + headers: { + Cookie: 'auth-token=abc-123', }, - ) + }) + const { responseText } = await waitForClientRequest(request) + + expect(responseText).toBe('{"cookies":{"auth-token":"abc-123"}}') }) diff --git a/test/msw-api/setup-server/scenarios/http.test.ts b/test/msw-api/setup-server/scenarios/http.test.ts index 5aff75a92..384a8d3f9 100644 --- a/test/msw-api/setup-server/scenarios/http.test.ts +++ b/test/msw-api/setup-server/scenarios/http.test.ts @@ -1,84 +1,75 @@ /** * @jest-environment node */ -import * as http from 'http' +/** + * @note Do not import as wildcard lest the ESM gods be displeased. + * Make sure "allowSyntheticDefaultImports" is true in tsconfig.json. + */ +import http from 'http' +import { ServerApi, createServer } from '@open-draft/test-server' import { rest } from 'msw' import { setupServer } from 'msw/node' +import { waitForClientRequest } from '../../../support/utils' + +let httpServer: ServerApi +const server = setupServer() -describe('setupServer / http', () => { - const server = setupServer( - rest.get('http://test.mswjs.io', (req, res, ctx) => { +beforeAll(async () => { + server.listen() + + httpServer = await createServer((app) => { + app.get('/resource', (_, res) => { + return res.status(500).send('original-response') + }) + }) +}) + +beforeEach(() => { + server.use( + rest.get(httpServer.http.makeUrl('/resource'), (req, res, ctx) => { return res( ctx.status(401), ctx.set('x-header', 'yes'), - ctx.json({ - firstName: 'John', - }), + ctx.json({ firstName: 'John' }), ) }), ) +}) - beforeAll(() => { - server.listen() - }) - - afterAll(() => { - server.close() - }) - - describe('given I perform a request using http.get', () => { - let res: http.IncomingMessage - let resBody = '' - - beforeAll((done) => { - http.get('http://test.mswjs.io', (message) => { - res = message - res.setEncoding('utf8') - res.on('data', (chunk) => (resBody += chunk)) - res.on('end', done) - }) - }) - - test('should return mocked status code', () => { - expect(res.statusCode).toEqual(401) - }) - - test('should return mocked headers', () => { - expect(res.headers).toHaveProperty('content-type', 'application/json') - expect(res.headers).toHaveProperty('x-header', 'yes') - }) - - test('should return mocked body', () => { - expect(resBody).toEqual('{"firstName":"John"}') - }) - }) - - describe('given I perform a request using http.request', () => { - let res: http.IncomingMessage - let resBody = '' +afterEach(() => { + server.resetHandlers() +}) - beforeAll((done) => { - const req = http.request('http://test.mswjs.io', (message) => { - res = message - res.setEncoding('utf8') - res.on('data', (chunk) => (resBody += chunk)) - res.on('end', done) - }) +afterAll(async () => { + server.close() + await httpServer.close() +}) - req.end() - }) +it('returns a mocked response to an "http.get" request', async () => { + const request = http.get(httpServer.http.makeUrl('/resource')) + const { response, responseText } = await waitForClientRequest(request) - test('should return mocked status code', () => { - expect(res.statusCode).toEqual(401) - }) + expect(response.statusCode).toBe(401) + expect(response.headers).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-header': 'yes', + }), + ) + expect(responseText).toBe('{"firstName":"John"}') +}) - test('should return mocked headers', () => { - expect(res.headers).toHaveProperty('content-type', 'application/json') - expect(res.headers).toHaveProperty('x-header', 'yes') - }) +it('returns a mocked response to an "http.request" request', async () => { + const request = http.request(httpServer.http.makeUrl('/resource')) + request.end() + const { response, responseText } = await waitForClientRequest(request) - test('should return mocked body', () => { - expect(resBody).toEqual('{"firstName":"John"}') - }) - }) + expect(response.statusCode).toBe(401) + expect(response.headers).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-header': 'yes', + }), + ) + expect(responseText).toBe('{"firstName":"John"}') }) diff --git a/test/msw-api/setup-server/scenarios/https.test.ts b/test/msw-api/setup-server/scenarios/https.test.ts index 27e80ab77..7c9fe7b64 100644 --- a/test/msw-api/setup-server/scenarios/https.test.ts +++ b/test/msw-api/setup-server/scenarios/https.test.ts @@ -1,85 +1,71 @@ /** * @jest-environment node */ -import * as https from 'https' -import { IncomingMessage } from 'http' +import https from 'https' +import { ServerApi, createServer } from '@open-draft/test-server' import { rest } from 'msw' import { setupServer } from 'msw/node' +import { waitForClientRequest } from '../../../support/utils' -describe('setupServer / https', () => { - const server = setupServer( - rest.get('https://test.mswjs.io', (req, res, ctx) => { +let httpServer: ServerApi +const server = setupServer() + +beforeAll(async () => { + server.listen() + + httpServer = await createServer((app) => { + app.get('/resource', (_, res) => { + return res.status(500).send('original-response') + }) + }) +}) + +beforeEach(() => { + server.use( + rest.get(httpServer.https.makeUrl('/resource'), (req, res, ctx) => { return res( ctx.status(401), ctx.set('x-header', 'yes'), - ctx.json({ - firstName: 'John', - }), + ctx.json({ firstName: 'John' }), ) }), ) +}) - beforeAll(() => { - server.listen() - }) - - afterAll(() => { - server.close() - }) - - describe('given I perform a request using https.get', () => { - let res: IncomingMessage - let resBody = '' - - beforeAll((done) => { - https.get('https://test.mswjs.io', (message) => { - res = message - res.setEncoding('utf8') - res.on('data', (chunk) => (resBody += chunk)) - res.on('end', done) - }) - }) - - test('should return mocked status code', () => { - expect(res.statusCode).toEqual(401) - }) - - test('should return mocked headers', () => { - expect(res.headers).toHaveProperty('content-type', 'application/json') - expect(res.headers).toHaveProperty('x-header', 'yes') - }) - - test('should return mocked body', () => { - expect(resBody).toEqual('{"firstName":"John"}') - }) - }) - - describe('given I perform a request using https.request', () => { - let res: IncomingMessage - let resBody = '' +afterEach(() => { + server.resetHandlers() +}) - beforeAll((done) => { - const req = https.request('https://test.mswjs.io', (message) => { - res = message - res.setEncoding('utf8') - res.on('data', (chunk) => (resBody += chunk)) - res.on('end', done) - }) +afterAll(async () => { + server.close() + await httpServer.close() +}) - req.end() - }) +it('returns a mocked response to an "https.get" request', async () => { + const request = https.get(httpServer.https.makeUrl('/resource')) + const { response, responseText } = await waitForClientRequest(request) - test('should return mocked status code', () => { - expect(res.statusCode).toEqual(401) - }) + expect(response.statusCode).toBe(401) + expect(response.headers).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-header': 'yes', + }), + ) + expect(responseText).toBe('{"firstName":"John"}') +}) - test('should return mocked headers', () => { - expect(res.headers).toHaveProperty('content-type', 'application/json') - expect(res.headers).toHaveProperty('x-header', 'yes') - }) +it('returns a mocked response to an "https.request" request', async () => { + const request = https.request(httpServer.https.makeUrl('/resource')) + request.end() + const { response, responseText } = await waitForClientRequest(request) - test('should return mocked body', () => { - expect(resBody).toEqual('{"firstName":"John"}') - }) - }) + expect(response.statusCode).toBe(401) + expect(response.headers).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-header': 'yes', + }), + ) + expect(responseText).toBe('{"firstName":"John"}') }) diff --git a/test/support/utils.ts b/test/support/utils.ts index 45e0ded8f..f783c5f04 100644 --- a/test/support/utils.ts +++ b/test/support/utils.ts @@ -1,5 +1,6 @@ import * as path from 'path' import { ChildProcess } from 'child_process' +import { ClientRequest, IncomingMessage } from 'http' export function sleep(duration: number) { return new Promise((resolve) => { @@ -43,3 +44,29 @@ export function clearCookies(): void { .replace(/=.*/, `=;expires=${new Date(0).toUTCString()};path=/`) }) } + +export async function waitForClientRequest(request: ClientRequest): Promise<{ + response: IncomingMessage + responseText: string +}> { + return new Promise((resolve, reject) => { + request.once('error', reject) + request.once('abort', () => reject(new Error('Request was aborted'))) + + request.on('response', (response) => { + response.once('error', reject) + + const responseChunks: Array = [] + + response.on('data', (chunk) => { + responseChunks.push(Buffer.from(chunk)) + }) + response.once('end', () => { + resolve({ + response, + responseText: Buffer.concat(responseChunks).toString('utf8'), + }) + }) + }) + }) +} diff --git a/test/tsconfig.json b/test/tsconfig.json index 7cc588052..4644efe66 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,9 +1,10 @@ { "compilerOptions": { + "strict": true, "target": "ES2015", "moduleResolution": "node", - "allowSyntheticDefaultImports": true, "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, "esModuleInterop": true, "declaration": false, "noEmit": true,