Skip to content

Commit

Permalink
tests(config): add unit tests from legacy config (#15209)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamraine committed Jun 28, 2023
1 parent d7e6f61 commit ac3b444
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 2 deletions.
116 changes: 114 additions & 2 deletions core/test/config/config-helpers-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,28 @@ describe('.resolveSettings', () => {
expect(settings).not.toHaveProperty('nonsense');
});

describe('sets UA string', () => {
it('to default value if provided value is undefined', () => {
const settings = resolveSettings({}, {emulatedUserAgent: undefined});
expect(settings.emulatedUserAgent).toMatch(/^Mozilla\/5.*moto.*Chrome/);
});

it('to default value if provided value is true', () => {
const settings = resolveSettings({}, {emulatedUserAgent: true});
expect(settings.emulatedUserAgent).toMatch(/^Mozilla\/5.*moto.*Chrome/);
});

it('to false if provided value is false', () => {
const settings = resolveSettings({}, {emulatedUserAgent: false});
expect(settings.emulatedUserAgent).toEqual(false);
});

it('to the provided string value if present', () => {
const settings = resolveSettings({}, {emulatedUserAgent: 'Random UA'});
expect(settings.emulatedUserAgent).toEqual('Random UA');
});
});

describe('budgets', () => {
it('initializes budgets', () => {
const settings = resolveSettings({
Expand Down Expand Up @@ -341,7 +363,7 @@ describe('.resolveSettings', () => {
describe('.resolveGathererToDefn', () => {
const coreList = Runner.getGathererList();

it('should expand gatherer path short-hand', async () => {
it('should expand core gatherer', async () => {
const result = await resolveGathererToDefn('image-elements', coreList);
expect(result).toEqual({
path: 'image-elements',
Expand All @@ -350,6 +372,15 @@ describe('.resolveGathererToDefn', () => {
});
});

it('should expand gatherer path short-hand', async () => {
const result = await resolveGathererToDefn({path: 'image-elements'}, coreList);
expect(result).toEqual({
path: 'image-elements',
implementation: ImageElementsGatherer,
instance: expect.any(ImageElementsGatherer),
});
});

it('should find relative to configDir', async () => {
const configDir = path.resolve(moduleDir, '../../gather/');
const result = await resolveGathererToDefn('gatherers/image-elements', [], configDir);
Expand All @@ -360,6 +391,19 @@ describe('.resolveGathererToDefn', () => {
});
});

it('should find custom gatherers', async () => {
const result1 =
await resolveGathererToDefn('../fixtures/valid-custom-gatherer', [], moduleDir);
const result2 =
await resolveGathererToDefn('../fixtures/valid-custom-gatherer.js', [], moduleDir);
const result3 =
await resolveGathererToDefn('../fixtures/valid-custom-gatherer.cjs', [], moduleDir);

expect(result1).toMatchObject({path: '../fixtures/valid-custom-gatherer'});
expect(result2).toMatchObject({path: '../fixtures/valid-custom-gatherer.js'});
expect(result3).toMatchObject({path: '../fixtures/valid-custom-gatherer.cjs'});
});

it('should expand gatherer impl short-hand', async () => {
const result = await resolveGathererToDefn({implementation: ImageElementsGatherer}, coreList);
expect(result).toEqual({
Expand All @@ -368,18 +412,60 @@ describe('.resolveGathererToDefn', () => {
});
});

it('should expand gatherer instance short-hand', async () => {
const result = await resolveGathererToDefn({instance: new ImageElementsGatherer()}, coreList);
expect(result).toEqual({
instance: expect.any(ImageElementsGatherer),
});
});

it('should expand gatherer instance directly', async () => {
const result = await resolveGathererToDefn(new ImageElementsGatherer(), coreList);
expect(result).toEqual({
instance: expect.any(ImageElementsGatherer),
});
});

it('throws for invalid gathererDefn', async () => {
await expect(resolveGathererToDefn({})).rejects.toThrow(/Invalid Gatherer type/);
});

it('throws for invalid path type', async () => {
await expect(resolveGathererToDefn({path: 1234})).rejects.toThrow(/Invalid Gatherer type/);
});

it('throws but not for missing gatherer when it has a node dependency error', async () => {
const resultPromise =
resolveGathererToDefn('../fixtures/invalid-gatherers/require-error.js', [], moduleDir);
await expect(resultPromise).rejects.toThrow(/Cannot find module/);
});
});

describe('.resolveAuditsToDefns', () => {
it('should expand audit short-hand', async () => {
it('should expand core audit', async () => {
const result = await resolveAuditsToDefns(['user-timings']);

expect(result).toEqual([{path: 'user-timings', options: {}, implementation: UserTimingsAudit}]);
});

it('should expand audit path short-hand', async () => {
const result = await resolveAuditsToDefns([{path: 'user-timings'}]);

expect(result).toEqual([{path: 'user-timings', options: {}, implementation: UserTimingsAudit}]);
});

it('should expand audit impl short-hand', async () => {
const result = await resolveAuditsToDefns([{implementation: UserTimingsAudit}]);

expect(result).toEqual([{options: {}, implementation: UserTimingsAudit}]);
});

it('should expand audit impl directly', async () => {
const result = await resolveAuditsToDefns([UserTimingsAudit]);

expect(result).toEqual([{options: {}, implementation: UserTimingsAudit}]);
});

it('should find relative to configDir', async () => {
const configDir = path.resolve(moduleDir, '../../');
const result = await resolveAuditsToDefns(['audits/user-timings'], configDir);
Expand All @@ -389,6 +475,19 @@ describe('.resolveAuditsToDefns', () => {
]);
});

it('should find custom audits', async () => {
const result = await resolveAuditsToDefns([
'../fixtures/valid-custom-audit',
'../fixtures/valid-custom-audit.js',
'../fixtures/valid-custom-audit.cjs',
], moduleDir);
expect(result).toMatchObject([
{path: '../fixtures/valid-custom-audit', options: {}},
{path: '../fixtures/valid-custom-audit.js', options: {}},
{path: '../fixtures/valid-custom-audit.cjs', options: {}},
]);
});

it('should handle multiple audit definition styles', async () => {
const result = await resolveAuditsToDefns(['user-timings', {implementation: UserTimingsAudit}]);

Expand All @@ -411,6 +510,13 @@ describe('.resolveAuditsToDefns', () => {
it('throws for invalid auditDefns', async () => {
await expect(resolveAuditsToDefns([new Gatherer()])).rejects.toThrow(/Invalid Audit type/);
});

it('throws but not for missing audit when it has a node dependency error', async () => {
const resultPromise = resolveAuditsToDefns([
'../fixtures/invalid-audits/require-error.js',
], moduleDir);
await expect(resultPromise).rejects.toThrow(/Cannot find module/);
});
});

describe('.resolveModulePath', () => {
Expand All @@ -426,6 +532,12 @@ describe('.resolveModulePath', () => {
expect(pathToPlugin).toEqual(require.resolve(pluginName));
});

it('throws for unknown resource', async () => {
expect(() => {
resolveModulePath('unknown', null, 'audit');
}).toThrow(/Unable to locate audit: `unknown`/);
});

describe('plugin paths to a file', () => {
it('relative to the current working directory', () => {
const pluginName = 'lighthouse-plugin-config-helper';
Expand Down
22 changes: 22 additions & 0 deletions core/test/config/config-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,22 @@ describe('Fraggle Rock Config', () => {
});
});

it('is idempotent when using the resolved config as the config input', async () => {
const config = {
extends: 'lighthouse:default',
settings: {
onlyCategories: ['seo'],
},
};

const {resolvedConfig} = await initializeConfig('navigation', config);
expect(Object.keys(resolvedConfig.categories || {})).toEqual(['seo']);
expect(resolvedConfig.settings.onlyCategories).toEqual(['seo']);

const {resolvedConfig: resolvedConfig2} = await initializeConfig('navigation', resolvedConfig);
expect(resolvedConfig2).toEqual(resolvedConfig);
});

describe('resolveArtifactDependencies', () => {
/** @type {LH.Gatherer.FRGathererInstance} */
let dependencyGatherer;
Expand Down Expand Up @@ -428,6 +444,12 @@ describe('Fraggle Rock Config', () => {
expect(resolvedConfig.categories.performance.auditRefs).toContain('extra-audit');
}
});

it('should only accept "lighthouse:default" as the extension method', async () => {
extensionConfig.extends = 'something:else';
const resolvedConfigPromise = initializeConfig('navigation', extensionConfig);
await expect(resolvedConfigPromise).rejects.toThrow(/`lighthouse:default` is the only valid/);
});
});

it('should use failure mode fatal for the fake navigation', async () => {
Expand Down
39 changes: 39 additions & 0 deletions core/test/config/filters-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ describe('Fraggle Rock Config Filtering', () => {
...auditMeta,
};
}
class OptionalAudit extends BaseAudit {
static meta = {
id: 'optional',
requiredArtifacts: /** @type {any} */ (['Snapshot']),
__internalOptionalArtifacts: /** @type {any} */ (['Timespan']),
...auditMeta,
};
}
class ManualAudit extends BaseAudit {
static meta = {
id: 'manual',
Expand Down Expand Up @@ -230,6 +238,16 @@ describe('Fraggle Rock Config Filtering', () => {
]);
});

it('should keep audits only missing optional artifacts', () => {
const partialArtifacts = [{id: 'Snapshot', gatherer: {instance: snapshotGatherer}}];
audits.push({implementation: OptionalAudit, options: {}});
expect(filters.filterAuditsByAvailableArtifacts(audits, partialArtifacts)).toEqual([
{implementation: SnapshotAudit, options: {}},
{implementation: ManualAudit, options: {}},
{implementation: OptionalAudit, options: {}},
]);
});

it('should not filter audits with dependencies on base artifacts', () => {
class SnapshotWithBase extends BaseAudit {
static meta = {
Expand Down Expand Up @@ -510,6 +528,27 @@ describe('Fraggle Rock Config Filtering', () => {
});
});

it('should combine category and audit filters additively', () => {
const filtered = filters.filterConfigByExplicitFilters(resolvedConfig, {
onlyCategories: ['navigation'],
onlyAudits: ['snapshot', 'timespan'],
skipAudits: [],
});
expect(filtered).toMatchObject({
artifacts: [{id: 'Snapshot'}, {id: 'Timespan'}],
audits: [
{implementation: SnapshotAudit},
{implementation: TimespanAudit},
{implementation: NavigationAudit},
],
categories: {
navigation: {
auditRefs: [{id: 'navigation'}],
},
},
});
});

it('should filter out audits and artifacts not in the categories by default', () => {
resolvedConfig = {
...resolvedConfig,
Expand Down
16 changes: 16 additions & 0 deletions core/test/config/validation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ describe('Fraggle Rock Config Validation', () => {
expect(invocation).toThrow(/has no audit.*method/);
});

it('should throw if audit id is missing', () => {
// @ts-expect-error - We are intentionally creating a malformed input.
ExampleAudit.meta.id = undefined;
const audit = {implementation: ExampleAudit, options: {}};
const invocation = () => validation.assertValidAudit(audit);
expect(invocation).toThrow(/has no meta.id/);
});

it('should throw if title is missing', () => {
// @ts-expect-error - We are intentionally creating a malformed input.
ExampleAudit.meta.title = undefined;
Expand All @@ -153,6 +161,14 @@ describe('Fraggle Rock Config Validation', () => {
expect(invocation).toThrow(/has no meta.title/);
});

it('should throw if audit description is missing', () => {
// @ts-expect-error - We are intentionally creating a malformed input.
ExampleAudit.meta.description = undefined;
const audit = {implementation: ExampleAudit, options: {}};
const invocation = () => validation.assertValidAudit(audit);
expect(invocation).toThrow(/has no meta.description/);
});

it('should throw if failureTitle is missing', () => {
ExampleAudit.meta.failureTitle = undefined;
ExampleAudit.meta.scoreDisplayMode = BaseAudit.SCORING_MODES.BINARY;
Expand Down

0 comments on commit ac3b444

Please sign in to comment.