# pytest-dev__pytest-7220
# Loki Mode Multi-Agent Patch
# Attempts: 1

--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -1,4 +1,5 @@
 import inspect
+import os
 import re
 import sys
 import traceback
@@ -551,13 +552,27 @@ class ReprFileLocation(TerminalRepr):
         self.lineno = lineno
         self.message = message
 
-    def toterminal(self, tw: TerminalWriter) -> None:
+    def toterminal(self, tw: TerminalWriter, invocation_dir=None) -> None:
         # filename and samples of underline
         msg = self.message
-        i = msg.find("\n")
-        if i != -1:
-            msg = msg[:i]
-        tw.write(self.path, bold=True, red=True)
+        lineno = self.lineno
+        path = self.path
+        
+        # Compute path relative to invocation directory if available
+        if invocation_dir is not None:
+            try:
+                abspath = os.path.abspath(path)
+                relpath = os.path.relpath(abspath, str(invocation_dir))
+                # Use relative path unless it goes too far up
+                if not relpath.startswith(".."):
+                    path = relpath
+                else:
+                    path = abspath
+            except (ValueError, OSError):
+                pass
+        
+        tw.write(path, bold=True, red=True)
         tw.line(":{}: {}".format(self.lineno, msg))
 
 
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -558,6 +558,10 @@ class ReprFileLocation(TerminalRepr):
         lineno = self.lineno
         path = self.path
         
+        i = msg.find("\n")
+        if i != -1:
+            msg = msg[:i]
+        
         # Compute path relative to invocation directory if available
         if invocation_dir is not None:
             try:
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -992,7 +992,7 @@ class TerminalReporter:
         for reprlocation_lines in rep.longrepr.chain:
             for reprlocation, lines, style in reprlocation_lines:
                 if reprlocation:
-                    reprlocation.toterminal(self._tw)
+                    reprlocation.toterminal(self._tw, self.config.invocation_dir)
             for line in lines:
                 self._tw.line(line)
 
@@ -1003,6 +1003,9 @@ class TerminalReporter:
             for line in rep.longrepr.splitlines():
                 self._tw.line(line)
         else:
-            rep.longrepr.toterminal(self._tw)
+            if hasattr(rep.longrepr, 'toterminal'):
+                rep.longrepr.toterminal(self._tw)
+            else:
+                self._tw.line(str(rep.longrepr))
 
     def _folded_skips(self) -> List[Tuple[int, str, Optional[int], str]]:
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -991,16 +991,7 @@ class TerminalReporter:
         if hasattr(rep.longrepr, "chain"):
             for reprlocation_lines in rep.longrepr.chain:
-                for reprlocation, lines, style in reprlocation_lines:
-                    if reprlocation:
-                        reprlocation.toterminal(self._tw, self.config.invocation_dir)
-                for line in lines:
-                    self._tw.line(line)
-
-            for line in rep.longrepr.chain[-1][1]:
-                self._tw.line(line)
-        elif isinstance(rep.longrepr, str):
-            for line in rep.longrepr.splitlines():
-                self._tw.line(line)
-        else:
-            if hasattr(rep.longrepr, 'toterminal'):
-                rep.longrepr.toterminal(self._tw)
-            else:
-                self._tw.line(str(rep.longrepr))
+            rep.longrepr.toterminal(self._tw)
+        elif isinstance(rep.longrepr, str):
+            for line in rep.longrepr.splitlines():
+                self._tw.line(line)
+        else:
+            rep.longrepr.toterminal(self._tw)
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -476,6 +476,7 @@ class ExceptionChainRepr(ExceptionRepr):
         super().__init__()
         self.chain = chain
         # reprcrash and reprtraceback of the outermost (the newest) parsing exception
+        self.invocation_dir = None
         self.reprtraceback = chain[-1][0]
         self.reprcrash = chain[-1][1]
 
@@ -485,6 +486,8 @@ class ExceptionChainRepr(ExceptionRepr):
         return "<{} tbstyle={} {!r}>".format(cls, style, self.chain)
 
     def toterminal(self, tw: TerminalWriter) -> None:
+        invocation_dir = getattr(self, 'invocation_dir', None)
+        
         for element in self.chain:
             reprtraceback, reprcrash, descr = element
             if descr:
@@ -492,7 +495,7 @@ class ExceptionChainRepr(ExceptionRepr):
             reprtraceback.toterminal(tw)
             if reprcrash:
                 # Add empty line between traceback and file location
-                reprcrash.toterminal(tw)
+                reprcrash.toterminal(tw, invocation_dir)
 
 
 class ReprTraceback(TerminalRepr):
