diff --git a/configuracao.delprops b/configuracao.delprops index 7749b69..ab29bde 100644 --- a/configuracao.delprops +++ b/configuracao.delprops @@ -13,6 +13,7 @@ liquido.roteador.cookieParser = verdadeiro liquido.roteador.passport = falso liquido.roteador.json = verdadeiro liquido.roteador.helmet = verdadeiro +liquido.roteador.porta = 3000 // Configuração de bases de dados liquido.dados.lincones.tecnologia = 'sqlite' diff --git a/fontes/delprops/roteador.ts b/fontes/delprops/roteador.ts index cb02913..eb75e6a 100644 --- a/fontes/delprops/roteador.ts +++ b/fontes/delprops/roteador.ts @@ -53,6 +53,11 @@ const roteador: DefinicaoPropriedade[] = [ tipo: 'logico', detalhe: 'Habilita o helmet para segurança de cabeçalhos HTTP (padrão: verdadeiro).', }, + { + nome: 'porta', + tipo: 'numero', + detalhe: 'Porta na qual o servidor irá subir (padrão: 3000).', + } ]; export default roteador; diff --git a/fontes/infraestrutura/centro-configuracoes/configuracao-roteador.ts b/fontes/infraestrutura/centro-configuracoes/configuracao-roteador.ts index 4314ff8..66a8819 100644 --- a/fontes/infraestrutura/centro-configuracoes/configuracao-roteador.ts +++ b/fontes/infraestrutura/centro-configuracoes/configuracao-roteador.ts @@ -4,14 +4,14 @@ import { ConfiguracaoComum } from "./configuracao-comum"; export class ConfiguracaoRoteador extends ConfiguracaoComum { diretorioEstatico: string = 'publico'; cors: boolean = false; - origensCors: string = '*'; + origensCors: string | string[] = '*'; bodyParser: boolean = true; morgan: boolean = false; cookieParser: boolean = true; passport: boolean = false; json: boolean = true; helmet: boolean = true; - + porta: number = 3000; constructor(valoresIniciais?: Partial) { super(); Object.assign(this, valoresIniciais); @@ -27,6 +27,7 @@ export class ConfiguracaoRoteador extends ConfiguracaoComum { roteador.ativarDesativarHelmet(this.helmet); roteador.ativarDesativarMorgan(this.morgan); roteador.ativarDesativarPassport(this.passport); + roteador.configurarPorta(this.porta); // Nota: configurarArquivosEstaticos é chamado em liquido.ts com caminho absoluto } } diff --git a/fontes/infraestrutura/roteador/roteador.ts b/fontes/infraestrutura/roteador/roteador.ts index 59464d1..6d5ad61 100644 --- a/fontes/infraestrutura/roteador/roteador.ts +++ b/fontes/infraestrutura/roteador/roteador.ts @@ -32,12 +32,12 @@ export class Roteador implements RoteadorInterface { bodyParser = false; cors = false; - origensCors = '*'; + origensCors: string[] = ['*']; passport = false; constructor(autoDocumentador: AutoDocumentador) { this.aplicacao = express(); - this.porta = Number(process.env.PORTA) || Number(process.env.PORT) || 3000; + this.porta = 3000; this.autoDocumentador = autoDocumentador; @@ -91,6 +91,10 @@ export class Roteador implements RoteadorInterface { }) ); } + configurarPorta(porta: number): void { + this.porta = porta; + + } configurarArquivosEstaticos(diretorio: string = 'publico'): void { this.aplicacao.use(express.static(diretorio, { redirect: true })); @@ -135,7 +139,6 @@ export class Roteador implements RoteadorInterface { this.aplicacao.use(cors(opcoesCors)); } } - if (this.passport) { try { this.aplicacao.use(autenticacao().initialize()); @@ -154,8 +157,14 @@ export class Roteador implements RoteadorInterface { * ou várias separadas por vírgula. O valor '*' (padrão) libera qualquer * origem e deve ser usado apenas em desenvolvimento. */ - configurarOrigensCors(origem: string): void { - this.origensCors = origem && origem.trim().length > 0 ? origem : '*'; + configurarOrigensCors(origem: string | string[]): void { + if (Array.isArray(origem)) { + this.origensCors = origem; + return; + } + + this.origensCors = origem.split(','). + map(origem => origem.trim()).filter(origem => origem.length > 0); } /** @@ -165,20 +174,17 @@ export class Roteador implements RoteadorInterface { * lista de origens permitidas. */ resolverOpcoesCors(): { origin: string[] } | undefined { - if (this.origensCors === '*') { + + if (Array.isArray(this.origensCors) + && this.origensCors.length === 1 + && this.origensCors[0] === '*') { return undefined; } - - const origens = this.origensCors - .split(',') - .map(origem => origem.trim()) - .filter(origem => origem.length > 0); - - if (origens.length === 0) { + if (this.origensCors.length === 0) { return undefined; } - return { origin: origens }; + return { origin: this.origensCors }; } ativarDesativarPassport(valor: boolean): void { diff --git a/fontes/interfaces/roteador-interface.ts b/fontes/interfaces/roteador-interface.ts index 6523007..4de4971 100644 --- a/fontes/interfaces/roteador-interface.ts +++ b/fontes/interfaces/roteador-interface.ts @@ -1,6 +1,6 @@ export interface RoteadorInterface { ativarDesativarCors(valor: boolean): void; - configurarOrigensCors(origem: string): void; + configurarOrigensCors(origem: string | string[]): void; ativarDesativarPassport(valor: boolean): void; ativarDesativarCookieParser(valor: boolean): void; ativarDesativarExpressJson(valor: boolean): void; @@ -8,4 +8,5 @@ export interface RoteadorInterface { ativarDesativarHelmet(valor: boolean): void; ativarDesativarMorgan(valor: boolean): void; configurarArquivosEstaticos(diretorio: string): void; + configurarPorta(porta: number): void; } diff --git a/testes/infraestrutura/centro-configuracoes.test.ts b/testes/infraestrutura/centro-configuracoes.test.ts index e2b79f4..b4ba896 100644 --- a/testes/infraestrutura/centro-configuracoes.test.ts +++ b/testes/infraestrutura/centro-configuracoes.test.ts @@ -180,7 +180,8 @@ describe('Testes das classes de configuração', () => { ativarDesativarHelmet: jest.fn(), ativarDesativarMorgan: jest.fn(), ativarDesativarPassport: jest.fn(), - configurarArquivosEstaticos: jest.fn() + configurarArquivosEstaticos: jest.fn(), + configurarPorta: jest.fn() }; config.configurar({ roteador }); expect(roteador.ativarDesativarBodyParser).toHaveBeenCalledWith(true); @@ -191,10 +192,14 @@ describe('Testes das classes de configuração', () => { expect(roteador.ativarDesativarHelmet).toHaveBeenCalledWith(true); expect(roteador.ativarDesativarMorgan).toHaveBeenCalledWith(false); expect(roteador.ativarDesativarPassport).toHaveBeenCalledWith(false); + expect(roteador.configurarOrigensCors).toHaveBeenCalledWith('*'); + expect(roteador.configurarPorta).toHaveBeenCalledWith(3000); // configurarArquivosEstaticos agora é chamado em liquido.ts com caminho absoluto expect(roteador.configurarArquivosEstaticos).not.toHaveBeenCalled(); }); + + it('não deve chamar configurarArquivosEstaticos quando diretorioEstatico for vazio', () => { const config = new ConfiguracaoRoteador({ diretorioEstatico: '' }); const roteador = { @@ -206,7 +211,8 @@ describe('Testes das classes de configuração', () => { ativarDesativarHelmet: jest.fn(), ativarDesativarMorgan: jest.fn(), ativarDesativarPassport: jest.fn(), - configurarArquivosEstaticos: jest.fn() + configurarArquivosEstaticos: jest.fn(), + configurarPorta: jest.fn() }; config.configurar({ roteador }); expect(roteador.configurarArquivosEstaticos).not.toHaveBeenCalled(); @@ -291,7 +297,8 @@ describe('Testes das classes de configuração', () => { ativarDesativarHelmet: jest.fn(), ativarDesativarMorgan: jest.fn(), ativarDesativarPassport: jest.fn(), - configurarArquivosEstaticos: jest.fn() + configurarArquivosEstaticos: jest.fn(), + configurarPorta: jest.fn() }; const provedorLincones = { configurar: jest.fn(), configurado: false, resolver: jest.fn() }; config.configurar({ autoDocumentador, roteador, provedorLincones }); @@ -318,6 +325,12 @@ describe('Testes das classes de configuração', () => { expect(config.roteador.cors).toBe(true); }); + it('deve aceitar porta via definirValor em roteador', () => { + const config = new ConfiguracaoLiquido(); + config.definirValor(config, ['liquido', 'roteador', 'porta'], 4000); + expect(config.roteador.porta).toBe(4000); + }); + it('deve lançar ErroConfiguracao para propriedade aninhada inexistente', () => { const config = new ConfiguracaoLiquido(); expect(() => config.definirValor(config, ['liquido', 'propriedadeInexistente', 'cors'], true)).toThrow(ErroConfiguracao); diff --git a/testes/infraestrutura/cors-origem.test.ts b/testes/infraestrutura/cors-origem.test.ts index 99f0368..f224fff 100644 --- a/testes/infraestrutura/cors-origem.test.ts +++ b/testes/infraestrutura/cors-origem.test.ts @@ -103,7 +103,8 @@ describe('CORS com origem configurável', () => { ativarDesativarExpressJson: jest.fn(), ativarDesativarHelmet: jest.fn(), ativarDesativarMorgan: jest.fn(), - ativarDesativarPassport: jest.fn() + ativarDesativarPassport: jest.fn(), + configurarPorta: jest.fn(), }; configuracao.configurar({ roteador: roteadorSimulado }); diff --git a/testes/infraestrutura/roteador.test.ts b/testes/infraestrutura/roteador.test.ts index c7d2f5e..d5ba7d3 100644 --- a/testes/infraestrutura/roteador.test.ts +++ b/testes/infraestrutura/roteador.test.ts @@ -32,6 +32,16 @@ describe('Testes do roteador', () => { expect(roteador).toBeTruthy(); }); + it('deve ignorar a porta do ambiente e usar o valor padrão até que a configuração seja aplicada', () => { + process.env.PORT = '4000'; + + const roteadorSemConfiguracao = new Roteador(new AutoDocumentador()); + + expect(roteadorSemConfiguracao.porta).toBe(3000); + + delete process.env.PORT; + }); + it('deve chamar o método iniciar', () => { roteador.iniciar(); expect(roteador.aplicacao.listen).toHaveBeenCalled();