add and use MockFetchApi
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
import '@testing-library/jest-dom';
|
||||
import 'cross-fetch/polyfill';
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { setupRequestMockHandlers } from '../../msw';
|
||||
import { MockFetchApi } from './MockFetchApi';
|
||||
|
||||
describe('MockFetchApi', () => {
|
||||
const worker = setupServer();
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
it('works with default constructor', async () => {
|
||||
worker.use(
|
||||
rest.get('http://example.com/data.json', (_, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json({ a: 'foo' })),
|
||||
),
|
||||
);
|
||||
const m = new MockFetchApi();
|
||||
const response = await m.fetch('http://example.com/data.json');
|
||||
await expect(response.json()).resolves.toEqual({ a: 'foo' });
|
||||
});
|
||||
|
||||
it('works with a mock implementation', async () => {
|
||||
const inner = jest.fn();
|
||||
const m = new MockFetchApi(inner);
|
||||
await m.fetch('http://example.com/data.json');
|
||||
expect(inner).lastCalledWith('http://example.com/data.json');
|
||||
});
|
||||
|
||||
describe('setAuthorization', () => {
|
||||
it('works with the default', async () => {
|
||||
const inner = jest.fn();
|
||||
const m = new MockFetchApi(inner).setAuthorization();
|
||||
await m.fetch('http://example.com/data.json');
|
||||
expect(inner.mock.calls[0][0].headers.get('authorization')).toBe(
|
||||
'Bearer mocked',
|
||||
);
|
||||
});
|
||||
|
||||
it('works with a static token', async () => {
|
||||
const inner = jest.fn();
|
||||
const m = new MockFetchApi(inner).setAuthorization({ token: 'hello' });
|
||||
await m.fetch('http://example.com/data.json');
|
||||
expect(inner.mock.calls[0][0].headers.get('authorization')).toBe(
|
||||
'Bearer hello',
|
||||
);
|
||||
});
|
||||
|
||||
it('works with an identity api', async () => {
|
||||
const inner = jest.fn();
|
||||
const m = new MockFetchApi(inner).setAuthorization({
|
||||
identityApi: {
|
||||
async getCredentials() {
|
||||
return { token: 'hello2' };
|
||||
},
|
||||
},
|
||||
});
|
||||
await m.fetch('http://example.com/data.json');
|
||||
expect(inner.mock.calls[0][0].headers.get('authorization')).toBe(
|
||||
'Bearer hello2',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FetchApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import crossFetch, { Request } from 'cross-fetch';
|
||||
|
||||
/**
|
||||
* A test helper implementation of {@link @backstage/core-plugin-api#FetchApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class MockFetchApi implements FetchApi {
|
||||
#implementation: typeof crossFetch;
|
||||
|
||||
/**
|
||||
* Creates a {@link MockFetchApi}.
|
||||
*
|
||||
* @param mockImplementation - Here you can pass in a `jest.fn()` for example,
|
||||
* if you want to track the calls being made through the
|
||||
* {@link @backstage/core-plugin-api#MockFetchApi}. If you pass in no
|
||||
* mock implementation, the created
|
||||
* {@link @backstage/core-plugin-api#MockFetchApi} will make actual
|
||||
* requests using the global `fetch`.
|
||||
*/
|
||||
constructor(implementation?: typeof crossFetch) {
|
||||
this.#implementation = implementation ?? crossFetch;
|
||||
}
|
||||
|
||||
/** {@inheritdoc @backstage/core-plugin-api#FetchApi.fetch} */
|
||||
get fetch(): typeof crossFetch {
|
||||
return this.#implementation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds token based Authorization headers to requests, basically simulating
|
||||
* what {@link @backstage/core-app-api#FetchMiddlewares.injectIdentityAuth}
|
||||
* does.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* You can supply either a static mock token or a mock identity API. If
|
||||
* neither is given, the static token string "mocked" is used.
|
||||
*/
|
||||
setAuthorization(options?: {
|
||||
identityApi?: Pick<IdentityApi, 'getCredentials'>;
|
||||
token?: string;
|
||||
}): this {
|
||||
const next = this.#implementation;
|
||||
|
||||
const getToken = async () => {
|
||||
if (options?.token) {
|
||||
return options.token;
|
||||
} else if (options?.identityApi) {
|
||||
const { token } = await options.identityApi.getCredentials();
|
||||
return token;
|
||||
}
|
||||
return 'mocked';
|
||||
};
|
||||
|
||||
this.#implementation = async (input, init) => {
|
||||
const request = new Request(input, init);
|
||||
const token = await getToken();
|
||||
if (token && !request.headers.get('authorization')) {
|
||||
request.headers.set('authorization', `Bearer ${token}`);
|
||||
}
|
||||
return next(request);
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { MockFetchApi } from './MockFetchApi';
|
||||
@@ -17,5 +17,6 @@
|
||||
export * from './AnalyticsApi';
|
||||
export * from './ConfigApi';
|
||||
export * from './ErrorApi';
|
||||
export * from './FetchApi';
|
||||
export * from './PermissionApi';
|
||||
export * from './StorageApi';
|
||||
|
||||
@@ -14,17 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets up handlers for request mocking
|
||||
* @public
|
||||
* @param worker - service worker
|
||||
*/
|
||||
export function setupRequestMockHandlers(worker: {
|
||||
listen: (t: any) => void;
|
||||
close: () => void;
|
||||
resetHandlers: () => void;
|
||||
}) {
|
||||
beforeAll(() => worker.listen({ onUnhandledRequest: 'error' }));
|
||||
afterAll(() => worker.close());
|
||||
afterEach(() => worker.resetHandlers());
|
||||
}
|
||||
export { setupRequestMockHandlers } from './setupRequestMockHandlers';
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets up handlers for request mocking
|
||||
* @public
|
||||
* @param worker - service worker
|
||||
*/
|
||||
export function setupRequestMockHandlers(worker: {
|
||||
listen: (t: any) => void;
|
||||
close: () => void;
|
||||
resetHandlers: () => void;
|
||||
}) {
|
||||
beforeAll(() => worker.listen({ onUnhandledRequest: 'error' }));
|
||||
afterAll(() => worker.close());
|
||||
afterEach(() => worker.resetHandlers());
|
||||
}
|
||||
Reference in New Issue
Block a user