From d9e8713b28c545991377ac3e601a91ef5dae9f61 Mon Sep 17 00:00:00 2001 From: Brian Leathem Date: Fri, 26 Feb 2021 11:16:35 -0800 Subject: [PATCH] Replaced nock usage in the oidc provider tests with msw --- plugins/auth-backend/package.json | 4 +- .../src/providers/oidc/provider.test.ts | 112 +++++++++++++----- yarn.lock | 20 ---- 3 files changed, 85 insertions(+), 51 deletions(-) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index f9dfdd5215..9742e872f6 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -33,6 +33,7 @@ "@backstage/catalog-client": "^0.3.6", "@backstage/catalog-model": "^0.7.2", "@backstage/config": "^0.1.3", + "@backstage/test-utils": "^0.1.8", "@types/express": "^4.17.6", "@types/passport": "^1.0.3", "compression": "^1.7.4", @@ -77,8 +78,7 @@ "@types/passport-saml": "^1.1.2", "@types/passport-strategy": "^0.2.35", "@types/xml2js": "^0.4.7", - "msw": "^0.21.2", - "nock": "^13.0.5" + "msw": "^0.21.2" }, "files": [ "dist", diff --git a/plugins/auth-backend/src/providers/oidc/provider.test.ts b/plugins/auth-backend/src/providers/oidc/provider.test.ts index 9a23f701e5..f44c32dc4c 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.test.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.test.ts @@ -14,15 +14,17 @@ * limitations under the License. */ +import { Config, ConfigReader } from '@backstage/config'; +import { msw } from '@backstage/test-utils'; import express from 'express'; import { Session } from 'express-session'; -import nock from 'nock'; +import { JWK, JWT } from 'jose'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; import { ClientMetadata, IssuerMetadata } from 'openid-client'; -import { createOidcProvider, OidcAuthProvider } from './provider'; -import { JWT, JWK } from 'jose'; -import { AuthProviderFactoryOptions } from '../types'; -import { Config, ConfigReader } from '@backstage/config'; import { OAuthAdapter } from '../../lib/oauth'; +import { AuthProviderFactoryOptions } from '../types'; +import { createOidcProvider, OidcAuthProvider } from './provider'; const issuerMetadata = { issuer: 'https://oidc.test', @@ -49,10 +51,24 @@ const clientMetadata = { }; describe('OidcAuthProvider', () => { + const worker = setupServer(); + msw.setupDefaultHandlers(worker); + + beforeEach(() => { + jest.clearAllMocks(); + }); + it('hit the metadata url', async () => { - const scope = nock('https://oidc.test') - .get('/.well-known/openid-configuration') - .reply(200, issuerMetadata); + const handler = jest.fn((_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }); + worker.use( + rest.get('https://oidc.test/.well-known/openid-configuration', handler), + ); const provider = new OidcAuthProvider(clientMetadata); const { strategy } = ((await (provider as any).implementation) as any) as { strategy: { @@ -61,7 +77,7 @@ describe('OidcAuthProvider', () => { }; }; // Assert that the expected request to the metadaurl was made. - expect(scope.isDone()).toBeTruthy(); + expect(handler).toBeCalledTimes(1); const { _client, _issuer } = strategy; expect(_client.client_id).toBe(clientMetadata.clientId); expect(_issuer.token_endpoint).toBe(issuerMetadata.token_endpoint); @@ -75,20 +91,49 @@ describe('OidcAuthProvider', () => { aud: clientMetadata.clientId, exp: Date.now() + 10000, }; - const scope = nock('https://oidc.test') - .get('/.well-known/openid-configuration') - .reply(200, issuerMetadata) - .post('/as/token.oauth2') - .reply(200, { - id_token: JWT.sign(jwt, JWK.None), - access_token: 'test', - authorization_signed_response_alg: 'HS256', - }) - .get('/idp/userinfo.openid') - .reply(200, { - sub: 'alice', - email: 'alice@oidc.test', - }); + const requestSequence: Array = []; + + // The array of expected requests executed by the provider handler + const requests: Array<{ + method: 'get' | 'post'; + url: string; + payload: object; + }> = [ + { + method: 'get', + url: 'https://oidc.test/.well-known/openid-configuration', + payload: issuerMetadata, + }, + { + method: 'post', + url: 'https://oidc.test/as/token.oauth2', + payload: { + id_token: JWT.sign(jwt, JWK.None), + access_token: 'test', + authorization_signed_response_alg: 'HS256', + }, + }, + { + method: 'get', + url: 'https://oidc.test/idp/userinfo.openid', + payload: { + sub: 'alice', + email: 'alice@oidc.test', + }, + }, + ]; + worker.use( + ...requests.map(r => { + return rest[r.method](r.url, (_req, res, ctx) => { + requestSequence.push(r.url); + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(r.payload), + ); + }); + }), + ); const provider = new OidcAuthProvider(clientMetadata); const req = { method: 'GET', @@ -96,13 +141,20 @@ describe('OidcAuthProvider', () => { session: ({ 'oidc:oidc.test': 'test' } as any) as Session, } as express.Request; await provider.handler(req); - expect(scope.isDone()).toBeTruthy(); + expect(requestSequence).toEqual([0, 1, 2].map(i => requests[i].url)); }); it('createOidcProvider', async () => { - const scope = nock('https://oidc.test') - .get('/.well-known/openid-configuration') - .reply(200, issuerMetadata); + const handler = jest.fn((_req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(issuerMetadata), + ); + }); + worker.use( + rest.get('https://oidc.test/.well-known/openid-configuration', handler), + ); const config: Config = new ConfigReader({ testEnv: { ...clientMetadata, @@ -118,7 +170,9 @@ describe('OidcAuthProvider', () => { } as AuthProviderFactoryOptions; const provider = createOidcProvider()(options) as OAuthAdapter; expect(provider.start).toBeDefined(); - await new Promise(resolve => process.nextTick(resolve)); // advance a tick to give nock a chance to intercept the request - expect(scope.isDone()).toBeTruthy(); + // Cast provider as any here to be able to inspect private members + await (provider as any).handlers.get('testEnv').handlers.implementation; + // Assert that the expected request to the metadaurl was made. + expect(handler).toBeCalledTimes(1); }); }); diff --git a/yarn.lock b/yarn.lock index c72f514853..d76735eb16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17305,11 +17305,6 @@ lodash.once@^4.0.0, lodash.once@^4.1.1: resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash.set@^4.3.2: - version "4.3.2" - resolved "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" - integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -18579,16 +18574,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -nock@^13.0.5: - version "13.0.5" - resolved "https://registry.npmjs.org/nock/-/nock-13.0.5.tgz#a618c6f86372cb79fac04ca9a2d1e4baccdb2414" - integrity sha512-1ILZl0zfFm2G4TIeJFW0iHknxr2NyA+aGCMTjDVUsBY4CkMRispF1pfIYkTRdAR/3Bg+UzdEuK0B6HczMQZcCg== - dependencies: - debug "^4.1.0" - json-stringify-safe "^5.0.1" - lodash.set "^4.3.2" - propagate "^2.0.0" - node-abi@^2.7.0: version "2.19.3" resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.19.3.tgz#252f5dcab12dad1b5503b2d27eddd4733930282d" @@ -20938,11 +20923,6 @@ prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, object-assign "^4.1.1" react-is "^16.8.1" -propagate@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" - integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== - property-expr@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.2.tgz#fff2a43919135553a3bc2fdd94bdb841965b2330"