Browser type and automation engine are settings, not structure, so running a workflow on every combination is a loop rather than a rewrite. Put the workflow in a method that takes the browser type, the engine, and whether to run headless, and the harness around it is a few lines. Skip the combinations that do not exist, such as Puppeteer driving Firefox, and skip the engine variants that do not change what the workflow is testing, such as the hardware and javascript click variants when nothing in the run clicks anything. Time each pass with a Stopwatch and count what the pass actually produced, because a run that finishes without throwing is not the same as a run that did the job.
foreach (BrowserType browserType in Enum
{
if (BrowserType
&& BrowserType
&& BrowserType
foreach (AutomationEngine engine in Enum
{
// puppeteer does not drive firefox
if (AutomationEngine
for (int headlessMode = 0; 2 > headlessMode; headlessMode++)
{
bool headless = (1 == headlessMode);
Stopwatch runStopwatch = Stopwatch
priced = 0;
PriceTheFestival(browserType, engine, headless, nights);
runStopwatch
(headless ? headlessRuntimes : windowRuntimes)[(browserType, engine)] = runStopwatch
(headless ? headlessPriced : windowPriced)[(browserType, engine)] = priced;
}
}
}
A dictionary keyed by a (row, column) tuple is already a table, so EmitTable prints it as one: row keys down the side, column keys across the top, one cell each, and a dash where a combination was never run. Rows and columns come out in the natural order of the key type, which for an enum is the order it is declared in, so the table reads the same way every time. The whole table is published as a single INFO event, which means it lands wherever the run's events already go: the console, a log file, the log tab of a form. EmitRuntimeTable is the same call with the formatting already chosen for elapsed times, since timing a matrix is what the pattern is mostly used for.
GPAL
GPAL
// Any two-axis dictionary, with the cell formatted however it reads best
GPAL
// Window runtime (min:sec
// Browser | OttoMagic | PuppeteerPort | Selenium
// Chrome | 1:04
// Edge | - | 0:44
// FireFox | - | - | 1:12
Emit two tables when the run has something to count: one for how long each combination took, one for how much each combination actually got. A combination that finishes fast and returns nothing is a failure that looks like a win in a timing table on its own.
Every feature in GPAL is expected to work on all three engines. The matrix is how that claim gets checked rather than assumed, and it is worth running whenever a workflow is finished, not just when something looks wrong. Differences it surfaces are usually real: an engine that cannot reach a closed shadow root, a headless run the site treats differently, a browser whose driver is behind its own version. Those are all better found by a table than by a support ticket.
Every combination repeats the whole workflow against the real site. A three-browser, three-engine, two-mode matrix is eighteen full runs, which is enough to get rate limited on a site that would never notice a single pass. Run the full matrix deliberately, and keep a single combination as the default for everyday work.
Showing off some plain text in these paragraphs eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Here you can find different accents and emphasis sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
This is a link and how it could look like bestlinkinthebeautifulworld. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Here's just some classic bold text adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam notBoldSecondbestlinkinthebeautifulworld illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at adipisicing elit libero vel voluptas? Expedita, adipisicing facere dolores voluptatem ad ab rem assumenda soluta!
Other cuple of colors in case we want to emphasize several ways adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at voluptatem libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae quas consequuntur illo numquam assumenda autem exercitationem distinctio perspiciatis in natus. Eius dicta similique ipsam ipsa minima, nemo quae enim tempore.
GPAL
.CallIfNotFound(GenericCallIfNotFound)
.WithPublishToConsole();
//System.Drawing.Rectangle windowSize = new System.Drawing.Rectangle(10, 10, 1500, 1024);
// NOTE: we have to set browser = before we execute any steps
// this is due to the 'GenericCallIfNotFound' which might throw an exception, and BankScraper will not have the browser set when it calls scraper.Close()
// until the complete fluent line gets executed (meaning every step, meaning browser is not set until everything else succeeds)
browser = GPAL.Browser
.WithBrowserType(Enums.BrowserType.Chrome)
.WithProfileDataDirectory(ChromeProfileLocation)
.WithUseAutomationEngine(AutomationEngine.Selenium)
.WithWindowSize(new System.Drawing.Rectangle(0,0,1920,1080))
.ToGPALObject();