--- a/src/_pytest/reports.py
+++ b/src/_pytest/reports.py
@@ -5,6 +5,7 @@ from typing import List
 from typing import Optional
 from typing import Tuple
 from typing import Union
+from pathlib import Path
 
 import py
 
@@ -131,6 +132,17 @@ class BaseReport:
             writer.line("")
         self.longrepr.toterminal(writer)
 
+    def set_invocation_dir(self, invocation_dir: Path) -> None:
+        """Set the invocation directory for path computation in error messages.
+        
+        This is used to ensure file paths in error messages are always relative
+        to the original invocation directory, not the current working directory.
+        """
+        if hasattr(self.longrepr, 'chain'):
+            self.longrepr.invocation_dir = invocation_dir
+        if hasattr(self.longrepr, 'reprcrash'):
+            self.longrepr.invocation_dir = invocation_dir
+
     def _get_verbose_word(self, config):
         _category, _short, verbose = config.hook.pytest_report_teststatus(
             report=self, config=config
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -994,6 +994,9 @@ class TerminalReporter:
         for rep in reports:
             if rep.outcome == "failed":
                 self._outrep_summary(rep)
+                if hasattr(rep.longrepr, 'invocation_dir'):
+                    rep.longrepr.invocation_dir = self.config.invocation_dir
+                self._outrep_summary(rep)
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -991,9 +991,11 @@ class TerminalReporter:
     def short_test_summary(self) -> None:
         if not self.reportchars:
             return
-
+        
         for rep in self._getfailures():
             msg = self._getfailrepr(rep)
+            if hasattr(rep.longrepr, 'invocation_dir'):
+                rep.longrepr.invocation_dir = self.config.invocation_dir
             self.write_sep("_", "FAILURES")
             for rep in self.stats.get("failed", []):
                 if self.verbosity <= 0:
@@ -1001,6 +1003,8 @@ class TerminalReporter:
                 else:
                     self._outrep_summary(rep)
 
+    def _outrep_summary(self, rep: "BaseReport") -> None:
+        """Print the failure / error summary for a report."""
         if hasattr(rep.longrepr, "chain"):
             rep.longrepr.toterminal(self._tw)
         elif isinstance(rep.longrepr, str):
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -982,6 +982,8 @@ class TerminalReporter:
                 self._tw.line(line)
 
     def _outrep_summary(self, rep: "BaseReport") -> None:
+        if hasattr(rep.longrepr, 'invocation_dir') and rep.longrepr.invocation_dir is None:
+            rep.longrepr.invocation_dir = self.config.invocation_dir
         rep.toterminal(self._tw)
 
     def summary_failures(self) -> None:
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -551,7 +551,7 @@ class ReprFileLocation(TerminalRepr):
         self.lineno = lineno
         self.message = message
 
-    def toterminal(self, tw: TerminalWriter, invocation_dir=None) -> None:
+    def toterminal(self, tw: TerminalWriter) -> None:
         # filename and samples of underline
         msg = self.message
         lineno = self.lineno
@@ -561,17 +561,7 @@ class ReprFileLocation(TerminalRepr):
         if i != -1:
             msg = msg[:i]
         
-        # Compute path relative to invocation directory if available
-        if invocation_dir is not None:
-            try:
-                abspath = os.path.abspath(path)
-                relpath = os.path.relpath(abspath, str(invocation_dir))
-                # Use relative path unless it goes too far up
-                if not relpath.startswith(".."):
-                    path = relpath
-                else:
-                    path = abspath
-            except (ValueError, OSError):
-                pass
-        
         tw.write(path, bold=True, red=True)
         tw.line(":{}: {}".format(self.lineno, msg))
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -485,7 +485,6 @@ class ExceptionChainRepr(ExceptionRepr):
         return "<{} tbstyle={} {!r}>".format(cls, style, self.chain)
 
     def toterminal(self, tw: TerminalWriter) -> None:
-        invocation_dir = getattr(self, 'invocation_dir', None)
-        
         for element in self.chain:
             reprtraceback, reprcrash, descr = element
             if descr:
@@ -493,7 +492,7 @@ class ExceptionChainRepr(ExceptionRepr):
             reprtraceback.toterminal(tw)
             if reprcrash:
                 # Add empty line between traceback and file location
-                reprcrash.toterminal(tw, invocation_dir)
+                reprcrash.toterminal(tw)
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -475,7 +475,6 @@ class ExceptionChainRepr(ExceptionRepr):
     ) -> None:
         super().__init__()
         self.chain = chain
-        self.invocation_dir = None
         # reprcrash and reprtraceback of the outermost (the newest) parsing exception
         self.reprtraceback = chain[-1][0]
         self.reprcrash = chain[-1][1]
