Skip to content

Commit

Permalink
feat: test for metabase client
Browse files Browse the repository at this point in the history
  • Loading branch information
zz-hh-aa committed Nov 25, 2024
1 parent 0dcdad4 commit 2d14b63
Showing 1 changed file with 177 additions and 1 deletion.
178 changes: 177 additions & 1 deletion api.planx.uk/modules/analytics/metabase/shared/client.test.ts
Original file line number Diff line number Diff line change
@@ -1 +1,177 @@
test.todo("should test configuration and errors");
import axios from "axios";
import type {
AxiosError,
AxiosInstance,
AxiosResponse,
InternalAxiosRequestConfig,
} from "axios";
import {
validateConfig,
createMetabaseClient,
MetabaseError,
} from "./client.js";

vi.mock("axios");
const mockedAxios = vi.mocked(axios, true);

describe("Metabase client", () => {
beforeEach(() => {
vi.clearAllMocks();
vi.resetModules();
vi.stubEnv("METABASE_URL_EXT", "https://metabase.mock.com");
vi.stubEnv("METABASE_API_KEY", "mockmetabasekey");

const mockAxiosInstance = {
interceptors: {
request: {
use: vi.fn(),
eject: vi.fn(),
clear: vi.fn(),
},
response: {
use: vi.fn((successFn, errorFn) => {
// Store error handler for testing
mockAxiosInstance.interceptors.response.errorHandler = errorFn;
return 1; // Return handler id
}),
eject: vi.fn(),
clear: vi.fn(),
errorHandler: null as any,

Check warning on line 39 in api.planx.uk/modules/analytics/metabase/shared/client.test.ts

View workflow job for this annotation

GitHub Actions / Run API Tests

Unexpected any. Specify a different type
},
},
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
};

mockedAxios.create.mockReturnValue(
mockAxiosInstance as unknown as AxiosInstance,
);

test("returns configured client", () => {
const client = createMetabaseClient();

Check warning on line 53 in api.planx.uk/modules/analytics/metabase/shared/client.test.ts

View workflow job for this annotation

GitHub Actions / Run API Tests

'client' is assigned a value but never used. Allowed unused vars must match /^_/u

expect(axios.create).toHaveBeenCalledWith({
baseURL: process.env.METABASE_URL_EXT,
headers: {
"X-API-Key": process.env.METABASE_API_KEY,
"Content-Type": "application/json",
},
timeout: 30_000,
});
});

describe("validates configuration", () => {
test("throws error when URL_EXT is missing", () => {
vi.unstubAllEnvs();
expect(() => validateConfig()).toThrow(
"Missing environment variable 'METABASE_URL_EXT'",
);
});

test("throws error when API_KEY is missing", () => {
vi.unstubAllEnvs();
vi.stubEnv("process.env.METABASE_URL_EXT", "https://metabase.mock.com");
expect(() => validateConfig()).toThrow(
"Missing environment variable 'METABASE_API_KEY'",
);
});

test("returns valid config object", () => {
const config = validateConfig;
expect(config).toMatchObject({
baseURL: process.env.METABASE_URL_EXT,
apiKey: process.env.METABASE_API_KEY,
timeout: 30_000,
retries: 3,
});
});
});

test("retries requests on 5xx errors", async () => {
const client = createMetabaseClient();

Check warning on line 93 in api.planx.uk/modules/analytics/metabase/shared/client.test.ts

View workflow job for this annotation

GitHub Actions / Run API Tests

'client' is assigned a value but never used. Allowed unused vars must match /^_/u
const mockAxiosInstance = mockedAxios.create.mock.results[0].value;

// Create headers instance
const headers = new axios.AxiosHeaders({
"Content-Type": "application/json",
});

// Create mock error with properly typed config
const error: AxiosError = {
config: {
headers: headers,
retryCount: 0,
url: "/test",
method: "get",
baseURL: "https://test.com",
transformRequest: [],
transformResponse: [],
timeout: 0,
adapter: axios.defaults.adapter,
xsrfCookieName: "",
xsrfHeaderName: "",
maxContentLength: -1,
maxBodyLength: -1,
env: {
FormData: window.FormData,
},
} as unknown as InternalAxiosRequestConfig,
response: {
status: 500,
statusText: "Internal Server Error",
data: { message: "Server Error" },
headers: headers,
config: {} as InternalAxiosRequestConfig,
} as AxiosResponse,
isAxiosError: true,
name: "AxiosError",
message: "Server Error",
toJSON: () => ({}),
};

// Get the error handler that was registered
const errorHandler = mockAxiosInstance.interceptors.response.errorHandler;
expect(errorHandler).toBeDefined();

// Call error handler and expect it to retry
await expect(errorHandler(error)).rejects.toThrow(MetabaseError);
});

test("throws non-5xx errors", async () => {
const error = new Error("Server Error") as AxiosError;
error.config = {} as InternalAxiosRequestConfig;
error.response = {
status: 500,
data: { message: "Server Error" },
statusText: "Server Error",
headers: {},
config: {} as InternalAxiosRequestConfig,
} as AxiosResponse;
error.isAxiosError = true;
error.name = "AxiosError";
error.message = "Server Error";
error.toJSON = () => ({});

mockedAxios.create.mockReturnValue({
interceptors: {
request: { use: vi.fn() },
response: {
use: (errorHandler: (error: AxiosError) => Promise<AxiosError>) =>
errorHandler(error),
},
},
} as any);

Check warning on line 165 in api.planx.uk/modules/analytics/metabase/shared/client.test.ts

View workflow job for this annotation

GitHub Actions / Run API Tests

Unexpected any. Specify a different type

const client = createMetabaseClient();
await expect(client.get("/test")).rejects.toThrow(
new MetabaseError("Bad Request", 400, error.response.data),
);
});

afterAll(() => {
vi.unstubAllEnvs();
});
});
});

0 comments on commit 2d14b63

Please sign in to comment.