import 'mocha' ; import { expect } from 'chai' ; import { ApplicationContext } from '@/application/Context/ApplicationContext' ; import { OperatingSystem } from '@/domain/OperatingSystem' ; import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState' ; import { IApplicationContext , IApplicationContextChangedEvent } from '@/application/Context/IApplicationContext' ; import { IApplication } from '@/domain/IApplication' ; import { ApplicationStub } from '@tests/unit/stubs/ApplicationStub' ; import { CategoryCollectionStub } from '@tests/unit/stubs/CategoryCollectionStub' ; import { EnumRangeTestRunner } from '@tests/unit/application/Common/EnumRangeTestRunner' ; describe ( 'ApplicationContext' , ( ) => { describe ( 'changeContext' , ( ) => { describe ( 'when initial os is changed to different one' , ( ) => { it ( 'collection is changed as expected' , ( ) => { const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( OperatingSystem . Windows , OperatingSystem . macOS ) ; const expectedCollection = testContext . app . getCollection ( OperatingSystem . macOS ) ; const sut = testContext . withInitialOs ( OperatingSystem . Windows ) . construct ( ) ; sut . changeContext ( OperatingSystem . macOS ) ; expect ( sut . state . collection ) . to . equal ( expectedCollection ) ; } ) ; it ( 'currentOs is changed as expected' , ( ) => { const expectedOs = OperatingSystem . macOS ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( OperatingSystem . Windows , expectedOs ) ; const sut = testContext . withInitialOs ( OperatingSystem . Windows ) . construct ( ) ; sut . changeContext ( expectedOs ) ; expect ( sut . state . os ) . to . equal ( expectedOs ) ; } ) ; it ( 'new state is empty' , ( ) => { const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( OperatingSystem . Windows , OperatingSystem . macOS ) ; const sut = testContext . withInitialOs ( OperatingSystem . Windows ) . construct ( ) ; sut . state . filter . setFilter ( 'filtered' ) ; sut . changeContext ( OperatingSystem . macOS ) ; expectEmptyState ( sut . state ) ; } ) ; } ) ; it ( 'remembers old state when changed backed to same os' , ( ) => { const os = OperatingSystem . Windows ; const changedOs = OperatingSystem . macOS ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( os , changedOs ) ; const expectedFilter = 'first-state' ; const sut = testContext . withInitialOs ( os ) . construct ( ) ; const firstState = sut . state ; firstState . filter . setFilter ( expectedFilter ) ; sut . changeContext ( os ) ; sut . changeContext ( changedOs ) ; sut . state . filter . setFilter ( 'second-state' ) ; sut . changeContext ( os ) ; const actualFilter = sut . state . filter . currentFilter . query ; expect ( actualFilter ) . to . equal ( expectedFilter ) ; } ) ; describe ( 'contextChanged' , ( ) => { it ( 'fired as expected on change' , ( ) => { const nextOs = OperatingSystem . macOS ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( OperatingSystem . Windows , nextOs ) ; const expectedCollection = testContext . app . getCollection ( OperatingSystem . macOS ) ; const sut = testContext . withInitialOs ( OperatingSystem . Windows ) . construct ( ) ; const oldState = sut . state ; sut . changeContext ( nextOs ) ; expect ( testContext . firedEvents . length ) . to . equal ( 1 ) ; expect ( testContext . firedEvents [ 0 ] . newState ) . to . equal ( sut . state ) ; expect ( testContext . firedEvents [ 0 ] . newState . collection ) . to . equal ( expectedCollection ) ; expect ( testContext . firedEvents [ 0 ] . oldState ) . to . equal ( oldState ) ; } ) ; it ( 'is not fired when initial os is changed to same one' , ( ) => { const os = OperatingSystem . Windows ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( os ) ; const sut = testContext . withInitialOs ( os ) . construct ( ) ; const initialState = sut . state ; initialState . filter . setFilter ( 'dirty-state' ) ; sut . changeContext ( os ) ; expect ( testContext . firedEvents . length ) . to . equal ( 0 ) ; } ) ; it ( 'new event is fired for each change' , ( ) => { const os = OperatingSystem . Windows ; const changedOs = OperatingSystem . macOS ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( os , changedOs ) ; const sut = testContext . withInitialOs ( os ) . construct ( ) ; sut . changeContext ( changedOs ) ; sut . changeContext ( os ) ; sut . changeContext ( changedOs ) ; const duplicates = getDuplicates ( testContext . firedEvents ) ; expect ( duplicates . length ) . to . be . equal ( 0 ) ; } ) ; } ) ; } ) ; describe ( 'ctor' , ( ) => { describe ( 'app' , ( ) => { it ( 'throw when app is undefined' , ( ) => { const expectedError = 'undefined app' ; const app = undefined ; const os = OperatingSystem . Windows ; const act = ( ) => new ApplicationContext ( app , os ) ; expect ( act ) . to . throw ( expectedError ) ; } ) ; } ) ; describe ( 'collection' , ( ) => { it ( 'returns right collection for expected OS' , ( ) => { const os = OperatingSystem . Windows ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( os ) ; const expected = testContext . app . getCollection ( os ) ; const sut = testContext . withInitialOs ( os ) . construct ( ) ; const actual = sut . state . collection ; expect ( actual ) . to . deep . equal ( expected ) ; } ) ; } ) ; describe ( 'state' , ( ) => { it ( 'initially returns an empty state' , ( ) => { const sut = new ObservableApplicationContextFactory ( ) . construct ( ) ; const actual = sut . state ; expectEmptyState ( actual ) ; } ) ; } ) ; describe ( 'os' , ( ) => { it ( 'set as initial OS' , ( ) => { const expected = OperatingSystem . Windows ; const testContext = new ObservableApplicationContextFactory ( ) . withAppContainingCollections ( OperatingSystem . macOS , expected ) ; const sut = testContext . withInitialOs ( expected ) . construct ( ) ; const actual = sut . state . os ; expect ( actual ) . to . deep . equal ( expected ) ; } ) ; describe ( 'throws when OS is invalid' , ( ) => { const act = ( os ) => new ObservableApplicationContextFactory ( ) . withInitialOs ( os ) . construct ( ) ; new EnumRangeTestRunner ( act ) . testOutOfRangeThrows ( ) . testUndefinedValueThrows ( ) . testInvalidValueThrows ( OperatingSystem . Android , 'os "Android" is not defined in application' ) ; } ) ; } ) ; describe ( 'app' , ( ) => { it ( 'sets app as expected' , ( ) => { const os = OperatingSystem . Windows ; const expected = new ApplicationStub ( ) . withCollection ( new CategoryCollectionStub ( ) . withOs ( os ) ) ; const sut = new ObservableApplicationContextFactory ( ) . withApp ( expected ) . withInitialOs ( os ) . construct ( ) ; expect ( expected ) . to . equal ( sut . app ) ; } ) ; } ) ; } ) ; } ) ; class ObservableApplicationContextFactory { private static DefaultOs = OperatingSystem . Windows ; public app : IApplication ; public firedEvents = new Array < IApplicationContextChangedEvent > ( ) ; private initialOs = ObservableApplicationContextFactory . DefaultOs ; constructor ( ) { this . withAppContainingCollections ( ObservableApplicationContextFactory . DefaultOs ) ; } public withAppContainingCollections ( ... oses ) { const collectionValues = oses . map ( ( os ) => new CategoryCollectionStub ( ) . withOs ( os ) ) ; const app = new ApplicationStub ( ) . withCollections ( ... collectionValues ) ; return this . withApp ( app ) ; } public withApp ( app ) { this . app = app ; return this ; } public withInitialOs ( initialOs ) { this . initialOs = initialOs ; return this ; } public construct ( ) { const sut = new ApplicationContext ( this . app , this . initialOs ) ; sut . contextChanged . on ( ( newContext ) => this . firedEvents . push ( newContext ) ) ; return sut ; } } function getDuplicates < T > ( list ) { return list . filter ( ( item , index ) => list . indexOf ( item ) !== index ) ; } function expectEmptyState ( state ) { expect ( ! state . code . current ) ; expect ( ! state . filter . currentFilter ) ; expect ( ! state . selection ) ; }