using System.Text.Json; namespace decePubClient.E2E.Support { // Each render and action test is also a cell of the town's matrix, appended to the pasture's out/client.jsonl in the // cell format town.sh check writes, so report.html shows decePub next to the servers. public static class Results { static readonly object Gate = new(); static readonly string FilePath = Path.Combine(Pasture.Root, "out", "client.jsonl"); public static async Task Cell(string feature, string origin, string reference, Func test) => await Cell(feature, origin, reference, test, page: null); // with a page, a failure also leaves its screenshot and text in the test output's .state/ (SignIn.Evidence) public static async Task Cell(string feature, string origin, string reference, Func test, Microsoft.Playwright.IPage page) { var ok = false; string got = null; try { await test(); ok = true; } catch (Exception e) { got = e.Message.Length > 400 ? e.Message[..400] : e.Message; if (page is not null) await SignIn.Evidence(page, $"{feature}-{origin}-{reference}".Replace('/', '_').Replace('@', '_')); throw; } finally { var line = JsonSerializer.Serialize(new { source = "client", cell = $"{feature}|{origin}|decepub|{(origin == "privapub" ? "local" : "in")}", feature, origin, observer = "decepub", direction = origin == "privapub" ? "local" : "in", ok, @ref = reference, got, t = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ") }); lock (Gate) { Directory.CreateDirectory(Path.GetDirectoryName(FilePath)!); File.AppendAllText(FilePath, line + "\n"); } } } } }