vitest-stylelint-utils
Version:
Utilities for testing Stylelint plugins with Vitest
164 lines (163 loc) • 5.37 kB
JavaScript
// src/get-test-rule.ts
import util from "node:util";
import stylelint from "stylelint";
var { lint } = stylelint;
function getTestRule(options) {
const { describe, expect, it } = 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) {
return async function() {
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([]);
expect(output.results[0].invalidOptionWarnings).toEqual([]);
if (!schema.fix) {
return;
}
const outputAfterFix = await lint({
...stylelintOptions,
fix: true
});
const fixedCode = getOutputCss(outputAfterFix);
expect(fixedCode).toBe(testCase.code);
};
},
describe,
it
});
setupTestCases({
name: "reject",
cases: schema.reject,
schema,
comparisons(testCase) {
return async function() {
const stylelintOptions = {
code: testCase.code,
config: stylelintConfig,
customSyntax: schema.customSyntax,
codeFilename: schema.codeFilename
};
const outputAfterLint = await lint(stylelintOptions);
const actualWarnings = [
...outputAfterLint.results[0].invalidOptionWarnings,
...outputAfterLint.results[0].warnings
];
expect(outputAfterLint.results[0]).toMatchObject({
parseErrors: []
});
expect(actualWarnings).toHaveLength(
testCase.warnings ? testCase.warnings.length : 1
);
const warnings = testCase.warnings || [testCase];
warnings.forEach((warning, index) => {
expect(
warning.message,
'Expected "reject" test case to have a "message" property'
).toBeDefined();
const expectedWarning = {
text: warning.message,
line: warning.line,
column: warning.column,
endLine: warning.endLine,
endColumn: warning.endColumn
};
Object.entries(expectedWarning).forEach(([key, value]) => {
if (value === void 0) {
delete expectedWarning[key];
}
});
expect(actualWarnings[index]).toMatchObject(expectedWarning);
});
if (!schema.fix) {
return;
}
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 {
if (testCase.fixed) {
expect(fixedCode).toBe(testCase.fixed);
}
expect(fixedCode).toBe(testCase.code);
}
const outputAfterLintOnFixedCode = await lint({
...stylelintOptions,
code: fixedCode,
fix: testCase.unfixable
});
expect(outputAfterLintOnFixedCode.results[0]).toMatchObject({
warnings: outputAfterFix.results[0].warnings,
parseErrors: []
});
};
},
describe,
it
});
});
};
}
function setupTestCases({
name,
cases,
schema,
comparisons,
describe,
it
}) {
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)
);
});
});
}
});
});
}
}
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");
}
export {
getTestRule
};