1+ using System ;
2+ using System . Threading ;
3+ using System . Threading . Tasks ;
4+ using OpenQA . Selenium ;
5+ using OpenQA . Selenium . Remote ;
6+ using static CSF . Screenplay . Selenium . PerformableBuilder ;
7+
8+ namespace CSF . Screenplay . Selenium . Tasks
9+ {
10+ /// <summary>
11+ /// Determines whether the current actor needs to use a JS technique to collect web browser console logs.
12+ /// If they do, executes the action which begins collecting them.
13+ /// </summary>
14+ /// <remarks>
15+ /// <para>
16+ /// When used, this action should be executed as soon as possible after the current page has completed loading.
17+ /// Ideally, directly after <see cref="ClickAndWaitForDocumentReady"/> and <see cref="Actions.OpenUrl"/>.
18+ /// This Task decides whether it is appropriate to make use of <see cref="Actions.BeginCollectingLogsWithJavaScript"/>
19+ /// action, invoking it if appropriate.
20+ /// </para>
21+ /// <para>
22+ /// Note that this action/the script needs to be re-run after each traditional web page navigation/reload.
23+ /// However, due to the nature of SPAs, it <em>does not need to be re-run</em> following an SPA-style navigation.
24+ /// On supported browsers, there is no harm in re-running this script when it is not needed, except for the impact on
25+ /// performance (wasted network roundtrips).
26+ /// </para>
27+ /// <para>
28+ /// The logic used by this task is:
29+ /// </para>
30+ /// <list type="bullet">
31+ /// <item><description>If the actor's <see cref="BrowseTheWeb"/> ability has <see cref="BrowseTheWeb.ShouldCollectLogs"/>
32+ /// set to <see langword="false"/> then the JavaScript technique <em>will not</em> be used.</description></item>
33+ /// <item><description>If the actor's <see cref="BrowseTheWeb"/> ability has the quirk <see cref="BrowserQuirks.HasNativeLogsSupport"/>
34+ /// <em>and</em> the implementation of <see cref="IWebDriver"/> is not a <see cref="RemoteWebDriver"/> then the JavaScript
35+ /// technique <em>will not</em> be used.</description></item>
36+ /// <item><description>If the <see cref="IWebDriver"/> does not have the quirk <see cref="BrowserQuirks.CanGetLogsWithJavascriptWorkaround"/>
37+ /// then the JavaScript technique <em>will not</em> be used.</description></item>
38+ /// <item><description>Otherwise, <see cref="BrowseTheWeb.ShouldCollectLogs"/> is <see langword="true"/>, the <see cref="IWebDriver"/>
39+ /// has the quirk <see cref="BrowserQuirks.CanGetLogsWithJavascriptWorkaround"/> and does not have a better way to get the logs, then the
40+ /// JavaScript technique <em>will be used</em>.</description></item>
41+ /// </list>
42+ /// <para>
43+ /// Note that <em><see cref="RemoteWebDriver"/> instances cannot collect the logs natively</em>. This is because the WebDriver remote protocol
44+ /// does not support this functionality. Web Drivers which support it locally cannot do so remotely. See
45+ /// <see href="https://github.com/w3c/webdriver/issues/1428">this issue about logging being missing from the w3c WebDriver standard</see>
46+ /// and the signposted <see href="https://www.w3.org/2018/10/25-webdriver-minutes.html#item05">minutes from this meeting</see> for more info.
47+ /// </para>
48+ /// </remarks>
49+ public class BeginCollectingLogsWithJavaScriptIfApplicable : IPerformable , ICanReport
50+ {
51+ /// <inheritdoc/>
52+ public ReportFragment GetReportFragment ( Actor actor , IFormatsReportFragment formatter )
53+ {
54+ var shouldPerform = ShouldCollectLogsWithJavaScript ( actor ) ;
55+ return formatter . Format ( "{Actor} chooses whether they should collect web browser console logs using JavaScript; {Outcome}" ,
56+ actor ,
57+ shouldPerform ? "they should" : "they should not" ) ;
58+
59+ }
60+
61+ /// <inheritdoc/>
62+ public async ValueTask PerformAsAsync ( ICanPerform actor , CancellationToken cancellationToken = default )
63+ {
64+ var shouldPerform = ShouldCollectLogsWithJavaScript ( actor ) ;
65+ if ( ! shouldPerform ) return ;
66+
67+ await actor . PerformAsync ( BeginCollectingLogsWithJavaScript ( ) , cancellationToken ) ;
68+ }
69+
70+ /// <summary>
71+ /// Gets a value indicating whether the specified actor should use the JavaScript technique to get browser logs.
72+ /// </summary>
73+ /// <remarks>
74+ /// <para>
75+ /// See the remarks for this type for more information about that logic.
76+ /// </para>
77+ /// </remarks>
78+ /// <param name="actor">The actor</param>
79+ /// <returns><see langword="true"/> if the JavaScript technique for log collection is applicable; <see langword="false"/> if not.</returns>
80+ public static bool ShouldCollectLogsWithJavaScript ( ICanPerform actor )
81+ {
82+ var browseTheWeb = actor . GetAbility < BrowseTheWeb > ( ) ;
83+ return ShouldCollectLogsWithJavaScript ( browseTheWeb ) ;
84+ }
85+
86+ /// <summary>
87+ /// Gets a value indicating whether the specified browse the web ability should use the JavaScript technique to get browser logs.
88+ /// </summary>
89+ /// <remarks>
90+ /// <para>
91+ /// See the remarks for this type for more information about that logic.
92+ /// </para>
93+ /// </remarks>
94+ /// <param name="browseTheWeb">The ability</param>
95+ /// <returns><see langword="true"/> if the JavaScript technique for log collection is applicable; <see langword="false"/> if not.</returns>
96+ public static bool ShouldCollectLogsWithJavaScript ( BrowseTheWeb browseTheWeb )
97+ {
98+ if ( ! browseTheWeb . ShouldCollectLogs ) return false ;
99+
100+ return browseTheWeb . WebDriver . HasQuirk ( BrowserQuirks . CanGetLogsWithJavascriptWorkaround )
101+ && ( ! browseTheWeb . WebDriver . HasQuirk ( BrowserQuirks . HasNativeLogsSupport )
102+ || browseTheWeb . WebDriver . Unproxy ( ) is RemoteWebDriver ) ;
103+ }
104+ }
105+ }
0 commit comments