Compare commits

..

2 Commits

Author SHA1 Message Date
cesnimda 5e431421aa feat(discovery): move mobile filters into accessible drawer 2026-11-11 07:05:29 +01:00
cesnimda b29c78e86d fix(i18n): sort discovery titles using selected UI locale 2026-11-10 23:16:58 +01:00
283 changed files with 73 additions and 9253 deletions
@@ -1,206 +0,0 @@
using JobTrackerApi.Controllers;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class RuleSettingsFreshnessTests
{
[Theory]
[InlineData("list")]
[InlineData("board")]
[InlineData("detail")]
[InlineData("reminders")]
[InlineData("readiness")]
public async Task Saved_owner_thresholds_are_visible_on_the_next_read(string surface)
{
await using var fixture = await Fixture.CreateAsync();
await using var read = fixture.Context("owner-a");
var controller = fixture.Controller(read);
Assert.False(await FollowUp(controller, fixture.JobA, surface));
await using (var write = fixture.Context("owner-a"))
Assert.IsType<NoContentResult>(await new RulesController(write).Update(Settings(1), default));
// Reuse the reader after the committed write: tracked entities must not mask persistence.
Assert.True(await FollowUp(controller, fixture.JobA, surface));
}
[Fact]
public async Task Saving_owner_a_preserves_owner_b_and_existing_readers_see_subsequent_writes()
{
await using var fixture = await Fixture.CreateAsync();
await using var a = fixture.Context("owner-a");
await using var b = fixture.Context("owner-b");
var ca = fixture.Controller(a);
var cb = fixture.Controller(b);
Assert.False(await FollowUp(ca, fixture.JobA, "list"));
Assert.False(await FollowUp(cb, fixture.JobB, "list"));
await using (var write = fixture.Context("owner-a"))
await new RulesController(write).Update(Settings(1), default);
Assert.True(await FollowUp(ca, fixture.JobA, "list"));
Assert.False(await FollowUp(cb, fixture.JobB, "list"));
// A later write in the opposite direction must also be visible through both old/new controllers.
await using (var write = fixture.Context("owner-a"))
await new RulesController(write).Update(Settings(30), default);
await using var fresh = fixture.Context("owner-a");
Assert.False(await FollowUp(fixture.Controller(fresh), fixture.JobA, "list"));
Assert.False(await FollowUp(ca, fixture.JobA, "list"));
}
[Fact]
public async Task Completing_an_older_request_cannot_restore_old_rules_after_a_save()
{
await using var fixture = await Fixture.CreateAsync();
await using var oldRead = fixture.Context("owner-a");
var reached = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
var release = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
var users = TestHostFactory.CreateUserManager();
users.Setup(x => x.FindByIdAsync("owner-a")).Returns(async () =>
{
// GetById has already loaded/evaluated the old rules; no model is called.
reached.TrySetResult(true);
await release.Task;
return (ApplicationUser?)null;
});
var older = new JobApplicationsController(oldRead, Mock.Of<ISummarizerService>(), users.Object)
{
ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "owner-a") }, "test")),
} },
};
var pending = FollowUp(older, fixture.JobA, "detail");
try
{
await reached.Task.WaitAsync(TimeSpan.FromSeconds(10));
await using (var write = fixture.Context("owner-a"))
await new RulesController(write).Update(Settings(1), default);
await using var freshRead = fixture.Context("owner-a");
var fresh = fixture.Controller(freshRead);
Assert.True(await FollowUp(fresh, fixture.JobA, "list"));
release.TrySetResult(true);
Assert.False(await pending); // A request begun before the save may return its earlier snapshot.
Assert.True(await FollowUp(fresh, fixture.JobA, "list"));
}
finally
{
release.TrySetResult(true);
await pending;
}
}
[Fact]
public async Task Global_save_refreshes_fallback_but_preserves_explicit_owner_override()
{
await using var fixture = await Fixture.CreateAsync();
await using (var setup = fixture.Context("owner-a"))
{
setup.UserRuleSettings.Remove(await setup.UserRuleSettings.SingleAsync());
await setup.SaveChangesAsync();
}
await using var fallback = fixture.Context("owner-a");
await using var overridden = fixture.Context("owner-b");
var ca = fixture.Controller(fallback);
var cb = fixture.Controller(overridden);
Assert.False(await FollowUp(ca, fixture.JobA, "list"));
Assert.False(await FollowUp(cb, fixture.JobB, "list"));
await using (var global = fixture.Context(null))
Assert.IsType<NoContentResult>(await new RulesController(global).Update(Settings(1), default));
Assert.True(await FollowUp(ca, fixture.JobA, "list"));
Assert.False(await FollowUp(cb, fixture.JobB, "list"));
}
private static RuleSettings Settings(int followUp) => new()
{
AppliedFollowUpDays = followUp, AppliedGhostDays = 365,
OfferFollowUpDays = 30, OfferGhostDays = 365,
FeedbackFollowUpDays = 30, FeedbackGhostDays = 365,
};
private static async Task<bool> FollowUp(JobApplicationsController controller, int id, string surface)
{
if (surface == "readiness")
{
var result = await controller.GetReadiness(id, default);
return Assert.IsType<ReadinessDto>(Assert.IsType<OkObjectResult>(result.Result).Value).WorkflowSignal.NeedsFollowUpAction;
}
if (surface == "detail")
{
var result = await controller.GetById(id, default);
return Assert.IsType<JobApplicationDto>(Assert.IsType<OkObjectResult>(result.Result).Value).NeedsFollowUp;
}
if (surface == "list")
{
var result = await controller.GetAll();
return Assert.Single(Assert.IsType<PagedResult<JobApplicationDto>>(Assert.IsType<OkObjectResult>(result.Result).Value).Items).NeedsFollowUp;
}
if (surface == "board")
{
var result = await controller.GetBoard(needsFollowUp: true);
return Assert.IsType<List<JobApplication>>(Assert.IsType<OkObjectResult>(result.Result).Value).Any(job => job.Id == id);
}
var response = await controller.GetReminders();
var jobs = Assert.IsType<List<JobApplicationDto>>(Assert.IsType<OkObjectResult>(response.Result).Value);
return jobs.SingleOrDefault(job => job.Id == id)?.NeedsFollowUp ?? false;
}
private sealed class Fixture : IAsyncDisposable
{
private readonly SqliteConnection _connection = new("Data Source=:memory:");
public int JobA { get; private set; }
public int JobB { get; private set; }
public JobTrackerContext Context(string? owner)
{
var user = new Mock<ICurrentUserService>();
user.SetupGet(x => x.UserId).Returns(owner);
return new JobTrackerContext(new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(_connection).Options, user.Object);
}
public JobApplicationsController Controller(JobTrackerContext db) =>
new(db, Mock.Of<ISummarizerService>(), TestHostFactory.CreateUserManager().Object);
public static async Task<Fixture> CreateAsync()
{
var fixture = new Fixture();
await fixture._connection.OpenAsync();
await using var db = fixture.Context("owner-a");
await db.Database.EnsureCreatedAsync();
db.Users.AddRange(new ApplicationUser { Id = "owner-a", UserName = "owner-a" }, new ApplicationUser { Id = "owner-b", UserName = "owner-b" });
var global = await db.RuleSettings.SingleAsync();
global.AppliedFollowUpDays = 30;
global.AppliedGhostDays = 365;
foreach (var owner in new[] { "owner-a", "owner-b" })
{
await using var owned = fixture.Context(owner);
owned.UserRuleSettings.Add(new UserRuleSettings { OwnerUserId = owner, AppliedFollowUpDays = 30, AppliedGhostDays = 365 });
// Complete package avoids unrelated package-gap reminders masking the rule decision.
var job = new JobApplication
{
OwnerUserId = owner, Company = new Company { Name = owner, OwnerUserId = owner },
JobTitle = "Synthetic engineer", Status = "Applied", DateApplied = DateTime.Now.AddDays(-10), FollowUpAt = DateTime.Now.AddDays(100),
TailoredCvText = "Synthetic CV", Notes = "<<<APPLICATION_ANSWER_DRAFT>>>\nSynthetic answer\n<<<END_APPLICATION_ANSWER_DRAFT>>>",
};
owned.JobApplications.Add(job);
// Users must exist before owner-scoped rows are inserted.
await db.SaveChangesAsync();
await owned.SaveChangesAsync();
if (owner == "owner-a") fixture.JobA = job.Id; else fixture.JobB = job.Id;
}
return fixture;
}
public async ValueTask DisposeAsync()
{
await _connection.DisposeAsync();
}
}
}
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
@@ -30,9 +31,10 @@ namespace JobTrackerApi.Controllers
private readonly ICvTemplateRenderer _cvTemplateRenderer;
private readonly ICvPdfExporter _cvPdfExporter;
private readonly IJobCvMatchService _matchService;
private readonly IMemoryCache _cache;
private readonly IApplicationChecklistService _checklist;
public JobApplicationsController(JobTrackerContext db, ISummarizerService summarizer, UserManager<ApplicationUser> users, ICvTemplateRenderer? cvTemplateRenderer = null, ICvPdfExporter? cvPdfExporter = null, IJobCvMatchService? matchService = null, IApplicationChecklistService? checklist = null)
public JobApplicationsController(JobTrackerContext db, ISummarizerService summarizer, UserManager<ApplicationUser> users, ICvTemplateRenderer? cvTemplateRenderer = null, ICvPdfExporter? cvPdfExporter = null, IJobCvMatchService? matchService = null, IMemoryCache? cache = null, IApplicationChecklistService? checklist = null)
{
_checklist = checklist ?? new ApplicationChecklistService(db);
_db = db;
@@ -41,6 +43,21 @@ namespace JobTrackerApi.Controllers
_cvTemplateRenderer = cvTemplateRenderer ?? new CvTemplateRenderer();
_cvPdfExporter = cvPdfExporter ?? new ThrowingCvPdfExporter();
_matchService = matchService ?? new JobCvMatchService();
_cache = cache ?? new MemoryCache(new MemoryCacheOptions());
}
// ponytail: RulesEngine.GetSettings is per-user (falls back to the global RuleSettings
// singleton only when the user has no override), so the cache key must include the
// current user id -- a single global key would leak one user's follow-up rules to another.
private async Task<RuleSettings> GetCachedRuleSettingsAsync(CancellationToken cancellationToken)
{
var cacheKey = $"rulesettings:{_db.CurrentUserId ?? "anon"}";
var cached = await _cache.GetOrCreateAsync(cacheKey, async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
return await RulesEngine.GetSettings(_db, cancellationToken);
});
return cached!;
}
private sealed class ThrowingCvPdfExporter : ICvPdfExporter
@@ -522,7 +539,7 @@ Canonical profile:
query = query.Where(j => j.Location != null && EF.Functions.Like(j.Location, like));
}
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
var now = DateTime.Now;
Task<Dictionary<int, DateTime?>> LoadLatestMessagesAsync(IQueryable<Correspondence> messages) => messages
@@ -633,7 +650,7 @@ Canonical profile:
if (job is null) return NotFound();
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
var now = DateTime.Now;
var lm = await _db.Correspondences
.AsNoTracking()
@@ -676,7 +693,7 @@ Canonical profile:
if (upcomingDays < 1) upcomingDays = 1;
if (upcomingDays > 90) upcomingDays = 90;
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
var now = DateTime.Now;
var upcomingTo = now.AddDays(upcomingDays);
@@ -822,7 +839,7 @@ Canonical profile:
.Include(j => j.Company)
.FirstAsync(j => j.Id == job.Id, cancellationToken);
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
var followUp = RulesEngine.Evaluate(settings, created, DateTime.Now, lastMessageAt: null);
return CreatedAtAction(nameof(GetById), new { id = created.Id }, BuildJobApplicationDto(created, followUp));
}
@@ -1012,7 +1029,7 @@ Canonical profile:
await _db.SaveChangesAsync(cancellationToken);
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
var lastMsg = await _db.Correspondences
.AsNoTracking()
.Where(c => c.JobApplicationId == id)
@@ -1366,7 +1383,7 @@ Candidate CV/profile:
.FirstOrDefaultAsync(j => j.Id == id, cancellationToken);
if (job is null) return NotFound();
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
var now = DateTime.Now;
var lastMessageAt = await _db.Correspondences
.AsNoTracking()
@@ -1,25 +0,0 @@
# PERF-01 Rules settings freshness
Source baseline: `9c9fe48d5f321c653049f09ced5b7e27701fe2a8`; isolated branch `codex/perf-rules-freshness`.
Successful Rules settings saves previously left the API's owner-keyed 30-second cache unchanged. Settings could therefore display the saved values while Applications, Board filtering, details, reminders and readiness continued using old thresholds. Invalidating only the owner's entry would also miss global-fallback dependencies and permit an older asynchronous cache fill to repopulate stale data.
The job controller now reads through the existing `RulesEngine.GetSettings` owner/fallback implementation on each request. There is no rules cache to repopulate, including across separate API processes. Existing database/query-filter contracts and global `AddMemoryCache` remain unchanged. The unused optional constructor cache argument is removed; the following optional checklist argument retains its name and all existing callers compile. Create and AI-refresh responses share the same corrected settings read; neither endpoint is activated by these tests.
The cost is one owner-primary-key settings lookup per job request, plus a singleton lookup when no override exists. This correctness fix is not a measured latency or throughput improvement. No distributed invalidation infrastructure was introduced. A read begun before a committed update may return its earlier snapshot; a completed older response cannot cache that snapshot for later requests.
## Verification
- **RED:** Seven real SQLite cases with a shared `MemoryCache` failed before the application change, all with expected `True` / actual `False` at the post-save freshness assertion. These cover list, Board follow-up filtering, detail, reminders, readiness, owner isolation and global fallback. Local receipt: `JobTrackerApi.Tests/TestResults/rules-red.trx`.
- **PASSED:** The final focused regression run passed **35 distinct tests**, including eight new freshness cases, plus query parity, workflow signals, prospect rules and concurrent initialization. The eighth case pauses an older detail request at a mock identity lookup after rule evaluation, saves new rules, verifies a fresh request, completes the older response and verifies another fresh read. This uses no model or provider. Local receipt: `JobTrackerApi.Tests/TestResults/rules-regression.trx`.
- **PASSED:** `dotnet build "Job tracker.sln" --no-restore --verbosity quiet`: zero warnings/errors.
- **PASSED:** `git diff --check`.
- **PASSED:** `graphify update .` rebuilt the local AST graph without API/model use. It reported missing optional PDF/SQL parsers and files without extracted symbols; those are graph coverage limits, not application test failures. Generated `graphify-out/` remains local and untracked, as at the source worktree.
Durable machine-readable red/final result names, outcomes, counts and timestamps: [verification.json](evidence/rules-freshness/verification.json). Exact native red, development-green and final-regression TRX files are preserved as `.trx.gz` files alongside it. [native-receipts.json](evidence/rules-freshness/native-receipts.json) records raw/compressed SHA256 hashes and byte lengths; gzip decompression reproduces the original receipts without text transformations. The seven-test development-green run overlaps the final regression run.
Commands use the installed `C:\Users\Connor\.dotnet\dotnet.exe` SDK; the runtime-only Program Files executable cannot execute SDK commands. Test command: `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --no-restore --filter "FullyQualifiedName~RuleSettingsFreshnessTests|FullyQualifiedName~JobQueryParityTests|FullyQualifiedName~JobApplicationsWorkflowSignalsTests|FullyQualifiedName~RulesEngineProspectTests|FullyQualifiedName~ConcurrentInitializationTests"`.
## Limits and rollback
The seven-test green development run overlaps the final 35-test run and is not added to its total. The controlled older-request check is not a database isolation stress test. Failed-save injection, hosted MariaDB execution, multi-process load and production latency were not run. This does not qualify Phase 10, integrated security or release readiness. Reverting the package restores the old caching behavior and reintroduces the reproduced stale-settings defect. Publication/integration remains with the parent development lane.
@@ -1,29 +0,0 @@
{
"format": "Native VSTest TRX compressed with gzip; no text transformations",
"receipts": [
{
"rawFile": "rules-red.trx",
"rawBytes": 30627,
"rawSha256": "c74e5e9703924e1a1775bddab662d8327f3d66ce502ca61d917cd827317e9d68",
"compressedFile": "rules-red.trx.gz",
"compressedBytes": 2844,
"compressedSha256": "630785b741059e1398e777f0c8f84bdf3f7e748844547d7c468ec913cf0261aa"
},
{
"rawFile": "rules-green.trx",
"rawBytes": 12087,
"rawSha256": "7960a65a79f9208178d91b41a47469c7839ef4e8c352d077d7fe0fa7745354b3",
"compressedFile": "rules-green.trx.gz",
"compressedBytes": 2092,
"compressedSha256": "131c814b17df0fbbde67dea15ed9e65db2e1f2c801afada903453b504b4a64f6"
},
{
"rawFile": "rules-regression.trx",
"rawBytes": 53741,
"rawSha256": "e2e7e51902a167cdcb6fa46339476759f63331863f5a2953e3d64cf08b97b106",
"compressedFile": "rules-regression.trx.gz",
"compressedBytes": 6020,
"compressedSha256": "7c229b8beb9d2fa8f3ff453f58d5f3cfeac8987d1f79c0bac65db1a55c0883ca"
}
]
}
@@ -1,228 +0,0 @@
{
"baseline": "9c9fe48d5f321c653049f09ced5b7e27701fe2a8",
"scope": "Offline SQLite and mocked identity; no models/providers",
"red": {
"times": {
"creation": "2026-11-10T23:15:22.2984079+01:00",
"queuing": "2026-11-10T23:15:22.2984084+01:00",
"start": "2026-11-10T23:15:19.6116487+01:00",
"finish": "2026-11-10T23:15:22.3054244+01:00"
},
"counters": {
"total": "7",
"executed": "7",
"passed": "0",
"failed": "7",
"error": "0",
"timeout": "0",
"aborted": "0",
"inconclusive": "0",
"passedButRunAborted": "0",
"notRunnable": "0",
"notExecuted": "0",
"disconnected": "0",
"warning": "0",
"completed": "0",
"inProgress": "0",
"pending": "0"
},
"results": [
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"detail\")",
"outcome": "Failed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"reminders\")",
"outcome": "Failed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saving_owner_a_does_not_change_owner_b_and_old_readers_do_not_republish_stale_settings",
"outcome": "Failed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Global_save_refreshes_fallback_but_preserves_explicit_owner_override",
"outcome": "Failed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"readiness\")",
"outcome": "Failed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"board\")",
"outcome": "Failed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"list\")",
"outcome": "Failed"
}
]
},
"regression": {
"times": {
"creation": "2026-11-10T23:16:27.2319904+01:00",
"queuing": "2026-11-10T23:16:27.2319908+01:00",
"start": "2026-11-10T23:16:25.2545706+01:00",
"finish": "2026-11-10T23:16:31.6005940+01:00"
},
"counters": {
"total": "35",
"executed": "35",
"passed": "35",
"failed": "0",
"error": "0",
"timeout": "0",
"aborted": "0",
"inconclusive": "0",
"passedButRunAborted": "0",
"notRunnable": "0",
"notExecuted": "0",
"disconnected": "0",
"warning": "0",
"completed": "0",
"inProgress": "0",
"pending": "0"
},
"results": [
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"needs-work\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"readiness\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"correspondence\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Ordinary_table_materialises_correspondence_groups_only_for_the_returned_page(size: 2500)",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"custom\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RulesEngineProspectTests.A_prospect_is_never_followed_up_or_ghosted_however_old(status: \"Saved\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RulesEngineProspectTests.An_applied_job_with_no_applied_date_is_not_ghosted",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"combined\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"follow-up\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobApplicationsWorkflowSignalsTests.Readiness_keeps_package_gap_when_notes_do_not_contain_saved_answer_block",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"standard\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"foreign-company\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saving_owner_a_preserves_owner_b_and_existing_readers_see_subsequent_writes",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"deleted\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"interview\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.ConcurrentInitializationTests.Concurrent_checklist_reads_share_the_single_default_item_set",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RulesEngineProspectTests.A_prospect_is_never_followed_up_or_ghosted_however_old(status: \"Interested\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"notes\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"detail\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.ConcurrentInitializationTests.Concurrent_rule_reads_share_the_single_created_settings_row",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Ordinary_table_materialises_correspondence_groups_only_for_the_returned_page(size: 250)",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"list\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"none\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"location\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RulesEngineProspectTests.A_prospect_is_never_followed_up_or_ghosted_however_old(status: \"Preparing\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RulesEngineProspectTests.An_applied_job_past_the_threshold_still_ghosts",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"reminders\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"include-deleted\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"company\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Saved_owner_thresholds_are_visible_on_the_next_read(surface: \"board\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"all\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Completing_an_older_request_cannot_restore_old_rules_after_a_save",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.RuleSettingsFreshnessTests.Global_save_refreshes_fallback_but_preserves_explicit_owner_override",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobQueryParityTests.Table_pages_and_board_have_identical_owned_membership(scenario: \"search\")",
"outcome": "Passed"
},
{
"test": "JobTrackerApi.Tests.JobApplicationsWorkflowSignalsTests.Reminders_return_normalized_workflow_routes_for_package_and_follow_up_actions",
"outcome": "Passed"
}
]
}
}
@@ -1,52 +0,0 @@
# Existing discovery browser tests: mobile drawer reconciliation
Status: **PASSED — all 11 existing tests passed together on the exact final test source, with no retries, skips or flaky outcomes.** This is bounded browser regression evidence, not full A3 or release acceptance.
Baseline: published A3 `ec57a24d77854bb416c9ea02b8b371be3e5554c0`. Isolated branch `codex/a3-discovery-native-drawer`; worktree `C:\Users\Connor\.codex\worktrees\a3-discovery-native-drawer\Job tracker`.
This package changes only `e2e/phase7-discovery.spec.ts`, `e2e/saved-search-repair.spec.ts` and bounded evidence. Final application source is the baseline plus the root-owned confirmation fix `df93bfb64eb80dbfa30f86c89b54a9021c43a9c6`, cherry-picked locally as `a584fc0b`. That separate source fix must not be applied twice when integrating this test/evidence package. The separate Add/Edit dates package is not included.
## Changes
Existing narrow journeys now explicitly open Search filters, edit drawer fields, close or jump to results, and reopen filters for saved-row actions/readback. The top-level query remains outside the modal; draft edits use the real visible controls in sequence. English/Bokmål drafts and native owner writes/readbacks remain asserted. Held requests continue checking disabled mounted controls, closed-drawer unavailability, one request per activation, progress announcements, stable retry context and focus. Busy assertions do not open a drawer or move focus away from the pending control. Drawer helpers use authoritative `aria-expanded` state and include hidden exiting dialog nodes when waiting for physical unmount, avoiding transition-time locator snapshots.
Confirmation locators identify their own title because the filter Drawer is also a dialog. Dismiss errors are scoped to the visible Results region, distinguishing its error from the retained hidden drawer copy. The result-region keyboard journey now asserts the new Return to search button before the existing Sort control. The desktop language test uses the current Norsk bokmål accessible name. The mobile user-moved-focus test uses the persistent header User control as its neutral focus destination.
No provider rights, routes, application behavior, persistence assertions, error/focus assertions or approval gates are relaxed. Only previously documented vacancy search/run output and explicitly injected faults/dismiss presentation use interception. Native saved-search listing/create/alert updates/delete and foreign/anonymous denials remain actual isolated API calls. The provider boundary remains recorded in each suite.
## Execution and evidence
All runs used one serialized Chromium worker, Playwright-managed API/Next servers, a unique disposable SQLite root, disabled model/import/alert workers and the installed .NET 9.0.317 executable. No reused server, external provider or model was used. The root's separate new drawer and controlled saved-search matrices were not repeated.
| Native run | Result | Scope |
| --- | --- | --- |
| pilot | 3 passed, 1 failed | Held saved B, failed saved-run retry, native keyboard create/alert/delete, native saved-list faults |
| remainder | 5 passed, 2 failed | Other seven existing cases; Dismiss and locale failed on obsolete selectors/tab assumptions |
| focused | 1 passed, 2 failed | Locale corrected; Dismiss reached new Return to search tab stop; confirmation focus diagnostic reproduced |
| dismiss | 3 passed | Corrected Dismiss plus held-B/retry; later helper review identified avoidable focus movement |
| focus-preserved | 2 passed, 1 failed | Busy checks preserved original focus; held-B exposed exiting-drawer locator timing |
| confirm-fix | 1 passed, 1 failed | Original native keyboard create/delete passed on root modal fix; held-B helper still transient |
| held-final | 1 failed | Isolated held-B helper race, retained as failed evidence |
| held-stable | 1 passed | Focus-preserving helper stabilization; later combined run exposed hidden-node timing |
| final11 | 10 passed, 1 failed | First combined run; only exiting-drawer locator timing remained |
| final-stable11 | **11 passed** | Exact final helpers/callers plus root modal fix; complete two-spec run |
These runs overlap and must not be summed. The final combined run alone passed **11 tests**, including the full native keyboard cancellation/held-delete journey, with **31 screenshots and 27 automated accessibility audits**. Early native-keyboard failures did not execute their subsequent steps; the final combined run did. The final raw receipt reports zero skipped, unexpected or flaky outcomes.
Exact native Playwright JSON/list outputs are gzip-preserved under [evidence/discovery-native-drawer](evidence/discovery-native-drawer/native-receipts.json). The manifest records raw/compressed byte lengths and SHA256 hashes. [Latest distinct outcomes](evidence/discovery-native-drawer/latest-distinct-outcomes.json) identifies the latest execution for every existing case. JSON retains screenshots/audits/request-boundary/focus attachments. These are actual local executions, not production or human/device acceptance.
- **PASSED:** Release API build: zero warnings/errors.
- **PASSED:** TypeScript and scoped ESLint.
- **PASSED:** `git diff --check`.
- **PASSED:** `graphify update .`, local AST-only graph refresh. Missing optional PDF/SQL extractors and files without extracted symbols remain graph coverage limits. Generated graph files remain local/untracked.
- **NOT RUN:** Hosted MariaDB, providers, live models, human accessibility/device qualification, production acceptance.
Startup logs contain existing SQLite migration and disposable Data Protection key warnings. The final combined run contains **zero UNIQUE-constraint errors**; no checklist recovery claim is needed for that run.
## Reproduced application issue and resolution
The Bokmål 360px native keyboard journey opens a saved-search Delete confirmation above the already open temporary Search filters Drawer. Before the root fix, Cancel had `autoFocus` but the actual active element was a `DIV` with `role="presentation"` containing the confirmation. The original Cancel-focus assertion reproduced the defect and remains intact.
The drawer was reopened after a manual Search had automatically returned to Results. [Failed active element](evidence/discovery-native-drawer/focused-confirmation-failure/active-element.json), native trace, screenshot and error context preserve the observation. The root fix recovers Cancel on transition completion only when focus remains exactly on the confirmation container, preserving intentional focus elsewhere. The single original case then passed; the final combined run passed its original focus trap, Cancel restoration, held native DELETE, request-count and persisted deletion checks. [Final pre-assertion focus snapshot](evidence/discovery-native-drawer/final-confirmation-focus.json) still observes the container before transition completion; the subsequent unchanged polling assertion establishes that Cancel receives focus afterward. No blanket focus-enforcement changes or relaxed assertions were introduced.
Rollback: revert this test/evidence package to restore the old callers. Application rollback is separately owned by the root confirmation fix. Publication/integration is left to the parent development lane. Hosted MariaDB, live providers/models, human/device accessibility and final integrated security/release gates remain separate.
@@ -5,7 +5,7 @@ Owner addendum received 9 November 2026. Source `E:/Storage/Projects/Active/temp
| Work package | Next independently eligible slice | Gate or residual requirement |
| --- | --- | --- |
| Admin information isolation | The original redaction patch passed 62 tests on the security branch. [A3 integration](ADMIN_AUDIT_ISOLATION_VALIDATION.md) matched the exact source/test patch and passed 57 selected tests. The runs overlap and remain separate evidence. | Integrated security, remaining delivery paths, broader minimisation and deployment checks remain separate. |
| Discover Jobs | [Search-first layout](visual-correction/DISCOVERY_SEARCH_FIRST.md) and [mobile filter drawer](visual-correction/DISCOVERY_MOBILE_FILTERS.md) qualify existing NAV search, retained drafts, keyboard submit, source disclosure and responsive focus. | Expose new filters, map and multilingual suggestions only with qualified data and the existing GJ architecture. Focused detail and broader saved-search browser qualification remain open. |
| Discover Jobs | [Search-first layout](visual-correction/DISCOVERY_SEARCH_FIRST.md) moves the query above filters and qualifies the existing NAV request, keyboard submit and source disclosure. | Expose new filters, map and multilingual suggestions only with qualified data and the existing GJ architecture. Mobile filter drawer and focused detail remain open. |
| Applications | [Title-first rows and explicit bulk mode](visual-correction/APPLICATION_SELECTION_REVIEW.md) and [compact row actions](visual-correction/APPLICATION_ACTIONS_REVIEW.md) qualified at 36 configurations each. | Final native/visual review and broader server-backed workflows remain open. |
| Admin Users and Audit | [Compact user actions](visual-correction/ADMIN_USER_ACTIONS_REVIEW.md) preserve alignment and read-only 2FA. [Recent audit filtering and details](visual-correction/AUDIT_FILTERS_REVIEW.md) passed its own 36-configuration checks. Additional audit filters remain open. | 2FA recovery and private support access require explicit owner approval of their technical and privacy designs. |
| Job Correspondence | Continue inbox layout, mailbox-status presentation and existing explicit consent flow. | Provider verification, restricted scopes, multiple-account persistence and retention decisions retain their gates. Signing in grants no mailbox access. |
-2
View File
@@ -2,8 +2,6 @@
Applications runtime `bfbfaeb9` consolidates existing row controls into one keyboard menu while preserving selection, status, edit, Trash and Restore. See [application action review](visual-correction/APPLICATION_ACTIONS_REVIEW.md).
Discovery runtime `4f3541e5` adds the existing mobile filter drawer with 36 controlled configurations and one server-backed keyboard/import case. Application density follow-up `64603f56` passed all four server-backed EN/NB/theme cases. See [drawer review](visual-correction/DISCOVERY_MOBILE_FILTERS.md) and [density verification](visual-correction/APPLICATION_DENSITY_SERVER_REVIEW.md). Broader historical saved-search mobile sequences and final acceptance remain open.
Admin Users runtime `171a6908` groups existing row actions into one keyboard menu. See [Admin action evidence](visual-correction/ADMIN_USER_ACTIONS_REVIEW.md).
Audit runtime `cd69b769` combines exact event type and inclusive local dates with recent search and adds keyboard-expandable details for already permitted values. See [Audit filter review](visual-correction/AUDIT_FILTERS_REVIEW.md).
@@ -1 +0,0 @@
{"state":"native-delete-confirm-initial","focused":{"tag":"DIV","id":"","role":"presentation","label":null,"text":"Slette lagret søk?Denne handlingen kan være vanskelig å angre.Slette «Gjennomgått utviklersøk Æ Ø Å» og historikken over viste og avviste st"},"qualification":"Actual document.activeElement in isolated Chromium, not a human screen-reader or physical-device acceptance claim."}
@@ -1 +0,0 @@
{"state":"native-delete-confirm-initial","focused":{"tag":"DIV","id":"","role":"presentation","label":null,"text":"Slette lagret søk?Denne handlingen kan være vanskelig å angre.Slette «Gjennomgått utviklersøk Æ Ø Å» og historikken over viste og avviste st"},"qualification":"Actual document.activeElement in isolated Chromium, not a human screen-reader or physical-device acceptance claim."}
@@ -1,239 +0,0 @@
# Instructions
- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.
# Test info
- Name: phase7-discovery.spec.ts >> [P7-05 Discovery] keyboard native create and alert updates persist; delete Cancel restores focus and held delete starts once
- Location: e2e\phase7-discovery.spec.ts:354:1
# Error details
```
Error: expect(locator).toBeFocused() failed
Locator: getByRole('dialog').filter({ has: getByRole('heading', { name: 'Slette lagret søk?', exact: true }) }).getByRole('button', { name: 'Avbryt', exact: true })
Expected: focused
Received: inactive
Timeout: 5000ms
Call log:
- Expect "toBeFocused" with timeout 5000ms
- waiting for getByRole('dialog').filter({ has: getByRole('heading', { name: 'Slette lagret søk?', exact: true }) }).getByRole('button', { name: 'Avbryt', exact: true })
14 × locator resolved to <button tabindex="0" type="button" class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary css-v8jn2b-MuiButtonBase-root-MuiButton-root">…</button>
- unexpected value "inactive"
```
```yaml
- button "Avbryt"
```
# Test source
```ts
300 | const job = vacancy('mutation-current');
301 | await page.route(`${savedUrl}/${saved.id}/run`, async route => route.fulfill({ json: await runPayload(page, saved, [job]) }));
302 | let createFails = true; let alertFails = true; let deleteFails = true;
303 | await page.route(savedUrl, route => route.request().method() === 'POST' && createFails
304 | ? route.fulfill({ status: 500, json: { message: 'Controlled create failure' } }) : route.continue());
305 | await page.route(`${savedUrl}/${saved.id}`, route => (route.request().method() === 'PATCH' && alertFails) || (route.request().method() === 'DELETE' && deleteFails)
306 | ? route.fulfill({ status: 500, json: { message: 'Controlled mutation failure' } }) : route.continue());
307 | await enter(page, session.owner);
308 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.jobDiscoveryRunSaved, exact: true }));
309 | await expect(article(page, job)).toBeVisible();
310 | await draftFilters(page, 'retained draft role', 'Ålesund');
311 | await page.getByLabel(t.jobDiscoverySavedName, { exact: true }).fill('Retained failed create draft');
312 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySaveSearch, exact: true }));
313 | await expect(page.getByText(t.jobDiscoverySaveSearchFailed, { exact: true })).toBeVisible();
314 | await expect(page.getByLabel(t.jobDiscoverySavedName, { exact: true })).toHaveValue('Retained failed create draft');
315 | await expect(page.getByLabel(t.jobDiscoveryRoleCompany, { exact: true })).toHaveValue('retained draft role');
316 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
317 | expect(await nativeList(page.request)).toEqual([saved]);
318 | createFails = false;
319 | const createdResponse = response(page, 'POST', savedUrl);
320 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySaveSearch, exact: true }));
321 | const created = await json<SavedSearch>(await createdResponse, 201);
322 | expect(created).toMatchObject({ name: 'Retained failed create draft', query: 'retained draft role', location: 'Ålesund' });
323 | await keyboardActivate(page, savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true }), 'Space');
324 | await expect(page.getByText(t.jobDiscoveryUpdateAlertsFailed, { exact: true })).toBeVisible();
325 | await expect(savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true })).toBeChecked();
326 | await expect(article(page, job)).toBeVisible();
327 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
328 | alertFails = false;
329 | const updatedResponse = response(page, 'PATCH', `${savedUrl}/${saved.id}`);
330 | await keyboardActivate(page, savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true }), 'Space');
331 | const updated = await json<SavedSearch>(await updatedResponse);
332 | expect(updated).toEqual({ ...saved, isActive: false });
333 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.adminUsersDelete, exact: true }));
334 | await keyboardActivate(page, page.getByRole('dialog').getByRole('button', { name: t.adminUsersDelete, exact: true }));
335 | await expect(page.getByText(t.jobDiscoveryDeleteSavedFailed, { exact: true })).toBeVisible();
336 | await expect(savedGroup(page, saved)).toBeVisible();
337 | await expect(article(page, job)).toBeVisible();
338 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
339 | // Native listing sorts by UpdatedAt, and pausing the older row updates that timestamp.
340 | // Compare every DTO value without inventing creation-order semantics for this readback.
341 | expect((await nativeList(page.request)).sort((left, right) => left.id - right.id)).toEqual([created, updated].sort((left, right) => left.id - right.id));
342 | expect(count(session.requests, 'GET', '/api/job-discovery/search')).toBe(0);
343 | await capture(page, info, desktop, 'mutation-failure-retains-context');
344 | deleteFails = false;
345 | const deletedResponse = response(page, 'DELETE', `${savedUrl}/${saved.id}`);
346 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.adminUsersDelete, exact: true }));
347 | await keyboardActivate(page, page.getByRole('dialog').getByRole('button', { name: t.adminUsersDelete, exact: true }));
348 | expect((await deletedResponse).status()).toBe(204);
349 | await expect(savedGroup(page, saved)).toHaveCount(0);
350 | expect(await nativeList(page.request)).toEqual([created]);
351 | expect(count(session.requests, 'GET', '/api/job-discovery/search')).toBe(0);
352 | });
353 |
354 | test('[P7-05 Discovery] keyboard native create and alert updates persist; delete Cancel restores focus and held delete starts once', async ({ page, session }, info) => {
355 | test.setTimeout(120_000);
356 | const t = translations.nb; const sample: Sample = { language: 'nb', theme: 'light', width: 360, height: 844 };
357 | const currentJob = vacancy('native-delete-current-manual');
358 | await page.route(`${searchUrl}**`, route => route.fulfill({ json: [currentJob] }));
359 | const createGate = hold(); const deleteGate = hold(); let creates = 0; let deletes = 0;
360 | await page.route(savedUrl, async route => {
361 | if (route.request().method() === 'POST') { creates++; await createGate.pending; }
362 | return route.continue();
363 | });
364 | await enter(page, session.owner, sample);
365 | await expect(page.getByText(t.jobDiscoveryNoSavedSearches, { exact: true })).toBeVisible();
366 | await draftFilters(page, ' utvikler ', ' Tromsø ', 'nb', ' Gjennomgått utviklersøk Æ Ø Å ');
367 | const createdResponse = response(page, 'POST', savedUrl);
368 | try {
369 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySaveSearch, exact: true }));
370 | await expect.poll(() => creates).toBe(1);
371 | await locked(page, 'nb'); await page.keyboard.press('Enter'); expect(creates).toBe(1);
372 | await capture(page, info, sample, 'native-create-held');
373 | } finally { createGate.release(); }
374 | const saved = await json<SavedSearch>(await createdResponse, 201);
375 | expect(saved).toMatchObject({ name: 'Gjennomgått utviklersøk Æ Ø Å', query: 'utvikler', location: 'Tromsø', isActive: true, resultCount: 0, dismissedCount: 0 });
376 | await expect(savedGroup(page, saved)).toBeVisible();
377 | expect(await nativeList(page.request)).toEqual([saved]);
378 | await page.reload(); await openFilters(page, 'nb'); await expect(savedGroup(page, saved)).toBeVisible();
379 | for (const isActive of [false, true]) {
380 | const updatedResponse = response(page, 'PATCH', `${savedUrl}/${saved.id}`);
381 | await keyboardActivate(page, savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true }), 'Space');
382 | expect(await json<SavedSearch>(await updatedResponse)).toEqual({ ...saved, isActive });
383 | expect(await nativeList(page.request)).toEqual([{ ...saved, isActive }]);
384 | await page.reload();
385 | await openFilters(page, 'nb');
386 | await expect(savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true })).toBeChecked({ checked: isActive });
387 | }
388 | // Keep a legitimate results control after deleting the saved row so the next Tab
389 | // has a concrete destination inside the stable region rather than browser chrome.
390 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySearchNav, exact: true }));
391 | await expect(article(page, currentJob)).toBeVisible();
392 | await openFilters(page, 'nb');
393 | const deleteButton = savedGroup(page, saved).getByRole('button', { name: t.adminUsersDelete, exact: true });
394 | await keyboardActivate(page, deleteButton);
395 | const dialog = page.getByRole('dialog').filter({ has: page.getByRole('heading', { name: t.jobDiscoveryDeleteSavedTitle, exact: true }) });
396 | await expect(dialog.getByRole('heading', { name: t.jobDiscoveryDeleteSavedTitle, exact: true })).toBeVisible();
397 | await expect(dialog.getByText(t.jobDiscoveryDeleteSavedConfirm.replace('{name}', saved.name), { exact: true })).toBeVisible();
398 | const cancel = dialog.getByRole('button', { name: t.cancel, exact: true });
399 | await recordFocus(page, info, 'native-delete-confirm-initial');
> 400 | await expect(cancel).toBeFocused();
| ^ Error: expect(locator).toBeFocused() failed
401 | await page.keyboard.press('Shift+Tab');
402 | const messageRegion = dialog.getByRole('region', { name: await dialog.getByRole('heading').innerText(), exact: true });
403 | await expect(messageRegion).toBeFocused();
404 | await messageRegion.press('Shift+Tab');
405 | await expect(dialog.getByRole('button', { name: t.adminUsersDelete, exact: true })).toBeFocused();
406 | await page.keyboard.press('Tab'); await expect(messageRegion).toBeFocused();
407 | await page.keyboard.press('Tab'); await expect(cancel).toBeFocused();
408 | await page.keyboard.press('Enter');
409 | await expect(dialog).toHaveCount(0); await expect(deleteButton).toBeFocused();
410 | expect(count(session.requests, 'DELETE', `/api/job-discovery/saved-searches/${saved.id}`)).toBe(0);
411 | expect(await nativeList(page.request)).toEqual([saved]);
412 | await page.route(`${savedUrl}/${saved.id}`, async route => {
413 | if (route.request().method() === 'DELETE') { deletes++; await deleteGate.pending; }
414 | return route.continue();
415 | });
416 | const deletedResponse = response(page, 'DELETE', `${savedUrl}/${saved.id}`);
417 | try {
418 | await keyboardActivate(page, deleteButton);
419 | await keyboardActivate(page, dialog.getByRole('button', { name: t.adminUsersDelete, exact: true }));
420 | await expect.poll(() => deletes).toBe(1);
421 | await expect(dialog).toHaveCount(0);
422 | await locked(page, 'nb'); await page.keyboard.press('Enter'); expect(deletes).toBe(1);
423 | await capture(page, info, sample, 'native-delete-held');
424 | } finally { deleteGate.release(); }
425 | expect((await deletedResponse).status()).toBe(204);
426 | await expect(savedGroup(page, saved)).toHaveCount(0);
427 | await closeFilters(page, 'nb', true);
428 | await recordFocus(page, info, 'native-delete-control-removed');
429 | await expect(results(page, 'nb')).toBeFocused();
430 | await page.keyboard.press('Tab');
431 | await recordFocus(page, info, 'native-delete-next-tab');
432 | await expect(page.getByLabel(t.jobDiscoverySort, { exact: true })).toBeFocused();
433 | await expect(article(page, currentJob)).toBeVisible();
434 | expect(await nativeList(page.request)).toEqual([]);
435 | await page.reload(); await openFilters(page, 'nb'); await expect(page.getByText(t.jobDiscoveryNoSavedSearches, { exact: true })).toBeVisible();
436 | expect(creates).toBe(1); expect(deletes).toBe(1);
437 | });
438 |
439 | test('[P7-05 Discovery] contextual Dismiss preserves a row on real missing-result denial and qualifies intercepted UI recovery', async ({ page, session }, info) => {
440 | test.setTimeout(90_000);
441 | const t = translations.en; const sample = { ...desktop, theme: 'dark' as const, width: 390, height: 844 };
442 | const saved = await createSaved(page, session.owner, 'Recorded dismiss owner context');
443 | const job = vacancy('p7-dismiss-encoded Æ Ø Å');
444 | const movedFocusJob = vacancy('p7-dismiss-second-moved-focus');
445 | await page.route(`${savedUrl}/${saved.id}/run`, async route => route.fulfill({ json: await runPayload(page, saved, [job, movedFocusJob]) }));
446 | await enter(page, session.owner, sample);
447 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.jobDiscoveryRunSaved, exact: true }));
448 | await expect(article(page, job)).toBeVisible();
449 | const dismissUrl = `${savedUrl}/${saved.id}/results/${encodeURIComponent(job.id)}/dismiss`;
450 | const deniedResponse = response(page, 'PATCH', dismissUrl);
451 | await keyboardActivate(page, article(page, job).getByRole('button', { name: t.jobDiscoveryDismiss, exact: true }));
452 | expect((await deniedResponse).status()).toBe(404);
453 | await expect(results(page).getByText(t.jobDiscoveryDismissFailed, { exact: true })).toBeVisible();
454 | await expect(article(page, job)).toBeVisible();
455 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
456 | expect(await nativeList(page.request)).toEqual([saved]);
457 | await capture(page, info, sample, 'dismiss-native-missing-denied');
458 | const gate = hold(); let starts = 0;
459 | await page.route(dismissUrl, async route => {
460 | expect(route.request().method()).toBe('PATCH'); expect(route.request().postDataJSON()).toEqual({ isDismissed: true });
461 | starts++; await gate.pending; return route.fulfill({ status: 204 });
462 | });
463 | try {
464 | await keyboardActivate(page, article(page, job).getByRole('button', { name: t.jobDiscoveryDismiss, exact: true }));
465 | await expect.poll(() => starts).toBe(1); await locked(page); await page.keyboard.press('Enter'); expect(starts).toBe(1);
466 | } finally { gate.release(); }
467 | await expect(article(page, job)).toHaveCount(0);
468 | await expect(results(page).getByText(t.jobDiscoveryDismissFailed, { exact: true })).toHaveCount(0);
469 | await recordFocus(page, info, 'dismiss-control-removed');
470 | await expect(results(page)).toBeFocused();
471 | await page.keyboard.press('Tab');
472 | await recordFocus(page, info, 'dismiss-next-tab');
473 | await expect(page.getByLabel(t.jobDiscoverySort, { exact: true })).toBeFocused();
474 | await expect(article(page, movedFocusJob)).toBeVisible();
475 | const movedGate = hold();
476 | const movedUrl = `${savedUrl}/${saved.id}/results/${encodeURIComponent(movedFocusJob.id)}/dismiss`;
477 | let movedStarts = 0;
478 | await page.route(movedUrl, async route => {
479 | expect(route.request().method()).toBe('PATCH'); expect(route.request().postDataJSON()).toEqual({ isDismissed: true });
480 | movedStarts++; await movedGate.pending; return route.fulfill({ status: 204 });
481 | });
482 | const headerControl = page.locator('header').getByRole('button', { name: t.user, exact: true });
483 | try {
484 | await keyboardActivate(page, article(page, movedFocusJob).getByRole('button', { name: t.jobDiscoveryDismiss, exact: true }));
485 | await expect.poll(() => movedStarts).toBe(1); await locked(page);
486 | await expect(headerControl).toBeEnabled(); await headerControl.focus(); await expect(headerControl).toBeFocused();
487 | await recordFocus(page, info, 'held-dismiss-user-moved-focus');
488 | } finally { movedGate.release(); }
489 | await expect(article(page, movedFocusJob)).toHaveCount(0);
490 | await recordFocus(page, info, 'dismiss-complete-user-focus-preserved');
491 | await expect(headerControl).toBeFocused();
492 | expect(movedStarts).toBe(1);
493 | expect(await nativeList(page.request)).toEqual([saved]);
494 | expect(count(session.requests, 'GET', '/api/job-discovery/search')).toBe(0);
495 | const patches = session.requests.filter(request => request.path.endsWith('/dismiss'));
496 | expect(patches).toHaveLength(3);
497 | expect(patches.map(request => request.body)).toEqual([{ isDismissed: true }, { isDismissed: true }, { isDismissed: true }]);
498 | await capture(page, info, sample, 'dismiss-intercepted-ui-only');
499 | await page.reload();
500 | await openFilters(page);
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

@@ -1,46 +0,0 @@
{
"[P7-05 Discovery] held saved B removes A rows, locks all mutations and starts one request": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] failed saved-run Retry posts the same ID with stable keyboard focus and held progress": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] keyboard native create and alert updates persist; delete Cancel restores focus and held delete starts once": {
"status": "passed",
"run": "final-stable11"
},
"[P5-15-01R-01] saved-list faults retry a native GET without resetting discovery across EN/Bokmål, themes and widths": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] saved A to manual search clears saved-result context and preserves native saved rows": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] mutation failures retain drafts and current rows without offering an unrelated manual-search retry": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] contextual Dismiss preserves a row on real missing-result denial and qualifies intercepted UI recovery": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] eight finite responsive locale/theme states retain source labels and all-enabled accessibility vectors": {
"status": "passed",
"run": "final-stable11"
},
"[P7-05 Discovery] header locale change retains drafts, selected saved source and rows without discovery refetch": {
"status": "passed",
"run": "final-stable11"
},
"[P5-15-01R-01] native saved NAV search survives Jobs navigation, reload, apply, pause/resume and delete": {
"status": "passed",
"run": "final-stable11"
},
"[P5-15-01R-01] native owner filters and crafted saved-search mutations deny foreign and anonymous access": {
"status": "passed",
"run": "final-stable11"
}
}
@@ -1,236 +0,0 @@
{
"baseline": "ec57a24d77854bb416c9ea02b8b371be3e5554c0",
"rootAppFix": "df93bfb64eb80dbfa30f86c89b54a9021c43a9c6",
"localAppFixCherryPick": "a584fc0b",
"qualification": "Final combined11 binds exact final test source. Intermediate runs overlap; do not sum them. Exact unmodified native Playwright JSON/list stdout compressed with gzip.",
"finalSourceSha256": {
"job-tracker-ui/e2e/phase7-discovery.spec.ts": "f200418dc84e99abbe0eb435e1356668ef568ff668d6179b748d927e4df846e6",
"job-tracker-ui/e2e/saved-search-repair.spec.ts": "d15f1736fca5f35e4b6ce2070314e3691bc0bd9ea9289c23cff4423a05a6ad61",
"job-tracker-ui/src/confirm.tsx": "add83991431cf3639acfcdbeb9a76eb24037477141153dca3a93082ed6cb1bb2",
"job-tracker-ui/src/confirm.test.tsx": "00d27162d74a405892e889dc3ce436104df48d2504d8ae554b3699e25a946d9d"
},
"runStats": {
"pilot": {
"startTime": "2026-11-11T06:34:24.274Z",
"duration": 82933.107,
"expected": 3,
"skipped": 0,
"unexpected": 1,
"flaky": 0
},
"remainder": {
"startTime": "2026-11-11T06:36:21.659Z",
"duration": 106519.323,
"expected": 5,
"skipped": 0,
"unexpected": 2,
"flaky": 0
},
"focused": {
"startTime": "2026-11-11T06:38:41.263Z",
"duration": 48073.14,
"expected": 1,
"skipped": 0,
"unexpected": 2,
"flaky": 0
},
"dismiss": {
"startTime": "2026-11-11T06:40:37.672Z",
"duration": 34489.103,
"expected": 3,
"skipped": 0,
"unexpected": 0,
"flaky": 0
},
"focus-preserved": {
"startTime": "2026-11-11T06:44:04.390Z",
"duration": 36403.344000000005,
"expected": 2,
"skipped": 0,
"unexpected": 1,
"flaky": 0
},
"confirm-fix": {
"startTime": "2026-11-11T06:45:15.340Z",
"duration": 39776.71599999999,
"expected": 1,
"skipped": 0,
"unexpected": 1,
"flaky": 0
},
"held-final": {
"startTime": "2026-11-11T06:46:26.787Z",
"duration": 22094.513,
"expected": 0,
"skipped": 0,
"unexpected": 1,
"flaky": 0
},
"held-stable": {
"startTime": "2026-11-11T06:48:03.414Z",
"duration": 19931.281,
"expected": 1,
"skipped": 0,
"unexpected": 0,
"flaky": 0
},
"final11": {
"startTime": "2026-11-11T06:48:46.652Z",
"duration": 151275.851,
"expected": 10,
"skipped": 0,
"unexpected": 1,
"flaky": 0
},
"final-stable11": {
"startTime": "2026-11-11T06:52:07.557Z",
"duration": 143011.842,
"expected": 11,
"skipped": 0,
"unexpected": 0,
"flaky": 0
}
},
"receipts": [
{
"file": "a3-discovery-native-confirm-fix.json.gz",
"rawBytes": 125386,
"rawSha256": "2bcdef8d0839552976b8d88cf28dd1fe1f0aacb1de5c8bb6a350e29c8a49c4b7",
"compressedBytes": 71828,
"compressedSha256": "44de61301ce4b46f7f9ef717ac03d8831d6596740599cc251cc0b5699c70ef2c"
},
{
"file": "a3-discovery-native-confirm-fix.txt.gz",
"rawBytes": 5561,
"rawSha256": "de74ee370d62bfbfe299921310f306fed0e3131a06143f275c7226825445105b",
"compressedBytes": 1637,
"compressedSha256": "3b7cc65423e552d35ea23455a48a3db8ca0cdc7273a5b51bf197fdbc5ef1a484"
},
{
"file": "a3-discovery-native-dismiss.json.gz",
"rawBytes": 360692,
"rawSha256": "03260dd567161339ca1f09f43e1c14ba5f21ade92b66b9c6e2f539c618fae319",
"compressedBytes": 225572,
"compressedSha256": "e09195b5cebbc325cfa54eaf0f9485bc1fd9f030499fdf5f0dd730c336b431f3"
},
{
"file": "a3-discovery-native-dismiss.txt.gz",
"rawBytes": 2351,
"rawSha256": "cf287911d67a050b00cc7102f0f27fc52538c63ddb348d660f8ee908a63b67e8",
"compressedBytes": 1064,
"compressedSha256": "4df447eb2bf08d56c54f851d6cea0acd5dfb1ef76677fa3ddaed16723f383259"
},
{
"file": "a3-discovery-native-final-stable11.json.gz",
"rawBytes": 2196635,
"rawSha256": "5b5958a516fd8fb22493ef982fee4b6ca8d512d78a460f0562c60755ab35b54c",
"compressedBytes": 1411952,
"compressedSha256": "106363b7f6e51914e947222608a2874903f03fd025e22bd7d91bcd38396193ad"
},
{
"file": "a3-discovery-native-final-stable11.txt.gz",
"rawBytes": 3831,
"rawSha256": "7d0e1b4c0cefb6fbf2ebf584ea90f35327d3618324f30ced0c1f102b7e2826cb",
"compressedBytes": 1536,
"compressedSha256": "4051bf8f98abd94f288b4c2e4e298e7aa20a1024a06d94b33eebaaed9ae0414f"
},
{
"file": "a3-discovery-native-final11.json.gz",
"rawBytes": 2152219,
"rawSha256": "8d4ab84e092066f7426bda9ebf4e2b519f94b06fe263874029afb0144ef83a70",
"compressedBytes": 1378115,
"compressedSha256": "df44a04ca26d7f089578655ebd35df19fd861b15eb9c8accaf9cc11bcd24081c"
},
{
"file": "a3-discovery-native-final11.txt.gz",
"rawBytes": 7208,
"rawSha256": "4d55fd6f94b1f8904f862d5cc16467e63e788531f6c85da06dbbb12293c7cee2",
"compressedBytes": 2185,
"compressedSha256": "706ba274f2e3fba37374e4386a72d9c845905d9782eac2b1202112c0e1aacb08"
},
{
"file": "a3-discovery-native-focus-preserved.json.gz",
"rawBytes": 318096,
"rawSha256": "6b45faa989b563911545cc02f314e1974d451a8ebab65dc57810da0c98252b03",
"compressedBytes": 195869,
"compressedSha256": "1b69b95028598529c62d437a56b3de3cfd0a81ec7599816eee0444a2612e3006"
},
{
"file": "a3-discovery-native-focus-preserved.txt.gz",
"rawBytes": 5727,
"rawSha256": "a4eae73ce086c281ed6eac7139dd565a1a865923654ec65f1a67ec21a7b7599e",
"compressedBytes": 1701,
"compressedSha256": "339f8035d58faecd6b636852fe49229646e008eca30edc4e24af13363364ab62"
},
{
"file": "a3-discovery-native-focused.json.gz",
"rawBytes": 353623,
"rawSha256": "98560a59a7b5691688207a5f85e9882a8394ed5a98809d86fd4bda6dd96bfa93",
"compressedBytes": 228545,
"compressedSha256": "201b1c076c9fc64857d76d084ae6155b6c2e343170457c158ed4f5d64930b40f"
},
{
"file": "a3-discovery-native-focused.txt.gz",
"rawBytes": 9509,
"rawSha256": "033d9699c6429416b3dfe35bc35afa56b0e3c7bef4f2a276aa1e6a6d3f85a298",
"compressedBytes": 2281,
"compressedSha256": "3de431d125ca055bc83e915aa858697b91a936d68a83e8b073d9b18cb94f9cdb"
},
{
"file": "a3-discovery-native-held-final.json.gz",
"rawBytes": 11327,
"rawSha256": "ff9bed8033718bac06e5de5753a5f6635bd497a1e988bee8f17b7858bdb010ee",
"compressedBytes": 3041,
"compressedSha256": "da36500a93e15a1df50dbeb5a3d4628c8eb83dc4a3f01074e63a61071e480274"
},
{
"file": "a3-discovery-native-held-final.txt.gz",
"rawBytes": 5178,
"rawSha256": "92c155554b30460916eb5f56362be08fdebf0924a272a10150fef3f11e3390a6",
"compressedBytes": 1547,
"compressedSha256": "ab599279a3857eb172395c0ddf36018368b7c96c9e37af26842978e9ee946a36"
},
{
"file": "a3-discovery-native-held-stable.json.gz",
"rawBytes": 53932,
"rawSha256": "91f44f31c4886cd690380cae1bc3d1084e59a9a00bc8dd48f09121c0bbf7c9bb",
"compressedBytes": 32756,
"compressedSha256": "40a43e88eb039f22d7c1740b2983f9acff25c139379c3dc764cf3f826fc32269"
},
{
"file": "a3-discovery-native-held-stable.txt.gz",
"rawBytes": 1987,
"rawSha256": "097b998c48681b4a5a1ffdd2a787a75bf3d53b08d702bceb7ee3e84ad97fdb5c",
"compressedBytes": 926,
"compressedSha256": "ab67b2a599a1f1bcc24634a290b986df9a4c009fa77862ecb495d27db2d4e45d"
},
{
"file": "a3-discovery-native-pilot.json.gz",
"rawBytes": 326700,
"rawSha256": "b364c617f90202d8071ea9a3af4386815ba3950378381c7031cae821884ed004",
"compressedBytes": 144420,
"compressedSha256": "d1bd1e7a4a41888134d580af9114095278fbd81301720dbd2a2eda17571da186"
},
{
"file": "a3-discovery-native-pilot.txt.gz",
"rawBytes": 6282,
"rawSha256": "4f936c3d29287363bfd113af20353e2e907615e7a678e5c08992149d3241306a",
"compressedBytes": 1956,
"compressedSha256": "009133f8d0677ee890b0f60cbe02a83285c347fa5188dad92f7367da8e6c78e4"
},
{
"file": "a3-discovery-native-remainder.json.gz",
"rawBytes": 1488998,
"rawSha256": "5c506906896c47efd8480aa6ed50737df05b4898a5a7ae84fd85c6f262862a21",
"compressedBytes": 1004042,
"compressedSha256": "aa38ca22efe7712c1fdca00a730e897147341bb922695f40825ee455811cdad5"
},
{
"file": "a3-discovery-native-remainder.txt.gz",
"rawBytes": 11442,
"rawSha256": "65fd7f3dd7e7929dd482ec9850bcc13907cf5cf7eb03e7844fb5f825a04849f3",
"compressedBytes": 2639,
"compressedSha256": "35ddf2e494f161177701f5ea6eb6f55124dd391a6e9a903bfc87102e0bce7526"
}
]
}
@@ -1,239 +0,0 @@
# Instructions
- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.
# Test info
- Name: phase7-discovery.spec.ts >> [P7-05 Discovery] keyboard native create and alert updates persist; delete Cancel restores focus and held delete starts once
- Location: e2e\phase7-discovery.spec.ts:354:1
# Error details
```
Error: expect(locator).toBeFocused() failed
Locator: getByRole('dialog').filter({ has: getByRole('heading', { name: 'Slette lagret søk?', exact: true }) }).getByRole('button', { name: 'Avbryt', exact: true })
Expected: focused
Received: inactive
Timeout: 5000ms
Call log:
- Expect "toBeFocused" with timeout 5000ms
- waiting for getByRole('dialog').filter({ has: getByRole('heading', { name: 'Slette lagret søk?', exact: true }) }).getByRole('button', { name: 'Avbryt', exact: true })
14 × locator resolved to <button tabindex="0" type="button" class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary css-v8jn2b-MuiButtonBase-root-MuiButton-root">…</button>
- unexpected value "inactive"
```
```yaml
- button "Avbryt"
```
# Test source
```ts
299 | const saved = await createSaved(page, session.owner, 'Recorded mutation recovery');
300 | const job = vacancy('mutation-current');
301 | await page.route(`${savedUrl}/${saved.id}/run`, async route => route.fulfill({ json: await runPayload(page, saved, [job]) }));
302 | let createFails = true; let alertFails = true; let deleteFails = true;
303 | await page.route(savedUrl, route => route.request().method() === 'POST' && createFails
304 | ? route.fulfill({ status: 500, json: { message: 'Controlled create failure' } }) : route.continue());
305 | await page.route(`${savedUrl}/${saved.id}`, route => (route.request().method() === 'PATCH' && alertFails) || (route.request().method() === 'DELETE' && deleteFails)
306 | ? route.fulfill({ status: 500, json: { message: 'Controlled mutation failure' } }) : route.continue());
307 | await enter(page, session.owner);
308 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.jobDiscoveryRunSaved, exact: true }));
309 | await expect(article(page, job)).toBeVisible();
310 | await draftFilters(page, 'retained draft role', 'Ålesund');
311 | await page.getByLabel(t.jobDiscoverySavedName, { exact: true }).fill('Retained failed create draft');
312 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySaveSearch, exact: true }));
313 | await expect(page.getByText(t.jobDiscoverySaveSearchFailed, { exact: true })).toBeVisible();
314 | await expect(page.getByLabel(t.jobDiscoverySavedName, { exact: true })).toHaveValue('Retained failed create draft');
315 | await expect(page.getByLabel(t.jobDiscoveryRoleCompany, { exact: true })).toHaveValue('retained draft role');
316 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
317 | expect(await nativeList(page.request)).toEqual([saved]);
318 | createFails = false;
319 | const createdResponse = response(page, 'POST', savedUrl);
320 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySaveSearch, exact: true }));
321 | const created = await json<SavedSearch>(await createdResponse, 201);
322 | expect(created).toMatchObject({ name: 'Retained failed create draft', query: 'retained draft role', location: 'Ålesund' });
323 | await keyboardActivate(page, savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true }), 'Space');
324 | await expect(page.getByText(t.jobDiscoveryUpdateAlertsFailed, { exact: true })).toBeVisible();
325 | await expect(savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true })).toBeChecked();
326 | await expect(article(page, job)).toBeVisible();
327 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
328 | alertFails = false;
329 | const updatedResponse = response(page, 'PATCH', `${savedUrl}/${saved.id}`);
330 | await keyboardActivate(page, savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true }), 'Space');
331 | const updated = await json<SavedSearch>(await updatedResponse);
332 | expect(updated).toEqual({ ...saved, isActive: false });
333 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.adminUsersDelete, exact: true }));
334 | await keyboardActivate(page, page.getByRole('dialog').getByRole('button', { name: t.adminUsersDelete, exact: true }));
335 | await expect(page.getByText(t.jobDiscoveryDeleteSavedFailed, { exact: true })).toBeVisible();
336 | await expect(savedGroup(page, saved)).toBeVisible();
337 | await expect(article(page, job)).toBeVisible();
338 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
339 | // Native listing sorts by UpdatedAt, and pausing the older row updates that timestamp.
340 | // Compare every DTO value without inventing creation-order semantics for this readback.
341 | expect((await nativeList(page.request)).sort((left, right) => left.id - right.id)).toEqual([created, updated].sort((left, right) => left.id - right.id));
342 | expect(count(session.requests, 'GET', '/api/job-discovery/search')).toBe(0);
343 | await capture(page, info, desktop, 'mutation-failure-retains-context');
344 | deleteFails = false;
345 | const deletedResponse = response(page, 'DELETE', `${savedUrl}/${saved.id}`);
346 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.adminUsersDelete, exact: true }));
347 | await keyboardActivate(page, page.getByRole('dialog').getByRole('button', { name: t.adminUsersDelete, exact: true }));
348 | expect((await deletedResponse).status()).toBe(204);
349 | await expect(savedGroup(page, saved)).toHaveCount(0);
350 | expect(await nativeList(page.request)).toEqual([created]);
351 | expect(count(session.requests, 'GET', '/api/job-discovery/search')).toBe(0);
352 | });
353 |
354 | test('[P7-05 Discovery] keyboard native create and alert updates persist; delete Cancel restores focus and held delete starts once', async ({ page, session }, info) => {
355 | test.setTimeout(120_000);
356 | const t = translations.nb; const sample: Sample = { language: 'nb', theme: 'light', width: 360, height: 844 };
357 | const currentJob = vacancy('native-delete-current-manual');
358 | await page.route(`${searchUrl}**`, route => route.fulfill({ json: [currentJob] }));
359 | const createGate = hold(); const deleteGate = hold(); let creates = 0; let deletes = 0;
360 | await page.route(savedUrl, async route => {
361 | if (route.request().method() === 'POST') { creates++; await createGate.pending; }
362 | return route.continue();
363 | });
364 | await enter(page, session.owner, sample);
365 | await expect(page.getByText(t.jobDiscoveryNoSavedSearches, { exact: true })).toBeVisible();
366 | await draftFilters(page, ' utvikler ', ' Tromsø ', 'nb', ' Gjennomgått utviklersøk Æ Ø Å ');
367 | const createdResponse = response(page, 'POST', savedUrl);
368 | try {
369 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySaveSearch, exact: true }));
370 | await expect.poll(() => creates).toBe(1);
371 | await locked(page, 'nb'); await page.keyboard.press('Enter'); expect(creates).toBe(1);
372 | await capture(page, info, sample, 'native-create-held');
373 | } finally { createGate.release(); }
374 | const saved = await json<SavedSearch>(await createdResponse, 201);
375 | expect(saved).toMatchObject({ name: 'Gjennomgått utviklersøk Æ Ø Å', query: 'utvikler', location: 'Tromsø', isActive: true, resultCount: 0, dismissedCount: 0 });
376 | await expect(savedGroup(page, saved)).toBeVisible();
377 | expect(await nativeList(page.request)).toEqual([saved]);
378 | await page.reload(); await openFilters(page, 'nb'); await expect(savedGroup(page, saved)).toBeVisible();
379 | for (const isActive of [false, true]) {
380 | const updatedResponse = response(page, 'PATCH', `${savedUrl}/${saved.id}`);
381 | await keyboardActivate(page, savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true }), 'Space');
382 | expect(await json<SavedSearch>(await updatedResponse)).toEqual({ ...saved, isActive });
383 | expect(await nativeList(page.request)).toEqual([{ ...saved, isActive }]);
384 | await page.reload();
385 | await openFilters(page, 'nb');
386 | await expect(savedGroup(page, saved).getByRole('switch', { name: t.jobDiscoveryAutomaticAlerts, exact: true })).toBeChecked({ checked: isActive });
387 | }
388 | // Keep a legitimate results control after deleting the saved row so the next Tab
389 | // has a concrete destination inside the stable region rather than browser chrome.
390 | await keyboardActivate(page, page.getByRole('button', { name: t.jobDiscoverySearchNav, exact: true }));
391 | await expect(article(page, currentJob)).toBeVisible();
392 | await openFilters(page, 'nb');
393 | const deleteButton = savedGroup(page, saved).getByRole('button', { name: t.adminUsersDelete, exact: true });
394 | await keyboardActivate(page, deleteButton);
395 | const dialog = page.getByRole('dialog').filter({ has: page.getByRole('heading', { name: t.jobDiscoveryDeleteSavedTitle, exact: true }) });
396 | await expect(dialog.getByRole('heading', { name: t.jobDiscoveryDeleteSavedTitle, exact: true })).toBeVisible();
397 | await expect(dialog.getByText(t.jobDiscoveryDeleteSavedConfirm.replace('{name}', saved.name), { exact: true })).toBeVisible();
398 | const cancel = dialog.getByRole('button', { name: t.cancel, exact: true });
> 399 | await expect(cancel).toBeFocused();
| ^ Error: expect(locator).toBeFocused() failed
400 | await page.keyboard.press('Shift+Tab');
401 | const messageRegion = dialog.getByRole('region', { name: await dialog.getByRole('heading').innerText(), exact: true });
402 | await expect(messageRegion).toBeFocused();
403 | await messageRegion.press('Shift+Tab');
404 | await expect(dialog.getByRole('button', { name: t.adminUsersDelete, exact: true })).toBeFocused();
405 | await page.keyboard.press('Tab'); await expect(messageRegion).toBeFocused();
406 | await page.keyboard.press('Tab'); await expect(cancel).toBeFocused();
407 | await page.keyboard.press('Enter');
408 | await expect(dialog).toHaveCount(0); await expect(deleteButton).toBeFocused();
409 | expect(count(session.requests, 'DELETE', `/api/job-discovery/saved-searches/${saved.id}`)).toBe(0);
410 | expect(await nativeList(page.request)).toEqual([saved]);
411 | await page.route(`${savedUrl}/${saved.id}`, async route => {
412 | if (route.request().method() === 'DELETE') { deletes++; await deleteGate.pending; }
413 | return route.continue();
414 | });
415 | const deletedResponse = response(page, 'DELETE', `${savedUrl}/${saved.id}`);
416 | try {
417 | await keyboardActivate(page, deleteButton);
418 | await keyboardActivate(page, dialog.getByRole('button', { name: t.adminUsersDelete, exact: true }));
419 | await expect.poll(() => deletes).toBe(1);
420 | await expect(dialog).toHaveCount(0);
421 | await locked(page, 'nb'); await page.keyboard.press('Enter'); expect(deletes).toBe(1);
422 | await capture(page, info, sample, 'native-delete-held');
423 | } finally { deleteGate.release(); }
424 | expect((await deletedResponse).status()).toBe(204);
425 | await expect(savedGroup(page, saved)).toHaveCount(0);
426 | await closeFilters(page, 'nb', true);
427 | await recordFocus(page, info, 'native-delete-control-removed');
428 | await expect(results(page, 'nb')).toBeFocused();
429 | await page.keyboard.press('Tab');
430 | await recordFocus(page, info, 'native-delete-next-tab');
431 | await expect(page.getByLabel(t.jobDiscoverySort, { exact: true })).toBeFocused();
432 | await expect(article(page, currentJob)).toBeVisible();
433 | expect(await nativeList(page.request)).toEqual([]);
434 | await page.reload(); await openFilters(page, 'nb'); await expect(page.getByText(t.jobDiscoveryNoSavedSearches, { exact: true })).toBeVisible();
435 | expect(creates).toBe(1); expect(deletes).toBe(1);
436 | });
437 |
438 | test('[P7-05 Discovery] contextual Dismiss preserves a row on real missing-result denial and qualifies intercepted UI recovery', async ({ page, session }, info) => {
439 | test.setTimeout(90_000);
440 | const t = translations.en; const sample = { ...desktop, theme: 'dark' as const, width: 390, height: 844 };
441 | const saved = await createSaved(page, session.owner, 'Recorded dismiss owner context');
442 | const job = vacancy('p7-dismiss-encoded Æ Ø Å');
443 | const movedFocusJob = vacancy('p7-dismiss-second-moved-focus');
444 | await page.route(`${savedUrl}/${saved.id}/run`, async route => route.fulfill({ json: await runPayload(page, saved, [job, movedFocusJob]) }));
445 | await enter(page, session.owner, sample);
446 | await keyboardActivate(page, savedGroup(page, saved).getByRole('button', { name: t.jobDiscoveryRunSaved, exact: true }));
447 | await expect(article(page, job)).toBeVisible();
448 | const dismissUrl = `${savedUrl}/${saved.id}/results/${encodeURIComponent(job.id)}/dismiss`;
449 | const deniedResponse = response(page, 'PATCH', dismissUrl);
450 | await keyboardActivate(page, article(page, job).getByRole('button', { name: t.jobDiscoveryDismiss, exact: true }));
451 | expect((await deniedResponse).status()).toBe(404);
452 | await expect(page.getByText(t.jobDiscoveryDismissFailed, { exact: true })).toBeVisible();
453 | await expect(article(page, job)).toBeVisible();
454 | await expect(page.getByRole('button', { name: t.retry, exact: true })).toHaveCount(0);
455 | expect(await nativeList(page.request)).toEqual([saved]);
456 | await capture(page, info, sample, 'dismiss-native-missing-denied');
457 | const gate = hold(); let starts = 0;
458 | await page.route(dismissUrl, async route => {
459 | expect(route.request().method()).toBe('PATCH'); expect(route.request().postDataJSON()).toEqual({ isDismissed: true });
460 | starts++; await gate.pending; return route.fulfill({ status: 204 });
461 | });
462 | try {
463 | await keyboardActivate(page, article(page, job).getByRole('button', { name: t.jobDiscoveryDismiss, exact: true }));
464 | await expect.poll(() => starts).toBe(1); await locked(page); await page.keyboard.press('Enter'); expect(starts).toBe(1);
465 | } finally { gate.release(); }
466 | await expect(article(page, job)).toHaveCount(0);
467 | await expect(page.getByText(t.jobDiscoveryDismissFailed, { exact: true })).toHaveCount(0);
468 | await recordFocus(page, info, 'dismiss-control-removed');
469 | await expect(results(page)).toBeFocused();
470 | await page.keyboard.press('Tab');
471 | await recordFocus(page, info, 'dismiss-next-tab');
472 | await expect(page.getByLabel(t.jobDiscoverySort, { exact: true })).toBeFocused();
473 | await expect(article(page, movedFocusJob)).toBeVisible();
474 | const movedGate = hold();
475 | const movedUrl = `${savedUrl}/${saved.id}/results/${encodeURIComponent(movedFocusJob.id)}/dismiss`;
476 | let movedStarts = 0;
477 | await page.route(movedUrl, async route => {
478 | expect(route.request().method()).toBe('PATCH'); expect(route.request().postDataJSON()).toEqual({ isDismissed: true });
479 | movedStarts++; await movedGate.pending; return route.fulfill({ status: 204 });
480 | });
481 | const headerControl = page.locator('header').getByRole('button', { name: 'Norsk', exact: true });
482 | try {
483 | await keyboardActivate(page, article(page, movedFocusJob).getByRole('button', { name: t.jobDiscoveryDismiss, exact: true }));
484 | await expect.poll(() => movedStarts).toBe(1); await locked(page);
485 | await expect(headerControl).toBeEnabled(); await headerControl.focus(); await expect(headerControl).toBeFocused();
486 | await recordFocus(page, info, 'held-dismiss-user-moved-focus');
487 | } finally { movedGate.release(); }
488 | await expect(article(page, movedFocusJob)).toHaveCount(0);
489 | await recordFocus(page, info, 'dismiss-complete-user-focus-preserved');
490 | await expect(headerControl).toBeFocused();
491 | expect(movedStarts).toBe(1);
492 | expect(await nativeList(page.request)).toEqual([saved]);
493 | expect(count(session.requests, 'GET', '/api/job-discovery/search')).toBe(0);
494 | const patches = session.requests.filter(request => request.path.endsWith('/dismiss'));
495 | expect(patches).toHaveLength(3);
496 | expect(patches.map(request => request.body)).toEqual([{ isDismissed: true }, { isDismissed: true }, { isDismissed: true }]);
497 | await capture(page, info, sample, 'dismiss-intercepted-ui-only');
498 | await page.reload();
499 | await openFilters(page);
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

@@ -1,11 +0,0 @@
# Application table server verification
Application presentation and browser test source `64603f5602e0efa03c33abd46dc4380e58c99e5a` passed all four table-density browser cases in 2.2 minutes. The API was built from `aac0f3b3` before the subsequent rules integration. Playwright started its own API and Next development server with a unique temporary SQLite data root. AI/import/search-alert workers were disabled. External browser requests were blocked.
The cases cover English/Bokmål, both themes, both densities and 320, 390, 768, 1024 and 1440 px. They verify selection persistence, keyboard scroll/focus, existing status PATCH, workspace/back navigation, confirmed synthetic Trash/Restore, column preferences and held/error/retry behaviour. These operations affect disposable fixture accounts only. Scoped axe assertions passed. Forty screenshots are retained with the raw log and file hashes in `evidence/application-actions-server/RECEIPT.json`.
The first attempt found stale mobile menu selectors. The next attempt found a long custom status reducing the selected phone title to about 90 px and a selected-row listing link at 4.4 contrast. The title group now wraps earlier, and both listing links use the existing theme-aware MUI Link. The final run retained the 150 px title assertion, 44 px phone targets and contrast checks. Earlier failures are retained. The light-English pilot overlaps the final four cases.
The API log includes EF unique-key errors during concurrent checklist seeding. Independent source review found the existing seed recovery catches the conflict, detaches its attempted inserts and reloads verified winning rows. The existing concurrent-initialization regression passed in the separate 35-test rules run. Recovery of individual log entries is inferred because the log lacks request correlation. Local migration and unencrypted test-key warnings also remain in the raw receipt.
The integrated `ce7e4866` source separately passed 63 selected frontend tests and 35 backend tests after the rules and discovery-collation fixes. Earlier runs overlap those totals. This server run predates the discovery drawer increment and does not qualify that increment. Native devices, MariaDB, provider/model access, full A3 acceptance, integrated security and release qualification remain open.
@@ -6,14 +6,4 @@ At widths up to 1000 px, the existing municipality, source disclosure and saved-
The initial mobile regression failed three cases against the previous page. The final 28 discovery cases passed, including EN/NB draft/submit/focus, breakpoint transitions, saved-write failure and existing permission, ordering and tracker behaviour. Type-check and scoped lint passed. Raw logs are in `evidence/discovery-mobile-filters/`.
## Integrated verification
Integrated source `4f3541e5b85f3d794d8e25f3376e30758b6656c0` passed 67 selected frontend tests in four suites, export/build with TypeScript and full application lint. The verifier and keyboard-test changes additionally passed scoped lint and type-check. The source-only drawer run of 28 tests overlaps the 67 and is not added. The separate rules integration passed 35 backend cases.
The exported UI passed 36 controlled journeys and 108 axe scans/captures across nine widths from 320 to 1920 px, English/Bokmål and both themes. Checks cover initial presentation, the source disclosure in the open filters, retained municipality/name drafts, Escape focus, original form submission and result focus. The four 320 px language/theme cases also cross to 1024 px and back with the draft intact. There were zero page errors or writes. Company reads were unavailable in all 36 fixture configurations, and Google Fonts was blocked. Pilot coverage overlaps the final matrix. Rendered 320 px Bokmål/dark and desktop screenshots were visually reviewed.
One server-backed browser case passed using Playwright's isolated SQLite/API and Next development servers. Keyboard navigation reaches the mobile drawer, Enter from municipality searches, results sort and reflow across 375/768/1440 px, and the selected vacancy opens reviewed import. Vacancy and import-preview responses were fixtures. The real local server log includes a cancelled dashboard-preferences request logged as HTTP 500 during navigation. That log remains in the evidence and does not establish a successful response for that cancelled request.
This package uses the current NAV search contract. New geography, taxonomy, map, providers and data persistence retain their roadmap dependencies. The broader historical phase7 discovery/saved-search browser suites need their mobile sequences reconciled with the drawer and remain unexecuted for this increment. Native-device and final owner acceptance remain open.
The existing controlled verifier modes have since been reconciled in [saved-search follow-up](DISCOVERY_SAVED_DRAWER.md), with 16 saved-search configurations and separate search/tracking pilots. These retain the separate persistent-state qualification above.
This package uses the current NAV search contract. New geography, taxonomy, map, providers and data persistence retain their roadmap dependencies. Exported browser, visual and accessibility validation is pending integration. Native-device and final owner acceptance remain open.
@@ -1,9 +0,0 @@
# Saved-search verification with the mobile drawer
Verifier source `07df0c688d903068a772ce9199346d4d3e1c29b1` updates the existing search, tracking and saved-search modes for the approved drawer. Narrow journeys explicitly open filters and wait for result focus after closing. The existing desktop rail and form-order assertions remain. An evidence-directory override keeps these receipts separate from the historical viewer captures.
The saved-search mode passed 16 controlled configurations at 320, 390, 768 and 1440 px, both languages and both themes. All 48 axe scans/captures passed, with zero page errors or unexpected writes. Each journey searches, saves a named query, pauses alerts, runs that saved query, dismisses its result and confirms deletion. Eighty intercepted fixture mutations were recorded. Company reads were unavailable in all 16 fixtures, and Google Fonts was blocked.
Search-first and reviewed-tracking pilots each passed at 320 and 1440 px. They produced six and eight scans respectively. The tracking pilot intercepted two creates after preview/review. The one-case saved-search pilot overlaps the final 16 and is not added. Scoped verifier lint passed.
The production application source matches the earlier drawer checkpoint. These checks refresh the existing controlled verifier paths. The historical server-backed phase7 discovery and saved-search tests still need their mobile sequences reconciled before broader persistent-state qualification. Native-device, provider, integrated security and release acceptance remain open.
@@ -42,8 +42,6 @@ Owner correction: 3 November 2026. This register extends IM10 and the original 3
| V32 | Admin Audit search | The first no-match state clipped its message inside the wide table on phones | RESOLVED in `1a8a97a5` | [Audit search review](AUDIT_SEARCH_REVIEW.md) records the narrow screenshot and fitting feedback. |
| V33 | Admin Users actions | Repeated role, reset and delete buttons used most of the action column and phone cards | RESOLVED in `171a6908` | [Admin actions review](ADMIN_USER_ACTIONS_REVIEW.md) covers keyboard menus and final-admin safeguards. |
| V34 | Application row actions | Repeated edit, Trash and status controls crowd rows and phone cards | RESOLVED in `bfbfaeb9` | [Application actions review](APPLICATION_ACTIONS_REVIEW.md) covers named keyboard menus, focus, Restore and responsive boundaries. Native and final owner review remain open. |
| V35 | Application density | Long custom status squeezes the selected phone title; selected dark listing links fall below AA | RESOLVED in `64603f56` | [Server verification](APPLICATION_DENSITY_SERVER_REVIEW.md) retains failures and all four passing cases. |
| V36 | Discovery mobile filters | The full filter and saved-search rail pushes phone results down the page | RESOLVED in `4f3541e5` scoped validation | [Drawer review](DISCOVERY_MOBILE_FILTERS.md) retains draft, form and focus checks. Broader saved-search/native qualification remains open. |
The owner-approved design foundation remains original A1 dashboard, D1 visual system, B1 tracking, editor left / preview right, application context right, desktop sidebar and hybrid mobile navigation. No controls, imports, revisions, permissions or provider rights may be removed to obtain visual simplicity.
@@ -59,9 +59,9 @@
"JobDiscoveryPage"
],
"visualStatus": "DIVIDED_ROWS_SCOPED_RENDERED_REVIEW",
"afterStatus": "PASSED:36 configurations /108 drawer/search states at 4f3541e5 and one isolated server-backed keyboard/import journey. Earlier tracker fixture journey retained. Broader saved-search mobile sequences, provider/backend and final acceptance remain open.",
"afterStatus": "PASSED:36 configurations /108 states; saved search synthetic actions only; full discovery-to-track journey remains open; successor discovery-to-tracker36/144 fixture states passed, exactlyone preview andcreate perconfiguration; provider/backend acceptance open",
"functionalCriteria": "Original preservation register retained; no capability acceptance promotion",
"evidence": "DISCOVERY_MOBILE_FILTERS.md; evidence/discovery-mobile-filters/BROWSER.json; earlier DISCOVERY_SEARCH_FIRST.md and DISCOVERY_TRACK_REVIEW.md"
"evidence": "DISCOVERY_SEARCH_FIRST.md; evidence/discovery-search-first/BROWSER.json; earlier DASHBOARD_DISCOVERY.md and DISCOVERY_TRACK_REVIEW.md"
},
{
"route": "/jobs",
@@ -1,7 +0,0 @@
JobTrackerApi -> C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi\bin\Release\net9.0\JobTrackerApi.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:03.60
@@ -1,367 +0,0 @@
[WebServer] Using launch settings from ..\JobTrackerApi\Properties\launchSettings.json...
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[30200]
[WebServer] An operation of type 'SqlOperation' will be attempted while a rebuild of table 'JobApplications' is pending. The database may not be in an expected state. Review the SQL generated by this migration to help diagnose any failures. Consider moving these operations to a subsequent migration.
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[20410]
[WebServer] The migration operation 'PRAGMA foreign_keys = 0;
[WebServer] ' from migration 'AddJobEntityAndProspectStages' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
[WebServer] warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
[WebServer] No XML encryptor configured. Key {2fa1cb79-2bd9-4a65-aab6-cdf9fcfd4bc9} may be persisted to storage in unencrypted form.
[WebServer] (node:36792) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (node:36644) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 4 tests using 1 worker
(node:5284) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (2ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbCo[WebServer] ntext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
ok 1 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities (30.5s)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
ok 2 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities (27.7s)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
ok 3 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities (30.3s)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (0ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
ok 4 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities (27.7s)
4 passed (2.2m)
@@ -1,350 +0,0 @@
[WebServer] Using launch settings from ..\JobTrackerApi\Properties\launchSettings.json...
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[30200]
[WebServer] An operation of type 'SqlOperation' will be attempted while a rebuild of table 'JobApplications' is pending. The database may not be in an expected state. Review the SQL generated by this migration to help diagnose any failures. Consider moving these operations to a subsequent migration.
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[20410]
[WebServer] The migration operation 'PRAGMA foreign_keys = 0;
[WebServer] ' from migration 'AddJobEntityAndProspectStages' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
[WebServer] warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
[WebServer] No XML encryptor configured. Key {cbfe3c75-02c3-4805-913d-cb802537967c} may be persisted to storage in unencrypted form.
[WebServer] (node:24112) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (node:9568) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 4 tests using 1 worker
(node:13532) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 1 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities (16.9s)
(node:16656) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 2 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities (17.2s)
(node:34188) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 3 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities (8.6s)
(node:2484) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 4 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities (6.5s)
1) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities
Error: expect(locator).toBeVisible() failed
Locator: getByRole('menuitem', { name: 'Offer', exact: true })
Expected: visible
Timeout: 5000ms
Error: element(s) not found
Call log:
- Expect "toBeVisible" with timeout 5000ms
- waiting for getByRole('menuitem', { name: 'Offer', exact: true })
141 | await capture(page, info, `jobs-top-phone-${suffix}`);
142 | await first.getByRole("button", { name: new RegExp(`^${t.jobTableActions}:`) }).click();
> 143 | await expect(page.getByRole("menuitem", { name: t.statusOffer, exact: true })).toBeVisible();
| ^
144 | await page.keyboard.press("Escape");
145 | }
146 | // Geometric containment alone misses a title squeezed into one-letter lines.
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:143:90
attachment #1: jobs-top-desktop-light-en (image/png) ───────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-light-en-f1416f5079e9dae7363d607aa6388e58f032e248.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-light-en (image/png) ────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\desktop-comfortable-light-en-660a3212eb13e3b829a092f58183ba46d2795276.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: desktop-compact-light-en (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\desktop-compact-light-en-97b5a9c08e474c6eaaba7612f2ae544d9d08eafd.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #7: jobs-top-phone-light-en (image/png) ─────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\jobs-top-phone-light-en-3de02167367b95b02cc2ad39b43c4e88c8f119c7.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #8: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\error-context.md
attachment #10: trace (application/zip) ────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
2) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities
Error: expect(locator).toBeVisible() failed
Locator: getByRole('menuitem', { name: 'Tilbud', exact: true })
Expected: visible
Timeout: 5000ms
Error: element(s) not found
Call log:
- Expect "toBeVisible" with timeout 5000ms
- waiting for getByRole('menuitem', { name: 'Tilbud', exact: true })
141 | await capture(page, info, `jobs-top-phone-${suffix}`);
142 | await first.getByRole("button", { name: new RegExp(`^${t.jobTableActions}:`) }).click();
> 143 | await expect(page.getByRole("menuitem", { name: t.statusOffer, exact: true })).toBeVisible();
| ^
144 | await page.keyboard.press("Escape");
145 | }
146 | // Geometric containment alone misses a title squeezed into one-letter lines.
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:143:90
attachment #1: jobs-top-desktop-light-nb (image/png) ───────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-light-nb-91cd77b8515e2fb9e6d33a692e137d751b850944.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-light-nb (image/png) ────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\desktop-comfortable-light-nb-7ac29ea19432eb0c09ddd49515a153b25212a5b3.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: desktop-compact-light-nb (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\desktop-compact-light-nb-dcc8a8f6c161069e74eaf09284a08f927ecfb487.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #7: jobs-top-phone-light-nb (image/png) ─────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\jobs-top-phone-light-nb-9c2d93ec71b3df07b88d6e4f2fa11d5bd70fce4b.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #8: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\error-context.md
attachment #10: trace (application/zip) ────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
3) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities
Error: expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 64
- Array []
+ Array [
+ Object {
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "id": "color-contrast",
+ "impact": "serious",
+ "nodes": Array [
+ Object {
+ "all": Array [],
+ "any": Array [
+ Object {
+ "data": Object {
+ "bgColor": "#443b53",
+ "contrastRatio": 4.4,
+ "expectedContrastRatio": "4.5:1",
+ "fgColor": "#9e9eff",
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": null,
+ },
+ "id": "color-contrast",
+ "impact": "serious",
+ "message": "Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "relatedNodes": Array [
+ Object {
+ "html": "<tr class=\"MuiTableRow-root Mui-selected MuiTableRow-hover css-11gbcel-MuiTableRow-root\" data-job-row-id=\"37\" tabindex=\"0\" aria-label=\"Open Density 00 — Seniorrådgiver for plattformutvikling og digitale fellestjenester at Nordlys æøå AS\">",
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root",
+ ],
+ },
+ Object {
+ "html": "<div class=\"MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 css-1j6eq80-MuiPaper-root\" data-content-density=\"comfortable\" style=\"--Paper-shadow: var(--shadows-0); --Paper-overlay: var(--overlays-0);\">",
+ "target": Array [
+ ".css-1j6eq80-MuiPaper-root",
+ ],
+ },
+ ],
+ },
+ ],
+ "failureSummary": "Fix any of the following:
+ Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "html": "<a href=\"https://example.test/listing\" target=\"_blank\" rel=\"noreferrer\">Link</a>",
+ "impact": "serious",
+ "none": Array [],
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root > .css-1ingqjh-MuiTableCell-root:nth-child(9) > a[href$=\"listing\"][target=\"_blank\"][rel=\"noreferrer\"]",
+ ],
+ },
+ ],
+ "tags": Array [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1",
+ ],
+ },
+ ]
52 | const result = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]).analyze();
53 | await info.attach(`${name}-axe`, { body: JSON.stringify({ violations: result.violations, incomplete: result.incomplete }), contentType: "application/json" });
> 54 | expect(result.violations).toEqual([]);
| ^
55 | }
56 | async function keyboardFocus(page: Page, target: Locator) {
57 | await target.focus();
at scan (C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:54:29)
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:125:7
attachment #1: jobs-top-desktop-dark-en (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-dark-en-9fc9d48bee9b6d70fd4bf7af72615f91740efea8.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-dark-en (image/png) ─────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\attachments\desktop-comfortable-dark-en-5bc72635596b9a7e3fa3211185a0fbfebaa6490f.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\error-context.md
attachment #6: trace (application/zip) ─────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
4) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities
Error: expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 64
- Array []
+ Array [
+ Object {
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "id": "color-contrast",
+ "impact": "serious",
+ "nodes": Array [
+ Object {
+ "all": Array [],
+ "any": Array [
+ Object {
+ "data": Object {
+ "bgColor": "#443b53",
+ "contrastRatio": 4.4,
+ "expectedContrastRatio": "4.5:1",
+ "fgColor": "#9e9eff",
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": null,
+ },
+ "id": "color-contrast",
+ "impact": "serious",
+ "message": "Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "relatedNodes": Array [
+ Object {
+ "html": "<tr class=\"MuiTableRow-root Mui-selected MuiTableRow-hover css-11gbcel-MuiTableRow-root\" data-job-row-id=\"55\" tabindex=\"0\" aria-label=\"Åpne Density 00 — Seniorrådgiver for plattformutvikling og digitale fellestjenester hos Nordlys æøå AS\">",
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root",
+ ],
+ },
+ Object {
+ "html": "<div class=\"MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 css-1j6eq80-MuiPaper-root\" data-content-density=\"comfortable\" style=\"--Paper-shadow: var(--shadows-0); --Paper-overlay: var(--overlays-0);\">",
+ "target": Array [
+ ".css-1j6eq80-MuiPaper-root",
+ ],
+ },
+ ],
+ },
+ ],
+ "failureSummary": "Fix any of the following:
+ Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "html": "<a href=\"https://example.test/listing\" target=\"_blank\" rel=\"noreferrer\">Lenke</a>",
+ "impact": "serious",
+ "none": Array [],
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root > .css-1ingqjh-MuiTableCell-root:nth-child(9) > a[href$=\"listing\"][target=\"_blank\"][rel=\"noreferrer\"]",
+ ],
+ },
+ ],
+ "tags": Array [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1",
+ ],
+ },
+ ]
52 | const result = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]).analyze();
53 | await info.attach(`${name}-axe`, { body: JSON.stringify({ violations: result.violations, incomplete: result.incomplete }), contentType: "application/json" });
> 54 | expect(result.violations).toEqual([]);
| ^
55 | }
56 | async function keyboardFocus(page: Page, target: Locator) {
57 | await target.focus();
at scan (C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:54:29)
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:125:7
attachment #1: jobs-top-desktop-dark-nb (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-dark-nb-de0939d685d6e747b8d560d1b6de29d02e5730c4.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-dark-nb (image/png) ─────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\attachments\desktop-comfortable-dark-nb-67fffcde180e1e34d26480532314959bb069d9e5.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\error-context.md
attachment #6: trace (application/zip) ─────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
4 failed
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities
@@ -1,11 +0,0 @@
JobTrackerApi -> C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi\bin\Debug\net9.0\JobTrackerApi.dll
PdfBrowserStub -> C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi.Tests\PdfBrowserStub\bin\Debug\net9.0\PdfBrowserStub.dll
JobTrackerApi.Tests -> C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi.Tests\bin\Debug\net9.0\JobTrackerApi.Tests.dll
Test run for C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi.Tests\bin\Debug\net9.0\JobTrackerApi.Tests.dll (.NETCoreApp,Version=v9.0)
VSTest version 17.14.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Results File: C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi.Tests\TestResults\rules-a3-integration.trx
Passed! - Failed: 0, Passed: 35, Skipped: 0, Total: 35, Duration: 6 s - JobTrackerApi.Tests.dll (net9.0)
@@ -1,10 +0,0 @@
> job-tracker-ui@0.1.0 test
> jest --runInBand job-table-density.test.tsx jobs-view-integration.test.tsx workflow-trust-signals.test.tsx job-discovery.test.tsx
Test Suites: 4 passed, 4 total
Tests: 63 passed, 63 total
Snapshots: 0 total
Time: 30.949 s, estimated 36 s
Ran all test suites matching job-table-density.test.tsx|jobs-view-integration.test.tsx|workflow-trust-signals.test.tsx|job-discovery.test.tsx.
@@ -1,4 +0,0 @@
{
"status": "passed",
"failedTests": []
}
@@ -1,106 +0,0 @@
[WebServer] Using launch settings from ..\JobTrackerApi\Properties\launchSettings.json...
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[30200]
[WebServer] An operation of type 'SqlOperation' will be attempted while a rebuild of table 'JobApplications' is pending. The database may not be in an expected state. Review the SQL generated by this migration to help diagnose any failures. Consider moving these operations to a subsequent migration.
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[20410]
[WebServer] The migration operation 'PRAGMA foreign_keys = 0;
[WebServer] ' from migration 'AddJobEntityAndProspectStages' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
[WebServer] warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
[WebServer] No XML encryptor configured. Key {bf7abd10-cd7a-42ae-b86b-3e9561cabe4a} may be persisted to storage in unencrypted form.
[WebServer] (node:38464) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (node:17336) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 1 test using 1 worker
(node:35684) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (2ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
[WebServer] Failed executing DbCommand (1ms) [Parameters=[@p0='?' (Size = 15), @p1='?' (Size = 11), @p2='?' (DbType = DateTimeOffset), @p3='?' (DbType = DateTimeOffset), @p4='?' (Size = 74), @p5='?' (DbType = Boolean), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 36), @p9='?' (Size = 11), @p10='?' (DbType = Int32), @p11='?' (Size = 7), @p12='?' (Size = 18), @p13='?' (Size = 18), @p14='?' (DbType = DateTimeOffset)], CommandType='Text', CommandTimeout='30']
[WebServer] INSERT INTO "ApplicationChecklistItems" ("AutoSignal", "Category", "CompletedAt", "CreatedAtUtc", "Description", "IsAutoCompleted", "IsSystemGenerated", "JobApplicationId", "OwnerUserId", "Section", "SortOrder", "Status", "SystemKey", "Title", "UpdatedAtUtc")
[WebServer] VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14)
[WebServer] RETURNING "Id";
[WebServer] fail: Microsoft.EntityFrameworkCore.Update[10000]
[WebServer] An exception occurred in the database while saving changes for context type 'JobTrackerApi.Data.JobTrackerContext'.
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
[WebServer] ---> Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'UNIQUE constraint failed: ApplicationChecklistItems.JobApplicationId, ApplicationChecklistItems.SystemKey'.
[WebServer] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
[WebServer] at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
[WebServer] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] --- End of inner exception stack trace ---
[WebServer] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
[WebServer] at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
ok 1 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities (28.9s)
1 passed (43.1s)
@@ -1,73 +0,0 @@
{
"browserSource": "64603f5602e0efa03c33abd46dc4380e58c99e5a",
"integrationSource": "ce7e48665ca681e1c059cb576a068957a8d562d5",
"browserCases": 4,
"frontendTests": 63,
"backendTests": 35,
"nativeTrxRawSha256": "521f3e2c6a4ac4c2fd0bc6dcde58d5df6dbcf52fd44bd6024094d74f116b8ac5",
"sources": {
"job-tracker-ui/src/components/JobTable.tsx": {
"commit": "64603f5602e0efa03c33abd46dc4380e58c99e5a",
"sha256": "7d970ba4182ed49ebb4431ad95e51f1507b2292d1d537b95b5fa7c60606274c6"
},
"job-tracker-ui/e2e/table-density.spec.ts": {
"commit": "64603f5602e0efa03c33abd46dc4380e58c99e5a",
"sha256": "f1aa88bf6d6fbfc4c156b26fc90f1ecfe1c4e390316d99cea6e5b8816e77bb05"
},
"JobTrackerApi/Controllers/JobApplicationsController.cs": {
"commit": "aac0f3b3a9b452b48126ddaf26e1837eeadd2f6d",
"sha256": "ba1c01766dd880fe46d18669097b26dafe50c2ffdd69adc39fa9e56c2ae5ce93"
}
},
"files": {
"API-BUILD.txt": "df8631d03cf4977f82c2a87166b0e2341ff5b9a6e0072cb7a49800709d3fc9ca",
"BROWSER.txt": "ee3a0e87a3fd14e1f754dc830fa11a2b07c39e3eaf3b694f82968642211b6f9b",
"desktop-comfortable-dark-en.png": "f015ff523a8a1c3e2f7675db57af9716bec3a329ab3db24a2f1c8e57503c8938",
"desktop-comfortable-dark-nb.png": "12781c10a970728c51db0e037bceacedf6750336f2e8aec38be903d64c0f621c",
"desktop-comfortable-light-en.png": "399ca52868d012da45af84853f8e622d0af8e892d89039d0ea7dc97e7d798687",
"desktop-comfortable-light-nb.png": "61f64cb71d31bc6e269c41d21fe1cf2dfafd6ee00b3a554d6c78180bdc01b68e",
"desktop-compact-dark-en.png": "636fb8a2b16b9a1880589f0ecc810d6311042a5ff317480f8eb7f97ce99f79a2",
"desktop-compact-dark-nb.png": "db5df96c259a38464859b65d399de7d9730ba32a48bd70977e114893ac24fd34",
"desktop-compact-light-en.png": "eb8fd8a63ca4e6800e88adca946310007f591b644f2ea367d0d4bd2c05bb5b38",
"desktop-compact-light-nb.png": "6807467b37762399f41d89d15514cbf2423e575ec1852b8c1d577e439e43d45f",
"FIRST-BROWSER.txt": "6e3cbc5953851b85667b66c4ce83046e5cfa5e46a2c2120eda68adaeff8208cd",
"INTEGRATED-BACKEND.txt": "174d39e26772e3cb7bf2f211e2c187f59e2fa04afbab75da9826aa9a55434972",
"INTEGRATED-FRONTEND.txt": "5c6a985ee4b2b402b187af143dfea28dfefdd782d0fc4dce9149c28e566c86eb",
"jobs-top-desktop-dark-en.png": "fdf472f7453316c5c7c841e368eb3208d656ce4866c0ca3aae509ebafec53362",
"jobs-top-desktop-dark-nb.png": "a4a50d1aaa9de922c1ed63f05f2f68f5536c0264b60bb0a5aa68ee9122f75d45",
"jobs-top-desktop-light-en.png": "f424c9cbfcf29f4efa9b0c5be21b6aaf957a25d4c8064a9fe0df06f83817ca92",
"jobs-top-desktop-light-nb.png": "e403c66690bb25ba7a983959aa45f0cb27de9a495dafab4d0860df556b6bfbfd",
"jobs-top-phone-dark-en.png": "f018e47bec2a670551c93e17f0871858b1bcdc335ecd01fcaba2d98393ea56d2",
"jobs-top-phone-dark-nb.png": "e51593d61abf63be17ba1158542c9c5d27805e670b92daf0d63a4f77d68ec87c",
"jobs-top-phone-light-en.png": "d1111616ba9a0fa6fcec26638448ca28bd61fd7887e203e73707754c1a775889",
"jobs-top-phone-light-nb.png": "add515e6e4dff31a225a235bf6e33659329caa3d0b5754fe590b095bd047fd01",
"LAST-RUN.json": "91d1c43004802cd49950d78eb11c8fa7d05da8ffffe219a8b13b2f561bc00903",
"list-error-dark-en.png": "5a38b2442718e1acfdbb8cc7372bd501fe50d00e042925131fd1e79ef05a81cd",
"list-error-dark-nb.png": "dfaab0803dd131a92b45bfb58bafadec45978ebbab9fa7cf5352ef215ea69c7c",
"list-error-light-en.png": "a928d7e5900d1572ea6a78ca689f315dbbd162fcd9b1859e7aafa01845584d1a",
"list-error-light-nb.png": "dc27e36f7e41a9135d6ea5fade8d23325c090f0ed1dbc62cc7b8726ec175c579",
"phone-320-comfortable-dark-en.png": "ec27177f766ad1aba6267e82f0ff31007540ce7276a9f223e230f2534d256624",
"phone-320-comfortable-dark-nb.png": "55dfb3ee461a49cd3c71cd5aa2ca2a91ab65c122108e11bf91bd501eec29d90d",
"phone-320-comfortable-light-en.png": "105378c4d53b8acffd20453b8b4e130d204e298d92be664daf0da597a6995495",
"phone-320-comfortable-light-nb.png": "598329debe21e512a9ba395f39328f6f083f8a8ca2155798644751a2b94f73ff",
"phone-320-compact-dark-en.png": "6e9e15710258a041eafa577fd397bbefbb4aeb1f18c7b383b8dbdb4d82c277f0",
"phone-320-compact-dark-nb.png": "60c06fc9baaaab41b67267559d954ed8a1d0a55248edf7ced32895632da65454",
"phone-320-compact-light-en.png": "a014489a98fb73237e9841f85d25b3dd4f63f1c25e12a7f4bc365a36deba71ce",
"phone-320-compact-light-nb.png": "7ca73feb7d43a4832729a193283a62e5d50ac6f8b1c13a4327441f665c4b5cd8",
"phone-390-comfortable-dark-en.png": "132646a606218191bfd7806981781f555b4696876315b6d9e7a19312b008db70",
"phone-390-comfortable-dark-nb.png": "bb0fab9936ec506a5b51a4779897069701e1a788181b0a517be015e0d8162848",
"phone-390-comfortable-light-en.png": "050ba384a15f86afa3050915499cfecb8f4793b3ca11daba3ca1d05f3248a9df",
"phone-390-comfortable-light-nb.png": "133e25cb17c3c014046a04c83b04ea4c92e7d1b8ac261e832b93b1d3e85142dc",
"phone-390-compact-dark-en.png": "864065c6ecc6dc0e7c3e095da3b0e7d6493a33c61019f3affa594dc59d4e6036",
"phone-390-compact-dark-nb.png": "2147bf3f3cd043a1c9a69b16854de4f37dcd47ff09a661a14ed0c524e272f527",
"phone-390-compact-light-en.png": "8f0cc7ca1dfc8c82005f4afdfe548ffee3718f3bef9ac7ba03a2ad4fa711fe41",
"phone-390-compact-light-nb.png": "59840446b3251ad7d32617e98b02a5b6172876505d7b82fc67409327efaa3538",
"PILOT.txt": "74deb468cad84b7ec56e5671bcb1a93b278d906d7639c40296464d3dd374d8f7",
"row-action-focus-dark-en.png": "511e37ab828e286691350b26c2853cb86b4b690959ca45023ce4add5cd912a47",
"row-action-focus-dark-nb.png": "a4b959e505aae98251128dd238726d4bea2a8c2998014c42b790f0d7949f2443",
"row-action-focus-light-en.png": "cfda70f4c860106d77d745ca622692779986be3b57e851172afeee173d834fcf",
"row-action-focus-light-nb.png": "6faae9d60bae87924347177b2d548f53a4590ebfd902f2160817cdd3d73fbb33",
"rules-a3-integration.trx.gz": "14db5b765b09b1a824cc256aedeab3115d8ae1f441be12df47e54714087b08a5",
"SECOND-BROWSER.txt": "5c3b3e128e25a8d3e5e72bea230e1fb571a78b8a2749c418813ed2d8d27e7e22"
}
}
@@ -1,336 +0,0 @@
[WebServer] Using launch settings from ..\JobTrackerApi\Properties\launchSettings.json...
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[30200]
[WebServer] An operation of type 'SqlOperation' will be attempted while a rebuild of table 'JobApplications' is pending. The database may not be in an expected state. Review the SQL generated by this migration to help diagnose any failures. Consider moving these operations to a subsequent migration.
[WebServer] warn: Microsoft.EntityFrameworkCore.Migrations[20410]
[WebServer] The migration operation 'PRAGMA foreign_keys = 0;
[WebServer] ' from migration 'AddJobEntityAndProspectStages' cannot be executed in a transaction. If the app is terminated or an unrecoverable error occurs while this operation is being executed then the migration will be left in a partially applied state and would need to be reverted manually before it can be applied again. Create a separate migration that contains just this operation.
[WebServer] warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
[WebServer] No XML encryptor configured. Key {ff113390-818c-4b00-aaed-dca8283bd29c} may be persisted to storage in unencrypted form.
[WebServer] (node:34416) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (node:18616) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 4 tests using 1 worker
(node:30220) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 1 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities (10.5s)
(node:32044) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 2 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities (10.4s)
(node:6168) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 3 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities (9.0s)
(node:19316) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
x 4 [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities (6.2s)
1) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities
Error: expect(received).toBeGreaterThanOrEqual(expected)
Expected: >= 150
Received: 89.890625
145 | }
146 | // Geometric containment alone misses a title squeezed into one-letter lines.
> 147 | expect((await first.getByText(/^Density 00/).boundingBox())!.width).toBeGreaterThanOrEqual(150);
| ^
148 | const metrics = await first.evaluate(card => Array.from(card.querySelectorAll("button,a,.MuiCheckbox-root")).map(node => {
149 | const rect = node.getBoundingClientRect(); return { text: node.textContent, width: rect.width, height: rect.height, left: rect.left, right: rect.right };
150 | }));
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:147:77
attachment #1: jobs-top-desktop-light-en (image/png) ───────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-light-en-f1416f5079e9dae7363d607aa6388e58f032e248.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-light-en (image/png) ────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\desktop-comfortable-light-en-660a3212eb13e3b829a092f58183ba46d2795276.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: desktop-compact-light-en (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\desktop-compact-light-en-97b5a9c08e474c6eaaba7612f2ae544d9d08eafd.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #7: jobs-top-phone-light-en (image/png) ─────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\attachments\jobs-top-phone-light-en-3de02167367b95b02cc2ad39b43c4e88c8f119c7.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #8: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\error-context.md
attachment #10: trace (application/zip) ────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-63938--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
2) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities
Error: expect(received).toBeGreaterThanOrEqual(expected)
Expected: >= 150
Received: 89.890625
145 | }
146 | // Geometric containment alone misses a title squeezed into one-letter lines.
> 147 | expect((await first.getByText(/^Density 00/).boundingBox())!.width).toBeGreaterThanOrEqual(150);
| ^
148 | const metrics = await first.evaluate(card => Array.from(card.querySelectorAll("button,a,.MuiCheckbox-root")).map(node => {
149 | const rect = node.getBoundingClientRect(); return { text: node.textContent, width: rect.width, height: rect.height, left: rect.left, right: rect.right };
150 | }));
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:147:77
attachment #1: jobs-top-desktop-light-nb (image/png) ───────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-light-nb-91cd77b8515e2fb9e6d33a692e137d751b850944.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-light-nb (image/png) ────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\desktop-comfortable-light-nb-7ac29ea19432eb0c09ddd49515a153b25212a5b3.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: desktop-compact-light-nb (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\desktop-compact-light-nb-dcc8a8f6c161069e74eaf09284a08f927ecfb487.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #7: jobs-top-phone-light-nb (image/png) ─────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\attachments\jobs-top-phone-light-nb-9c2d93ec71b3df07b88d6e4f2fa11d5bd70fce4b.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #8: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\error-context.md
attachment #10: trace (application/zip) ────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-63307--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
3) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities
Error: expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 64
- Array []
+ Array [
+ Object {
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "id": "color-contrast",
+ "impact": "serious",
+ "nodes": Array [
+ Object {
+ "all": Array [],
+ "any": Array [
+ Object {
+ "data": Object {
+ "bgColor": "#443b53",
+ "contrastRatio": 4.4,
+ "expectedContrastRatio": "4.5:1",
+ "fgColor": "#9e9eff",
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": null,
+ },
+ "id": "color-contrast",
+ "impact": "serious",
+ "message": "Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "relatedNodes": Array [
+ Object {
+ "html": "<tr class=\"MuiTableRow-root Mui-selected MuiTableRow-hover css-11gbcel-MuiTableRow-root\" data-job-row-id=\"37\" tabindex=\"0\" aria-label=\"Open Density 00 — Seniorrådgiver for plattformutvikling og digitale fellestjenester at Nordlys æøå AS\">",
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root",
+ ],
+ },
+ Object {
+ "html": "<div class=\"MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 css-1j6eq80-MuiPaper-root\" data-content-density=\"comfortable\" style=\"--Paper-shadow: var(--shadows-0); --Paper-overlay: var(--overlays-0);\">",
+ "target": Array [
+ ".css-1j6eq80-MuiPaper-root",
+ ],
+ },
+ ],
+ },
+ ],
+ "failureSummary": "Fix any of the following:
+ Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "html": "<a href=\"https://example.test/listing\" target=\"_blank\" rel=\"noreferrer\">Link</a>",
+ "impact": "serious",
+ "none": Array [],
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root > .css-1ingqjh-MuiTableCell-root:nth-child(9) > a[href$=\"listing\"][target=\"_blank\"][rel=\"noreferrer\"]",
+ ],
+ },
+ ],
+ "tags": Array [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1",
+ ],
+ },
+ ]
52 | const result = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]).analyze();
53 | await info.attach(`${name}-axe`, { body: JSON.stringify({ violations: result.violations, incomplete: result.incomplete }), contentType: "application/json" });
> 54 | expect(result.violations).toEqual([]);
| ^
55 | }
56 | async function keyboardFocus(page: Page, target: Locator) {
57 | await target.focus();
at scan (C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:54:29)
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:125:7
attachment #1: jobs-top-desktop-dark-en (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-dark-en-9fc9d48bee9b6d70fd4bf7af72615f91740efea8.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-dark-en (image/png) ─────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\attachments\desktop-comfortable-dark-en-5bc72635596b9a7e3fa3211185a0fbfebaa6490f.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\error-context.md
attachment #6: trace (application/zip) ─────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-96d9c--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
4) [chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities
Error: expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 64
- Array []
+ Array [
+ Object {
+ "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
+ "help": "Elements must meet minimum color contrast ratio thresholds",
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.13/color-contrast?application=playwright",
+ "id": "color-contrast",
+ "impact": "serious",
+ "nodes": Array [
+ Object {
+ "all": Array [],
+ "any": Array [
+ Object {
+ "data": Object {
+ "bgColor": "#443b53",
+ "contrastRatio": 4.4,
+ "expectedContrastRatio": "4.5:1",
+ "fgColor": "#9e9eff",
+ "fontSize": "10.5pt (14px)",
+ "fontWeight": "normal",
+ "messageKey": null,
+ },
+ "id": "color-contrast",
+ "impact": "serious",
+ "message": "Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "relatedNodes": Array [
+ Object {
+ "html": "<tr class=\"MuiTableRow-root Mui-selected MuiTableRow-hover css-11gbcel-MuiTableRow-root\" data-job-row-id=\"55\" tabindex=\"0\" aria-label=\"Åpne Density 00 — Seniorrådgiver for plattformutvikling og digitale fellestjenester hos Nordlys æøå AS\">",
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root",
+ ],
+ },
+ Object {
+ "html": "<div class=\"MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 css-1j6eq80-MuiPaper-root\" data-content-density=\"comfortable\" style=\"--Paper-shadow: var(--shadows-0); --Paper-overlay: var(--overlays-0);\">",
+ "target": Array [
+ ".css-1j6eq80-MuiPaper-root",
+ ],
+ },
+ ],
+ },
+ ],
+ "failureSummary": "Fix any of the following:
+ Element has insufficient color contrast of 4.4 (foreground color: #9e9eff, background color: #443b53, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1",
+ "html": "<a href=\"https://example.test/listing\" target=\"_blank\" rel=\"noreferrer\">Lenke</a>",
+ "impact": "serious",
+ "none": Array [],
+ "target": Array [
+ ".css-11gbcel-MuiTableRow-root > .css-1ingqjh-MuiTableCell-root:nth-child(9) > a[href$=\"listing\"][target=\"_blank\"][rel=\"noreferrer\"]",
+ ],
+ },
+ ],
+ "tags": Array [
+ "cat.color",
+ "wcag2aa",
+ "wcag143",
+ "TTv5",
+ "TT13.c",
+ "EN-301-549",
+ "EN-9.1.4.3",
+ "ACT",
+ "RGAAv4",
+ "RGAA-3.2.1",
+ ],
+ },
+ ]
52 | const result = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]).analyze();
53 | await info.attach(`${name}-axe`, { body: JSON.stringify({ violations: result.violations, incomplete: result.incomplete }), contentType: "application/json" });
> 54 | expect(result.violations).toEqual([]);
| ^
55 | }
56 | async function keyboardFocus(page: Page, target: Locator) {
57 | await target.focus();
at scan (C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:54:29)
at C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\job-tracker-ui\e2e\table-density.spec.ts:125:7
attachment #1: jobs-top-desktop-dark-nb (image/png) ────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\attachments\jobs-top-desktop-dark-nb-de0939d685d6e747b8d560d1b6de29d02e5730c4.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #2: desktop-comfortable-dark-nb (image/png) ─────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\attachments\desktop-comfortable-dark-nb-67fffcde180e1e34d26480532314959bb069d9e5.png
────────────────────────────────────────────────────────────────────────────────────────────────
attachment #4: screenshot (image/png) ──────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────
Error Context: test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\error-context.md
attachment #6: trace (application/zip) ─────────────────────────────────────────────────────────
test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\trace.zip
Usage:
npx playwright show-trace test-results\table-density--PRES-J05-J0-e66f3--behavior-at-both-densities-chromium\trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
4 failed
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/en table and cards preserve behavior at both densities
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] light/nb table and cards preserve behavior at both densities
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/en table and cards preserve behavior at both densities
[chromium] › e2e\table-density.spec.ts:73:3 › [PRES-J05 J06 W01 W02 S03 E08 E09] dark/nb table and cards preserve behavior at both densities
Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

@@ -1,7 +0,0 @@
JobTrackerApi -> C:\Users\Connor\.codex\worktrees\direct-roadmap-integration\Job tracker\JobTrackerApi\bin\Release\net9.0\JobTrackerApi.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:11.51

Some files were not shown because too many files have changed in this diff Show More