import parse from "node-html-parser";
import { CheckerMessage, CheckerStatus, FetchResponse, MessageId, WebAppManifestReport } from "./types";
import { checkWebAppManifest, checkWebAppManifestFile } from "./web-app-manifest";
import { testFetcher } from "./test-helper";
import { bufferToDataUrl, filePathToReadableStream, readableStreamToBuffer } from "./helper";
type TestOutput = {
messages: Pick[],
name?: string,
shortName?: string,
backgroundColor?: string,
themeColor?: string,
icon?: string | null
}
const filterOutput = (report: WebAppManifestReport): any => ({
...report,
messages: report.messages.map(m => ({ status: m.status, id: m.id }))
})
const runCheckTouchIconTitleTest = async (
headFragment: string | null,
output: TestOutput,
fetchDatabase: { [url: string]: FetchResponse } = {}
) => {
const root = headFragment ? parse(headFragment) : null;
const result = await checkWebAppManifest('https://example.com/', root, testFetcher(fetchDatabase));
expect(filterOutput(result)).toEqual({
name: undefined,
shortName: undefined,
backgroundColor: undefined,
themeColor: undefined,
icon: null,
...output,
});
}
test('checkWebAppManifest - noHead', async () => {
await runCheckTouchIconTitleTest(null, { messages: [{
status: CheckerStatus.Error,
id: MessageId.noHead,
}]});
})
test('checkWebAppManifest - noManifest', async () => {
await runCheckTouchIconTitleTest('Hey', { messages: [{
status: CheckerStatus.Error,
id: MessageId.noManifest,
}]});
})
test('checkWebAppManifest - noManifestHref', async () => {
await runCheckTouchIconTitleTest('', { messages: [{
status: CheckerStatus.Error,
id: MessageId.noManifestHref,
}]});
})
test('checkWebAppManifest - manifest404', async () => {
await runCheckTouchIconTitleTest('', { messages: [{
status: CheckerStatus.Error,
id: MessageId.manifest404,
}]});
})
test('checkWebAppManifest - manifestCannotGet', async () => {
await runCheckTouchIconTitleTest('', { messages: [{
status: CheckerStatus.Error,
id: MessageId.manifestCannotGet,
}]}, {
'https://example.com/error.json': {
status: 500,
contentType: 'application/json',
readableStream: null
}
});
})
test('checkWebAppManifest - manifestInvalidJson', async () => {
await runCheckTouchIconTitleTest('', { messages: [{
status: CheckerStatus.Error,
id: MessageId.manifestInvalidJson,
}]}, {
'https://example.com/bad-manifest.json': {
status: 200,
contentType: 'application/json',
readableStream: stringToReadableStream('{ bad JSON }')
}
});
})
const stringToReadableStream = (str: string) => {
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode(str));
controller.close();
}
});
return stream;
}
test('checkWebAppManifestFile - Missing fields', async () => {
const report = await checkWebAppManifestFile({
name: null,
short_name: null,
background_color: null,
theme_color: null,
icons: []
}, 'https://example.com/', testFetcher({}));
expect(filterOutput(report)).toEqual({
messages: [{
status: CheckerStatus.Error,
id: MessageId.noManifestName,
}, {
status: CheckerStatus.Error,
id: MessageId.noManifestShortName,
}, {
status: CheckerStatus.Error,
id: MessageId.noManifestBackgroundColor,
}, {
status: CheckerStatus.Error,
id: MessageId.noManifestThemeColor,
}, {
status: CheckerStatus.Error,
id: MessageId.noManifestIcons,
}],
name: undefined,
shortName: undefined,
backgroundColor: undefined,
themeColor: undefined,
icon: null
});
})
const testIcon192 = './fixtures/192x192.png';
const testIcon512 = './fixtures/512x512.png';
test('checkWebAppManifestFile - Everything is fine', async () => {
const report = await checkWebAppManifestFile({
name: 'My long name',
short_name: 'Short!',
background_color: '#123456',
theme_color: '#abcdef',
icons: [
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' }
]
}, 'https://example.com/', testFetcher({
'https://example.com/icon-192.png': {
status: 200,
contentType: 'image/png',
readableStream: await filePathToReadableStream(testIcon192)
},
'https://example.com/icon-512.png': {
status: 200,
contentType: 'image/png',
readableStream: await filePathToReadableStream(testIcon512)
}
}));
const expectedIconReport = [
{
status: CheckerStatus.Ok,
id: MessageId.manifestIconDeclared,
}, {
status: CheckerStatus.Ok,
id: MessageId.manifestIconDownloadable,
}, {
status: CheckerStatus.Ok,
id: MessageId.manifestIconRightSize,
}
];
expect(filterOutput(report)).toEqual({
messages: [{
status: CheckerStatus.Ok,
id: MessageId.manifestName,
}, {
status: CheckerStatus.Ok,
id: MessageId.manifestShortName,
}, {
status: CheckerStatus.Ok,
id: MessageId.manifestBackgroundColor,
}, {
status: CheckerStatus.Ok,
id: MessageId.manifestThemeColor,
},
...expectedIconReport, ...expectedIconReport], // Two icons
name: 'My long name',
shortName: 'Short!',
backgroundColor: '#123456',
themeColor: '#abcdef',
icon: {
content: bufferToDataUrl(await readableStreamToBuffer(await filePathToReadableStream(testIcon512)), 'image/png'),
url: "https://example.com/icon-512.png",
width: 512,
height: 512,
},
});
})