import { Home } from "../views/Home.js";
import { Chat } from "../views/pages/Chat/index.js";
import { Error } from "../views/pages/Error/index.js";
import { Grupo } from "../views/pages/Grupo/index.js";
import { navigateTo, queryStringToObject, setRootEl, setRoutes, rootEl } from '../router.js';
describe('Teste da aplicação de roteamento', () => {
let mockRoutes; // Defina mockRoutes em um escopo mais amplo
// Mocking the DOM
beforeAll(() => {
// Simulate root element
document.body.innerHTML = '<div id="root"></div>';
setRootEl(document.getElementById('root'));
// Define mock routes
mockRoutes = {
"/": Home,
"/chat": Chat,
"/error": Error,
"/grupo": Grupo
};
setRoutes(mockRoutes);
});
test('Teste de definição de rotas', () => {
expect(Object.keys(mockRoutes).length).toBe(4);
expect(mockRoutes['/']).toBe(Home);
expect(mockRoutes['/chat']).toBe(Chat);
expect(mockRoutes['/error']).toBe(Error);
expect(mockRoutes['/grupo']).toBe(Grupo);
});
test('Teste de inicialização da aplicação', () => {
// Simulate DOMContentLoaded event
window.dispatchEvent(new Event('DOMContentLoaded'));
expect(document.getElementById('root')).toBeDefined();
expect(window.location.pathname).toBe('/');
});
});
describe('Testes adicionais', () => {
let rootElement;
beforeEach(() => {
// Crie um novo elemento raiz antes de cada teste
rootElement = document.createElement('div');
rootElement.id = 'root';
document.body.appendChild(rootElement);
});
afterEach(() => {
// Remova o elemento raiz após cada teste
document.body.removeChild(rootElement);
});
test('navigateTo modifica a URL corretamente', () => {
navigateTo('/nova-rota');
expect(window.location.pathname).toBe('/nova-rota');
});
test('navigateTo chama renderView com os argumentos corretos', () => {
const renderViewMock = jest.fn();
window.history.pushState = jest.fn(); // Mock pushState para evitar mudanças reais na URL
setRoutes({ '/nova-rota': jest.fn() }); // Mock das rotas
setRootEl(rootElement); // Defina o elemento raiz
navigateTo('/nova-rota');
expect(renderViewMock).toHaveBeenCalledWith('/nova-rota', {});
});
test('queryStringToObject converte corretamente uma string de consulta em um objeto', () => {
const queryString = 'param1=value1¶m2=value2';
const expectedObject = { param1: 'value1', param2: 'value2' };
expect(queryStringToObject(queryString)).toEqual(expectedObject);
});
test('setRootEl atribui corretamente o elemento raiz', () => {
const element = document.createElement('div');
setRootEl(element);
expect(rootEl).toEqual(element);
});
test('setRoutes atribui corretamente as rotas', () => {
const routes = { '/nova-rota': jest.fn() };
setRoutes(routes);
expect(routes).toEqual(routes);
});
// Adicione mais testes conforme necessário para cobrir outras partes do código
});
let routes = {};
let rootEl = null;
const ERROR_PATH = "/error";
export const setRoutes = (newRoutes) => {
// Adiciona validação para garantir que newRoutes seja um objeto
if (typeof newRoutes !== 'object' || newRoutes === null) {
throw new Error('As rotas devem ser um objeto.');
}
routes = newRoutes;
};
export const setRootEl = (element) => {
// Adiciona validação para garantir que element seja um elemento DOM válido
if (!(element instanceof Element)) {
throw new Error('O elemento raiz deve ser um elemento DOM válido.');
}
rootEl = element;
};
const queryStringToObject = (queryString) =>
Object.fromEntries(new URLSearchParams(queryString).entries());
const renderView = (pathName, props = {}) => {
// Adiciona tratamento para rota não encontrada
if (!(pathName in routes)) {
console.error(`Rota não encontrada: ${pathName}`);
pathName = ERROR_PATH;
}
// Usa textContent para evitar injeção de HTML
rootEl.textContent = "";
const viewEl = routes[pathName](props);
rootEl.appendChild(viewEl);
};
export const navigateTo = (pathname, props = {}) => {
const url = window.location.origin + pathname;
window.history.pushState({}, pathname, url);
renderView(pathname, props);
};
export const onURLChange = () => {
const { pathname, search } = window.location;
const props = queryStringToObject(search);
renderView(pathname, props);
};
Um aplicativo de página única (SPA) é uma aplicação web que carrega todo o seu conteúdo a partir de um único arquivo HTML (comumente chamado de index.html
) e atualiza dinamicamente o conteúdo enquanto o usuário interage com a aplicação.
Em vez de carregar páginas HTML completas e separadas cada vez que uma ação é executada, como clicar em um link, ele apenas carrega o conteúdo necessário para atualizar a visualização atual. Uma SPA dá a ilusão de que estamos navegando em páginas HTML separadas, mas na verdade é a mesma página com conteúdo diferente renderizado (desenhado) dinamicamente.
// Objeto que armazena as rotas da aplicação
let routes = {};
// Elemento raiz da aplicação
let rootEl = null;
// Caminho de erro padrão
const ERROR_PATH = "/error";
// Função para definir as rotas da aplicação
export const setRoutes = (newRoutes) => {
routes = newRoutes;
};
// Função para definir o elemento raiz da aplicação
export const setRootEl = (element) => {
rootEl = element;
};
// Função para converter uma string de consulta em um objeto
const queryStringToObject = (queryString) =>
Object.fromEntries(new URLSearchParams(queryString).entries());
// Função para renderizar a visualização da rota especificada
const renderView = (pathName, props = {}) => {
// Verificar se o caminho não existe nas rotas, redirecionar para o caminho de erro
if (!(pathName in routes)) {
pathName = ERROR_PATH;
}
// Limpar o conteúdo do elemento raiz
rootEl.innerHTML = "";
// Obter o elemento de visualização da rota e adicioná-lo ao elemento raiz
const viewEl = routes[pathName](props);
rootEl.appendChild(viewEl);
};
// Função para navegar para um novo caminho e renderizar sua visualização correspondente
export const navigateTo = (pathname, props = {}) => {
// Construir a URL completa
const url = window.location.origin + pathname;
// Atualizar a URL no histórico do navegador
window.history.pushState({}, pathname, url);
// Renderizar a visualização da nova rota
renderView(pathname, props);
};
// Função para lidar com alterações na URL do navegador
export const onURLChange = () => {
// Obter o pathname e a string de busca da URL atual
const { pathname, search } = window.location;
// Converter a string de busca em um objeto de parâmetros
const props = queryStringToObject(search);
// Renderizar a visualização da rota correspondente ao pathname atual
renderView(pathname, props);
};
No contexto de SPAs, um router é um módulo
JavaScript que gerencia a navegação dentro do aplicativo sem precisar recarregar a página inteira. Sua principal função é atribuir URLs às diferentes visualizações ou componentes do aplicativo e atualizar a interface com base no URL atual.
Por exemplo, se um usuário estiver na página inicial de um SPA www.website.com
, e em seguida, você clica no link "About" que leva você para www.website.com/about
, o router detecta alterações na URL, encontra e carrega dinamicamente o conteúdo correspondente para "about". Não existe um arquivo about.html
, mas o router e a view criam a sensação de que estamos navegando para uma nova página. Isso permite que o SPA simule a experiência de navegação de uma aplicação web de várias páginas, mesmo que você tenha carregado apenas uma única página HTML a princípio.
Esta página implementa um sistema de roteamento e renderização dinâmica de visualizações em uma aplicação web. Aqui está um resumo das principais funcionalidades e conceitos abordados:
onURLChange
é acionada. Ela obtém o pathname da URL e usa-o para determinar qual visualização deve ser renderizada. A função renderView
é então chamada para renderizar a visualização correspondente no elemento raiz da aplicação (rootEl
).navigateTo
é responsável por navegar para um novo caminho, atualizando a URL no histórico do navegador e renderizando a visualização correspondente.history.pushState
, para manipular a URL e o histórico de navegação sem recarregar a página.Em resumo, esta página implementa um sistema de roteamento e renderização dinâmica de visualizações em uma aplicação web, seguindo o conceito de Single Page Application (SPA). Isso permite uma experiência de usuário mais fluída e responsiva, sem a necessidade de recarregar a página a cada mudança de rota.