Expose which test methods cover a line of apex

Issue #1352 resolved
James Melville created an issue

When test methods have been run in IC2 a green or red marker is added to the gutter. Clicking on the marker gives a small widget which shows the text “Hits: 1” if the code is covered by one or more test method(s) (i.e. it’s always 1 even when covered by multiple test methods).

It would be really useful if the text actually showed a list of test methods (with their class name (and namespace?)) which cover this line number. The list should be clickable so I can navigate directly to the test method.

Bonus points:

Provide a picker like dev console which allows you to choose which methods (or all) is used in coverage highlighting. Which method is selected should not affect the previous methods per line functionality.

Comments (6)

  1. Scott Wells repo owner

    One thing to point out about this implementation is that it'll always show "Hits: 1" even when there are multiple hits because the more detailed ApexCoverage information that includes the invoking test correlation details is queried lazily when you click Show Tests Covering Line. It's prohibitively expensive to query large that object on a large scale, so the normal coverage view still uses ApexCodeCoverageAggregate which doesn't include hit-level information, just whether a line has been covered or not.

  2. Scott Wells repo owner

    Delivered in 2.1.4.2 with the previously-stated caveat that it doesn't work in 2020.2, though JetBrains has now stated that the underlying problem will be fixed in 2020.3 (including the next 2020.3 EAP build).

  3. James Melville reporter

    Hi Scott, thanks for doing this work! I’m now on WebStorm 2020.3, Build #WS-203.5981.135, built on November 27, 2020 with IC2.1.5.2, and when I click “Show tests covering line” nothing happens. I’m guessing because https://youtrack.jetbrains.com/issue/IDEA-251691 is still “In Progress” and didn’t make 2020.3? My idea.log shows an almost identical stack trace:

    java.lang.NullPointerException
        at com.intellij.openapi.editor.impl.EditorMarkupModelImpl$5.beforeActionPerformed(EditorMarkupModelImpl.java:324)
        at jdk.internal.reflect.GeneratedMethodAccessor216.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at com.intellij.util.messages.impl.MessageBusImpl.invokeListener(MessageBusImpl.java:652)
        at com.intellij.util.messages.impl.MessageBusImpl.access$300(MessageBusImpl.java:33)
        at com.intellij.util.messages.impl.MessageBusImpl$MessagePublisher.executeOrAddToQueue(MessageBusImpl.java:218)
        at com.intellij.util.messages.impl.CompositeMessageBus$ToDirectChildrenMessagePublisher.publish(CompositeMessageBus.java:113)
        at com.intellij.util.messages.impl.MessageBusImpl$MessagePublisher.invoke(MessageBusImpl.java:185)
        at com.sun.proxy.$Proxy148.beforeActionPerformed(Unknown Source)
        at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.fireBeforeActionPerformed(ActionManagerImpl.java:1535)
        at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:172)
        at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:160)
        at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:477)
        at java.desktop/java.awt.Component.processEvent(Component.java:6417)
        at java.desktop/java.awt.Container.processEvent(Container.java:2263)
        at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5027)
        at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
        at java.desktop/java.awt.Component.dispatchEvent(Component.java:4859)
        at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
        at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
        at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
        at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
        at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
        at java.desktop/java.awt.Component.dispatchEvent(Component.java:4859)
        at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
        at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
        at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
        at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
        at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:976)
        at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:911)
        at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:840)
        at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8(IdeEventQueue.java:454)
        at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:773)
        at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$9(IdeEventQueue.java:453)
        at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:822)
        at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:507)
        at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    

  4. Scott Wells repo owner

    It's the exact same behavior that I was seeing in 2020.2 and the EAP builds of 2020.3 that JetBrains thought they'd fixed. I just updated the JetBrains issue linked above stating that it's not in fact fixed. Hopefully they'll work the proper fix into a near-term patch for 2020.3.

  5. Log in to comment