diff --git a/CHANGELOG.md b/CHANGELOG.md index c339672921..785d76b229 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.7.3](https://github.com/webern-unibas-ch/awg-app/compare/v0.7.2...v0.7.3) (2020-04-09) + +### Bug Fixes + +- **app:** move editor info from home to edition view ([f0434cc](https://github.com/webern-unibas-ch/awg-app/commit/f0434cce4962f5ff7c06e8bfe1033e4b2c91c69a)) +- **app:** use rel attribute for target links instead of wrong ref attr ([04578ee](https://github.com/webern-unibas-ch/awg-app/commit/04578ee1bfa811613beb72bf0faa2084bbd88a2c)) +- **core:** add sagw logo to footer ([b41d013](https://github.com/webern-unibas-ch/awg-app/commit/b41d013deec3e30fca6ae03e1398676199b48a82)) +- **core:** remove MetaEdition from MetaModel ([010d02f](https://github.com/webern-unibas-ch/awg-app/commit/010d02f07173d93a152ec9fe0f48c81da4baa5fe)) +- **edition:** add dropdown for sample queries in graph view ([c995ada](https://github.com/webern-unibas-ch/awg-app/commit/c995ada1d10101b2e8fb3f0930b798f7b309d220)) +- **edition:** add modal hint on how to use graph ([626d024](https://github.com/webern-unibas-ch/awg-app/commit/626d0240f7e75ba9a6ad1d44ded459217ff8d579)) +- **edition:** add resp statement to work model ([d9eefae](https://github.com/webern-unibas-ch/awg-app/commit/d9eefae9f4f5ae15f55ce687d749cdf481b20941)) +- **edition:** do not remove all svg when redrawing force graph ([e6cfdac](https://github.com/webern-unibas-ch/awg-app/commit/e6cfdac716aadb11211834be0d6be8bb9266910d)) +- **edition:** improve general remarks for graph view ([b1b1c24](https://github.com/webern-unibas-ch/awg-app/commit/b1b1c2499080728b5f0ca144a512331094187a87)) +- **edition:** improve handling of triples dropdown button in force-graph ([c41925b](https://github.com/webern-unibas-ch/awg-app/commit/c41925b796815a1670fbc415bfb96541e89f30cc)) +- **edition:** improve query reset in graph view ([09e309c](https://github.com/webern-unibas-ch/awg-app/commit/09e309ca8dcfa0e6290e32cdbb1535a965d725dc)) +- **edition:** refactor EditionWork to provide all needed info ([0319790](https://github.com/webern-unibas-ch/awg-app/commit/03197908d689c59a0235a1a9616b362edf6eeeff)) +- **edition:** remove unused EditionDetailNotification ([4e1f151](https://github.com/webern-unibas-ch/awg-app/commit/4e1f15100fa6de68346c991d284825edf0318315)) +- **edition:** shorten short forms of some EditionConstants ([61a297d](https://github.com/webern-unibas-ch/awg-app/commit/61a297d8c5af924dc69ef096b67015143970982d)) +- **edition:** use full EditionRoute for EditionWork routes ([2c98f5d](https://github.com/webern-unibas-ch/awg-app/commit/2c98f5d39b28a4cf961cc9812dd8e160eeb054aa)) +- **edition:** use modal for edition detail hint & improve hint message ([0383470](https://github.com/webern-unibas-ch/awg-app/commit/0383470e67715b76898562329f3f90b1b34d1707)) +- **edition:** use queryList in graph data to allow multiple queries ([ca988f2](https://github.com/webern-unibas-ch/awg-app/commit/ca988f208a699045063679245effa200089afd69)) +- **home:** add sketch edition link to Opus 25 header ([aaeaa80](https://github.com/webern-unibas-ch/awg-app/commit/aaeaa801669f4d8a3a32823e0e8872d39f7f14ea)) + ### [0.7.2](https://github.com/webern-unibas-ch/awg-app/compare/v0.7.1...v0.7.2) (2020-03-20) ### Features diff --git a/package.json b/package.json index 5be3720275..3c8cba303d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "awg-app", - "version": "0.7.2", + "version": "0.7.3", "license": "MIT", "author": { "name": "Stefan Münnich", diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 4bf75ab143..e7a180a95e 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -7,6 +7,7 @@ import { of as observableOf } from 'rxjs'; import Spy = jasmine.Spy; +import { cleanStylesFromDOM } from '@testing/clean-up-helper'; import { getAndExpectDebugElementByDirective } from '@testing/expect-helper'; import { RouterEventsService } from '@awg-core/services'; @@ -71,6 +72,10 @@ describe('AppComponent (DONE)', () => { (window as any).ga = undefined; }); + afterAll(() => { + cleanStylesFromDOM(); + }); + it('should create the app', async(() => { expect(component).toBeTruthy(); })); diff --git a/src/app/app.globals.ts b/src/app/app.globals.ts index 1d4b68318a..669035662b 100644 --- a/src/app/app.globals.ts +++ b/src/app/app.globals.ts @@ -1,15 +1,15 @@ // THIS IS AN AUTO-GENERATED FILE. DO NOT CHANGE IT MANUALLY! -// Generated last time on Sat Mar 21 00:35:34 2020 +// Generated last time on Thu Apr 9 12:48:35 2020 /** * The latest version of the AWG App */ -export const appVersion = '0.7.2'; +export const appVersion = '0.7.3'; /** * The release date of the latest version of the AWG App */ -export const appVersionReleaseDate = '21. März 2020'; +export const appVersionReleaseDate = '09. April 2020'; /** * The URL of the AWG App diff --git a/src/app/core/core-models/geo-names.model.ts b/src/app/core/core-models/geo-names.model.ts index a92d930dc0..7e30ed91f4 100644 --- a/src/app/core/core-models/geo-names.model.ts +++ b/src/app/core/core-models/geo-names.model.ts @@ -77,7 +77,7 @@ export class GeoNames { this.gnid + '" title="' + this.longLabel + - '" target="_blank" ref="noopener noreferrer">' + + '" target="_blank" rel="noopener noreferrer">' + geoIcon + ''; let wikiLink = ''; @@ -88,7 +88,7 @@ export class GeoNames { this.wiki + '" title="' + this.wiki + - '" target="_blank" ref="noopener noreferrer">' + + '" target="_blank" rel="noopener noreferrer">' + wikiIcon + ''; } diff --git a/src/app/core/core-models/index.ts b/src/app/core/core-models/index.ts index 8dcf01f50d..cb1323674d 100644 --- a/src/app/core/core-models/index.ts +++ b/src/app/core/core-models/index.ts @@ -9,6 +9,6 @@ import { GeoNames } from './geo-names.model'; import { Logo, Logos } from './logos.model'; -import { Meta, MetaContact, MetaEdition, MetaPage, MetaStructure, MetaSectionTypes } from './meta.model'; +import { Meta, MetaContact, MetaPage, MetaStructure, MetaSectionTypes } from './meta.model'; -export { GeoNames, Logo, Logos, Meta, MetaContact, MetaEdition, MetaPage, MetaStructure, MetaSectionTypes }; +export { GeoNames, Logo, Logos, Meta, MetaContact, MetaPage, MetaStructure, MetaSectionTypes }; diff --git a/src/app/core/core-models/meta.model.ts b/src/app/core/core-models/meta.model.ts index 4ad7d807cb..205b313b37 100644 --- a/src/app/core/core-models/meta.model.ts +++ b/src/app/core/core-models/meta.model.ts @@ -5,7 +5,6 @@ */ export enum MetaSectionTypes { page = 'page', - edition = 'edition', structure = 'structure', contact = 'contact' } @@ -17,14 +16,14 @@ export enum MetaSectionTypes { */ export class MetaPerson { /** - * The name of the person. + * The (FOAF) name of the person. */ name: string; /** - * The contact (webadress) of a person. + * The (FOAF) homepage of a person. */ - contactUrl: string; + homepage: string; } /** @@ -80,24 +79,6 @@ export class MetaPage { versionReleaseDate: string; } -/** - * The MetaEdition class. - * - * It is used in the context of the edition view - * to store the meta data about the edition. - */ -export class MetaEdition { - /** - * The editors of an edition. - */ - editors: MetaPerson[]; - - /** - * The last modification date of an edition. - */ - lastModified: string; -} - /** * The MetaStructure class. * @@ -205,11 +186,6 @@ export class Meta { */ page: MetaPage; - /** - * The meta data for the edition view. - */ - edition: MetaEdition; - /** * The meta data for the structure view. */ diff --git a/src/app/core/footer/footer-copyright/footer-copyright.component.spec.ts b/src/app/core/footer/footer-copyright/footer-copyright.component.spec.ts index e00cc7a1ac..2561b2db4d 100644 --- a/src/app/core/footer/footer-copyright/footer-copyright.component.spec.ts +++ b/src/app/core/footer/footer-copyright/footer-copyright.component.spec.ts @@ -1,9 +1,10 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { DebugElement } from '@angular/core'; +import { cleanStylesFromDOM } from '@testing/clean-up-helper'; import { getAndExpectDebugElementByCss } from '@testing/expect-helper'; -import { Meta, MetaPage, MetaSectionTypes } from '@awg-core/core-models'; +import { MetaPage, MetaSectionTypes } from '@awg-core/core-models'; import { METADATA } from '@awg-core/mock-data'; import { FooterCopyrightComponent } from './footer-copyright.component'; @@ -32,6 +33,10 @@ describe('FooterCopyrightComponent (DONE)', () => { expectedPageMetaData = METADATA[MetaSectionTypes.page]; }); + afterAll(() => { + cleanStylesFromDOM(); + }); + it('should create', () => { expect(component).toBeTruthy(); }); diff --git a/src/app/core/footer/footer-declaration/footer-declaration.component.spec.ts b/src/app/core/footer/footer-declaration/footer-declaration.component.spec.ts index 32052ce05b..659257b910 100644 --- a/src/app/core/footer/footer-declaration/footer-declaration.component.spec.ts +++ b/src/app/core/footer/footer-declaration/footer-declaration.component.spec.ts @@ -1,6 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { DebugElement } from '@angular/core'; +import { cleanStylesFromDOM } from '@testing/clean-up-helper'; import { click } from '@testing/click-helper'; import { getAndExpectDebugElementByCss, getAndExpectDebugElementByDirective } from '@testing/expect-helper'; import { RouterLinkStubDirective } from '@testing/router-stubs'; @@ -36,6 +37,10 @@ describe('FooterDeclarationComponent (DONE)', () => { expectedPageMetaData = METADATA[MetaSectionTypes.page]; }); + afterAll(() => { + cleanStylesFromDOM(); + }); + it('should create', () => { expect(component).toBeTruthy(); }); diff --git a/src/app/core/footer/footer-logo/footer-logo.component.html b/src/app/core/footer/footer-logo/footer-logo.component.html index b69002cdf0..6bf3d74f1c 100644 --- a/src/app/core/footer/footer-logo/footer-logo.component.html +++ b/src/app/core/footer/footer-logo/footer-logo.component.html @@ -1,3 +1,3 @@ - - {{ logo.alt }} + + {{ logo.alt }} diff --git a/src/app/core/footer/footer-logo/footer-logo.component.spec.ts b/src/app/core/footer/footer-logo/footer-logo.component.spec.ts index d8f72aa98e..894b34f197 100644 --- a/src/app/core/footer/footer-logo/footer-logo.component.spec.ts +++ b/src/app/core/footer/footer-logo/footer-logo.component.spec.ts @@ -1,9 +1,14 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { DebugElement } from '@angular/core'; -import { getAndExpectDebugElementByCss } from '@testing/expect-helper'; +import Spy = jasmine.Spy; + +import { cleanStylesFromDOM } from '@testing/clean-up-helper'; +import { detectChangesOnPush } from '@testing/detect-changes-on-push-helper'; +import { expectSpyCall, getAndExpectDebugElementByCss } from '@testing/expect-helper'; import { Logo } from '@awg-core/core-models'; +import { LOGOSDATA } from '@awg-core/mock-data'; import { FooterLogoComponent } from './footer-logo.component'; @@ -13,7 +18,14 @@ describe('FooterLogoComponent (DONE)', () => { let compDe: DebugElement; let compEl: any; + let getLogoClassSpy: Spy; + let expectedLogo: Logo; + let expectedNonRightMainFooterLogo: Logo; + let expectedNonMainFooterLogo: Logo; + + const cssClassFloatRight = 'float-right'; + const cssClassMarginY2 = 'my-2'; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -28,12 +40,18 @@ describe('FooterLogoComponent (DONE)', () => { compEl = compDe.nativeElement; // test data - expectedLogo = { - id: 'unibaslogo', - src: 'assets/img/logos/uni.svg', - alt: 'Logo Uni Basel', - href: 'https://www.unibas.ch' - }; + expectedLogo = LOGOSDATA.unibas; + expectedNonRightMainFooterLogo = LOGOSDATA.sagw; + expectedNonMainFooterLogo = LOGOSDATA.angular; + + // spies on component functions + // `.and.callThrough` will track the spy down the nested describes, see + // https://jasmine.github.io/2.0/introduction.html#section-Spies:_%3Ccode%3Eand.callThrough%3C/code%3E + getLogoClassSpy = spyOn(component, 'getLogoClass').and.callThrough(); + }); + + afterAll(() => { + cleanStylesFromDOM(); }); it('should create', () => { @@ -42,11 +60,17 @@ describe('FooterLogoComponent (DONE)', () => { describe('BEFORE initial data binding', () => { it('should not have logo', () => { - expect(component.logo).toBeUndefined('should be undefined'); + expect(component.logo).toBeUndefined(`should be undefined`); + }); + + describe('#getLogoClass', () => { + it('... should not have been called yet', () => { + expectSpyCall(getLogoClassSpy, 0); + }); }); describe('VIEW', () => { - it('... should contain one image inside an anchor', () => { + it('... should contain one image inside an anchor a', () => { const imageDes = getAndExpectDebugElementByCss(compDe, 'a > img', 1, 1); }); @@ -60,16 +84,16 @@ describe('FooterLogoComponent (DONE)', () => { const imageEl = imageDes[0].nativeElement; expect(anchorEl.href).toBeDefined(); - expect(anchorEl.href).toBe('', 'should be empty string'); + expect(anchorEl.href).not.toBeTruthy('should be empty string'); expect(imageEl.id).toBeDefined(); - expect(imageEl.id).toBe('', 'should be empty string'); + expect(imageEl.id).not.toBeTruthy('should be empty string'); expect(imageEl.src).toBeDefined(); - expect(imageEl.src).toBe('', 'should be empty string'); + expect(imageEl.src).not.toBeTruthy('should be empty string'); expect(imageEl.alt).toBeDefined(); - expect(imageEl.alt).toBe('', 'should be empty string'); + expect(imageEl.alt).not.toBeTruthy('should be empty string'); }); }); }); @@ -77,19 +101,123 @@ describe('FooterLogoComponent (DONE)', () => { describe('AFTER initial data binding', () => { beforeEach(() => { // simulate the parent setting the input properties - component.logo = expectedLogo; + component.logo = LOGOSDATA.unibas; // trigger initial data binding fixture.detectChanges(); }); it('should have logo', () => { + expect(component.logo).toBeDefined(`should be defined`); + expect(component.logo).toBe(expectedLogo, `should be ${expectedLogo}`); + }); + + it('should change logo if input changes', () => { expect(component.logo).toBeDefined(); expect(component.logo).toBe(expectedLogo); + + // trigger changes in data binding + component.logo = LOGOSDATA.sagw; + fixture.detectChanges(); + + expect(component.logo).toBeDefined(`should be defined`); + expect(component.logo).toEqual( + expectedNonRightMainFooterLogo, + `should equal ${expectedNonRightMainFooterLogo}` + ); + + // trigger changes in data binding + component.logo = LOGOSDATA.angular; + fixture.detectChanges(); + + expect(component.logo).toBeDefined(`should be defined`); + expect(component.logo).toEqual(expectedNonMainFooterLogo, `should equal ${expectedNonMainFooterLogo}`); + }); + + describe('#getLogoClass', () => { + it('... should have been called with logo id', () => { + expectSpyCall(getLogoClassSpy, 1, expectedLogo.id); + }); + + it('... should return class `my-2 float-right` for right main footer logos', () => { + expectSpyCall(getLogoClassSpy, 1, expectedLogo.id); + + const classList = component.getLogoClass(component.logo.id); + + expect(classList).toBeTruthy(`should not be empty`); + expect(classList).toContain(cssClassFloatRight, `should contain ${cssClassFloatRight}`); + expect(classList).toContain(cssClassMarginY2, `should contain ${cssClassMarginY2}`); + expect(classList).toBe( + cssClassMarginY2 + ' ' + cssClassFloatRight, + `should be ${cssClassMarginY2} ${cssClassFloatRight}` + ); + }); + + it('... should return class `float-right` only for right main footer logos', () => { + expectSpyCall(getLogoClassSpy, 1, expectedLogo.id); + + let classList = component.getLogoClass(component.logo.id); + + expect(classList).toBeTruthy(`should not be empty`); + expect(classList).toContain(cssClassFloatRight, `should contain ${cssClassFloatRight}`); + + // main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.sagw; + fixture.detectChanges(); + + classList = component.getLogoClass(component.logo.id); + + expect(classList).toBeTruthy(`should not be empty`); + expect(classList).not.toContain(cssClassFloatRight, `should not contain ${cssClassFloatRight}`); + + // not main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.angular; + fixture.detectChanges(); + + classList = component.getLogoClass(component.logo.id); + + expect(classList).not.toBeTruthy(`should be empty`); + }); + + it('... should return class `my-2` only for main footer logos', () => { + let classList = component.getLogoClass(component.logo.id); + + expect(classList).toBeTruthy(`should not be empty`); + expect(classList).toContain(cssClassMarginY2, `should contain ${cssClassMarginY2}`); + + // trigger changes in data binding + component.logo = LOGOSDATA.sagw; + fixture.detectChanges(); + + classList = component.getLogoClass(component.logo.id); + + expect(classList).toBeTruthy(`should not be empty`); + expect(classList).toContain(cssClassMarginY2, `should contain ${cssClassMarginY2}`); + + // trigger changes in data binding + component.logo = LOGOSDATA.angular; + fixture.detectChanges(); + + classList = component.getLogoClass(component.logo.id); + + expect(classList).not.toBeTruthy(`should be empty`); + }); }); describe('VIEW', () => { - it('... should render logo', () => { + it('... should have correct logo link in anchor', () => { + // find debug elements + const anchorDes = getAndExpectDebugElementByCss(compDe, 'a', 1, 1); + + // find native elements + const anchorEl = anchorDes[0].nativeElement; + + expect(anchorEl.href).toContain(expectedLogo.href, `should contain ${expectedLogo.href}`); + }); + + it('... should have correct logo id in img', () => { // find debug elements const anchorDes = getAndExpectDebugElementByCss(compDe, 'a', 1, 1); const imageDes = getAndExpectDebugElementByCss(compDe, 'img', 1, 1); @@ -98,10 +226,136 @@ describe('FooterLogoComponent (DONE)', () => { const anchorEl = anchorDes[0].nativeElement; const imageEl = imageDes[0].nativeElement; - expect(anchorEl.href).toContain(expectedLogo.href); - expect(imageEl.id).toContain(expectedLogo.id); - expect(imageEl.src).toContain(expectedLogo.src); - expect(imageEl.alt).toContain(expectedLogo.alt); + expect(imageEl.id).toBe(expectedLogo.id, `should be ${expectedLogo.id}`); + }); + + it('... should have correct logo src and alt in img', () => { + // find debug elements + const anchorDes = getAndExpectDebugElementByCss(compDe, 'a', 1, 1); + const imageDes = getAndExpectDebugElementByCss(compDe, 'img', 1, 1); + + // find native elements + const anchorEl = anchorDes[0].nativeElement; + const imageEl = imageDes[0].nativeElement; + + expect(imageEl.src).toContain(expectedLogo.src, `should contain ${expectedLogo.src}`); + expect(imageEl.alt).toBe(expectedLogo.alt, `should be ${expectedLogo.alt}`); + }); + + it('... should have CSS class `my-2 float-right` applied only to right main footer logos', async () => { + // for CSS class karma tests cf. https://stackoverflow.com/a/49157894 + + // right main footer logo + // find debug elements + const imageDes = getAndExpectDebugElementByCss(compDe, 'img', 1, 1); + + // find native elements + const imageEl = imageDes[0].nativeElement; + const imageClasses = imageDes[0].classes; + + expect(imageEl.classList).toContain(cssClassFloatRight, `should contain ${cssClassFloatRight}`); + expect(imageClasses[cssClassFloatRight]).toBeTruthy(`should not be empty`); + expect(imageEl.classList).toContain(cssClassMarginY2, `should contain ${cssClassMarginY2}`); + expect(imageClasses[cssClassMarginY2]).toBeTruthy(`should not be empty`); + }); + + it('... should have CSS class `float-right` applied only to right main footer logos', async () => { + // for CSS class karma tests cf. https://stackoverflow.com/a/49157894 + + // right main footer logo + // find debug elements + const imageDes = getAndExpectDebugElementByCss(compDe, 'img', 1, 1); + + // find native elements + const imageEl = imageDes[0].nativeElement; + const imageClasses = imageDes[0].classes; + + expect(imageEl.classList).toContain(cssClassFloatRight, `should contain ${cssClassFloatRight}`); + expect(imageClasses[cssClassFloatRight]).toBeTruthy(`should not be empty`); + + // main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.sagw; + await detectChangesOnPush(fixture); // fixture.detectChanges with onPush strategy + + expect(imageEl.classList).not.toContain(cssClassFloatRight, `should contain ${cssClassFloatRight}`); + expect(imageClasses[cssClassFloatRight]).not.toBeTruthy(`should not be empty`); + + // not main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.angular; + await detectChangesOnPush(fixture); // fixture.detectChanges with onPush + + expect(imageEl.classList).not.toContain(cssClassFloatRight, `should contain ${cssClassFloatRight}`); + expect(imageClasses[cssClassFloatRight]).not.toBeTruthy(`should be empty`); + }); + + it('... should have CSS class `my-2` applied only to main footer logos', async () => { + // right main footer logo + // find debug elements + const imageDes = getAndExpectDebugElementByCss(compDe, 'img', 1, 1); + + // find native elements + const imageEl = imageDes[0].nativeElement; + const imageClasses = imageDes[0].classes; + + expect(imageEl.classList).toContain(cssClassMarginY2, `should contain ${cssClassMarginY2}`); + expect(imageClasses[cssClassMarginY2]).toBeTruthy(`should not be empty`); + + // main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.sagw; + await detectChangesOnPush(fixture); // fixture.detectChanges with onPush strategy + + expect(imageEl.classList).toContain(cssClassMarginY2, `should contain ${cssClassMarginY2}`); + expect(imageClasses[cssClassMarginY2]).toBeTruthy(`should not be empty`); + + // not main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.angular; + await detectChangesOnPush(fixture); // fixture.detectChanges with onPush + + expect(imageEl.classList).not.toContain(cssClassMarginY2, `should not contain ${cssClassMarginY2}`); + expect(imageClasses[cssClassMarginY2]).not.toBeTruthy(`should be empty`); + }); + + it('... should have [ngClass] resolve to correct classes', async () => { + // right main footer logo + // find debug elements + const imageDes = getAndExpectDebugElementByCss(compDe, 'img', 1, 1); + const imageAttributes = imageDes[0].attributes; + + // find native elements + const imageEl = imageDes[0].nativeElement; + const imageElAttributes = imageEl.attributes; + + expect(imageAttributes['ng-reflect-ng-class']).toBe( + cssClassMarginY2 + ' ' + cssClassFloatRight, + `should be ${cssClassMarginY2} ${cssClassFloatRight}` + ); + expect(imageElAttributes['ng-reflect-ng-class'].value).toBe( + cssClassMarginY2 + ' ' + cssClassFloatRight, + `should be ${cssClassMarginY2} ${cssClassFloatRight}` + ); + + // main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.sagw; + await detectChangesOnPush(fixture); // fixture.detectChanges with onPush strategy + + expect(imageAttributes['ng-reflect-ng-class']).toBe(cssClassMarginY2, `should be ${cssClassMarginY2}`); + expect(imageElAttributes['ng-reflect-ng-class'].value).toBe( + cssClassMarginY2, + `should be ${cssClassMarginY2}` + ); + + // not main footer logo + // trigger changes in data binding + component.logo = LOGOSDATA.angular; + await detectChangesOnPush(fixture); // fixture.detectChanges with onPush strategy + + expect(imageAttributes['ng-reflect-ng-class']).not.toBeTruthy(`should be empty string`); + expect(imageElAttributes['ng-reflect-ng-class'].value).not.toBeTruthy(`should be empty string`); }); }); }); diff --git a/src/app/core/footer/footer-logo/footer-logo.component.ts b/src/app/core/footer/footer-logo/footer-logo.component.ts index 2cdc776fb4..23a2d245ec 100644 --- a/src/app/core/footer/footer-logo/footer-logo.component.ts +++ b/src/app/core/footer/footer-logo/footer-logo.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Logo } from '@awg-core/core-models'; +import { LOGOSDATA } from '@awg-core/mock-data'; /** * The FooterLogo component. @@ -21,4 +22,29 @@ export class FooterLogoComponent { */ @Input() logo: Logo; + + /** + * Public variable: getLogoClass. + * + * It checks a given logo id for the logo + * being part of the (right) main footer. + * + * @param {string} id The given logo id. + * + * @returns {boolean} The boolean value of the comparison. + */ + getLogoClass(id: string) { + const isSnfLogo = id === LOGOSDATA.snf.id; + const isUnibasLogo = id === LOGOSDATA.unibas.id; + const isSagwLogo = id === LOGOSDATA.sagw.id; + + let classList = ''; + if (isUnibasLogo || isSnfLogo || isSagwLogo) { + classList = 'my-2'; + } + if (isUnibasLogo || isSnfLogo) { + classList += ' float-right'; + } + return classList; + } } diff --git a/src/app/core/footer/footer-poweredby/footer-poweredby.component.spec.ts b/src/app/core/footer/footer-poweredby/footer-poweredby.component.spec.ts index cfde76dfdd..9bf6097fe1 100644 --- a/src/app/core/footer/footer-poweredby/footer-poweredby.component.spec.ts +++ b/src/app/core/footer/footer-poweredby/footer-poweredby.component.spec.ts @@ -1,10 +1,10 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { Component, DebugElement, Input } from '@angular/core'; +import { cleanStylesFromDOM } from '@testing/clean-up-helper'; import { getAndExpectDebugElementByCss, getAndExpectDebugElementByDirective } from '@testing/expect-helper'; import { Logo, Logos } from '@awg-core/core-models'; - import { FooterPoweredbyComponent } from './footer-poweredby.component'; @Component({ selector: 'awg-footer-logo', template: '' }) @@ -68,6 +68,10 @@ describe('FooterPoweredbyComponent (DONE)', () => { }; }); + afterAll(() => { + cleanStylesFromDOM(); + }); + it('should create', () => { expect(component).toBeTruthy(); }); diff --git a/src/app/core/footer/footer.component.html b/src/app/core/footer/footer.component.html index 39efd46b5b..d8db3cb845 100644 --- a/src/app/core/footer/footer.component.html +++ b/src/app/core/footer/footer.component.html @@ -1,14 +1,15 @@