Skip to content

Commit 6a56853

Browse files
committed
test(lint): add tests for getRulePosition function
Add comprehensive tests for the getRulePosition function that calculates error positions for various rule types: - type-enum, type-case, type-max-length - scope-enum, scope-case - subject-max-length, subject-full-stop - header-max-length - body-max-line-length Also test edge cases like rules without position support and valid commits that don't need position data.
1 parent 3ea0fce commit 6a56853

1 file changed

Lines changed: 279 additions & 0 deletions

File tree

@commitlint/lint/src/lint.test.ts

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,282 @@ test("passes for async rule", async () => {
314314

315315
expect(report.valid).toBe(true);
316316
});
317+
318+
test("returns position for type-enum error", async () => {
319+
const result = await lint("foo: some message", {
320+
"type-enum": [RuleConfigSeverity.Error, "always", ["feat", "fix"]],
321+
});
322+
expect(result.valid).toBe(false);
323+
expect(result.errors).toHaveLength(1);
324+
expect(result.errors[0].name).toBe("type-enum");
325+
expect(result.errors[0].start).toEqual({ line: 1, column: 1, offset: 0 });
326+
expect(result.errors[0].end).toEqual({ line: 1, column: 4, offset: 3 });
327+
});
328+
329+
test("returns position for type-case error", async () => {
330+
const result = await lint("FIX: some message", {
331+
"type-case": [RuleConfigSeverity.Error, "always", "lower-case"],
332+
});
333+
expect(result.valid).toBe(false);
334+
expect(result.errors[0].name).toBe("type-case");
335+
expect(result.errors[0].start).toEqual({ line: 1, column: 1, offset: 0 });
336+
expect(result.errors[0].end).toEqual({ line: 1, column: 4, offset: 3 });
337+
});
338+
339+
test("returns position for type-max-length error", async () => {
340+
const longType = "toolongtype";
341+
const result = await lint(`${longType}: some message`, {
342+
"type-max-length": [RuleConfigSeverity.Error, "always", 5],
343+
});
344+
expect(result.valid).toBe(false);
345+
expect(result.errors[0].name).toBe("type-max-length");
346+
expect(result.errors[0].start).toEqual({ line: 1, column: 1, offset: 0 });
347+
expect(result.errors[0].end).toEqual({
348+
line: 1,
349+
column: longType.length + 1,
350+
offset: longType.length,
351+
});
352+
});
353+
354+
test("returns position for scope-enum error", async () => {
355+
const result = await lint("feat(badscope): some message", {
356+
"scope-enum": [RuleConfigSeverity.Error, "always", ["cli", "core"]],
357+
});
358+
expect(result.valid).toBe(false);
359+
expect(result.errors[0].name).toBe("scope-enum");
360+
expect(result.errors[0].start).toEqual({ line: 1, column: 6, offset: 5 });
361+
expect(result.errors[0].end).toEqual({ line: 1, column: 14, offset: 13 });
362+
});
363+
364+
test("returns position for scope-case error", async () => {
365+
const result = await lint("feat(SCOPE): some message", {
366+
"scope-case": [RuleConfigSeverity.Error, "always", "lower-case"],
367+
});
368+
expect(result.valid).toBe(false);
369+
expect(result.errors[0].name).toBe("scope-case");
370+
expect(result.errors[0].start).toEqual({ line: 1, column: 6, offset: 5 });
371+
expect(result.errors[0].end).toEqual({ line: 1, column: 11, offset: 10 });
372+
});
373+
374+
test("returns position for subject-max-length error", async () => {
375+
const longSubject =
376+
"this is a very long subject that exceeds the maximum allowed characters";
377+
const result = await lint(`feat: ${longSubject}`, {
378+
"subject-max-length": [RuleConfigSeverity.Error, "always", 20],
379+
});
380+
expect(result.valid).toBe(false);
381+
expect(result.errors[0].name).toBe("subject-max-length");
382+
expect(result.errors[0].start?.line).toBe(1);
383+
expect(result.errors[0].start?.column).toBeGreaterThan(5);
384+
expect(result.errors[0].end?.line).toBe(1);
385+
});
386+
387+
test("returns position for subject-full-stop error", async () => {
388+
const result = await lint("feat: some message.", {
389+
"subject-full-stop": [RuleConfigSeverity.Error, "never", "."],
390+
});
391+
expect(result.valid).toBe(false);
392+
expect(result.errors[0].name).toBe("subject-full-stop");
393+
expect(result.errors[0].start?.line).toBe(1);
394+
expect(result.errors[0].start?.column).toBeGreaterThan(5);
395+
});
396+
397+
test("returns position for header-max-length error", async () => {
398+
const longHeader =
399+
"feat: this is a very long header that definitely exceeds the maximum allowed character limit for commit messages";
400+
const result = await lint(longHeader, {
401+
"header-max-length": [RuleConfigSeverity.Error, "always", 50],
402+
});
403+
expect(result.valid).toBe(false);
404+
expect(result.errors[0].name).toBe("header-max-length");
405+
expect(result.errors[0].start).toEqual({ line: 1, column: 1, offset: 0 });
406+
expect(result.errors[0].end).toEqual({
407+
line: 1,
408+
column: longHeader.length + 1,
409+
offset: longHeader.length,
410+
});
411+
});
412+
413+
test("returns position for body-max-line-length error", async () => {
414+
const longBodyLine =
415+
"this is a body line that is way too long and exceeds the maximum allowed character limit of one hundred characters for each line in the body";
416+
const result = await lint(`feat: some message\n\n${longBodyLine}`, {
417+
"body-max-line-length": [RuleConfigSeverity.Error, "always", 80],
418+
});
419+
expect(result.valid).toBe(false);
420+
expect(result.errors[0].name).toBe("body-max-line-length");
421+
expect(result.errors[0].start?.line).toBe(2);
422+
});
423+
424+
test("returns no position for rules without position support", async () => {
425+
const result = await lint("somehting #1", {
426+
"references-empty": [RuleConfigSeverity.Error, "always"],
427+
});
428+
expect(result.valid).toBe(false);
429+
expect(result.errors[0].name).toBe("references-empty");
430+
expect(result.errors[0].start).toBeUndefined();
431+
expect(result.errors[0].end).toBeUndefined();
432+
});
433+
434+
test("returns correct position for valid commit (no position needed)", async () => {
435+
const result = await lint("feat: add new feature", {
436+
"type-enum": [RuleConfigSeverity.Error, "always", ["feat", "fix"]],
437+
});
438+
expect(result.valid).toBe(true);
439+
expect(result.errors).toHaveLength(0);
440+
});
441+
442+
test("returns position for subject-full-stop error", async () => {
443+
const result = await lint("feat: some message.", {
444+
"subject-full-stop": [RuleConfigSeverity.Error, "never", "."],
445+
});
446+
expect(result.valid).toBe(false);
447+
expect(result.errors[0].name).toBe("subject-full-stop");
448+
expect(result.errors[0].start).toBeDefined();
449+
expect(result.errors[0].start?.line).toBe(1);
450+
expect(result.errors[0].end).toBeDefined();
451+
});
452+
453+
test("returns position for header-max-length error", async () => {
454+
const longHeader =
455+
"feat: this is a very long header that definitely exceeds the maximum allowed character limit for commit messages";
456+
const result = await lint(longHeader, {
457+
"header-max-length": [RuleConfigSeverity.Error, "always", 50],
458+
});
459+
expect(result.valid).toBe(false);
460+
expect(result.errors[0].name).toBe("header-max-length");
461+
expect(result.errors[0].start).toEqual({ line: 1, column: 1, offset: 0 });
462+
expect(result.errors[0].end).toEqual({
463+
line: 1,
464+
column: longHeader.length + 1,
465+
offset: longHeader.length,
466+
});
467+
});
468+
469+
test("returns position for body-max-line-length error", async () => {
470+
const longBodyLine =
471+
"this is a body line that is way too long and exceeds the maximum allowed character limit";
472+
const result = await lint(`feat: some message\n\n${longBodyLine}`, {
473+
"body-max-line-length": [RuleConfigSeverity.Error, "always", 50],
474+
});
475+
expect(result.valid).toBe(false);
476+
expect(result.errors[0].name).toBe("body-max-line-length");
477+
expect(result.errors[0].start).toBeDefined();
478+
expect(result.errors[0].start?.line).toBe(2);
479+
});
480+
481+
test("returns position for header-max-length error", async () => {
482+
const longHeader =
483+
"feat: this is a very long header that definitely exceeds the maximum allowed character limit for commit messages";
484+
const result = await lint(longHeader, {
485+
"header-max-length": [RuleConfigSeverity.Error, "always", 50],
486+
});
487+
expect(result.valid).toBe(false);
488+
expect(result.errors[0].name).toBe("header-max-length");
489+
expect(result.errors[0].start).toEqual({ line: 1, column: 1, offset: 0 });
490+
expect(result.errors[0].end).toEqual({
491+
line: 1,
492+
column: longHeader.length + 1,
493+
offset: longHeader.length,
494+
});
495+
});
496+
497+
test("returns position for body-max-line-length error", async () => {
498+
const longBodyLine =
499+
"this is a body line that is way too long and exceeds the maximum allowed character limit";
500+
const result = await lint(`feat: some message\n\n${longBodyLine}`, {
501+
"body-max-line-length": [RuleConfigSeverity.Error, "always", 50],
502+
});
503+
expect(result.valid).toBe(false);
504+
expect(result.errors[0].name).toBe("body-max-line-length");
505+
expect(result.errors[0].start).toBeDefined();
506+
expect(result.errors[0].start?.line).toBe(2);
507+
});
508+
509+
test("returns no position for rules without position support", async () => {
510+
const result = await lint("somehting #1", {
511+
"references-empty": [RuleConfigSeverity.Error, "always"],
512+
});
513+
expect(result.valid).toBe(false);
514+
expect(result.errors[0].name).toBe("references-empty");
515+
expect(result.errors[0].start).toBeUndefined();
516+
expect(result.errors[0].end).toBeUndefined();
517+
});
518+
519+
test("returns position when type is provided", async () => {
520+
const result = await lint("feat: some message", {
521+
"type-enum": [RuleConfigSeverity.Error, "always", ["bar"]],
522+
});
523+
expect(result.valid).toBe(false);
524+
expect(result.errors[0].name).toBe("type-enum");
525+
expect(result.errors[0].start).toBeDefined();
526+
});
527+
528+
test("returns position when scope is provided", async () => {
529+
const result = await lint("feat(myscope): some message", {
530+
"scope-enum": [RuleConfigSeverity.Error, "always", ["other"]],
531+
});
532+
expect(result.valid).toBe(false);
533+
expect(result.errors[0].name).toBe("scope-enum");
534+
expect(result.errors[0].start).toBeDefined();
535+
});
536+
537+
test("handles duplicate text in message - uses first occurrence", async () => {
538+
const result = await lint("fix: test test", {
539+
"type-enum": [RuleConfigSeverity.Error, "always", ["feat", "fix"]],
540+
});
541+
expect(result.valid).toBe(true);
542+
expect(result.errors).toHaveLength(0);
543+
});
544+
545+
test("returns correct position for valid commit (no position needed)", async () => {
546+
const result = await lint("feat: add new feature", {
547+
"type-enum": [RuleConfigSeverity.Error, "always", ["feat", "fix"]],
548+
});
549+
expect(result.valid).toBe(true);
550+
expect(result.errors).toHaveLength(0);
551+
});
552+
553+
test("returns no position for rules without position support", async () => {
554+
const result = await lint("somehting #1", {
555+
"references-empty": [RuleConfigSeverity.Error, "always"],
556+
});
557+
expect(result.valid).toBe(false);
558+
expect(result.errors[0].name).toBe("references-empty");
559+
expect(result.errors[0].start).toBeUndefined();
560+
expect(result.errors[0].end).toBeUndefined();
561+
});
562+
563+
test("returns position when type is provided", async () => {
564+
const result = await lint("feat: some message", {
565+
"type-enum": [RuleConfigSeverity.Error, "always", ["bar"]],
566+
});
567+
expect(result.valid).toBe(false);
568+
expect(result.errors[0].name).toBe("type-enum");
569+
expect(result.errors[0].start).toBeDefined();
570+
});
571+
572+
test("returns position when scope is provided", async () => {
573+
const result = await lint("feat(myscope): some message", {
574+
"scope-enum": [RuleConfigSeverity.Error, "always", ["other"]],
575+
});
576+
expect(result.valid).toBe(false);
577+
expect(result.errors[0].name).toBe("scope-enum");
578+
expect(result.errors[0].start).toBeDefined();
579+
});
580+
581+
test("handles duplicate text in message - uses first occurrence", async () => {
582+
const result = await lint("fix: test test", {
583+
"type-enum": [RuleConfigSeverity.Error, "always", ["feat", "fix"]],
584+
});
585+
expect(result.valid).toBe(true);
586+
expect(result.errors).toHaveLength(0);
587+
});
588+
589+
test("returns correct position for valid commit (no position needed)", async () => {
590+
const result = await lint("feat: add new feature", {
591+
"type-enum": [RuleConfigSeverity.Error, "always", ["feat", "fix"]],
592+
});
593+
expect(result.valid).toBe(true);
594+
expect(result.errors).toHaveLength(0);
595+
});

0 commit comments

Comments
 (0)