feat(docs-infra): add shortcuts for the angular.io PWA (#40393)
This commits adds some shortcut definitions for the angular.io PWA. The user agent can use them to assemble a context menu to be displayed by the operating system when a user engages with the app's icon. (In addition, shortcuts provide an easy way for users to add links to specific pages on their home screen.) See [here][1] for more details on the `shortcuts` property of the PWA manifest. The choice of pages to create shortcuts to was influenced by the following facts/criteria: - It seems that only the first 4 shortcuts are displayed by Chrome (at least on my Android phone). - Since the PWA is mostly used on mobile, I omitted pages that are less likely to be useful for mobile users (such as pages related to CLI). [1]: https://developer.mozilla.org/en-US/docs/Web/Manifest/shortcuts PR Close #40393
This commit is contained in:
parent
4065c98054
commit
96690ed3a4
|
@ -22,5 +22,31 @@
|
|||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"start_url": "/?utm_source=homescreen"
|
||||
"start_url": "/?utm_source=homescreen",
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Go to API Reference",
|
||||
"short_name": "API",
|
||||
"description": "Go to the Angular API reference page.",
|
||||
"url": "/api?utm_source=homescreen"
|
||||
},
|
||||
{
|
||||
"name": "Go to Glossary",
|
||||
"short_name": "Glossary",
|
||||
"description": "Go to the glossary page: A list of common Angular terms and their explanation.",
|
||||
"url": "/guide/glossary?utm_source=homescreen"
|
||||
},
|
||||
{
|
||||
"name": "Go to Resources",
|
||||
"short_name": "Resources",
|
||||
"description": "Go to the resources page: A list of Angular resouces, such as development tooling, UI libraries, books, courses, community publications, podcasts, etc.",
|
||||
"url": "/resources?utm_source=homescreen"
|
||||
},
|
||||
{
|
||||
"name": "Go to Tutorial: Tour of Heroes",
|
||||
"short_name": "Tutorial",
|
||||
"description": "Go to the \"Tour of Heroes\" tutorial page: Learn how to create your first Angular application.",
|
||||
"url": "/tutorial?utm_source=homescreen"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export class SitePage {
|
|||
|
||||
async navigateTo(pageUrl: string) {
|
||||
// Navigate to the page, disable animations, and wait for Angular.
|
||||
await browser.get(`/${pageUrl}`);
|
||||
await browser.get(`/${pageUrl.replace(/^\//, '')}`);
|
||||
await browser.executeScript('document.body.classList.add(\'no-animations\')');
|
||||
await browser.waitForAngular();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { PwaManifestPage, PwaShortcutItem } from './pwa-manifest.po';
|
||||
|
||||
|
||||
describe('PWA manifest', () => {
|
||||
const page = new PwaManifestPage();
|
||||
|
||||
describe('shortcuts', () => {
|
||||
let shortcuts: PwaShortcutItem[];
|
||||
|
||||
// Helpers
|
||||
const pageExists = async (url: string) => {
|
||||
await page.navigateTo(url);
|
||||
const content = await page.getDocViewerText();
|
||||
return !/page not found/i.test(content);
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
shortcuts = await page.getPwaShortcuts();
|
||||
});
|
||||
|
||||
it('should exist', async () => {
|
||||
for (const {short_name, url} of shortcuts) {
|
||||
expect(await pageExists(url)).toBe(
|
||||
true,
|
||||
`Page for shortcut '${short_name}' (from '${page.pwaManifestUrl}') does not exist. (URL: ${url})`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,74 @@
|
|||
import { get as httpGet } from 'http';
|
||||
import { get as httpsGet } from 'https';
|
||||
import { browser } from 'protractor';
|
||||
import { SitePage } from './app.po';
|
||||
|
||||
|
||||
export type Json = null | boolean | number | string | Json[] | { [key: string]: Json };
|
||||
|
||||
/**
|
||||
* The shape of a PWA manifest.
|
||||
* For simplicity, we only define types for the properties we care about in tests.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/Manifest
|
||||
*/
|
||||
export type PwaManifest = Json & {
|
||||
shortcuts?: PwaShortcutItem[],
|
||||
};
|
||||
|
||||
/**
|
||||
* The shape of an item in a PWA manifest's `shortcuts` list.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/Manifest/shortcuts
|
||||
*/
|
||||
export type PwaShortcutItem = Json & {
|
||||
url: string,
|
||||
name: string,
|
||||
short_name?: string,
|
||||
description?: string,
|
||||
icons?: PwaImageResource[],
|
||||
};
|
||||
|
||||
/**
|
||||
* The shape of an item in a PWA manifest's icons list (such as the value of the top-level `icons` property or that of
|
||||
* the `icons` property of a shortcut item).
|
||||
* @see https://w3c.github.io/manifest/#manifestimageresource-and-its-members
|
||||
*/
|
||||
export type PwaImageResource = Json & {
|
||||
src: string,
|
||||
sizes?: string,
|
||||
type?: string,
|
||||
purpose?: string,
|
||||
};
|
||||
|
||||
|
||||
export class PwaManifestPage extends SitePage {
|
||||
/** The base URL with the trailing `/` stripped off (if any). */
|
||||
baseUrl = browser.baseUrl.replace(/\/$/, '');
|
||||
|
||||
/** The URL to the app's PWA manifest. */
|
||||
pwaManifestUrl = `${this.baseUrl}/pwa-manifest.json`;
|
||||
|
||||
private pwaManifestText: string | null = null;
|
||||
|
||||
/** Get the app's PWA manifest as an object. */
|
||||
async getPwaManifest(): Promise<PwaManifest> {
|
||||
if (this.pwaManifestText === null) {
|
||||
const get = /^https:/.test(this.pwaManifestUrl) ? httpsGet : httpGet;
|
||||
|
||||
this.pwaManifestText = await new Promise<string>((resolve, reject) => {
|
||||
let responseText = '';
|
||||
get(this.pwaManifestUrl, res => res
|
||||
.on('data', chunk => responseText += chunk)
|
||||
.on('end', () => resolve(responseText))
|
||||
.on('error', reject));
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.parse(this.pwaManifestText);
|
||||
}
|
||||
|
||||
/** Get a list of PWA shortcuts as extracted from the app's PWA manifest. */
|
||||
async getPwaShortcuts(): Promise<PwaShortcutItem[]> {
|
||||
const {shortcuts = []} = await this.getPwaManifest();
|
||||
return shortcuts;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue