YamlImportTests.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using Microsoft.Playwright;
  2. using Tests.E2e.Infra;
  3. using Tests.E2e.PageObjectModels;
  4. using Xunit.Abstractions;
  5. namespace Tests.E2e;
  6. /// <summary>
  7. /// Coverage for /yaml/import and the /yaml config view.
  8. /// Issue #308: connections in an imported document were parsed but silently
  9. /// dropped — they never showed in the preview and never reached the config.
  10. /// The preview assertions here are the regression guard; the /yaml
  11. /// round-trip proves the connection actually persisted.
  12. /// </summary>
  13. public class YamlImportTests(
  14. PlaywrightFixture fixture,
  15. ITestOutputHelper output) : E2ETestBase(fixture, output) {
  16. private readonly PlaywrightFixture _fixture = fixture;
  17. private readonly ITestOutputHelper _output = output;
  18. private static string TwoSwitchesWithConnection(string switchA, string switchB) =>
  19. $"""
  20. version: 3
  21. resources:
  22. - kind: Switch
  23. name: {switchA}
  24. ports:
  25. - type: rj45
  26. speed: 1
  27. count: 4
  28. - kind: Switch
  29. name: {switchB}
  30. ports:
  31. - type: rj45
  32. speed: 1
  33. count: 4
  34. connections:
  35. - a:
  36. resource: {switchA}
  37. portGroup: 0
  38. portIndex: 0
  39. b:
  40. resource: {switchB}
  41. portGroup: 0
  42. portIndex: 0
  43. """;
  44. // =============================================================
  45. // Connections reach the preview (issue #308 regression)
  46. // =============================================================
  47. [Fact]
  48. public async Task Import_Preview_Lists_Connections_From_The_Document() {
  49. (IBrowserContext context, IPage page) = await CreatePageAsync();
  50. var switchA = $"e2e-ia-{Guid.NewGuid():N}"[..14];
  51. var switchB = $"e2e-ib-{Guid.NewGuid():N}"[..14];
  52. try {
  53. var import = new YamlImportPom(page);
  54. await import.GotoAsync(_fixture.BaseUrl);
  55. await import.PasteAsync(TwoSwitchesWithConnection(switchA, switchB));
  56. await import.AssertNoErrorAsync();
  57. // Before the #308 fix this section never rendered: the connection
  58. // was dropped between parsing and the diff.
  59. await import.AssertConnectionsSummaryVisibleAsync();
  60. await Assertions.Expect(import.ConnectionsAdded).ToHaveCountAsync(1);
  61. await import.AssertConnectionAddedContainsAsync(switchA);
  62. await import.AssertConnectionAddedContainsAsync(switchB);
  63. }
  64. catch (Exception) {
  65. await DumpAsync(page);
  66. throw;
  67. }
  68. finally {
  69. await context.CloseAsync();
  70. }
  71. }
  72. // =============================================================
  73. // Applying the import persists the connection
  74. // =============================================================
  75. [Fact]
  76. public async Task Applying_An_Import_Persists_Resources_And_Their_Connection() {
  77. (IBrowserContext context, IPage page) = await CreatePageAsync();
  78. var switchA = $"e2e-pa-{Guid.NewGuid():N}"[..14];
  79. var switchB = $"e2e-pb-{Guid.NewGuid():N}"[..14];
  80. try {
  81. var import = new YamlImportPom(page);
  82. await import.GotoAsync(_fixture.BaseUrl);
  83. await import.PasteAsync(TwoSwitchesWithConnection(switchA, switchB));
  84. await import.AssertNoErrorAsync();
  85. await import.ApplyAsync();
  86. // The saved config is the source of truth — read it back rather
  87. // than trusting the preview we just asserted on.
  88. await page.GotoAsync($"{_fixture.BaseUrl}/yaml");
  89. ILocator yaml = page.GetByTestId("yaml-file-content");
  90. await Assertions.Expect(yaml).ToBeVisibleAsync();
  91. await Assertions.Expect(yaml).ToContainTextAsync(switchA);
  92. await Assertions.Expect(yaml).ToContainTextAsync(switchB);
  93. await Assertions.Expect(yaml).ToContainTextAsync("connections:");
  94. }
  95. catch (Exception) {
  96. await DumpAsync(page);
  97. throw;
  98. }
  99. finally {
  100. await context.CloseAsync();
  101. }
  102. }
  103. // =============================================================
  104. // Malformed input is reported, not swallowed
  105. // =============================================================
  106. [Fact]
  107. public async Task Import_Surfaces_An_Error_For_Malformed_Yaml() {
  108. (IBrowserContext context, IPage page) = await CreatePageAsync();
  109. try {
  110. var import = new YamlImportPom(page);
  111. await import.GotoAsync(_fixture.BaseUrl);
  112. // Unclosed bracket — a parser error rather than a schema violation.
  113. await import.PasteAsync("""
  114. version: 3
  115. resources: [
  116. - kind: Switch
  117. """);
  118. await import.AssertErrorShownAsync();
  119. // A broken document must not be applyable.
  120. await Assertions.Expect(import.ApplyButton).ToBeDisabledAsync();
  121. }
  122. catch (Exception) {
  123. await DumpAsync(page);
  124. throw;
  125. }
  126. finally {
  127. await context.CloseAsync();
  128. }
  129. }
  130. private async Task DumpAsync(IPage page) {
  131. _output.WriteLine("TEST FAILED — Capturing diagnostics");
  132. _output.WriteLine($"Current URL: {page.Url}");
  133. var html = await page.ContentAsync();
  134. _output.WriteLine("==== DOM SNAPSHOT START ====");
  135. _output.WriteLine(html);
  136. _output.WriteLine("==== DOM SNAPSHOT END ====");
  137. }
  138. }