UNPKG

stylelint-vitest-rule-tester

Version:
484 lines (411 loc) 10.1 kB
# stylelint-vitest-rule-tester [![CI](https://github.com/ntnyq/stylelint-vitest-rule-tester/workflows/CI/badge.svg)](https://github.com/ntnyq/stylelint-vitest-rule-tester/actions) [![NPM VERSION](https://img.shields.io/npm/v/stylelint-vitest-rule-tester.svg)](https://www.npmjs.com/package/stylelint-vitest-rule-tester) [![NPM DOWNLOADS](https://img.shields.io/npm/dy/stylelint-vitest-rule-tester.svg)](https://www.npmjs.com/package/stylelint-vitest-rule-tester) [![CODECOV](https://codecov.io/github/ntnyq/stylelint-vitest-rule-tester/graph/badge.svg?token=34A8PZF57N)](https://codecov.io/github/ntnyq/stylelint-vitest-rule-tester) [![LICENSE](https://img.shields.io/github/license/ntnyq/stylelint-vitest-rule-tester.svg)](https://github.com/ntnyq/stylelint-vitest-rule-tester/blob/main/LICENSE) > Styellint rule tester with Vitest, with more powerful and friendly APIs ## Install ```shell npm install stylelint-vitest-rule-tester -D ``` ```shell yarn add stylelint-vitest-rule-tester -D ``` ```shell pnpm add stylelint-vitest-rule-tester -D ``` ## Usage ```ts import stylelintSCSS from 'stylelint-scss' import { run } from 'stylelint-vitest-rule-tester' import { expect } from 'vitest' run({ name: 'scss/dollar-variable-default', /** * stylelint config * * @see https://stylelint.io/user-guide/configure */ stylelintConfig: { plugins: stylelintSCSS, customSyntax: 'postcss-scss', }, /** * valid cases */ valid: [ `a { color: blue }`, `$var: 10px !default`, `a { $var: 10px !default }`, `.class { a { $var: 10px !default } }`, ], /** * invalid cases */ invalid: [ { description: 'global vars without !default', filename: 'global.scss', code: $` $var: 10px `, warnings(warnings) { expect(warnings).toMatchInlineSnapshot(` [ { "column": 1, "endColumn": 11, "endLine": 1, "fix": undefined, "line": 1, "rule": "scss/dollar-variable-default", "severity": "error", "text": "Expected !default flag for "$var" (scss/dollar-variable-default)", "url": "https://github.com/stylelint-scss/stylelint-scss/blob/master/src/rules/dollar-variable-default", }, ] `) }, }, ], }) ``` <details> <summary>🟩 Built-in rule test</summary> <br> ```ts import { run } from 'stylelint-vitest-rule-tester' import { expect } from 'vitest' run({ name: 'no-empty-source', valid: [ // string case `.class {}`, // object case with rule options { filename: 'disable.css', code: '', ruleOptions: [false], }, // object case with stylelint config { description: 'HTML without CSS', stylelintConfig: { customSyntax: 'postcss-html', }, code: '<html></html>', }, ], invalid: [ // invalid case { filename: 'empty.css', code: '', warnings(warnings) { expect(warnings).toHaveLength(1) expect(warnings).toMatchInlineSnapshot(` [ { "column": 1, "endColumn": 2, "endLine": 1, "line": 1, "rule": "no-empty-source", "severity": "error", "text": "Unexpected empty source (no-empty-source)", "url": undefined, }, ] `) }, }, // invalid case with rule options url { filename: 'empty-with-url.css', code: '', ruleOptions: [ true, { url: 'https://github.com/stylelint/stylelint/tree/main/lib/rules/no-empty-source', }, ], warnings(warnings) { expect(warnings).toMatchInlineSnapshot(` [ { "column": 1, "endColumn": 2, "endLine": 1, "line": 1, "rule": "no-empty-source", "severity": "error", "text": "Unexpected empty source (no-empty-source)", "url": "https://github.com/stylelint/stylelint/tree/main/lib/rules/no-empty-source", }, ] `) }, }, // invalid case with stylelint config { description: 'CSS block in HTML', stylelintConfig: { customSyntax: 'postcss-html', }, code: '<style>\n</style>', warnings(warnings) { expect(warnings).toMatchInlineSnapshot(` [ { "column": 1, "endColumn": 2, "endLine": 2, "line": 2, "rule": "no-empty-source", "severity": "error", "text": "Unexpected empty source (no-empty-source)", "url": undefined, }, ] `) }, }, ], }) ``` </details> ## API ### `run` - `Type:`: `(options: TestCasesOptions & RuleTesterInitOptions) => void` Create a tester and run. ### `runClassic` - `Type:`: `(ruleName: string, cases: TestCasesOptions, options?: RuleTesterInitOptions) => void` Create a classic style tester and run. ## Interface <details> <summary>🟦 RuleTesterInitOptions types</summary> <br> ```ts import type Stylelint from 'stylelint' /** * default filename when not provided */ export interface DefaultFilenames { css: string less: string postcss: string sass: string scss: string styl: string stylus: string [key: string]: string } /** * Stylelint options */ export interface StylelintOptions { /** * linter options for `stylelint.lint(options)` */ linterOptions?: Stylelint.LinterOptions /** * rule options */ ruleOptions?: any /** * stylelint config */ stylelintConfig?: Stylelint.Config } /** * Rule tester behavior options */ export type RuleTesterBehaviorOptions = { /** * the number of times to recursively apply the rule * * @default 10 */ recursive?: false | number /** * run verification after applying the fix * * @default true */ verifyAfterFix?: boolean /** * verify that fix allways changes the code * * @default true */ verifyFixChanges?: boolean } /** * Rule tester init options */ export type RuleTesterInitOptions = RuleTesterBehaviorOptions & StylelintOptions & { /** * rule name to test */ name: string /** * default filenames to be used for tests */ defaultFileNames?: Partial<DefaultFilenames> } ``` </details> <details> <summary>🟦 TestCasesOptions types</summary> <br> ```ts import type Stylelint from 'stylelint' /** * Test case options */ export interface TestCasesOptions { /** * invalid cases */ invalid?: (string | InvalidTestCase)[] /** * valid cases */ valid?: (string | ValidTestCase)[] /** * callback to be called after each test case */ onResult?: ( testCase: NormalizedTestCase, result: TestExecutionResult, ) => Promise<void> | void } /** * Invalid test case */ export type InvalidTestCase = string | InvalidTestCaseBase export type InvalidTestCaseBase = ValidTestCaseBase & { /** * Assert if output is expected. * Pass `null` to assert that the output is the same as the input. */ output?: string | ((output: string, input: string) => void) | null /** * expect for {@link LintResultDeprecation} */ deprecations?: | number | (string | LintResultDeprecation)[] | ((deprecations: LintResultDeprecation[]) => void) /** * expect for {@link LintResultInvalidOptionWarning} */ invalidOptionWarnings?: | number | (string | LintResultInvalidOptionWarning)[] | ((invalidOptionWarnings: LintResultInvalidOptionWarning[]) => void) /** * expect for {@link LintResultParseError} */ parseErrors?: | number | (string | LintResultParseError)[] | ((parseErrors: LintResultParseError[]) => void) /** * expect for {@link LintResultWarning} */ warnings?: | number | (string | LintResultWarning)[] | ((warnings: LintResultWarning[]) => void) } /** * Valid test case */ export type ValidTestCase = string | ValidTestCaseBase export type ValidTestCaseBase = RuleTesterBehaviorOptions & StylelintOptions & { /** * code to test */ code: string /** * test case description */ description?: string /** * test case filename */ filename?: string /** * test case name */ name?: string /** * only run this test case */ only?: boolean /** * skip this test case */ skip?: boolean /** * lint result */ onResult?: (result: TestExecutionResult) => void } /** * Test case * @pg */ export type TestCase = InvalidTestCase | ValidTestCase /** * Normalized test case * @pg */ export type NormalizedTestCase = InvalidTestCaseBase & { code: string filename: string type: 'invalid' | 'valid' } export type LintResultDeprecation = { text: string reference?: string } export type LintResultInvalidOptionWarning = { text: string } export type LintResultParseError = Postcss.Warning & { stylelintType: 'parseError' } export type LintResultWarning = Stylelint.Warning export type LintResultMessage = | LintResultDeprecation | LintResultInvalidOptionWarning | LintResultParseError | LintResultWarning export type StylelintLinterResult = Omit< Stylelint.LinterResult, 'cwd' | 'report' > /** * Test execution result */ export type TestExecutionResult = StylelintLinterResult & { /** * whether the code was fixed */ fixed?: boolean /** * if the rule fixes in multiple steps, the result of each step is present here */ steps?: StylelintLinterResult[] } ``` </details> ## Credits - [antfu/eslint-vitest-rule-tester](https://github.com/antfu/eslint-vitest-rule-tester) ## License [MIT](./LICENSE) License © 2024-PRESENT [ntnyq](https://github.com/ntnyq)