import { HttpClientTestingModule , HttpTestingController } from "@angular/common/http/testing" ; import { getTestBed , TestBed } from "@angular/core/testing" ; import * as log4javascript from "log4javascript" ; import { AjaxAppender } from "./ajax-appender.model" ; import { LocalStorageAppender } from "./local-storage-appender.model" ; import { LogMessage } from "./log-message.model" ; import { Logger } from "./logger.model" ; import { LoggingServiceConfiguration } from "./logging-service.configuration" ; import { LoggingService } from "./logging.service" ; import { MemoryAppender } from "./memory-appender.model" ; describe ( "LoggingService" , ( ) => { let loggingService ; let httpMock ; beforeEach ( ( ) => { TestBed . configureTestingModule ( { imports : [ HttpClientTestingModule ] , providers : [ LoggingService , ] , } ) ; loggingService = TestBed . inject ( LoggingService ) ; httpMock = TestBed . inject ( HttpTestingController ) ; } ) ; afterEach ( ( ) => { httpMock . verify ( ) ; log4javascript . resetConfiguration ( ) ; log4javascript . getRootLogger ( ) . removeAllAppenders ( ) ; } ) ; describe ( "ctor()" , ( ) => { it ( "root logger has log level WARN" , ( ) => { const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const browserConsoleAppender = appenders . find ( ( a ) => a . toString ( ) === "BrowserConsoleAppender" ) ; browserConsoleAppender . setThreshold ( log4javascript . Level . OFF ) ; loggingService . getRootLogger ( ) . info ( "test" ) ; loggingService . getRootLogger ( ) . warn ( "test" ) ; const messages = loggingService . getLogMessages ( ) ; expect ( messages . length ) . toBe ( 1 ) ; } ) ; } ) ; describe ( "configure(configuration: LoggingServiceConfiguration): void" , ( ) => { it ( "throws no error if no configuration is provided" , ( ) => { loggingService . configure ( undefined ) ; } ) ; it ( "throws no error if configuration is empty" , ( ) => { const config = { } ; loggingService . configure ( config ) ; } ) ; describe ( "logLevels" , ( ) => { it ( "throws no error if logLevels is empty" , ( ) => { const logLevels = [ ] ; const config = { logLevels , } ; loggingService . configure ( config ) ; } ) ; it ( "change log level of root logger" , ( ) => { const logLevels = [ { loggerName : "root" , logLevel : "INFO" } ] ; const config = { logLevels , } ; loggingService . configure ( config ) ; const internalLogger = new Logger ( ) . getInternalLogger ( ) ; expect ( internalLogger . getEffectiveLevel ( ) ) . toBe ( log4javascript . Level . INFO ) ; } ) ; it ( "change log level of custom logger, root logger remains unchanged" , ( ) => { const logLevels = [ { loggerName : "me" , logLevel : "INFO" } ] ; const config = { logLevels , } ; loggingService . configure ( config ) ; const internalLoggerMe = new Logger ( "me" ) . getInternalLogger ( ) ; expect ( internalLoggerMe . getEffectiveLevel ( ) ) . toBe ( log4javascript . Level . INFO ) ; const internalLoggerRoot = new Logger ( ) . getInternalLogger ( ) ; expect ( internalLoggerRoot . getEffectiveLevel ( ) ) . toBe ( log4javascript . Level . WARN ) ; } ) ; it ( "throws error if custom logger has an invalid log level" , ( ) => { const logLevels = [ { loggerName : "me" , logLevel : "xxx" } ] ; const config = { logLevels , } ; expect ( ( ) => loggingService . configure ( config ) ) . toThrowError ( "invalid log level xxx" ) ; } ) ; } ) ; describe ( "ajaxAppender" , ( ) => { it ( "adds no ajaxAppender if not configured" , ( ) => { const config = { } ; const internalLogger = new Logger ( ) . getInternalLogger ( ) ; const oldAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; loggingService . configure ( config ) ; const newAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; expect ( newAppenderCount ) . toBe ( oldAppenderCount ) ; } ) ; it ( "adds ajaxAppender if configured" , ( ) => { const config = { ajaxAppender : { url : "myUrl" , } , } ; const internalLogger = new Logger ( ) . getInternalLogger ( ) ; const oldAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; loggingService . configure ( config ) ; const newAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; expect ( newAppenderCount ) . toBe ( oldAppenderCount + 1 ) ; } ) ; it ( "throws error if ajaxAppender has an invalid threshold" , ( ) => { const config = { ajaxAppender : { threshold : "xxx" , url : "myUrl" , } , } ; expect ( ( ) => loggingService . configure ( config ) ) . toThrowError ( "invalid level xxx" ) ; } ) ; it ( "ajaxAppender has default threshold of WARN" , ( ) => { const config = { ajaxAppender : { url : "myUrl" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const ajaxAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.AjaxAppender" ) as AjaxAppender ; expect ( ajaxAppender . getThreshold ( ) ) . toBe ( log4javascript . Level . WARN ) ; } ) ; it ( "ajaxAppender has default timer interval of 0" , ( ) => { const config = { ajaxAppender : { url : "myUrl" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const ajaxAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.AjaxAppender" ) as AjaxAppender ; expect ( ajaxAppender . getInternalAppender ( ) . isTimed ( ) ) . toBeFalsy ( ) ; expect ( ajaxAppender . getTimerInterval ( ) ) . toBe ( 0 ) ; } ) ; it ( "ajaxAppender has given timer interval" , ( ) => { const config = { ajaxAppender : { timerInterval : 1234 , url : "myUrl" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const ajaxAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.AjaxAppender" ) as AjaxAppender ; expect ( ajaxAppender . getInternalAppender ( ) . isTimed ( ) ) . toBeTruthy ( ) ; expect ( ajaxAppender . getTimerInterval ( ) ) . toBe ( 1234 ) ; } ) ; it ( "ajaxAppender has default batch size of 1" , ( ) => { const config = { ajaxAppender : { url : "myUrl" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const ajaxAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.AjaxAppender" ) as AjaxAppender ; expect ( ajaxAppender . getBatchSize ( ) ) . toBe ( 1 ) ; } ) ; it ( "ajaxAppender has given timer interval" , ( ) => { const config = { ajaxAppender : { batchSize : 1234 , url : "myUrl" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const ajaxAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.AjaxAppender" ) as AjaxAppender ; expect ( ajaxAppender . getBatchSize ( ) ) . toBe ( 1234 ) ; } ) ; } ) ; describe ( "localStorageAppender" , ( ) => { it ( "adds no localStorageAppender if not configured" , ( ) => { const config = { } ; const internalLogger = new Logger ( ) . getInternalLogger ( ) ; const oldAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; loggingService . configure ( config ) ; const newAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; expect ( newAppenderCount ) . toBe ( oldAppenderCount ) ; } ) ; it ( "adds localStorageAppender if configured" , ( ) => { const config = { localStorageAppender : { localStorageKey : "myLocalStorage" , } , } ; const internalLogger = new Logger ( ) . getInternalLogger ( ) ; const oldAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; loggingService . configure ( config ) ; const newAppenderCount = internalLogger . getEffectiveAppenders ( ) . length ; expect ( newAppenderCount ) . toBe ( oldAppenderCount + 1 ) ; } ) ; it ( "throws error if localStorageAppender has an invalid threshold" , ( ) => { const config = { localStorageAppender : { localStorageKey : "myLocalStorage" , threshold : "xxx" , } , } ; expect ( ( ) => loggingService . configure ( config ) ) . toThrowError ( "invalid level xxx" ) ; } ) ; it ( "localStorageAppender has default threshold of WARN" , ( ) => { const config = { localStorageAppender : { localStorageKey : "myLocalStorage" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const localStorageAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.LocalStorageAppender" ) as LocalStorageAppender ; expect ( localStorageAppender . getThreshold ( ) ) . toBe ( log4javascript . Level . WARN ) ; } ) ; it ( "localStorageAppender has given threshold" , ( ) => { const config = { localStorageAppender : { localStorageKey : "myLocalStorage" , threshold : "INFO" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const localStorageAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.LocalStorageAppender" ) as LocalStorageAppender ; expect ( localStorageAppender . getThreshold ( ) ) . toBe ( log4javascript . Level . INFO ) ; } ) ; it ( "localStorageAppender has default max messages of 250" , ( ) => { const config = { localStorageAppender : { localStorageKey : "myLocalStorage" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const localStorageAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.LocalStorageAppender" ) as LocalStorageAppender ; expect ( localStorageAppender . getMaxMessages ( ) ) . toBe ( 250 ) ; } ) ; it ( "localStorageAppender has given max messages" , ( ) => { const config = { localStorageAppender : { localStorageKey : "myLocalStorage" , maxMessages : 1234 , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const localStorageAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.LocalStorageAppender" ) as LocalStorageAppender ; expect ( localStorageAppender . getMaxMessages ( ) ) . toBe ( 1234 ) ; } ) ; } ) ; describe ( "memoryAppender" , ( ) => { it ( "memoryAppender has default max messages of 250" , ( ) => { const config = { } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const memoryAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.MemoryAppender" ) as MemoryAppender ; expect ( memoryAppender . getMaxMessages ( ) ) . toBe ( 250 ) ; } ) ; it ( "memoryAppender has default configuration id memoryAppender configuration is empty" , ( ) => { const config = { memoryAppender : { } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const memoryAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.MemoryAppender" ) as MemoryAppender ; expect ( memoryAppender . getMaxMessages ( ) ) . toBe ( 250 ) ; } ) ; it ( "memoryAppender has given max messages" , ( ) => { const config = { memoryAppender : { maxMessages : 1234 , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const memoryAppender = appenders . find ( ( a ) => a . toString ( ) === "Ionic.Logging.MemoryAppender" ) as MemoryAppender ; expect ( memoryAppender . getMaxMessages ( ) ) . toBe ( 1234 ) ; } ) ; } ) ; describe ( "browserConsoleAppender" , ( ) => { it ( "browserConsoleAppender has default threshold" , ( ) => { const config = { } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const browserConsoleAppender = appenders . find ( ( a ) => a . toString ( ) === "BrowserConsoleAppender" ) ; expect ( browserConsoleAppender . getThreshold ( ) ) . toBe ( log4javascript . Level . ALL ) ; } ) ; it ( "empty configuration for browserConsoleAppender" , ( ) => { const config = { browserConsoleAppender : { } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const browserConsoleAppender = appenders . find ( ( a ) => a . toString ( ) === "BrowserConsoleAppender" ) ; expect ( browserConsoleAppender . getThreshold ( ) ) . toBe ( log4javascript . Level . ALL ) ; } ) ; it ( "browserConsoleAppender has given threshold" , ( ) => { const config = { browserConsoleAppender : { threshold : "OFF" , } , } ; loggingService . configure ( config ) ; const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const browserConsoleAppender = appenders . find ( ( a ) => a . toString ( ) === "BrowserConsoleAppender" ) ; expect ( browserConsoleAppender . getThreshold ( ) ) . toBe ( log4javascript . Level . OFF ) ; } ) ; } ) ; } ) ; describe ( "getLogger(loggerName: string): Logger" , ( ) => { it ( "returns logger with given name" , ( ) => { const logger = loggingService . getLogger ( "myLogger" ) ; const loggerName = logger . getInternalLogger ( ) . name ; expect ( loggerName ) . toBe ( "myLogger" ) ; } ) ; } ) ; describe ( "getRootLogger(): Logger" , ( ) => { it ( "returns logger with root name" , ( ) => { const logger = loggingService . getRootLogger ( ) ; const loggerName = logger . getInternalLogger ( ) . name ; expect ( loggerName ) . toBe ( "root" ) ; } ) ; } ) ; describe ( "getLogMessages(): LogMessage[]" , ( ) => { it ( "returns empty array if no log message is written" , ( ) => { const messages = loggingService . getLogMessages ( ) ; expect ( messages . length ) . toBe ( 0 ) ; } ) ; it ( "returns array with written log message" , ( ) => { const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const browserConsoleAppender = appenders . find ( ( a ) => a . toString ( ) === "BrowserConsoleAppender" ) ; browserConsoleAppender . setThreshold ( log4javascript . Level . OFF ) ; loggingService . getRootLogger ( ) . warn ( "test" ) ; const messages = loggingService . getLogMessages ( ) ; expect ( messages . length ) . toBe ( 1 ) ; } ) ; } ) ; describe ( "logMessagesChanged: EventEmitter<void>" , ( ) => { it ( "logged messages are emitted" , ( done ) => { const appenders = new Logger ( ) . getInternalLogger ( ) . getEffectiveAppenders ( ) ; const browserConsoleAppender = appenders . find ( ( a ) => a . toString ( ) === "BrowserConsoleAppender" ) ; browserConsoleAppender . setThreshold ( log4javascript . Level . OFF ) ; loggingService . logMessagesChanged . subscribe ( ( ) => { expect ( 1 ) . toBe ( loggingService . getLogMessages ( ) . length ) ; done ( ) ; } ) ; loggingService . getRootLogger ( ) . warn ( "test" ) ; } ) ; } ) ; describe ( "ajaxAppenderFailed: EventEmitter<string>" , ( ) => { it ( "error message emitted" , ( done ) => { const config = { ajaxAppender : { url : "badUrl" , } , browserConsoleAppender : { threshold : "OFF" , } , } ; loggingService . configure ( config ) ; loggingService . ajaxAppenderFailed . subscribe ( ( message ) => { expect ( message ) . toBe ( "AjaxAppender.append: XMLHttpRequest request to URL badUrl returned status code 404" ) ; done ( ) ; } ) ; loggingService . getRootLogger ( ) . warn ( "test" ) ; } ) ; } ) ; describe ( "getLogMessagesFromLocalStorage(localStorageKey: string): LogMessage[]" , ( ) => { it ( "returns empty array if no log message is written" , ( ) => { localStorage . removeItem ( "xxx" ) ; const messages = loggingService . getLogMessagesFromLocalStorage ( "xxx" ) ; expect ( messages . length ) . toBe ( 0 ) ; } ) ; it ( "returns array with written log message" , ( ) => { const messagesIn = [ { level : "DEBUG" , logger : "myLogger" , message : [ "myMessage" ] , methodName : "myMethod" , timeStamp : new Date ( ) , } ] ; localStorage . setItem ( "xxx" , JSON . stringify ( messagesIn ) ) ; const messages = loggingService . getLogMessagesFromLocalStorage ( "xxx" ) ; expect ( messages . length ) . toBe ( 1 ) ; } ) ; } ) ; describe ( "removeLogMessages(): void" , ( ) => { it ( "removes messages" , ( done ) => { loggingService . getRootLogger ( ) . info ( "test" ) ; loggingService . logMessagesChanged . subscribe ( ( ) => { expect ( loggingService . getLogMessages ( ) . length ) . toBe ( 0 ) ; done ( ) ; } ) ; loggingService . removeLogMessages ( ) ; } ) ; } ) ; describe ( "removeLogMessagesFromLocalStorage(localStorageKey: string): void" , ( ) => { it ( "removes messages" , ( done ) => { const messagesIn = [ { level : "DEBUG" , logger : "myLogger" , message : [ "myMessage" ] , methodName : "myMethod" , timeStamp : new Date ( ) , } ] ; localStorage . setItem ( "xxx" , JSON . stringify ( messagesIn ) ) ; loggingService . logMessagesChanged . subscribe ( ( ) => { expect ( localStorage . getItem ( "xxx" ) ) . toBeNull ( ) ; done ( ) ; } ) ; loggingService . removeLogMessagesFromLocalStorage ( "xxx" ) ; } ) ; } ) ; } ) ;