blob: 25c1f2131a192f9e2ba0dc590069c77b17d5321e [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {assert} from 'chai';
import {describe, it} from 'mocha';
import sinon from 'sinon';
import type * as SDK from '../../core/sdk/sdk.js';
import * as Protocol from '../../generated/protocol.js';
import {MockIssuesModel} from '../../testing/MockIssuesModel.js';
import * as IssuesManager from './issues_manager.js';
describe('WebInstallIssue', () => {
const mockModel = new MockIssuesModel([]) as unknown as SDK.IssuesModel.IssuesModel;
const manifestUrl = 'https://example.com/manifest.json';
for (const [reason, descriptionFile] of [
[
Protocol.Audits.WebInstallIssueReason.ManifestParsingOrNetworkError,
'webInstallManifestParsingOrNetworkError.md',
],
[Protocol.Audits.WebInstallIssueReason.StartUrlInvalid, 'webInstallStartUrlInvalid.md'],
[
Protocol.Audits.WebInstallIssueReason.ManifestMissingNameOrShortName,
'webInstallManifestMissingNameOrShortName.md',
],
[Protocol.Audits.WebInstallIssueReason.ManifestMissingId, 'webInstallManifestMissingId.md'],
] as const) {
it(`creates an issue for ${reason}`, () => {
const inspectorIssue: Protocol.Audits.InspectorIssue = {
code: Protocol.Audits.InspectorIssueCode.WebInstallIssue,
details: {webInstallIssueDetails: {manifestUrl, reason}},
};
const issues = IssuesManager.WebInstallIssue.WebInstallIssue.fromInspectorIssue(mockModel, inspectorIssue);
assert.lengthOf(issues, 1);
assert.strictEqual(issues[0].getCategory(), IssuesManager.Issue.IssueCategory.OTHER);
assert.strictEqual(issues[0].getKind(), IssuesManager.Issue.IssueKind.PAGE_ERROR);
const description = issues[0].getDescription();
assert.exists(description);
assert.strictEqual(description.file, descriptionFile);
assert.deepEqual(issues[0].requests(), [{url: manifestUrl}]);
});
}
it('creates a no-manifest issue without an affected request', () => {
const inspectorIssue: Protocol.Audits.InspectorIssue = {
code: Protocol.Audits.InspectorIssueCode.WebInstallIssue,
details: {
webInstallIssueDetails: {
reason: Protocol.Audits.WebInstallIssueReason.NoManifest,
},
},
};
const issues = IssuesManager.WebInstallIssue.WebInstallIssue.fromInspectorIssue(mockModel, inspectorIssue);
assert.lengthOf(issues, 1);
assert.strictEqual(issues[0].getDescription()?.file, 'webInstallNoManifest.md');
assert.deepEqual(issues[0].requests(), []);
assert.strictEqual(issues[0].primaryKey(),
JSON.stringify({reason: Protocol.Audits.WebInstallIssueReason.NoManifest}));
});
it('rejects an issue without details', () => {
const inspectorIssue: Protocol.Audits.InspectorIssue = {
code: Protocol.Audits.InspectorIssueCode.WebInstallIssue,
details: {},
};
assert.deepEqual(IssuesManager.WebInstallIssue.WebInstallIssue.fromInspectorIssue(mockModel, inspectorIssue), []);
});
it('rejects an issue with an unknown reason', () => {
const consoleWarn = sinon.stub(console, 'warn');
const inspectorIssue: Protocol.Audits.InspectorIssue = {
code: Protocol.Audits.InspectorIssueCode.WebInstallIssue,
details: {
webInstallIssueDetails: {
manifestUrl,
reason: 'UnknownReason' as Protocol.Audits.WebInstallIssueReason,
},
},
};
const issues = IssuesManager.WebInstallIssue.WebInstallIssue.fromInspectorIssue(mockModel, inspectorIssue);
assert.lengthOf(issues, 1);
assert.isNull(issues[0].getDescription());
sinon.assert.calledOnceWithExactly(consoleWarn, 'Unknown WebInstallIssueReason:', 'UnknownReason');
});
});