diff --git a/ui/src/app/metadata/domain/domain.util.spec.ts b/ui/src/app/metadata/domain/domain.util.spec.ts
new file mode 100644
index 000000000..548379455
--- /dev/null
+++ b/ui/src/app/metadata/domain/domain.util.spec.ts
@@ -0,0 +1,36 @@
+import * as util from './domain.util';
+
+describe('Domain Utility methods', () => {
+
+ describe('combineAllFn', () => {
+ it('should return true when the selected id is found', () => {
+ expect(util.combineAllFn(['foo'], ['bar'])).toEqual(['bar', 'foo']);
+ });
+ });
+
+ describe('doesExistFn', () => {
+ it('should return true when the selected id is found', () => {
+ expect(util.doesExistFn(['foo', 'bar'], 'foo')).toBe(true);
+ });
+ it('should return false when the selected id is not found', () => {
+ expect(util.doesExistFn(['foo'], 'bar')).toBe(false);
+ });
+ });
+
+ describe('getInCollectionFn', () => {
+ const entities = { foo: {}, bar: {} };
+ it('should return the entity with the given id', () => {
+ expect(util.getInCollectionFn(entities, 'foo')).toBe(entities.foo);
+ });
+ it('should return null when provided a null id', () => {
+ expect(util.getInCollectionFn(entities, null)).toBeNull();
+ });
+ });
+
+ describe('getEntityIdsFn', () => {
+ const entities = [{ entityId: 'foo' }, { entityId: 'bar' }];
+ it('should return a list of ids', () => {
+ expect(util.getEntityIdsFn(entities)).toEqual(['foo', 'bar']);
+ });
+ });
+});
diff --git a/ui/src/app/metadata/domain/entity/provider/file-backed-http-metadata-provider.spec.ts b/ui/src/app/metadata/domain/entity/provider/file-backed-http-metadata-provider.spec.ts
new file mode 100644
index 000000000..37d74a6a8
--- /dev/null
+++ b/ui/src/app/metadata/domain/entity/provider/file-backed-http-metadata-provider.spec.ts
@@ -0,0 +1,104 @@
+import { FileBackedHttpMetadataProvider } from './file-backed-http-metadata-provider';
+
+describe('Resolver construct', () => {
+
+ const config = {
+ id: 'foo',
+ entityId: 'string',
+ serviceProviderName: 'string',
+ organization: {
+ 'name': 'string',
+ 'displayName': 'string',
+ 'url': 'string'
+ },
+ contacts: [
+ {
+ 'name': 'string',
+ 'type': 'string',
+ 'emailAddress': 'string'
+ }
+ ],
+ mdui: {
+ 'displayName': 'string',
+ 'informationUrl': 'string',
+ 'privacyStatementUrl': 'string',
+ 'logoUrl': 'string',
+ 'logoHeight': 100,
+ 'logoWidth': 100,
+ 'description': 'string'
+ },
+ securityInfo: {
+ 'x509CertificateAvailable': true,
+ 'authenticationRequestsSigned': true,
+ 'wantAssertionsSigned': true,
+ 'x509Certificates': [
+ {
+ 'name': 'string',
+ 'type': 'string',
+ 'value': 'string'
+ }
+ ]
+ },
+ assertionConsumerServices: [
+ {
+ 'binding': 'string',
+ 'locationUrl': 'string',
+ 'makeDefault': true
+ }
+ ],
+ serviceProviderSsoDescriptor: {
+ 'protocolSupportEnum': 'string',
+ 'nameIdFormats': [
+ 'string'
+ ]
+ },
+
+ logoutEndpoints: [
+ {
+ 'url': 'string',
+ 'bindingType': 'string'
+ }
+ ],
+ serviceEnabled: true,
+ createdDate: new Date().toDateString(),
+ modifiedDate: new Date().toDateString(),
+ relyingPartyOverrides: {
+ 'signAssertion': true,
+ 'dontSignResponse': true,
+ 'turnOffEncryption': true,
+ 'useSha': true,
+ 'ignoreAuthenticationMethod': true,
+ 'omitNotBefore': true,
+ 'responderId': 'string',
+ 'nameIdFormats': [
+ 'string'
+ ],
+ 'authenticationMethods': [
+ 'string'
+ ]
+ },
+ attributeRelease: [
+ 'eduPersonPrincipalName',
+ 'uid',
+ 'mail'
+ ]
+ };
+
+ let entity;
+
+ beforeEach(() => {
+ entity = new FileBackedHttpMetadataProvider(config);
+ });
+
+ it('should populate its own values', () => {
+ Object.keys(config).forEach(key => {
+ expect(entity[key]).toEqual(config[key]);
+ });
+ });
+
+ describe('interface methods', () => {
+ it('should return a date object from getCreationDate', () => {
+ expect(entity.getCreationDate()).toEqual(new Date(config.createdDate));
+ });
+ });
+});
diff --git a/ui/src/app/metadata/metadata.component.spec.ts b/ui/src/app/metadata/metadata.component.spec.ts
new file mode 100644
index 000000000..fb9d5f329
--- /dev/null
+++ b/ui/src/app/metadata/metadata.component.spec.ts
@@ -0,0 +1,55 @@
+import { Component, ViewChild } from '@angular/core';
+import { TestBed, async, ComponentFixture } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { StoreModule, Store, combineReducers } from '@ngrx/store';
+import { MetadataPageComponent } from './metadata.component';
+
+import * as fromRoot from '../core/reducer';
+import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
+
+@Component({
+ template: `
+
+ `
+})
+class TestHostComponent {
+ @ViewChild(MetadataPageComponent)
+ public componentUnderTest: MetadataPageComponent;
+}
+
+describe('AppComponent', () => {
+
+ let fixture: ComponentFixture;
+ let instance: TestHostComponent;
+ let app: MetadataPageComponent;
+ let store: Store;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ NgbDropdownModule.forRoot(),
+ RouterTestingModule,
+ StoreModule.forRoot({
+ core: combineReducers(fromRoot.reducers)
+ })
+ ],
+ declarations: [
+ MetadataPageComponent,
+ TestHostComponent
+ ],
+ }).compileComponents();
+
+ store = TestBed.get(Store);
+ spyOn(store, 'dispatch');
+
+ fixture = TestBed.createComponent(TestHostComponent);
+ instance = fixture.componentInstance;
+ app = instance.componentUnderTest;
+ fixture.detectChanges();
+ }));
+
+ it('should create the app', async(() => {
+ expect(app).toBeTruthy();
+ expect(store.dispatch).toHaveBeenCalledTimes(3);
+ }));
+});
diff --git a/ui/src/app/shared/pipe/highlight.pipe.spec.ts b/ui/src/app/shared/pipe/highlight.pipe.spec.ts
new file mode 100644
index 000000000..40a5cffce
--- /dev/null
+++ b/ui/src/app/shared/pipe/highlight.pipe.spec.ts
@@ -0,0 +1,28 @@
+import { HighlightPipe } from './highlight.pipe';
+import { DomSanitizer } from '@angular/platform-browser';
+
+describe('Pipe: Highlight', () => {
+ let pipe: HighlightPipe;
+
+ beforeEach(() => {
+ pipe = new HighlightPipe({
+ bypassSecurityTrustHtml: jasmine.createSpy('bypassSecurityTrustHtml'),
+ sanitize: jasmine.createSpy('sanitize'),
+ bypassSecurityTrustStyle: jasmine.createSpy('bypassSecurityTrustStyle'),
+ bypassSecurityTrustScript: jasmine.createSpy('bypassSecurityTrustScript'),
+ bypassSecurityTrustUrl: jasmine.createSpy('bypassSecurityTrustUrl'),
+ bypassSecurityTrustResourceUrl: jasmine.createSpy('bypassSecurityTrustResourceUrl')
+ });
+ });
+
+ it('should return the attribute value', () => {
+ const str = 'foobar';
+ const query = 'foo';
+ expect(pipe.transform(str, query)).toBeUndefined();
+ });
+ it('should return - if the attribute is null', () => {
+ expect(pipe.transform(null, null)).toBeNull();
+ expect(pipe.transform('foo', null)).toEqual('foo');
+ expect(pipe.transform(null, 'foo')).toBeNull();
+ });
+});
diff --git a/ui/src/app/shared/pipe/pretty-xml.pipe.spec.ts b/ui/src/app/shared/pipe/pretty-xml.pipe.spec.ts
new file mode 100644
index 000000000..9aa1d875a
--- /dev/null
+++ b/ui/src/app/shared/pipe/pretty-xml.pipe.spec.ts
@@ -0,0 +1,20 @@
+import { PrettyXml } from './pretty-xml.pipe';
+import * as XmlFormatter from 'xml-formatter';
+
+describe('Pipe: Pretty Xml', () => {
+ let pipe: PrettyXml;
+
+ beforeEach(() => {
+ pipe = new PrettyXml();
+ });
+
+ it('should return the formatted xml', () => {
+ const str = '';
+ expect(pipe.transform(str)).toEqual(XmlFormatter(str));
+ });
+
+ it('should return the provided string if not truthy', () => {
+ const str = '';
+ expect(pipe.transform(str)).toEqual('');
+ });
+});