@@ -510,3 +510,214 @@ def pytest_markdown_docs_markdown_it():
510510 )
511511 result = testdir .runpytest ("--markdown-docs" )
512512 result .assert_outcomes (passed = 1 , failed = 2 )
513+
514+
515+ def test_retry_eventually_succeeds (testdir ):
516+ """Test that a flaky test succeeds after retrying."""
517+ testdir .makepyfile (
518+ conftest = """
519+ attempt_counter = {}
520+ """
521+ )
522+ testdir .makefile (
523+ ".md" ,
524+ test_file = """
525+ ```python retry:3
526+ import conftest
527+ key = "test_1"
528+ conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
529+ assert conftest.attempt_counter[key] >= 2 # Fails first time, passes on retry
530+ ```
531+ """ ,
532+ )
533+ result = testdir .runpytest ("--markdown-docs" )
534+ result .assert_outcomes (passed = 1 )
535+
536+
537+ def test_retry_exhausted (testdir ):
538+ """Test that a test fails after all retry attempts are exhausted."""
539+ testdir .makefile (
540+ ".md" ,
541+ test_file = """
542+ ```python retry:2
543+ assert False # Always fails
544+ ```
545+ """ ,
546+ )
547+ result = testdir .runpytest ("--markdown-docs" )
548+ result .assert_outcomes (failed = 1 )
549+
550+
551+ def test_retry_with_fixture (testdir ):
552+ """Test that fixtures are not re-run between retries."""
553+ testdir .makepyfile (
554+ conftest = """
555+ import pytest
556+
557+ fixture_call_count = 0
558+
559+ @pytest.fixture
560+ def counting_fixture():
561+ global fixture_call_count
562+ fixture_call_count += 1
563+ return fixture_call_count
564+
565+ attempt_counter = {}
566+ """
567+ )
568+ testdir .makefile (
569+ ".md" ,
570+ test_file = """
571+ ```python retry:3 fixture:counting_fixture
572+ import conftest
573+ key = "test_2"
574+ conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
575+
576+ # Fixture should only be called once (value should stay 1)
577+ assert counting_fixture == 1
578+
579+ # Fail on first attempt, pass on second
580+ assert conftest.attempt_counter[key] >= 2
581+ ```
582+ """ ,
583+ )
584+ result = testdir .runpytest ("--markdown-docs" )
585+ result .assert_outcomes (passed = 1 )
586+
587+
588+ def test_retry_with_continuation (testdir ):
589+ """Test that retry works with continuation blocks."""
590+ testdir .makepyfile (
591+ conftest = """
592+ attempt_counter = {}
593+ """
594+ )
595+ testdir .makefile (
596+ ".md" ,
597+ test_file = """
598+ ```python
599+ a = "hello"
600+ ```
601+
602+ ```python retry:2 continuation
603+ import conftest
604+ key = "test_3"
605+ conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
606+
607+ # Variable 'a' from previous block should be available
608+ assert a + " world" == "hello world"
609+
610+ # Fail on first attempt, pass on second
611+ assert conftest.attempt_counter[key] >= 2
612+ ```
613+ """ ,
614+ )
615+ result = testdir .runpytest ("--markdown-docs" )
616+ result .assert_outcomes (passed = 2 )
617+
618+
619+ def test_retry_invalid_negative (testdir ):
620+ """Test that negative retry counts raise an error."""
621+ testdir .makefile (
622+ ".md" ,
623+ test_file = """
624+ ```python retry:-1
625+ assert True
626+ ```
627+ """ ,
628+ )
629+ result = testdir .runpytest ("--markdown-docs" )
630+ result .assert_outcomes (errors = 1 )
631+ result .stdout .fnmatch_lines (["*Invalid retry count*non-negative integer*" ])
632+
633+
634+ def test_retry_invalid_non_numeric (testdir ):
635+ """Test that non-numeric retry counts raise an error."""
636+ testdir .makefile (
637+ ".md" ,
638+ test_file = """
639+ ```python retry:abc
640+ assert True
641+ ```
642+ """ ,
643+ )
644+ result = testdir .runpytest ("--markdown-docs" )
645+ result .assert_outcomes (errors = 1 )
646+ result .stdout .fnmatch_lines (["*Invalid retry count*non-negative integer*" ])
647+
648+
649+ def test_retry_multiple_values_error (testdir ):
650+ """Test that multiple retry values raise an error."""
651+ testdir .makefile (
652+ ".md" ,
653+ test_file = """
654+ ```python retry:2 retry:3
655+ assert True
656+ ```
657+ """ ,
658+ )
659+ result = testdir .runpytest ("--markdown-docs" )
660+ result .assert_outcomes (errors = 1 )
661+ result .stdout .fnmatch_lines (["*Multiple retry counts are not supported*" ])
662+
663+
664+ def test_retry_zero (testdir ):
665+ """Test that retry:0 behaves the same as no retry."""
666+ testdir .makefile (
667+ ".md" ,
668+ test_file = """
669+ ```python retry:0
670+ assert False
671+ ```
672+ """ ,
673+ )
674+ result = testdir .runpytest ("--markdown-docs" )
675+ result .assert_outcomes (failed = 1 )
676+
677+
678+ def test_retry_mdx_comment (testdir ):
679+ """Test that retry works with MDX comment metadata."""
680+ testdir .makepyfile (
681+ conftest = """
682+ attempt_counter = {}
683+ """
684+ )
685+ testdir .makefile (
686+ ".mdx" ,
687+ test_file = """
688+ {/* pmd-metadata: retry:3 */}
689+ ```python
690+ import conftest
691+ key = "test_4"
692+ conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
693+ assert conftest.attempt_counter[key] >= 2
694+ ```
695+ """ ,
696+ )
697+ result = testdir .runpytest ("--markdown-docs" )
698+ result .assert_outcomes (passed = 1 )
699+
700+
701+ def test_retry_with_docstring (testdir ):
702+ """Test that retry works in Python docstrings."""
703+ testdir .makepyfile (
704+ conftest = """
705+ attempt_counter = {}
706+ """
707+ )
708+ testdir .makepyfile (
709+ test_module = """
710+ def my_function():
711+ \" \" \"
712+ ```python retry:3
713+ import conftest
714+ key = "test_5"
715+ conftest.attempt_counter[key] = conftest.attempt_counter.get(key, 0) + 1
716+ assert conftest.attempt_counter[key] >= 2
717+ ```
718+ \" \" \"
719+ pass
720+ """
721+ )
722+ result = testdir .runpytest ("--markdown-docs" )
723+ result .assert_outcomes (passed = 1 )
0 commit comments