UNPKG

jest-preset-ec0lint-style

Version:
194 lines (157 loc) 5.17 kB
'use strict'; const util = require('util'); // eslint-disable-next-line node/no-unpublished-require -- Avoid auto-install of `ec0lint-style` peer dependency. const { lint } = require('ec0lint-style'); /** * @typedef {import('.').TestCase} TestCase * @typedef {import('.').TestSchema} TestSchema */ /** @type {import('.').getTestRule} */ module.exports = function getTestRule(options = {}) { return function testRule(schema) { describe(`${schema.ruleName}`, () => { const stylelintConfig = { plugins: options.plugins || schema.plugins, rules: { [schema.ruleName]: schema.config, }, }; setupTestCases({ name: 'accept', cases: schema.accept, schema, comparisons: (testCase) => async () => { const stylelintOptions = { code: testCase.code, config: stylelintConfig, customSyntax: schema.customSyntax, codeFilename: schema.codeFilename, }; const output = await lint(stylelintOptions); expect(output.results[0].warnings).toEqual([]); expect(output.results[0].parseErrors).toEqual([]); if (!schema.fix) return; // Check that --fix doesn't change code const outputAfterFix = await lint({ ...stylelintOptions, fix: true }); const fixedCode = getOutputCss(outputAfterFix); expect(fixedCode).toBe(testCase.code); }, }); setupTestCases({ name: 'reject', cases: schema.reject, schema, comparisons: (testCase) => async () => { const stylelintOptions = { code: testCase.code, config: stylelintConfig, customSyntax: schema.customSyntax, codeFilename: schema.codeFilename, }; const outputAfterLint = await lint(stylelintOptions); const actualWarnings = outputAfterLint.results[0].warnings; expect(outputAfterLint.results[0].parseErrors).toEqual([]); expect(actualWarnings).toHaveLength(testCase.warnings ? testCase.warnings.length : 1); (testCase.warnings || [testCase]).forEach((expected, i) => { const warning = actualWarnings[i]; // @ts-expect-error -- This is our custom matcher. expect(expected).toHaveMessage(); expect(warning.text).toBe(expected.message); if (expected.line !== undefined) { expect(warning.line).toBe(expected.line); } if (expected.column !== undefined) { expect(warning.column).toBe(expected.column); } // if (expected.endLine !== undefined) { // expect(warning.endLine).toBe(expected.endLine); // } // if (expected.endColumn !== undefined) { // expect(warning.endColumn).toBe(expected.endColumn); // } }); if (!schema.fix) return; // Check that --fix doesn't change code if (schema.fix && !testCase.fixed && testCase.fixed !== '' && !testCase.unfixable) { throw new Error( 'If using { fix: true } in test schema, all reject cases must have { fixed: .. }', ); } const outputAfterFix = await lint({ ...stylelintOptions, fix: true }); const fixedCode = getOutputCss(outputAfterFix); if (!testCase.unfixable) { expect(fixedCode).toBe(testCase.fixed); expect(fixedCode).not.toBe(testCase.code); } else { // can't fix if (testCase.fixed) { expect(fixedCode).toBe(testCase.fixed); } expect(fixedCode).toBe(testCase.code); } // Checks whether only errors other than those fixed are reported const outputAfterLintOnFixedCode = await lint({ ...stylelintOptions, code: fixedCode, }); expect(outputAfterLintOnFixedCode.results[0].warnings).toEqual( outputAfterFix.results[0].warnings, ); expect(outputAfterLintOnFixedCode.results[0].parseErrors).toEqual([]); }, }); }); expect.extend({ toHaveMessage(testCase) { if (testCase.message === undefined) { return { message: () => 'Expected "reject" test case to have a "message" property', pass: false, }; } return { message: () => '', pass: true, }; }, }); }; }; /** * @template {TestCase} T * @param {{ * name: string, * cases: T[] | undefined, * schema: TestSchema, * comparisons: (testCase: T) => jest.ProvidesCallback, * }} args * @returns {void} */ function setupTestCases({ name, cases, schema, comparisons }) { if (cases && cases.length) { const testGroup = schema.only ? describe.only : schema.skip ? describe.skip : describe; testGroup(`${name}`, () => { cases.forEach((testCase) => { if (testCase) { const spec = testCase.only ? it.only : testCase.skip ? it.skip : it; describe(`${util.inspect(schema.config)}`, () => { describe(`${util.inspect(testCase.code)}`, () => { spec(testCase.description || 'no description', comparisons(testCase)); }); }); } }); }); } } /** * @param {import('ec0lint-style').LinterResult} output * @returns {string} */ function getOutputCss(output) { const result = output.results[0]._postcssResult; if (result && result.root && result.opts) { return result.root.toString(result.opts.syntax); } throw new TypeError('Invalid result'); }