From f50e93357c10f505eeb60535f1df5493b8739a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C4=83t=C4=83lin=20Mari=C8=99?= Date: Mon, 6 Aug 2018 10:41:24 -0700 Subject: [PATCH] Breaking: Normalize error messages Fix #1170 Fix #1133 Close #1208 --- .../src/templates/partial-event-code.hbs | 4 +- .../create-hint/tests/fixtures/new-quotes.txt | 12 +-- packages/create-hint/tests/fixtures/new.txt | 12 +-- .../tests/fixtures/new-quotes.txt | 12 +-- packages/create-parser/tests/fixtures/new.txt | 12 +-- packages/hint-amp-validator/src/hint.ts | 10 +- packages/hint-apple-touch-icons/src/hint.ts | 31 +++--- .../hint-apple-touch-icons/tests/tests.ts | 61 +++++++---- packages/hint-axe/src/hint.ts | 2 +- packages/hint-content-type/src/hint.ts | 18 ++-- packages/hint-content-type/tests/tests.ts | 81 +++++++------- packages/hint-disown-opener/src/hint.ts | 3 +- packages/hint-disown-opener/tests/tests.ts | 3 +- .../src/hint.ts | 101 ++++++++++-------- .../tests/tests.ts | 94 +++++++++------- packages/hint-html-checker/src/hint.ts | 2 +- packages/hint-html-checker/tests/tests.ts | 2 +- packages/hint-http-compression/src/hint.ts | 20 ++-- .../hint-http-compression/tests/_tests.ts | 18 ++-- packages/hint-https-only/src/hint.ts | 14 ++- packages/hint-https-only/tests/tests-https.ts | 18 ++-- packages/hint-https-only/tests/tests.ts | 2 +- .../src/hint.ts | 6 +- .../tests/tests.ts | 6 +- packages/hint-manifest-app-name/src/hint.ts | 6 +- .../hint-manifest-app-name/tests/tests.ts | 10 +- packages/hint-manifest-exists/src/hint.ts | 6 +- packages/hint-manifest-exists/tests/tests.ts | 22 ++-- .../hint-manifest-file-extension/src/hint.ts | 2 +- .../tests/tests.ts | 4 +- packages/hint-manifest-is-valid/src/hint.ts | 8 +- .../hint-manifest-is-valid/tests/tests.ts | 20 ++-- packages/hint-meta-charset-utf-8/src/hint.ts | 48 ++++----- .../hint-meta-charset-utf-8/tests/tests.ts | 45 ++++---- packages/hint-meta-theme-color/src/hint.ts | 32 +++--- packages/hint-meta-theme-color/tests/tests.ts | 43 ++++---- packages/hint-meta-viewport/src/hint.ts | 70 ++++++------ packages/hint-meta-viewport/tests/tests.ts | 64 ++++++----- packages/hint-minified-js/src/hint.ts | 2 +- .../tests/{minified-js.ts => tests.ts} | 17 +-- packages/hint-no-bom/src/hint.ts | 9 +- packages/hint-no-bom/tests/tests.ts | 4 +- packages/hint-no-broken-links/src/hint.ts | 6 +- .../tests/{no-broken-links.ts => tests.ts} | 30 +++--- .../hint-no-disallowed-headers/src/hint.ts | 16 +-- .../hint-no-disallowed-headers/tests/tests.ts | 19 ++-- .../hint-no-friendly-error-pages/src/hint.ts | 2 +- .../tests/tests.ts | 8 +- .../hint-no-html-only-headers/src/hint.ts | 12 ++- .../hint-no-html-only-headers/tests/tests.ts | 3 +- packages/hint-no-http-redirects/src/hint.ts | 2 +- .../hint-no-http-redirects/tests/tests.ts | 8 +- packages/hint-no-p3p/src/hint.ts | 3 +- packages/hint-no-p3p/tests/tests.ts | 2 +- .../src/hint.ts | 2 +- .../tests/tests.ts | 10 +- .../src/hint.ts | 4 +- .../tests/tests.ts | 10 +- packages/hint-performance-budget/src/hint.ts | 3 +- .../tests/tests-http.ts | 20 +--- .../tests/tests-https.ts | 20 +--- packages/hint-ssllabs/src/hint.ts | 8 +- packages/hint-ssllabs/tests/tests.ts | 10 +- .../hint-x-content-type-options/src/hint.ts | 6 +- .../tests/tests.ts | 39 ++++--- .../src/lib/utils/misc/pretty-print-array.ts | 33 ++++++ packages/parser-manifest/src/parser.ts | 4 +- 67 files changed, 693 insertions(+), 543 deletions(-) rename packages/hint-minified-js/tests/{minified-js.ts => tests.ts} (96%) rename packages/hint-no-broken-links/tests/{no-broken-links.ts => tests.ts} (82%) create mode 100644 packages/hint/src/lib/utils/misc/pretty-print-array.ts diff --git a/packages/create-hint/src/templates/partial-event-code.hbs b/packages/create-hint/src/templates/partial-event-code.hbs index 9b4d968e0b5..82ee51c57ab 100644 --- a/packages/create-hint/src/templates/partial-event-code.hbs +++ b/packages/create-hint/src/templates/partial-event-code.hbs @@ -5,12 +5,12 @@ debug(`Validating hint {{name}}`); /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } diff --git a/packages/create-hint/tests/fixtures/new-quotes.txt b/packages/create-hint/tests/fixtures/new-quotes.txt index 9bb85ff8359..4234bd9b619 100644 --- a/packages/create-hint/tests/fixtures/new-quotes.txt +++ b/packages/create-hint/tests/fixtures/new-quotes.txt @@ -49,14 +49,14 @@ export default class NewHint implements IHint { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchEnd = async (fetchEnd: FetchEnd) => { @@ -69,14 +69,14 @@ export default class NewHint implements IHint { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchError = async (fetchError: FetchError) => { @@ -89,14 +89,14 @@ export default class NewHint implements IHint { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; diff --git a/packages/create-hint/tests/fixtures/new.txt b/packages/create-hint/tests/fixtures/new.txt index 9f5f007dd9f..a2b2dbe45cc 100644 --- a/packages/create-hint/tests/fixtures/new.txt +++ b/packages/create-hint/tests/fixtures/new.txt @@ -30,14 +30,14 @@ const hint: IHintBuilder = { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchEnd = async (fetchEnd: FetchEnd) => { @@ -50,14 +50,14 @@ const hint: IHintBuilder = { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchError = async (fetchError: FetchError) => { @@ -70,14 +70,14 @@ const hint: IHintBuilder = { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; diff --git a/packages/create-parser/tests/fixtures/new-quotes.txt b/packages/create-parser/tests/fixtures/new-quotes.txt index 57b82675fdc..f19cefcd0e6 100644 --- a/packages/create-parser/tests/fixtures/new-quotes.txt +++ b/packages/create-parser/tests/fixtures/new-quotes.txt @@ -49,14 +49,14 @@ export default class NewHint implements IHint { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchEnd = async (fetchEnd: FetchEnd) => { @@ -69,14 +69,14 @@ export default class NewHint implements IHint { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchError = async (fetchError: FetchError) => { @@ -89,14 +89,14 @@ export default class NewHint implements IHint { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; diff --git a/packages/create-parser/tests/fixtures/new.txt b/packages/create-parser/tests/fixtures/new.txt index 9f5f007dd9f..a2b2dbe45cc 100644 --- a/packages/create-parser/tests/fixtures/new.txt +++ b/packages/create-parser/tests/fixtures/new.txt @@ -30,14 +30,14 @@ const hint: IHintBuilder = { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchEnd = async (fetchEnd: FetchEnd) => { @@ -50,14 +50,14 @@ const hint: IHintBuilder = { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; const validateFetchError = async (fetchError: FetchError) => { @@ -70,14 +70,14 @@ const hint: IHintBuilder = { /* * This is where all the magic happens. Any errors found should be * reported using the `context` object. E.g.: - * await context.report(resource, null, 'Your error message was here'); + * await context.report(resource, null, 'Add error message here.'); * * More information on how to develop a hint is available in: * https://webhint.io/docs/contributor-guide/hints/ */ if (Math.ceil(Math.random()) === 0) { - await context.report(resource, null, 'Your error message here'); + await context.report(resource, null, 'Add error message here.'); } }; diff --git a/packages/hint-amp-validator/src/hint.ts b/packages/hint-amp-validator/src/hint.ts index 25712a4a2d4..f0ef50083e6 100644 --- a/packages/hint-amp-validator/src/hint.ts +++ b/packages/hint-amp-validator/src/hint.ts @@ -45,7 +45,10 @@ export default class AmpValidatorHint implements IHint { return; } - // events has to be an array in order to work with the local connector. + /* + * `events` has to be an array in order + * to work with the local connector. + */ events.push(fetchEnd); validPromise = amphtmlValidator.getInstance(); }; @@ -70,7 +73,10 @@ export default class AmpValidatorHint implements IHint { message += ` (${error.specUrl})`; } - // We ignore errors that are not 'ERROR' if user has configured the hint like that + /* + * We ignore errors that are not 'ERROR' + * if user has configured the hint like that. + */ if (errorsOnly && error.severity !== 'ERROR') { debug(`AMP error doesn't meet threshold for reporting`); } else { diff --git a/packages/hint-apple-touch-icons/src/hint.ts b/packages/hint-apple-touch-icons/src/hint.ts index 7a7306ed81d..f590adb467d 100644 --- a/packages/hint-apple-touch-icons/src/hint.ts +++ b/packages/hint-apple-touch-icons/src/hint.ts @@ -84,13 +84,14 @@ export default class AppleTouchIconsHint implements IHint { */ if (!appleTouchIconHref) { - await context.report(resource, appleTouchIcon, `'apple-touch-icon' should have non-empty 'href' attribute`); + await context.report(resource, appleTouchIcon, `'apple-touch-icon' link element should have non-empty 'href' attribute.`); return; } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * The following checks don't make sense for non-HTTP(S). */ @@ -120,7 +121,7 @@ export default class AppleTouchIconsHint implements IHint { networkData = await context.fetchContent(appleTouchIconURL); } catch (e) { debug(`Failed to fetch the ${appleTouchIconHref} file`); - await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' file request failed`); + await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' could not be fetched (request failed).`); return; } @@ -128,7 +129,7 @@ export default class AppleTouchIconsHint implements IHint { const response = networkData.response; if (response.statusCode !== 200) { - await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' could not be fetched (status code: ${response.statusCode})`); + await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' could not be fetched (status code: ${response.statusCode}).`); return; } @@ -154,7 +155,7 @@ export default class AppleTouchIconsHint implements IHint { image = getImageData(response.body.rawContent); } catch (e) { if (e instanceof TypeError) { - await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' is not a valid PNG`); + await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' should be a valid PNG image.`); } else { debug(`'getImageData' failed for '${appleTouchIconURL}'`); } @@ -165,13 +166,13 @@ export default class AppleTouchIconsHint implements IHint { // Check if the image is a PNG. if (image.type !== 'png') { - await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' is not a PNG`); + await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' should be a PNG image.`); } // Check if the image is 180x180px. if (image.width !== 180 || image.height !== 180) { - await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' is not 180x180px`); + await context.report(resource, appleTouchIcon, `'${appleTouchIconHref}' should be 180x180px.`); } // TODO: Check if the image has some kind of transparency. @@ -218,13 +219,12 @@ export default class AppleTouchIconsHint implements IHint { const appleTouchIcons: Array = getAppleTouchIcons(await pageDOM.querySelectorAll('link')); if (appleTouchIcons.length === 0) { - await context.report(resource, null, `No 'apple-touch-icon' was specified`); + await context.report(resource, null, `'apple-touch-icon' link element was not specified.`); return; } /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Choose the icon that will most likely * pass most of the following tests. */ @@ -232,17 +232,15 @@ export default class AppleTouchIconsHint implements IHint { const appleTouchIcon: IAsyncHTMLElement = chooseBestIcon(appleTouchIcons); /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Check if `rel='apple-touch-icon'`. * See `getAppleTouchIcons` function for more details. */ if (normalizeString(appleTouchIcon.getAttribute('rel')) !== 'apple-touch-icon') { - await context.report(resource, appleTouchIcon, `'rel' attribute value should be 'apple-touch-icon'`); + await context.report(resource, appleTouchIcon, `'apple-touch-icon' link element should have 'rel="apple-touch-icon".`); } /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Since we are recommending one icon, the `sizes` attribute * is not needed. Also, pre-4.2 versions of iOS ignore the * `sizes` attribute. @@ -252,11 +250,10 @@ export default class AppleTouchIconsHint implements IHint { */ if (appleTouchIcon.getAttribute('sizes')) { - await context.report(resource, appleTouchIcon, `'sizes' attribute is not needed`); + await context.report(resource, appleTouchIcon, `'apple-touch-icon' link element should not have 'sizes' attribute.`); } /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Check if the `apple-touch-icon` exists, is the right * image format, the right size, etc. */ @@ -264,7 +261,6 @@ export default class AppleTouchIconsHint implements IHint { await checkImage(appleTouchIcon, resource); /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Check if the `apple-touch-icon` is included in the ``. */ @@ -272,18 +268,17 @@ export default class AppleTouchIconsHint implements IHint { for (const icon of bodyAppleTouchIcons) { if (icon.isSame(appleTouchIcon)) { - await context.report(resource, appleTouchIcon, `'apple-touch-icon' should be specified in the ''`); + await context.report(resource, appleTouchIcon, `'apple-touch-icon' link element should be specified in the ''.`); } } /* - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * All other `apple-touch-icon`s should not be included. */ for (const icon of appleTouchIcons) { if (!icon.isSame(appleTouchIcon)) { - await context.report(resource, icon, `A 'apple-touch-icon' was already specified`); + await context.report(resource, icon, `'apple-touch-icon' link element is not needed as one was already specified.`); } } }; diff --git a/packages/hint-apple-touch-icons/tests/tests.ts b/packages/hint-apple-touch-icons/tests/tests.ts index 12fe26b2542..c44ff73f547 100644 --- a/packages/hint-apple-touch-icons/tests/tests.ts +++ b/packages/hint-apple-touch-icons/tests/tests.ts @@ -5,14 +5,31 @@ import { getHintPath } from 'hint/dist/src/lib/utils/hint-helpers'; import { HintTest } from '@hint/utils-tests-helpers/dist/src/hint-test-type'; import * as hintRunner from '@hint/utils-tests-helpers/dist/src/hint-runner'; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + const hintPath = getHintPath(__filename); +// Images + +const appleTouchIconLinkTag = ''; const defaultImage = fs.readFileSync(`${__dirname}/fixtures/apple-touch-icon.png`); // eslint-disable-line no-sync -const imageWithIncorrectDimensions = fs.readFileSync(`${__dirname}/fixtures/incorrect-dimensions.png`); // eslint-disable-line no-sync const imageThatIsNotSquare = fs.readFileSync(`${__dirname}/fixtures/not-square.png`); // eslint-disable-line no-sync +const imageWithIncorrectDimensions = fs.readFileSync(`${__dirname}/fixtures/incorrect-dimensions.png`); // eslint-disable-line no-sync const imageWithIncorrectFileFormat = fs.readFileSync(`${__dirname}/fixtures/incorrect-file-format.png`); // eslint-disable-line no-sync -// const imageWithTransparentBackground = fs.readFileSync(`${__dirname}/fixtures/transparent-background.png`); // eslint-disable-line no-sync -const appleTouchIconLinkTag = ''; + +// Error messages + +const elementAlreadySpecifiedErrorMessage = `'apple-touch-icon' link element is not needed as one was already specified.`; +const elementHasEmptyHrefAttributeErrorMessage = `'apple-touch-icon' link element should have non-empty 'href' attribute.`; +const elementHasIncorrectRelAttributeErrorMessage = `'apple-touch-icon' link element should have 'rel="apple-touch-icon".`; +const elementHasUnneededSizesAttributeErrorMessage = `'apple-touch-icon' link element should not have 'sizes' attribute.`; +const elementNotSpecifiedErrorMessage = `'apple-touch-icon' link element was not specified.`; +const elementNotSpecifiedInHeadErrorMessage = `'apple-touch-icon' link element should be specified in the ''.`; +const fileCouldNotBeFetchedErrorMessage = `'/apple-touch-icon.png' could not be fetched (status code: 404).`; +const fileHasIncorrectSizeErrorMessage =`'/apple-touch-icon.png' should be 180x180px.`; +const fileIsInvalidPNGErrorMessage = `'/apple-touch-icon.png' should be a valid PNG image.`; +const fileIsNotPNGErrorMessage = `'/apple-touch-icon.png' should be a PNG image.`; +const fileRequestFailedErrorMessage = `'/apple-touch-icon.png' could not be fetched (request failed).`; const generateImageData = (content: Buffer = defaultImage): Object => { return { @@ -21,6 +38,8 @@ const generateImageData = (content: Buffer = defaultImage): Object => { }; }; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + const tests: Array = [ { name: `Resource is not an HTML document`, @@ -28,12 +47,12 @@ const tests: Array = [ }, { name: `'apple-touch-icon' is not specified`, - reports: [{ message: `No 'apple-touch-icon' was specified` }], + reports: [{ message: elementNotSpecifiedErrorMessage }], serverConfig: generateHTMLPage('') }, { name: `'apple-touch-icon' has 'rel="apple-touch-icon-precomposed"`, - reports: [{ message: `'rel' attribute value should be 'apple-touch-icon'` }], + reports: [{ message: elementHasIncorrectRelAttributeErrorMessage }], serverConfig: { '/': generateHTMLPage(''), '/apple-touch-icon-precomposed.png': generateImageData() @@ -41,7 +60,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' has 'rel="apple-touch-icon-precomposed apple-touch-icon"`, - reports: [{ message: `'rel' attribute value should be 'apple-touch-icon'` }], + reports: [{ message: elementHasIncorrectRelAttributeErrorMessage }], serverConfig: { '/': generateHTMLPage(''), '/apple-touch-icon-precomposed.png': generateImageData() @@ -49,17 +68,17 @@ const tests: Array = [ }, { name: `'apple-touch-icon' has no 'href' attribute`, - reports: [{ message: `'apple-touch-icon' should have non-empty 'href' attribute` }], + reports: [{ message: elementHasEmptyHrefAttributeErrorMessage }], serverConfig: generateHTMLPage('') }, { name: `'apple-touch-icon' has 'href' attribute with no value`, - reports: [{ message: `'apple-touch-icon' should have non-empty 'href' attribute` }], + reports: [{ message: elementHasEmptyHrefAttributeErrorMessage }], serverConfig: generateHTMLPage('') }, { name: `'apple-touch-icon' has 'href' attribute with the value of empty string`, - reports: [{ message: `'apple-touch-icon' should have non-empty 'href' attribute` }], + reports: [{ message: elementHasEmptyHrefAttributeErrorMessage }], serverConfig: generateHTMLPage('') }, { @@ -71,7 +90,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' has 'sizes' attribute`, - reports: [{ message: `'sizes' attribute is not needed` }], + reports: [{ message: elementHasUnneededSizesAttributeErrorMessage }], serverConfig: { '/': generateHTMLPage(''), '/apple-touch-icon.png': generateImageData() @@ -79,7 +98,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' is not PNG`, - reports: [{ message: `'/apple-touch-icon.png' is not a PNG` }], + reports: [{ message: fileIsNotPNGErrorMessage }], serverConfig: { '/': generateHTMLPage(appleTouchIconLinkTag), '/apple-touch-icon.png': generateImageData(imageWithIncorrectFileFormat) @@ -87,7 +106,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' is not an image`, - reports: [{ message: `'/apple-touch-icon.png' is not a valid PNG` }], + reports: [{ message: fileIsInvalidPNGErrorMessage }], serverConfig: { '/': generateHTMLPage(appleTouchIconLinkTag), '/apple-touch-icon.png': generateHTMLPage() @@ -95,7 +114,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' is not 180x180px`, - reports: [{ message: `'/apple-touch-icon.png' is not 180x180px` }], + reports: [{ message: fileHasIncorrectSizeErrorMessage }], serverConfig: { '/': generateHTMLPage(appleTouchIconLinkTag), '/apple-touch-icon.png': generateImageData(imageWithIncorrectDimensions) @@ -103,7 +122,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' is not 180x180px and it's also not square`, - reports: [{ message: `'/apple-touch-icon.png' is not 180x180px` }], + reports: [{ message: fileHasIncorrectSizeErrorMessage }], serverConfig: { '/': generateHTMLPage(appleTouchIconLinkTag), '/apple-touch-icon.png': generateImageData(imageThatIsNotSquare) @@ -111,7 +130,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' could not be fetched`, - reports: [{ message: `'/apple-touch-icon.png' could not be fetched (status code: 404)` }], + reports: [{ message: fileCouldNotBeFetchedErrorMessage }], serverConfig: { '/': generateHTMLPage(appleTouchIconLinkTag), '/apple-touch-icon.png': { status: 404 } @@ -119,7 +138,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' file request failed`, - reports: [{ message: `'/apple-touch-icon.png' file request failed` }], + reports: [{ message: fileRequestFailedErrorMessage }], serverConfig: { '/': generateHTMLPage(appleTouchIconLinkTag), '/apple-touch-icon.png': null @@ -127,7 +146,7 @@ const tests: Array = [ }, { name: `'apple-touch-icon' is specified in the ''`, - reports: [{ message: `'apple-touch-icon' should be specified in the ''` }], + reports: [{ message: elementNotSpecifiedInHeadErrorMessage }], serverConfig: { '/': generateHTMLPage(null, appleTouchIconLinkTag), '/apple-touch-icon.png': generateImageData() @@ -136,9 +155,9 @@ const tests: Array = [ { name: `Multiple 'apple-touch-icon's are specified`, reports: [ - { message: `'sizes' attribute is not needed` }, - { message: `A 'apple-touch-icon' was already specified` }, - { message: `A 'apple-touch-icon' was already specified` } + { message: elementHasUnneededSizesAttributeErrorMessage }, + { message: elementAlreadySpecifiedErrorMessage }, + { message: elementAlreadySpecifiedErrorMessage } ], serverConfig: { '/': generateHTMLPage(` @@ -151,7 +170,7 @@ const tests: Array = [ }, { name: `Multiple 'apple-touch-icon's are specified (different usage)`, - reports: [{ message: `A 'apple-touch-icon' was already specified` }], + reports: [{ message: elementAlreadySpecifiedErrorMessage }], serverConfig: { '/': generateHTMLPage(` diff --git a/packages/hint-axe/src/hint.ts b/packages/hint-axe/src/hint.ts index b4d7798bba8..4985164bfc0 100644 --- a/packages/hint-axe/src/hint.ts +++ b/packages/hint-axe/src/hint.ts @@ -117,7 +117,7 @@ export default class AxeHint implements IHint { try { result = await context.evaluate(script); } catch (e) { - await context.report(resource, null, `Error executing script: "${e.message}". Please try with another connector`, null, null, Severity.warning); + await context.report(resource, null, `Error executing script: '${e.message}'. Please try with another connector.`, null, null, Severity.warning); debug('Error executing script %O', e); return; diff --git a/packages/hint-content-type/src/hint.ts b/packages/hint-content-type/src/hint.ts index 162cfb58be6..c151df64ea6 100644 --- a/packages/hint-content-type/src/hint.ts +++ b/packages/hint-content-type/src/hint.ts @@ -80,7 +80,7 @@ export default class ContentTypeHint implements IHint { // Check if the `Content-Type` header was sent. if (contentTypeHeaderValue === null) { - await context.report(resource, element, `'content-type' header was not specified`); + await context.report(resource, element, `Response should include 'content-type' header.`); return; } @@ -94,7 +94,7 @@ export default class ContentTypeHint implements IHint { if (userDefinedMediaType) { if (normalizeString(userDefinedMediaType) !== contentTypeHeaderValue) { - await context.report(resource, element, `'content-type' header should have the value '${userDefinedMediaType}'`); + await context.report(resource, element, `'content-type' header value should be '${userDefinedMediaType}'.`); } return; @@ -111,7 +111,7 @@ export default class ContentTypeHint implements IHint { contentType = parse(contentTypeHeaderValue); } catch (e) { - await context.report(resource, element, `'content-type' header value is invalid (${e.message})`); + await context.report(resource, element, `'content-type' header value should be valid (${e.message}).`); return; } @@ -140,17 +140,21 @@ export default class ContentTypeHint implements IHint { // * media type if (mediaType && (mediaType !== originalMediaType)) { - await context.report(resource, element, `'content-type' header should have media type '${mediaType}' (not '${originalMediaType}')`); + await context.report(resource, element, `'content-type' header media type value should be '${mediaType}', not '${originalMediaType}'.`); } // * charset value if (charset) { if (!originalCharset || (charset !== originalCharset)) { - await context.report(resource, element, `'content-type' header should have 'charset=${charset}'${originalCharset ? ` (not '${originalCharset}')` : ''}`); + await context.report(resource, element, `'content-type' header charset value should be '${charset}'${originalCharset ? `, not '${originalCharset}'` : ''}.`); } - } else if (originalCharset && !['text/html', 'application/xhtml+xml'].includes(originalMediaType)) { - await context.report(resource, element, `'content-type' header should not have 'charset=${originalCharset}'`); + } else if (originalCharset && + ![ + 'text/html', + 'application/xhtml+xml' + ].includes(originalMediaType)) { + await context.report(resource, element, `'content-type' header value should not contain 'charset=${originalCharset}'.`); } }; diff --git a/packages/hint-content-type/tests/tests.ts b/packages/hint-content-type/tests/tests.ts index 07192440b4f..817b853d7fe 100644 --- a/packages/hint-content-type/tests/tests.ts +++ b/packages/hint-content-type/tests/tests.ts @@ -7,25 +7,26 @@ import { getHintPath } from 'hint/dist/src/lib/utils/hint-helpers'; import { HintTest } from '@hint/utils-tests-helpers/dist/src/hint-test-type'; import * as hintRunner from '@hint/utils-tests-helpers/dist/src/hint-runner'; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + const hintPath = getHintPath(__filename); -const pngFileContent = fs.readFileSync(`${__dirname}/fixtures/image.png`); // eslint-disable-line no-sync -const svgFileContent = ''; -// const woff2FileContent = fs.readFileSync(`${__dirname}/fixtures/test.woff2`); +const pngImage = fs.readFileSync(`${__dirname}/fixtures/image.png`); // eslint-disable-line no-sync +const svgImage = ''; -const incorrectCharsetMessage = `'content-type' header should have 'charset=utf-8' (not 'iso-8859-1')`; -const invalidMediaTypeMessage = `'content-type' header value is invalid (invalid media type)`; -const invalidParameterFormatMessage = `'content-type' header value is invalid (invalid parameter format)`; -const noCharsetMessage = `'content-type' header should have 'charset=utf-8'`; -const noHeaderMessage = `'content-type' header was not specified`; -const unneededCharsetMessage = `'content-type' header should not have 'charset=utf-8'`; +const incorrectCharsetErrorMessage = `'content-type' header charset value should be 'utf-8', not 'iso-8859-1'.`; +const invalidMediaTypeErrorMessage = `'content-type' header value should be valid (invalid media type).`; +const invalidParameterFormatErrorMessage = `'content-type' header value should be valid (invalid parameter format).`; +const noCharsetErrorMessage = `'content-type' header charset value should be 'utf-8'.`; +const noHeaderErrorMessage = `Response should include 'content-type' header.`; +const unneededCharsetErrorMessage = `'content-type' header value should not contain 'charset=utf-8'.`; -const generateIncorrectMediaTypeMessage = (expectedType: string, actualType: string) => { - return `'content-type' header should have media type '${expectedType}' (not '${actualType}')`; +const generateIncorrectMediaTypeErrorMessage = (expectedType: string, actualType: string) => { + return `'content-type' header media type value should be '${expectedType}', not '${actualType}'.`; }; -const generateRequireValueMessage = (expectedValue: string) => { - return `'content-type' header should have the value '${expectedValue}'`; +const generateRequireValueErrorMessage = (expectedValue: string) => { + return `'content-type' header value should be '${expectedValue}'.`; }; const generateHTMLPageData = (content: string) => { @@ -35,18 +36,20 @@ const generateHTMLPageData = (content: string) => { }; }; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + const testsForDefaults: Array = [ // No `Content-Type` header. { name: `HTML page is served without 'Content-Type' header`, - reports: [{ message: noHeaderMessage }], + reports: [{ message: noHeaderErrorMessage }], serverConfig: { '/': { headers: { 'Content-Type': null } } } }, { name: `Resource is served without 'Content-Type' header`, - reports: [{ message: noHeaderMessage }], + reports: [{ message: noHeaderErrorMessage }], serverConfig: { '/': generateHTMLPageData(generateHTMLPage('')), '/test.css': { headers: { 'Content-Type': null } } @@ -61,12 +64,12 @@ const testsForDefaults: Array = [ { name: `HTML page is served with 'Content-Type' header with invalid media type`, - reports: [{ message: invalidMediaTypeMessage }], + reports: [{ message: invalidMediaTypeErrorMessage }], serverConfig: { '/': { headers: { 'Content-Type': 'invalid' } } } }, { name: `Resource is served with 'Content-Type' header with invalid media type (empty media type)`, - reports: [{ message: invalidMediaTypeMessage }], + reports: [{ message: invalidMediaTypeErrorMessage }], serverConfig: { '/': generateHTMLPageData(generateHTMLPage(undefined, '')), '/test.png': { headers: { 'Content-Type': '' } } @@ -77,12 +80,12 @@ const testsForDefaults: Array = [ { name: `HTML page is served with 'Content-Type' header with an invalid parameter format`, - reports: [{ message: invalidParameterFormatMessage }], + reports: [{ message: invalidParameterFormatErrorMessage }], serverConfig: { '/': { headers: { 'Content-Type': 'text/html; invalid' } } } }, { name: `Resource is served with 'Content-Type' header with an invalid parameter format`, - reports: [{ message: invalidParameterFormatMessage }], + reports: [{ message: invalidParameterFormatErrorMessage }], serverConfig: { '/': generateHTMLPageData(generateHTMLPage(undefined, '')), '/test.js': { headers: { 'Content-Type': 'text/javascript; charset=inva/id' } } @@ -93,7 +96,7 @@ const testsForDefaults: Array = [ { name: `HTML page is served with 'Content-Type' header without 'charset' parameter`, - reports: [{ message: noCharsetMessage }], + reports: [{ message: noCharsetErrorMessage }], serverConfig: { '/': { headers: { 'Content-Type': 'text/html' } } } }, { @@ -105,7 +108,7 @@ const testsForDefaults: Array = [ }, { name: `Script is served with 'Content-Type' header without 'charset' parameter`, - reports: [{ message: noCharsetMessage }], + reports: [{ message: noCharsetErrorMessage }], serverConfig: { '/': generateHTMLPageData(generateHTMLPage(undefined, '')), '/test.js': { headers: { 'Content-Type': 'text/javascript' } } @@ -116,12 +119,12 @@ const testsForDefaults: Array = [ { name: `HTML page is served with 'Content-Type' header with wrong 'charset'`, - reports: [{ message: incorrectCharsetMessage }], + reports: [{ message: incorrectCharsetErrorMessage }], serverConfig: { '/': { headers: { 'Content-Type': 'text/html; charset=iso-8859-1' } } } }, { name: `Image is served with 'Content-Type' header with unneeded 'charset' parameter`, - reports: [{ message: unneededCharsetMessage }], + reports: [{ message: unneededCharsetErrorMessage }], serverConfig: { '/': generateHTMLPageData(generateHTMLPage(undefined, '')), '/test.png': { headers: { 'Content-Type': 'image/png; charset=utf-8' } } @@ -129,7 +132,7 @@ const testsForDefaults: Array = [ }, { name: `Script is served with 'Content-Type' header with wrong 'charset'`, - reports: [{ message: incorrectCharsetMessage }], + reports: [{ message: incorrectCharsetErrorMessage }], serverConfig: { '/': generateHTMLPageData(generateHTMLPage(undefined, '')), '/test.js': { headers: { 'Content-Type': 'text/javascript;charset=iso-8859-1' } } @@ -141,7 +144,7 @@ const testsForDefaults: Array = [ * TODO: Enable if `jsdom` supports downloading fonts, or #250 is implemented. * { * name: `WOFF2 font is served with 'Content-Type' header with the wrong media type`, - * reports: [{ message: generateIncorrectMediaTypeMessage('font/woff2', 'application/font-woff2') }], + * reports: [{ message: generateIncorrectMediaTypeErrorMessage('font/woff2', 'application/font-woff2') }], * serverConfig: { * '/': generateHTMLPageData(generateHTMLPage(` *