--- a/src/_pytest/reports.py
+++ b/src/_pytest/reports.py
@@ -5,7 +5,6 @@ from typing import List
 from typing import Optional
 from typing import Tuple
 from typing import Union
-from pathlib import Path
 
 import py
 
@@ -132,17 +131,6 @@ class BaseReport:
             writer.line("")
         self.longrepr.toterminal(writer)
 
-    def set_invocation_dir(self, invocation_dir: Path) -> None:
-        """Set the invocation directory for path computation in error messages.
-        
-        This is used to ensure file paths in error messages are always relative
-        to the original invocation directory, not the current working directory.
-        """
-        if hasattr(self.longrepr, 'chain'):
-            self.longrepr.invocation_dir = invocation_dir
-        if hasattr(self.longrepr, 'reprcrash'):
-            self.longrepr.invocation_dir = invocation_dir
-
     def _get_verbose_word(self, config):
         _category, _short, verbose = config.hook.pytest_report_teststatus(
             report=self, config=config
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -982,8 +982,6 @@ class TerminalReporter:
                 self._tw.line(line)
 
     def _outrep_summary(self, rep: "BaseReport") -> None:
-        if hasattr(rep.longrepr, 'invocation_dir') and rep.longrepr.invocation_dir is None:
-            rep.longrepr.invocation_dir = self.config.invocation_dir
         rep.toterminal(self._tw)
 
     def summary_failures(self) -> None:
--- a/src/_pytest/nodes.py
+++ b/src/_pytest/nodes.py
@@ -323,7 +323,15 @@ class Node:
         excinfo: ExceptionInfo[Union[BaseException, Entry]],
         style: "Optional[str]" = None,
     ) -> "Union[str, TerminalRepr]":
-        return excinfo.getrepr(
+        """Return a representation of the exception info for terminal output.
+        
+        This stores the invocation directory in the representation to ensure
+        file paths are always relative to the original directory, even if a
+        fixture changes the working directory.
+        """
+        invocation_dir = self.config.invocation_dir
+        
+        repr_result = excinfo.getrepr(
             funcargs=True,
             abspath=False,
             showlocals=self.config.option.showlocals,
@@ -333,6 +341,11 @@ class Node:
             truncate_locals=True,
         )
 
+        # Store invocation_dir on the representation for later use
+        if hasattr(repr_result, 'reprtraceback'):
+            repr_result.invocation_dir = invocation_dir
+        return repr_result
+
     # Methods for ordering nodes
     @property
     def nodeid(self) -> str:
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -475,6 +475,7 @@ class ExceptionChainRepr(ExceptionRepr):
     ) -> None:
         super().__init__()
         self.chain = chain
+        self.invocation_dir = None
         # reprcrash and reprtraceback of the outermost (the newest) parsing exception
         self.reprtraceback = chain[-1][0]
         self.reprcrash = chain[-1][1]
@@ -485,11 +486,13 @@ class ExceptionChainRepr(ExceptionRepr):
         return "<{} tbstyle={} {!r}>".format(cls, style, self.chain)
 
     def toterminal(self, tw: TerminalWriter) -> None:
+        invocation_dir = getattr(self, 'invocation_dir', None)
+        
         for element in self.chain:
             reprtraceback, reprcrash, descr = element
             if descr:
                 tw.line(descr, yellow=True)
             reprtraceback.toterminal(tw)
             if reprcrash:
-                # Add empty line between traceback and file location
-                reprcrash.toterminal(tw)
+                reprcrash.toterminal(tw, invocation_dir)
 
 
 class ReprTraceback(TerminalRepr):
--- a/src/_pytest/_code/code.py
+++ b/src/_pytest/_code/code.py
@@ -551,7 +551,7 @@ class ReprFileLocation(TerminalRepr):
         self.lineno = lineno
         self.message = message
 
-    def toterminal(self, tw: TerminalWriter) -> None:
+    def toterminal(self, tw: TerminalWriter, invocation_dir=None) -> None:
         # filename and samples of underline
         msg = self.message
         lineno = self.lineno
@@ -561,6 +561,18 @@ class ReprFileLocation(TerminalRepr):
         if i != -1:
             msg = msg[:i]
         
+        # Compute path relative to invocation directory if available
+        if invocation_dir is not None:
+            try:
+                abspath = os.path.abspath(path)
+                relpath = os.path.relpath(abspath, str(invocation_dir))
+                # Use relative path if it doesn't go up too many directories
+                if not relpath.startswith(".."):
+                    path = relpath
+                else:
+                    path = abspath
+            except (ValueError, OSError):
+                pass
+        
         tw.write(path, bold=True, red=True)
         tw.line(":{}: {}".format(self.lineno, msg))