feat(aio): add prettier network fail page (#16139)

This commit is contained in:
Ward Bell 2017-04-20 15:09:02 +01:00 committed by Miško Hevery
parent db4e9ea04a
commit c390b06da2
3 changed files with 46 additions and 29 deletions

View File

@ -49,21 +49,21 @@ describe('DocumentService', () => {
describe('currentDocument', () => {
it('should fetch a document for the initial location url', () => {
const { docService, backend } = getServices('initial/url');
it('should fetch a document for the initial location', () => {
const { docService, backend } = getServices('initial/doc');
const connections = backend.connectionsArray;
docService.currentDocument.subscribe();
expect(connections.length).toEqual(1);
expect(connections[0].request.url).toEqual(CONTENT_URL_PREFIX + 'initial/url.json');
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'initial/url.json');
expect(connections[0].request.url).toEqual(CONTENT_URL_PREFIX + 'initial/doc.json');
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'initial/doc.json');
});
it('should emit a document each time the location changes', () => {
let latestDocument: DocumentContents;
const doc0 = { title: 'doc 0', url: 'initial/url' };
const doc1 = { title: 'doc 1', url: 'new/url' };
const { docService, backend, locationService } = getServices('initial/url');
const doc0 = { title: 'doc 0', id: 'initial/doc' };
const doc1 = { title: 'doc 1', id: 'new/doc' };
const { docService, backend, locationService } = getServices('initial/doc');
const connections = backend.connectionsArray;
docService.currentDocument.subscribe(doc => latestDocument = doc);
@ -72,13 +72,13 @@ describe('DocumentService', () => {
connections[0].mockRespond(createResponse(doc0));
expect(latestDocument).toEqual(doc0);
locationService.go('new/url');
locationService.go('new/doc');
connections[1].mockRespond(createResponse(doc1));
expect(latestDocument).toEqual(doc1);
});
it('should emit the not-found document if the document is not found on the server', () => {
const { docService, backend } = getServices('missing/url');
const { docService, backend } = getServices('missing/doc');
const connections = backend.connectionsArray;
let currentDocument: DocumentContents;
docService.currentDocument.subscribe(doc => currentDocument = doc);
@ -94,7 +94,7 @@ describe('DocumentService', () => {
it('should emit a hard-coded not-found document if the not-found document is not found on the server', () => {
let currentDocument: DocumentContents;
const notFoundDoc: DocumentContents = { title: 'Not Found', contents: 'Document not found', id: 'file-not-found' };
const nextDoc = { title: 'Next Doc', url: 'new/url' };
const nextDoc = { title: 'Next Doc', id: 'new/doc' };
const { docService, backend, locationService } = getServices('file-not-found');
const connections = backend.connectionsArray;
docService.currentDocument.subscribe(doc => currentDocument = doc);
@ -104,23 +104,23 @@ describe('DocumentService', () => {
expect(currentDocument).toEqual(notFoundDoc);
// now check that we haven't killed the currentDocument observable sequence
locationService.go('new/url');
locationService.go('new/doc');
connections[1].mockRespond(createResponse(nextDoc));
expect(currentDocument).toEqual(nextDoc);
});
it('should not crash the app if the response is not valid JSON', () => {
it('should not crash the app if the response is invalid JSON', () => {
let latestDocument: DocumentContents;
const { docService, backend, locationService} = getServices('initial/url');
const { docService, backend, locationService} = getServices('initial/doc');
const connections = backend.connectionsArray;
docService.currentDocument.subscribe(doc => latestDocument = doc);
connections[0].mockRespond(new Response(new ResponseOptions({ body: 'this is invalid JSON' })));
expect(latestDocument.title).toEqual('Error fetching document');
expect(latestDocument.title).toMatch('Document retrieval error');
const doc1 = { title: 'doc 1' };
locationService.go('new/url');
locationService.go('new/doc');
connections[1].mockRespond(createResponse(doc1));
expect(latestDocument).toEqual(jasmine.objectContaining(doc1));
});

View File

@ -14,8 +14,18 @@ export { DocumentContents } from './document-contents';
import { LocationService } from 'app/shared/location.service';
import { Logger } from 'app/shared/logger.service';
const FILE_NOT_FOUND_URL = 'file-not-found';
const FETCHING_ERROR_URL = 'fetching-error';
const CONTENT_URL_PREFIX = 'content/docs/';
const FILE_NOT_FOUND_ID = 'file-not-found';
const FETCHING_ERROR_ID = 'fetching-error';
const FETCHING_ERROR_CONTENTS = `
<div class="nf-container l-flex-wrap flex-center">
<div class="nf-icon material-icons">error_outline</div>
<div class="nf-response l-flex-wrap">
<h1>Request for document failed.</h1>
<p>We are unable to retrieve the "<current-location></current-location>" page at this time.
Please check your connection and try again later.</p>
</div></div>
`;
@Injectable()
export class DocumentService {
@ -49,32 +59,33 @@ export class DocumentService {
.get(requestPath)
.map(response => response.json())
.catch((error: Response) => {
return error.status === 404 ? this.getFileNotFoundDoc(id) : this.getErrorDoc(error);
return error.status === 404 ? this.getFileNotFoundDoc(id) : this.getErrorDoc(id, error);
})
.subscribe(subject);
return subject.asObservable();
}
private getFileNotFoundDoc(url: string): Observable<DocumentContents> {
if (url !== FILE_NOT_FOUND_URL) {
this.logger.error(`Document file not found at '${url}'`);
private getFileNotFoundDoc(id: string): Observable<DocumentContents> {
if (id !== FILE_NOT_FOUND_ID) {
this.logger.error(`Document file not found at '${id}'`);
// using `getDocument` means that we can fetch the 404 doc contents from the server and cache it
return this.getDocument(FILE_NOT_FOUND_URL);
return this.getDocument(FILE_NOT_FOUND_ID);
} else {
return of({
title: 'Not Found',
contents: 'Document not found',
id: FILE_NOT_FOUND_URL
id: FILE_NOT_FOUND_ID
});
}
}
private getErrorDoc(error: Response): Observable<DocumentContents> {
private getErrorDoc(id: string, error: Response): Observable<DocumentContents> {
this.logger.error('Error fetching document', error);
this.cache.delete(id);
return Observable.of({
title: 'Error fetching document',
contents: 'Sorry we were not able to fetch that document.',
id: FETCHING_ERROR_URL
title: 'Document retrieval error',
contents: FETCHING_ERROR_CONTENTS,
id: FETCHING_ERROR_ID
});
}
}

View File

@ -1,6 +1,6 @@
#file-not-found {
padding: 3rem 3rem 3rem;
}
}
.nf-container {
align-items: center;
@ -18,4 +18,10 @@
text-transform: uppercase;
margin: 8px 0;
}
}
}
.nf-icon.material-icons {
color: $blue;
font-size: 100px;
position: static;
}