// Import módulos import axios, { AxiosError, AxiosInstance } from "axios"; // Import interfaces import { IParams } from "./interfaces"; class Tester { /** * Instância do axios * @memberof Tester */ api: AxiosInstance; /** * URL base da API * @memberof Tester */ baseUrl: string; /** * Porta da API * @memberof Tester */ port: number; /** * Construtor * @constructor * @param baseURL URL base da API * @param port Porta da API */ constructor(baseURL: string, port: number) { // Salva a URL base e a porta this.baseUrl = baseURL; this.port = port; // Cria a instância do axios this.api = axios.create({ baseURL: `${baseURL}:${port}/` }); } /** * Muda a URL base da API * @param baseURL URL base da API */ changeBaseUrl(baseURL: string) { this.baseUrl = baseURL; this.api = axios.create({ baseURL: `${baseURL}:${this.port}/` }); } /** * Muda a porta da API * @param port Porta da API */ changePort(port: number) { this.port = port; this.api = axios.create({ baseURL: `${this.baseUrl}:${port}/` }); } /** * Método recursivo para comparar a tipagem percorrendo objetos * @param answer Resposta esperada * @param response Resposta obtida * @returns Comparação da tipagem das respostas */ checkType(answer: any, response: any) { // Se as respostas forem objetos if (typeof answer === "object" && typeof response === "object") { // Para cada chave da resposta esperada for (const key in answer) { // Se a tipagem não for a mesma if (!this.checkType(answer[key], response[key])) { // Retorna falso return false; } } // Para cada chave da resposta obtida for (const key in response) { // Se a tipagem não for a mesma if (!this.checkType(answer[key], response[key])) { // Retorna falso return false; } } // Retorna verdadeiro return true; } // Retorna comparação da tipagem // eslint-disable-next-line valid-typeof return typeof response === answer; } /** * Método para testar uma rota * @param answer Resposta esperada * @param url Rota * @param method Método * @param comparation Tipo de comparação * @param params Parâmetros da requisição * @param body Corpo da requisição * @param headers Cabeçalho da requisição * @returns Objeto com o resultado do teste */ async testOne( answer: any, url: string, method: "GET" | "POST" | "PUT" | "DELETE" = "GET", comparation: "EQUAL" | "TYPE" | "INTERFACE" = "EQUAL", params: { [key: string]: string } = {}, body: { [key: string]: any } = {}, headers: { [key: string]: string } = {}, ) { // Inicia a rota let completedUrl = url; // Variável temporária para armezenar a posição do parâmetro let first = true; // Para cada parâmetro for (const key in params) { // Se for o primeiro if (first) { // Adiciona o sinal de interrogação e o parâmetro completedUrl += `?${key}=${params[key]}`; // Não é mais o primeiro first = false; // Senão } else { // Adiciona o sinal de & e o parâmetro completedUrl += `&${key}=${params[key]}`; } } // Inicia a requisição const response = await this.api({ method, url: completedUrl, data: body, headers, }) .then(res => res.data) .catch((err: AxiosError) => err.response?.data); // Se o tipo de comparação for switch (comparation) { // igual case "EQUAL": // Compara as respostas return { success: JSON.stringify(response) === JSON.stringify(answer), response: JSON.stringify(response) }; // tipo case "TYPE": // Compara o tipo das respostas return { success: typeof response === typeof answer, response }; // interface case "INTERFACE": // Retorna comparação return { success: this.checkType(answer, response), response }; // outro default: // Retorna resposta com erro return { success: false, response }; } } async test(routes: IParams[]) { // Variável temporária para armazenar o resultado let result = false; // Para cada rota for (const route of routes) { // Recebe parâmetros da rota const { answer, url, method, comparation, params, body, headers } = route; // Testa a rota const response = await this.testOne(answer, url, method, comparation, params, body, headers); // Se a resposta não for a esperada if (!response || !response.success) { // Mostra erro console.error(`\u001b[31mErro na rota: ${url}`); console.error(`Comparação: ${comparation}`); console.error(`Resposta esperada: ${JSON.stringify(answer)}`); console.error(`Resposta obtida: ${JSON.stringify(response.response) ?? "Sem resposta"}\n\u001b[0m`); // Caso contrário } else { // Mostra sucesso console.info(`\u001b[32mSucesso na rota: ${url}\n\u001b[0m`); // Define resultado como sucesso result = true; } } // Retorna resultado return result; } } /** * Função para criar uma instância do teste * @param baseURL URL base da API * @param port Porta da API * @returns Instância do teste */ const Testinha = (baseURL: string, port: number): Tester => { return new Tester(baseURL, port); }; // Exporta função module.exports = Testinha; export default Testinha; // Exporta interface export { IParams };