Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f9522b1f9 | |||
| 9f63cff3c8 | |||
| d027754d15 | |||
| df8f4dbbd3 | |||
| 5a880a6ac7 | |||
| 9143927609 | |||
| 265794e010 | |||
| df93bfb64e | |||
| ec57a24d77 | |||
| 07df0c688d | |||
| 1d73367576 | |||
| 4f3541e5b8 | |||
| 7e23a27463 | |||
| a6ec225598 | |||
| ce7e48665c | |||
| 6c75e97bdb | |||
| e286be48ba | |||
| 64603f5602 | |||
| aac0f3b3a9 |
@@ -0,0 +1,246 @@
|
||||
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 Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace JobTrackerApi.Tests;
|
||||
|
||||
public sealed class RuleSettingsFreshnessTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Failed_owner_save_preserves_committed_rules_and_a_later_success_refreshes_existing_readers()
|
||||
{
|
||||
await using var fixture = await Fixture.CreateAsync();
|
||||
await using var readA = fixture.Context("owner-a");
|
||||
await using var readB = fixture.Context("owner-b");
|
||||
var ownerA = fixture.Controller(readA);
|
||||
var ownerB = fixture.Controller(readB);
|
||||
Assert.False(await FollowUp(ownerA, fixture.JobA, "list"));
|
||||
Assert.False(await FollowUp(ownerB, fixture.JobB, "list"));
|
||||
|
||||
var failure = new SaveFailureInterceptor();
|
||||
await using var write = fixture.Context("owner-a", failure);
|
||||
await Assert.ThrowsAsync<DbUpdateException>(() => new RulesController(write).Update(Settings(1), default));
|
||||
Assert.Equal(1, write.UserRuleSettings.Local.Single().AppliedFollowUpDays);
|
||||
Assert.Equal(30, (await RulesEngine.GetSettings(write, default)).AppliedFollowUpDays);
|
||||
Assert.False(await FollowUp(ownerA, fixture.JobA, "list"));
|
||||
Assert.False(await FollowUp(ownerB, fixture.JobB, "list"));
|
||||
|
||||
failure.RejectWrites = false;
|
||||
Assert.IsType<NoContentResult>(await new RulesController(write).Update(Settings(1), default));
|
||||
Assert.True(await FollowUp(ownerA, fixture.JobA, "list"));
|
||||
Assert.False(await FollowUp(ownerB, fixture.JobB, "list"));
|
||||
}
|
||||
|
||||
private sealed class SaveFailureInterceptor : SaveChangesInterceptor
|
||||
{
|
||||
public bool RejectWrites { get; set; } = true;
|
||||
|
||||
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
|
||||
DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (RejectWrites) throw new DbUpdateException("Synthetic settings storage failure");
|
||||
return base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
[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, IInterceptor? interceptor = null)
|
||||
{
|
||||
var user = new Mock<ICurrentUserService>();
|
||||
user.SetupGet(x => x.UserId).Returns(owner);
|
||||
var options = new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(_connection);
|
||||
if (interceptor is not null) options.AddInterceptors(interceptor);
|
||||
return new JobTrackerContext(options.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,7 +1,6 @@
|
||||
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;
|
||||
@@ -31,10 +30,9 @@ 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, IMemoryCache? cache = null, IApplicationChecklistService? checklist = null)
|
||||
public JobApplicationsController(JobTrackerContext db, ISummarizerService summarizer, UserManager<ApplicationUser> users, ICvTemplateRenderer? cvTemplateRenderer = null, ICvPdfExporter? cvPdfExporter = null, IJobCvMatchService? matchService = null, IApplicationChecklistService? checklist = null)
|
||||
{
|
||||
_checklist = checklist ?? new ApplicationChecklistService(db);
|
||||
_db = db;
|
||||
@@ -43,21 +41,6 @@ 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
|
||||
@@ -539,7 +522,7 @@ Canonical profile:
|
||||
query = query.Where(j => j.Location != null && EF.Functions.Like(j.Location, like));
|
||||
}
|
||||
|
||||
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
|
||||
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
|
||||
var now = DateTime.Now;
|
||||
|
||||
Task<Dictionary<int, DateTime?>> LoadLatestMessagesAsync(IQueryable<Correspondence> messages) => messages
|
||||
@@ -650,7 +633,7 @@ Canonical profile:
|
||||
|
||||
if (job is null) return NotFound();
|
||||
|
||||
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
|
||||
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
|
||||
var now = DateTime.Now;
|
||||
var lm = await _db.Correspondences
|
||||
.AsNoTracking()
|
||||
@@ -693,7 +676,7 @@ Canonical profile:
|
||||
if (upcomingDays < 1) upcomingDays = 1;
|
||||
if (upcomingDays > 90) upcomingDays = 90;
|
||||
|
||||
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
|
||||
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
|
||||
var now = DateTime.Now;
|
||||
var upcomingTo = now.AddDays(upcomingDays);
|
||||
|
||||
@@ -839,7 +822,7 @@ Canonical profile:
|
||||
.Include(j => j.Company)
|
||||
.FirstAsync(j => j.Id == job.Id, cancellationToken);
|
||||
|
||||
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
|
||||
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
|
||||
var followUp = RulesEngine.Evaluate(settings, created, DateTime.Now, lastMessageAt: null);
|
||||
return CreatedAtAction(nameof(GetById), new { id = created.Id }, BuildJobApplicationDto(created, followUp));
|
||||
}
|
||||
@@ -1029,7 +1012,7 @@ Canonical profile:
|
||||
|
||||
await _db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
|
||||
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
|
||||
var lastMsg = await _db.Correspondences
|
||||
.AsNoTracking()
|
||||
.Where(c => c.JobApplicationId == id)
|
||||
@@ -1383,7 +1366,7 @@ Candidate CV/profile:
|
||||
.FirstOrDefaultAsync(j => j.Id == id, cancellationToken);
|
||||
if (job is null) return NotFound();
|
||||
|
||||
var settings = await GetCachedRuleSettingsAsync(cancellationToken);
|
||||
var settings = await RulesEngine.GetSettings(_db, cancellationToken);
|
||||
var now = DateTime.Now;
|
||||
var lastMessageAt = await _db.Correspondences
|
||||
.AsNoTracking()
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Date-picker calendar-day preservation
|
||||
|
||||
11 November 2026. Baseline `ec57a24d77854bb416c9ea02b8b371be3e5554c0`, isolated branch `codex/i18n-deadline-picker-date`.
|
||||
|
||||
The Add and Edit job dialogs passed date-only strings through `new Date(value)`, which interprets a literal `YYYY-MM-DD` at UTC midnight. In Los Angeles, opening 23 November displayed the 22nd. Their picker change handlers then used `toISOString().slice(0, 10)`. Selecting local midnight on 23 November in Oslo or Kiritimati submitted the 22nd.
|
||||
|
||||
The existing wrapper pairs now use installed date-fns `parseISO` for literal dates and `format(value, "yyyy-MM-dd")` for the picker's local Date output. Non-literal parsing retains `new Date(value)`. Empty and invalid picker values retain their existing clearing behaviour. Edit's separate legacy `toDateInputValue` loading policy is preserved.
|
||||
|
||||
The affected callers are Add's applied date and deadline, and Edit's applied date, status-change date, reply date, follow-up date and deadline. All seven controls are date pickers backed by date-only state and request values. Revision and submit handlers are retained. There is no backend, timestamp serialization, dependency or migration change.
|
||||
|
||||
## Verification
|
||||
|
||||
The new component regression drives the actual Add/Edit state and conversion handlers with a picker test double implementing MUI's local-Date callback contract. Each run starts a new Jest process with the recorded timezone. It checks EN/NB values, a full create/save payload, source revision, five Edit/two Add controls, clearing, invalid picker values and an offset timestamp using the existing legacy loading policy.
|
||||
|
||||
| Process timezone | Before fix | After fix |
|
||||
| --- | --- | --- |
|
||||
| America/Los_Angeles | 5 failed | 5 passed |
|
||||
| Europe/Oslo | 4 failed, 1 passed | 5 passed |
|
||||
| Pacific/Kiritimati | 4 failed, 1 passed | 5 passed |
|
||||
|
||||
These are the same five cases executed in three environments. The nearby run passed 21 cases across date-picker, edit-revision, quick-capture and native file-input suites, including those same five cases. TypeScript without emit, ESLint on the three changed files and tracked source whitespace checks passed. The cached evidence check flagged the original TypeScript receipt's blank line at EOF. That raw receipt is retained unchanged in `evidence/date-picker-calendar-day/`.
|
||||
|
||||
Actual MUI browser interaction, screenshots, native devices and provider/API server verification were not run in this isolated increment. The root integration owner will qualify the rendered picker separately. Final I18N, A3, security and release acceptance remain open.
|
||||
|
||||
## Other reviewed date contracts
|
||||
|
||||
`CalendarAgenda` validates its date-only response, parses it at UTC noon and explicitly formats in UTC. The reviewed 23 November value stayed on the 23rd in all three zones. Its backend groups by the stored calendar date and explicitly retains the legacy timezone/precision limitation.
|
||||
|
||||
`CompaniesTable` formats next-contact and relationship dates using the viewer's local timezone. Its edit form takes the raw first ten characters. Literal `2026-11-23` therefore displays as the 22nd in Los Angeles, while `2026-11-23T23:30:00Z` displays as the 24th in Oslo and opens as the 23rd in the editor. The backend fields remain legacy `DateTime?` with no precision discriminator. The current locale test covers a noon UTC timestamp. These display/loading cases require a qualified date-versus-timestamp contract before a broader change.
|
||||
|
||||
The Jobs table similarly formats a literal deadline through local `Date`, and its current test expects that expression. Edit's retained `toDateInputValue` can also move an unspecified midnight timestamp back a day in positive zones. These are separate legacy precision/loading findings. This fix does not claim their closure or reconstruct missing timezone metadata.
|
||||
|
||||
Rollback reverts the two wrapper changes and their regression package. Existing persisted dates are not rewritten.
|
||||
|
||||
## Follow-up local-today default
|
||||
|
||||
From isolated checkpoint `f7c3617e`, Add's `getTodayIso` still selected the UTC date for initialization and a successful form reset. It now uses the already imported `format` with the browser's local Date. No persisted record is rewritten.
|
||||
|
||||
Two new component cases fix the UTC clock at `2026-11-23T00:30:00Z` and `2026-11-23T23:30:00Z`. Each timezone's red run had one failure and one pass, with the earlier five cases skipped. The final full suite passed seven cases in each of Los Angeles, Oslo and Kiritimati. That is seven distinct cases repeated in three environments, including the five earlier picker cases. TypeScript and two-file lint passed. The earlier 21-case nearby run belongs to the preceding checkpoint and was not rerun for this one-line follow-up.
|
||||
|
||||
The new cases cover initial creation, Create and add another resetting the default, and closing/reopening the resulting draft. Closing and reopening the same mounted dialog preserves its existing step and draft. It does not reset every open. The initial test draft assumed otherwise and was corrected to exercise the actual successful reset path. The only write is the explicit mocked creation request, whose selected date is asserted. API server, actual browser, export build and native checks remain unexecuted.
|
||||
|
||||
Follow-up receipts are in `evidence/date-picker-local-today/`. The legacy loading and Companies contract findings above remain open.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Discovery title order follows UI language
|
||||
|
||||
10 November 2026. Baseline `aac0f3b3a9b452b48126ddaf26e1837eeadd2f6d`, branch `codex/i18n-discovery-order`.
|
||||
|
||||
The title sort used the browser's default collation and its memo omitted the UI language. Switching English to Bokmål left Å-prefixed titles before Z. The focused regression reproduced this on the unchanged baseline.
|
||||
|
||||
`JobDiscoveryPage` now passes its existing English/Bokmål display locale to `localeCompare` and includes that locale in the memo dependencies. The same locale still formats recorded timestamps. The change reaches ordinary and saved-search result arrays through their shared title sort.
|
||||
|
||||
The regression switches English → Bokmål → English with Å/Z fixtures, verifies each order, and checks that the role, municipality and title sort remain selected. Switching adds zero API reads and triggers no writes. Existing submitted search and provider contracts are retained.
|
||||
|
||||
24 tests in `job-discovery.test.tsx`, TypeScript without emit and ESLint on the two changed files passed. The initial red run selected one test and skipped the other 23. It is retained separately from the final suite result in `evidence/discovery-title-order/`.
|
||||
|
||||
Export build, rendered browser, native language/device and live-provider verification were not run in this isolated increment. Existing whole-application, European locale and final acceptance gates remain open. The root integration owner will review and publish this branch separately.
|
||||
|
||||
Rollback is the inverse of the two source/test changes. There are no schema, dependency or persisted-data changes.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 5 passed, 5 total
|
||||
Snapshots: 0 total
|
||||
Time: 6.688 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 5 passed, 5 total
|
||||
Snapshots: 0 total
|
||||
Time: 6.561 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 5 passed, 5 total
|
||||
Snapshots: 0 total
|
||||
Time: 7.132 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx edit-job-revision.test.tsx quick-capture.test.tsx file-picker-activation.test.tsx
|
||||
|
||||
|
||||
Test Suites: 4 passed, 4 total
|
||||
Tests: 21 passed, 21 total
|
||||
Snapshots: 0 total
|
||||
Time: 15.02 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx|edit-job-revision.test.tsx|quick-capture.test.tsx|file-picker-activation.test.tsx.
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
FAIL src/job-date-picker-calendar.test.tsx
|
||||
● en Add date-only picker round trip retains the selected day and existing creation payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
39 | render(wrap(<AddJobModal open initialUrl="https://example.test/job" onClose={jest.fn()} onCreated={jest.fn()} />));
|
||||
40 | await screen.findByDisplayValue("Teacher");
|
||||
> 41 | expect(screen.getByLabelText(copy.addJobModalDeadline)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
42 | fireEvent.click(screen.getByRole("button", { name: `${copy.addJobModalDeadline} clear` }));
|
||||
43 | expect(screen.getByLabelText(copy.addJobModalDeadline)).toBeEmptyDOMElement();
|
||||
44 | fireEvent.click(screen.getByRole("button", { name: `${copy.addJobModalDeadline} invalid` }));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:41:59)
|
||||
|
||||
● nb Add date-only picker round trip retains the selected day and existing creation payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
39 | render(wrap(<AddJobModal open initialUrl="https://example.test/job" onClose={jest.fn()} onCreated={jest.fn()} />));
|
||||
40 | await screen.findByDisplayValue("Teacher");
|
||||
> 41 | expect(screen.getByLabelText(copy.addJobModalDeadline)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
42 | fireEvent.click(screen.getByRole("button", { name: `${copy.addJobModalDeadline} clear` }));
|
||||
43 | expect(screen.getByLabelText(copy.addJobModalDeadline)).toBeEmptyDOMElement();
|
||||
44 | fireEvent.click(screen.getByRole("button", { name: `${copy.addJobModalDeadline} invalid` }));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:41:59)
|
||||
|
||||
● en Edit date-only picker round trip preserves all five date controls and revision payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
59 | render(wrap(<EditJobDialog open jobId={1} onClose={jest.fn()} onSaved={jest.fn()} />));
|
||||
60 | await screen.findByDisplayValue("Teacher");
|
||||
> 61 | expect(screen.getByLabelText(copy.editJobDeadline)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
62 | fireEvent.click(screen.getByRole("button", { name: `${copy.editJobDeadline} clear` }));
|
||||
63 | fireEvent.click(screen.getByRole("button", { name: `${copy.editJobDeadline} invalid` }));
|
||||
64 | expect(screen.getByLabelText(copy.editJobDeadline)).toBeEmptyDOMElement();
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:61:55)
|
||||
|
||||
● nb Edit date-only picker round trip preserves all five date controls and revision payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
59 | render(wrap(<EditJobDialog open jobId={1} onClose={jest.fn()} onSaved={jest.fn()} />));
|
||||
60 | await screen.findByDisplayValue("Teacher");
|
||||
> 61 | expect(screen.getByLabelText(copy.editJobDeadline)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
62 | fireEvent.click(screen.getByRole("button", { name: `${copy.editJobDeadline} clear` }));
|
||||
63 | fireEvent.click(screen.getByRole("button", { name: `${copy.editJobDeadline} invalid` }));
|
||||
64 | expect(screen.getByLabelText(copy.editJobDeadline)).toBeEmptyDOMElement();
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:61:55)
|
||||
|
||||
● Edit retains its existing UTC calendar-day loading policy for a legacy offset timestamp
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-24
|
||||
Received:
|
||||
2026-11-23
|
||||
|
||||
75 | render(wrap(<EditJobDialog open jobId={1} onClose={jest.fn()} onSaved={jest.fn()} />));
|
||||
76 | await screen.findByDisplayValue("Teacher");
|
||||
> 77 | expect(screen.getByLabelText(translations.en.editJobDeadline)).toHaveTextContent("2026-11-24");
|
||||
| ^
|
||||
78 | expect(client.put).not.toHaveBeenCalled();
|
||||
79 | });
|
||||
80 |
|
||||
|
||||
at Object.toHaveTextContent (src/job-date-picker-calendar.test.tsx:77:66)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 5 failed, 5 total
|
||||
Snapshots: 0 total
|
||||
Time: 4.077 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
FAIL src/job-date-picker-calendar.test.tsx
|
||||
● en Add date-only picker round trip retains the selected day and existing creation payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
46 | for (const label of [copy.addJobModalDateApplied, copy.addJobModalDeadline]) {
|
||||
47 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 48 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
49 | }
|
||||
50 | fireEvent.click(screen.getByRole("button", { name: copy.continue }));
|
||||
51 | for (let step = 0; step < 3; step++) fireEvent.click(screen.getByRole("button", { name: copy.skipAndContinue }));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:48:42)
|
||||
|
||||
● nb Add date-only picker round trip retains the selected day and existing creation payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
46 | for (const label of [copy.addJobModalDateApplied, copy.addJobModalDeadline]) {
|
||||
47 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 48 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
49 | }
|
||||
50 | fireEvent.click(screen.getByRole("button", { name: copy.continue }));
|
||||
51 | for (let step = 0; step < 3; step++) fireEvent.click(screen.getByRole("button", { name: copy.skipAndContinue }));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:48:42)
|
||||
|
||||
● en Edit date-only picker round trip preserves all five date controls and revision payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
65 | for (const label of [copy.editJobAppliedOn, copy.editJobStatusChangedOn, copy.editJobReplyReceivedOn, copy.editJobFollowUpOn, copy.editJobDeadline]) {
|
||||
66 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 67 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
68 | }
|
||||
69 | fireEvent.click(screen.getByRole("button", { name: copy.save }));
|
||||
70 | await waitFor(() => expect(client.put).toHaveBeenCalledWith("/jobapplications/1", expect.objectContaining({ expectedVersion: 7, dateApplied: "2026-11-23", deadline: "2026-11-23", followUpAt: "2026-11-23", responseDate: "2026-11-23" })));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:67:42)
|
||||
|
||||
● nb Edit date-only picker round trip preserves all five date controls and revision payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
65 | for (const label of [copy.editJobAppliedOn, copy.editJobStatusChangedOn, copy.editJobReplyReceivedOn, copy.editJobFollowUpOn, copy.editJobDeadline]) {
|
||||
66 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 67 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
68 | }
|
||||
69 | fireEvent.click(screen.getByRole("button", { name: copy.save }));
|
||||
70 | await waitFor(() => expect(client.put).toHaveBeenCalledWith("/jobapplications/1", expect.objectContaining({ expectedVersion: 7, dateApplied: "2026-11-23", deadline: "2026-11-23", followUpAt: "2026-11-23", responseDate: "2026-11-23" })));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:67:42)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 4 failed, 1 passed, 5 total
|
||||
Snapshots: 0 total
|
||||
Time: 4.882 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
FAIL src/job-date-picker-calendar.test.tsx
|
||||
● en Add date-only picker round trip retains the selected day and existing creation payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
46 | for (const label of [copy.addJobModalDateApplied, copy.addJobModalDeadline]) {
|
||||
47 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 48 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
49 | }
|
||||
50 | fireEvent.click(screen.getByRole("button", { name: copy.continue }));
|
||||
51 | for (let step = 0; step < 3; step++) fireEvent.click(screen.getByRole("button", { name: copy.skipAndContinue }));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:48:42)
|
||||
|
||||
● nb Add date-only picker round trip retains the selected day and existing creation payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
46 | for (const label of [copy.addJobModalDateApplied, copy.addJobModalDeadline]) {
|
||||
47 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 48 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
49 | }
|
||||
50 | fireEvent.click(screen.getByRole("button", { name: copy.continue }));
|
||||
51 | for (let step = 0; step < 3; step++) fireEvent.click(screen.getByRole("button", { name: copy.skipAndContinue }));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:48:42)
|
||||
|
||||
● en Edit date-only picker round trip preserves all five date controls and revision payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
65 | for (const label of [copy.editJobAppliedOn, copy.editJobStatusChangedOn, copy.editJobReplyReceivedOn, copy.editJobFollowUpOn, copy.editJobDeadline]) {
|
||||
66 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 67 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
68 | }
|
||||
69 | fireEvent.click(screen.getByRole("button", { name: copy.save }));
|
||||
70 | await waitFor(() => expect(client.put).toHaveBeenCalledWith("/jobapplications/1", expect.objectContaining({ expectedVersion: 7, dateApplied: "2026-11-23", deadline: "2026-11-23", followUpAt: "2026-11-23", responseDate: "2026-11-23" })));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:67:42)
|
||||
|
||||
● nb Edit date-only picker round trip preserves all five date controls and revision payload
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-23
|
||||
Received:
|
||||
2026-11-22
|
||||
|
||||
65 | for (const label of [copy.editJobAppliedOn, copy.editJobStatusChangedOn, copy.editJobReplyReceivedOn, copy.editJobFollowUpOn, copy.editJobDeadline]) {
|
||||
66 | fireEvent.click(screen.getByRole("button", { name: `${label} choose` }));
|
||||
> 67 | expect(screen.getByLabelText(label)).toHaveTextContent("2026-11-23");
|
||||
| ^
|
||||
68 | }
|
||||
69 | fireEvent.click(screen.getByRole("button", { name: copy.save }));
|
||||
70 | await waitFor(() => expect(client.put).toHaveBeenCalledWith("/jobapplications/1", expect.objectContaining({ expectedVersion: 7, dateApplied: "2026-11-23", deadline: "2026-11-23", followUpAt: "2026-11-23", responseDate: "2026-11-23" })));
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:67:42)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 4 failed, 1 passed, 5 total
|
||||
Snapshots: 0 total
|
||||
Time: 4.669 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 typecheck
|
||||
> tsc --noEmit --incremental false
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 7 passed, 7 total
|
||||
Snapshots: 0 total
|
||||
Time: 8.432 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 7 passed, 7 total
|
||||
Snapshots: 0 total
|
||||
Time: 8.287 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 7 passed, 7 total
|
||||
Snapshots: 0 total
|
||||
Time: 8.955 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx.
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx -t Add defaults and successful reset
|
||||
|
||||
FAIL src/job-date-picker-calendar.test.tsx
|
||||
● Add defaults and successful reset use local today at 2026-11-23T00:30:00Z
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-22
|
||||
Received:
|
||||
2026-11-23
|
||||
|
||||
43 | const view = render(form(true));
|
||||
44 | fireEvent.click(screen.getByRole("button", { name: translations.en.addJobModalEnterManually }));
|
||||
> 45 | expect(screen.getByLabelText(translations.en.addJobModalDateApplied)).toHaveTextContent(expected);
|
||||
| ^
|
||||
46 | fireEvent.click(screen.getByRole("button", { name: `${translations.en.addJobModalDateApplied} choose` }));
|
||||
47 | fireEvent.change(screen.getByRole("combobox", { name: translations.en.company }), { target: { value: "Synthetic school" } });
|
||||
48 | fireEvent.change(screen.getByLabelText(translations.en.addJobModalJobTitle), { target: { value: "Teacher" } });
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:45:73)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 1 failed, 5 skipped, 1 passed, 7 total
|
||||
Snapshots: 0 total
|
||||
Time: 4.694 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx with tests matching "Add defaults and successful reset".
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx -t Add defaults and successful reset
|
||||
|
||||
FAIL src/job-date-picker-calendar.test.tsx
|
||||
● Add defaults and successful reset use local today at 2026-11-23T23:30:00Z
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-24
|
||||
Received:
|
||||
2026-11-23
|
||||
|
||||
43 | const view = render(form(true));
|
||||
44 | fireEvent.click(screen.getByRole("button", { name: translations.en.addJobModalEnterManually }));
|
||||
> 45 | expect(screen.getByLabelText(translations.en.addJobModalDateApplied)).toHaveTextContent(expected);
|
||||
| ^
|
||||
46 | fireEvent.click(screen.getByRole("button", { name: `${translations.en.addJobModalDateApplied} choose` }));
|
||||
47 | fireEvent.change(screen.getByRole("combobox", { name: translations.en.company }), { target: { value: "Synthetic school" } });
|
||||
48 | fireEvent.change(screen.getByLabelText(translations.en.addJobModalJobTitle), { target: { value: "Teacher" } });
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:45:73)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 1 failed, 5 skipped, 1 passed, 7 total
|
||||
Snapshots: 0 total
|
||||
Time: 4.977 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx with tests matching "Add defaults and successful reset".
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-date-picker-calendar.test.tsx -t Add defaults and successful reset
|
||||
|
||||
FAIL src/job-date-picker-calendar.test.tsx
|
||||
● Add defaults and successful reset use local today at 2026-11-23T23:30:00Z
|
||||
|
||||
expect(element).toHaveTextContent()
|
||||
|
||||
Expected element to have text content:
|
||||
2026-11-24
|
||||
Received:
|
||||
2026-11-23
|
||||
|
||||
43 | const view = render(form(true));
|
||||
44 | fireEvent.click(screen.getByRole("button", { name: translations.en.addJobModalEnterManually }));
|
||||
> 45 | expect(screen.getByLabelText(translations.en.addJobModalDateApplied)).toHaveTextContent(expected);
|
||||
| ^
|
||||
46 | fireEvent.click(screen.getByRole("button", { name: `${translations.en.addJobModalDateApplied} choose` }));
|
||||
47 | fireEvent.change(screen.getByRole("combobox", { name: translations.en.company }), { target: { value: "Synthetic school" } });
|
||||
48 | fireEvent.change(screen.getByLabelText(translations.en.addJobModalJobTitle), { target: { value: "Teacher" } });
|
||||
|
||||
at toHaveTextContent (src/job-date-picker-calendar.test.tsx:45:73)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 1 failed, 5 skipped, 1 passed, 7 total
|
||||
Snapshots: 0 total
|
||||
Time: 4.542 s
|
||||
Ran all test suites matching job-date-picker-calendar.test.tsx with tests matching "Add defaults and successful reset".
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 typecheck
|
||||
> tsc --noEmit --incremental false
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-discovery.test.tsx -t title sorting follows UI language changes
|
||||
|
||||
FAIL src/job-discovery.test.tsx
|
||||
● title sorting follows UI language changes without refetching or changing discovery filters
|
||||
|
||||
expect(received).toEqual(expected) // deep equality
|
||||
|
||||
- Expected - 1
|
||||
+ Received + 1
|
||||
|
||||
Array [
|
||||
- "Zoologist",
|
||||
"Åker agronom",
|
||||
+ "Zoologist",
|
||||
]
|
||||
|
||||
115 |
|
||||
116 | act(() => { window.dispatchEvent(new StorageEvent("storage", { key: "uiLanguage", newValue: "nb" })); });
|
||||
> 117 | expect(titles()).toEqual(["Zoologist", "Åker agronom"]);
|
||||
| ^
|
||||
118 | expect(screen.getByLabelText("Rolle eller bedrift")).toHaveValue("science");
|
||||
119 | expect(screen.getByLabelText("Kommune")).toHaveValue("Oslo");
|
||||
120 | expect(screen.getByRole("combobox", { name: translations.nb.jobDiscoverySort })).toHaveTextContent(translations.nb.jobDiscoverySortTitle);
|
||||
|
||||
at Object.toEqual (src/job-discovery.test.tsx:117:20)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 1 failed, 23 skipped, 24 total
|
||||
Snapshots: 0 total
|
||||
Time: 5.888 s
|
||||
Ran all test suites matching job-discovery.test.tsx with tests matching "title sorting follows UI language changes".
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand job-discovery.test.tsx
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 24 passed, 24 total
|
||||
Snapshots: 0 total
|
||||
Time: 8.499 s
|
||||
Ran all test suites matching job-discovery.test.tsx.
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 typecheck
|
||||
> tsc --noEmit --incremental false
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Rules settings failed-save verification
|
||||
|
||||
11 November 2026. Baseline `d027754d15fadd945e0d9d38e6ca85b50d8dc885`; branch `codex/perf-rules-failed-save`; test source `9f63cff3c89a2eb1f576df16e9a44bf79dc69c84`.
|
||||
|
||||
The additional real-SQLite case warms owner A/B application decisions, then injects a SaveChanges failure while changing A's follow-up threshold. It verifies that A's tracked proposed value differs from the committed value, the shared RulesEngine read still returns committed settings even in that failed writer context, and both owners retain their previous decisions. Allowing a later save through the same writer updates A's existing reader while B remains unaffected.
|
||||
|
||||
All nine RuleSettingsFreshnessTests passed with zero failures/skips. Eight existing cases overlap the previous 35-case regression and are not added to that total. The native TRX, compressed/raw hashes and command log are retained under `evidence/rules-failed-save/`. Dependency restore used only the existing local NuGet cache. No application or dependency source changed.
|
||||
|
||||
The injected exception occurs before database save. This verifies committed-read behaviour after that failure and subsequent successful retry. Mid-transaction connection loss, MariaDB, multi-process load, latency, operational restore and release qualification remain separate.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"testSourceCommit": "9f63cff3c89a2eb1f576df16e9a44bf79dc69c84",
|
||||
"rawSha256": "7a8d4ade19612005c7f8fe648f973e646044d559b624bc15daa3230084648200",
|
||||
"compressedSha256": "50ed32b4eb8539ddc34b70e37a376be8482b5c207fa8207ae47b8d4237d51ee3",
|
||||
"rawBytes": 15156,
|
||||
"compressedBytes": 2403,
|
||||
"total": 9,
|
||||
"passed": 9,
|
||||
"failed": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Determining projects to restore...
|
||||
Restored C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\Job tracker\JobTrackerApi.Tests\PdfBrowserStub\PdfBrowserStub.csproj (in 65 ms).
|
||||
Restored C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\Job tracker\JobTrackerApi\JobTrackerApi.csproj (in 278 ms).
|
||||
Restored C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\Job tracker\JobTrackerApi.Tests\JobTrackerApi.Tests.csproj (in 287 ms).
|
||||
@@ -0,0 +1,11 @@
|
||||
JobTrackerApi -> C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\Job tracker\JobTrackerApi\bin\Debug\net9.0\JobTrackerApi.dll
|
||||
PdfBrowserStub -> C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\Job tracker\JobTrackerApi.Tests\PdfBrowserStub\bin\Debug\net9.0\PdfBrowserStub.dll
|
||||
JobTrackerApi.Tests -> C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\Job tracker\JobTrackerApi.Tests\bin\Debug\net9.0\JobTrackerApi.Tests.dll
|
||||
Test run for C:\Users\Connor\.codex\worktrees\perf-rules-failed-save\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\perf-rules-failed-save\Job tracker\JobTrackerApi.Tests\TestResults\failed-save.trx
|
||||
|
||||
Passed! - Failed: 0, Passed: 9, Skipped: 0, Total: 9, Duration: 2 s - JobTrackerApi.Tests.dll (net9.0)
|
||||
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,28 @@
|
||||
# IM10 confirmation, date and native discovery follow-up
|
||||
|
||||
Application source `5a880a6ac711db53cdcab01146542f94694a6275` adds the bounded fixes below. Native discovery caller/evidence integration is `df8f4dbbd33dc9001ae9dd4965b5d6a1b0e55748`. This report records development verification. Final A3 Gate F remains open.
|
||||
|
||||
## Confirmation focus
|
||||
|
||||
The real mobile saved-search deletion journey reproduced Cancel losing initial focus when confirmation opens above the filter Drawer. The active element was the confirmation's presentation container. Shared `ConfirmProvider` now recovers Cancel on opening-transition completion only while focus remains on that exact container. Deliberate focus already moved inside the dialog is preserved. Focus enforcement, cancellation, restoration and confirmed writes retain their existing owners.
|
||||
|
||||
The deterministic new case failed before the fix while three existing confirmation cases passed. The final selected confirmation/discovery run passed 34 cases, including the prior deliberate-focus transition regression. Raw red/green/type/lint receipts are in `evidence/im10-followup-2026-11-11/`.
|
||||
|
||||
## Calendar-day inputs
|
||||
|
||||
Add/Edit picker wrappers now parse literal dates as local calendar days and format the selected local day. The seven controls retain their request and revision contracts. Add's initial and successful-reset default now uses local today. Existing reopening draft retention remains intact. [Calendar-day report](../i18n/DATE_PICKER_CALENDAR_DAY.md) records the actual component callbacks and exact payloads.
|
||||
|
||||
Seven component cases passed separately in Los Angeles, Oslo and Kiritimati processes. They include EN/NB, all seven controls, null/invalid callbacks, exact creation/save payloads, revision7 and two fixed UTC clocks around midnight. The previous five cases and nearby suite overlap these results. These are seven cases executed in three environments. Actual MUI date-widget browser interaction and native devices remain unexecuted for this date package.
|
||||
|
||||
## Integrated checks and native browser evidence
|
||||
|
||||
- 96 selected frontend tests in 11 suites passed together on `5a880a6a`. Full application lint and export/build with TypeScript passed. Earlier 67, 34 and nearby date counts overlap this combined run.
|
||||
- Both complete existing native discovery specs passed together, 11 tests with zero skips/retries/flaky outcomes, on `ec57a24d` plus the exact confirmation fix. The separate date package was not included in that browser source. Its controls are outside those saved-search journeys. [Native reconciliation](DISCOVERY_NATIVE_DRAWER_RECONCILIATION.md) preserves the source hashes, failed/intermediate receipts and final combined native JSON/list.
|
||||
- Native JSON embeds all 31 screenshots and 27 accessibility-audit attachments. Root independently inspected the final counters and screenshot bodies, verified all 20 compressed/raw receipt hashes and four raw working-source hashes, and matched those sources to Git after LF normalization. Native owner reads/writes/foreign denials remain actual disposable SQLite API calls; provider-shaped search/run results retain their documented fixtures.
|
||||
- The earlier controlled drawer36/108 and saved16/48 matrices remain their own source-bound receipts. They were not repeated by this native package. Earlier page-query/rules tests remain separately scoped.
|
||||
|
||||
## Remaining qualifications
|
||||
|
||||
Legacy Edit timestamp loading and Company/Jobs date display still need a qualified date-versus-timestamp contract. The current fix preserves legacy parsing/loading and does not rewrite persisted records or reconstruct timezone/precision metadata. These findings are tracked in the date report.
|
||||
|
||||
Complete route/visual consistency review, affected broader regression, human/device/native-language checks and final A3 review remain open. Provider/model activation, integrated security, actual recovery, hosted/production and final release qualifications retain their separate gates. Rollback reverts the confirmation/date source commits and reruns affected checks before publication.
|
||||
@@ -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) 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. |
|
||||
| Discover Jobs | [Search-first layout](visual-correction/DISCOVERY_SEARCH_FIRST.md), [mobile filters](visual-correction/DISCOVERY_MOBILE_FILTERS.md) and [all11 native discovery cases](DISCOVERY_NATIVE_DRAWER_RECONCILIATION.md) qualify retained drafts, keyboard/focus and bounded local saved-search persistence. | Expose new filters, map and multilingual suggestions only with qualified data and the existing GJ architecture. Focused detail, actual provider-run persistence and native/owner acceptance 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,6 +2,10 @@
|
||||
|
||||
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).
|
||||
|
||||
The [11 November follow-up](IM10_FOLLOWUP_2026-11-11.md) records shared confirmation recovery, calendar-day input/default fixes, 96 combined frontend tests and both reconciled native discovery specs passing11 cases. Broader route/visual/human qualification and final Gate F remain open.
|
||||
|
||||
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).
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{"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 +1 @@
|
||||
{"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."}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
# 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);
|
||||
```
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
Binary file not shown.
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"[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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
# 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);
|
||||
```
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 build
|
||||
> node --max-old-space-size=4096 ./node_modules/next/dist/bin/next build
|
||||
|
||||
▲ Next.js 16.4.1 (Turbopack)
|
||||
✓ Running next.config.js took 29ms
|
||||
|
||||
Creating an optimized production build ...
|
||||
✓ Compiled successfully in 767ms
|
||||
Running TypeScript ...
|
||||
Finished TypeScript in 6.5s ...
|
||||
Collecting page data using 4 workers ...
|
||||
Generating static pages using 4 workers (0/3) ...
|
||||
✓ Generating static pages using 4 workers (3/3) in 816ms
|
||||
Finalizing page optimization ...
|
||||
|
||||
Route (app)
|
||||
┌ ○ /
|
||||
└ ○ /_not-found
|
||||
|
||||
|
||||
○ (Static) prerendered as static content
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand confirm.test.tsx
|
||||
|
||||
console.error
|
||||
An update to ForwardRef(ButtonBase) inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
34 | const messageRegion = screen.getByRole('region', { name: 'Delete job' });
|
||||
35 | expect(messageRegion).toHaveAttribute('tabindex', '0');
|
||||
> 36 | messageRegion.focus();
|
||||
| ^
|
||||
37 | expect(messageRegion).toHaveFocus();
|
||||
38 | });
|
||||
39 |
|
||||
|
||||
at node_modules/react-dom/cjs/react-dom-client.development.js:18758:19
|
||||
at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:874:13)
|
||||
at warnIfUpdatesNotWrappedWithActDEV (node_modules/react-dom/cjs/react-dom-client.development.js:18757:9)
|
||||
at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom-client.development.js:16409:11)
|
||||
at dispatchSetStateInternal (node_modules/react-dom/cjs/react-dom-client.development.js:9170:13)
|
||||
at dispatchSetState (node_modules/react-dom/cjs/react-dom-client.development.js:9127:7)
|
||||
at node_modules/@mui/material/ButtonBase/ButtonBase.js:162:7
|
||||
at node_modules/@mui/material/ButtonBase/ButtonBase.js:290:7
|
||||
at node_modules/@mui/utils/useEventCallback/useEventCallback.js:24:19
|
||||
at executeDispatch (node_modules/react-dom/cjs/react-dom-client.development.js:19116:9)
|
||||
at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:874:13)
|
||||
at processDispatchQueue (node_modules/react-dom/cjs/react-dom-client.development.js:19166:19)
|
||||
at node_modules/react-dom/cjs/react-dom-client.development.js:19767:9
|
||||
at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom-client.development.js:3255:40)
|
||||
at dispatchEventForPluginEventSystem (node_modules/react-dom/cjs/react-dom-client.development.js:19320:7)
|
||||
at dispatchEvent (node_modules/react-dom/cjs/react-dom-client.development.js:23585:11)
|
||||
at dispatchDiscreteEvent (node_modules/react-dom/cjs/react-dom-client.development.js:23553:11)
|
||||
at HTMLBodyElement.callTheUserObjectsOperation (node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30)
|
||||
at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25)
|
||||
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
|
||||
at HTMLButtonElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
|
||||
at Object.exports.fireFocusEventWithTargetAdjustment (node_modules/jsdom/lib/jsdom/living/helpers/focusing.js:103:10)
|
||||
at HTMLDivElementImpl.focus (node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js:58:16)
|
||||
at HTMLDivElement.focus (node_modules/jsdom/lib/jsdom/living/generated/HTMLElement.js:128:34)
|
||||
at Object.focus (src/confirm.test.tsx:36:17)
|
||||
|
||||
console.error
|
||||
An update to ForwardRef(TouchRipple) inside a test was not wrapped in act(...).
|
||||
|
||||
When testing, code that causes React state updates should be wrapped into act(...):
|
||||
|
||||
act(() => {
|
||||
/* fire events that update state */
|
||||
});
|
||||
/* assert on the output */
|
||||
|
||||
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://react.dev/link/wrap-tests-with-act
|
||||
|
||||
at node_modules/react-dom/cjs/react-dom-client.development.js:18758:19
|
||||
at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:874:13)
|
||||
at warnIfUpdatesNotWrappedWithActDEV (node_modules/react-dom/cjs/react-dom-client.development.js:18757:9)
|
||||
at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom-client.development.js:16409:11)
|
||||
at dispatchSetStateInternal (node_modules/react-dom/cjs/react-dom-client.development.js:9170:13)
|
||||
at dispatchSetState (node_modules/react-dom/cjs/react-dom-client.development.js:9127:7)
|
||||
at Object.stop (node_modules/@mui/material/ButtonBase/TouchRipple.js:292:5)
|
||||
at node_modules/@mui/material/useLazyRipple/useLazyRipple.js:74:47
|
||||
|
||||
FAIL src/confirm.test.tsx
|
||||
● finishing the opening transition recovers Cancel from the nested-modal container fallback
|
||||
|
||||
expect(element).toHaveFocus()
|
||||
|
||||
Expected element with focus:
|
||||
<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-1dn15bh-MuiButtonBase-root-MuiButton-root" tabindex="0" type="button">Cancel<span class="MuiTouchRipple-root css-r3djoj-MuiTouchRipple-root" /></button>
|
||||
Received element with focus:
|
||||
<div class="MuiDialog-container MuiDialog-scrollPaper css-19do60a-MuiDialog-container" role="presentation" style="opacity: 1; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;" tabindex="-1"><div aria-describedby="_r_f_" aria-labelledby="_r_g_" aria-modal="true" class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthXs MuiDialog-paperFullWidth css-n24a7g-MuiPaper-root-MuiDialog-paper" role="dialog" style="--Paper-shadow: 0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12);"><h2 class="MuiTypography-root MuiTypography-h6 MuiDialogTitle-root css-rcehg8-MuiTypography-root-MuiDialogTitle-root" id="_r_g_">Delete job</h2><div aria-labelledby="_r_g_" class="MuiDialogContent-root css-kw13he-MuiDialogContent-root" role="region" tabindex="0"><div class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 MuiAlert-root MuiAlert-colorWarning MuiAlert-outlinedWarning MuiAlert-outlined css-15us3fl-MuiPaper-root-MuiAlert-root" role="alert" style="--Paper-shadow: none;"><div class="MuiAlert-icon css-1wrdnka-MuiAlert-icon"><svg aria-hidden="true" class="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit css-1ckov0h-MuiSvgIcon-root" data-testid="ReportProblemOutlinedIcon" focusable="false" viewBox="0 0 24 24"><path d="M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z" /></svg></div><div class="MuiAlert-message css-zioonp-MuiAlert-message">This action may be hard to undo.</div></div><p class="MuiTypography-root MuiTypography-body1 css-3yi46c-MuiTypography-root" id="_r_f_">Are you sure?</p></div><div class="MuiDialogActions-root MuiDialogActions-spacing css-1uwjd7y-MuiDialogActions-root"><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-1dn15bh-MuiButtonBase-root-MuiButton-root" tabindex="0" type="button">Cancel<span class="MuiTouchRipple-root css-r3djoj-MuiTouchRipple-root" /></button><button class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedError MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorError MuiButton-root MuiButton-contained MuiButton-containedError MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorError css-1c26q6j-MuiButtonBase-root-MuiButton-root" tabindex="0" type="button">Delete</button></div></div></div>
|
||||
|
||||
79 | expect(container).toHaveFocus();
|
||||
80 | await act(async () => { jest.advanceTimersByTime(1000); });
|
||||
> 81 | expect(screen.getByRole('button', { name: 'Cancel' })).toHaveFocus();
|
||||
| ^
|
||||
82 | } finally {
|
||||
83 | jest.useRealTimers();
|
||||
84 | }
|
||||
|
||||
at Object.toHaveFocus (src/confirm.test.tsx:81:60)
|
||||
|
||||
Test Suites: 1 failed, 1 total
|
||||
Tests: 1 failed, 3 passed, 4 total
|
||||
Snapshots: 0 total
|
||||
Time: 3.412 s
|
||||
Ran all test suites matching confirm.test.tsx.
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 test
|
||||
> jest --runInBand confirm.test.tsx confirm-flow.test.tsx dialog-flow.test.tsx job-discovery.test.tsx
|
||||
|
||||
|
||||
Test Suites: 4 passed, 4 total
|
||||
Tests: 34 passed, 34 total
|
||||
Snapshots: 0 total
|
||||
Time: 18.477 s
|
||||
Ran all test suites matching confirm.test.tsx|confirm-flow.test.tsx|dialog-flow.test.tsx|job-discovery.test.tsx.
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 typecheck
|
||||
> tsc --noEmit --incremental false
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 typecheck
|
||||
> tsc --noEmit --incremental false
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
> 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 confirm.test.tsx confirm-flow.test.tsx dialog-flow.test.tsx job-date-picker-calendar.test.tsx edit-job-revision.test.tsx quick-capture.test.tsx file-picker-activation.test.tsx
|
||||
|
||||
|
||||
Test Suites: 11 passed, 11 total
|
||||
Tests: 96 passed, 96 total
|
||||
Snapshots: 0 total
|
||||
Time: 54.244 s, estimated 61 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|confirm.test.tsx|confirm-flow.test.tsx|dialog-flow.test.tsx|job-date-picker-calendar.test.tsx|edit-job-revision.test.tsx|quick-capture.test.tsx|file-picker-activation.test.tsx.
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
> job-tracker-ui@0.1.0 lint
|
||||
> eslint . --max-warnings=0
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
"docs/ui-modernisation/visual-correction/APPLICATION_ACTIONS_REVIEW.md": "4c6a12ddeb5d33521c6ac336492aeca3b0f115ebf08a1756d04b56f0593a4081",
|
||||
"docs/ui-modernisation/visual-correction/APPROVED_REFERENCE_MANIFEST.json": "50a9dfb53280ac44dc5e4fa1350441dab78d3ef6e66c3c0f448737c22efc6977",
|
||||
"docs/ui-modernisation/visual-correction/DISCREPANCIES.md": "db5accf7682d706cc83b8dae1ebf085b9c932deb0d875d72e144700e0e4b2812",
|
||||
"docs/ui-modernisation/visual-correction/ROUTE_COVERAGE.json": "db22044e6afbe753a1fadf37b1488b5cf8cbb49df5f236ee22f5e6e4055b5012",
|
||||
"docs/ui-modernisation/visual-correction/ROUTE_COVERAGE.json": "bbef6d0021496de3c533efb728bed282f5a7f126755b26f3347fbf4fb7e5a61d",
|
||||
"docs/ui-modernisation/visual-correction/evidence/admin-headings/processing-detail-en-dark-1024.png": "e4020cb49c37b486ed5e90b5ad7340ff3448b3c9232f10744e4a2821c48b3793",
|
||||
"docs/ui-modernisation/visual-correction/evidence/admin-headings/processing-detail-en-dark-1280.png": "3f05bdaebe605f541183277bb819903cd18ceb11b24f1339253012c137d2559e",
|
||||
"docs/ui-modernisation/visual-correction/evidence/admin-headings/processing-detail-en-dark-1440.png": "7bbe998ef813f6b1fea77b60769d6ccaaa3dcbd309ada4d783a1798b1a534e2a",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Discovery mobile filters
|
||||
|
||||
The approved A3 refinement calls for a mobile filter drawer while retaining the desktop search rail. This package starts from locale-sort checkpoint `b29c78e86d256f0c4e29f104bcd0c45572116635` on isolated branch `codex/a3-discovery-mobile-filters`.
|
||||
|
||||
At widths up to 1000 px, the existing municipality, source disclosure and saved-search controls open from a named Filters button. Wider layouts retain the permanent rail. Search drafts and saved-search definitions remain in their existing state owner. The municipality control and drawer submit button target the original search form. Search and Jump to results close the drawer and move focus to results. Escape/Close return focus to the trigger. Crossing to the desktop rail closes the modal and focuses the query. Failed saved-search writes remain visible inside the drawer with their draft.
|
||||
|
||||
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 and providers retain their roadmap dependencies. The historical phase7 discovery/saved-search suites have since been reconciled and passed all11 cases in [native reconciliation](../DISCOVERY_NATIVE_DRAWER_RECONCILIATION.md), with their exact local API/provider-fixture boundaries. Native-device, actual provider-run persistence 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.
|
||||
+1873
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
# 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.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,10 @@ 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. |
|
||||
| V37 | Shared confirmation | A confirmation opened over the filter Drawer can leave initial focus on its presentation container | RESOLVED in `df93bfb6` | [Follow-up](../IM10_FOLLOWUP_2026-11-11.md) includes red unit/native proof, preserved deliberate focus and all11 final native discovery cases. |
|
||||
| V38 | Add/Edit dates | Date-only picker values shift through UTC, and Add defaults to UTC today | RESOLVED in `265794e0` / `5a880a6a` | Seven cases in each of three timezone processes, exact payloads, null/invalid values and successful reset checked. Legacy timestamp loading and Company/Jobs display semantics remain separate. |
|
||||
|
||||
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.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,9 +59,9 @@
|
||||
"JobDiscoveryPage"
|
||||
],
|
||||
"visualStatus": "DIVIDED_ROWS_SCOPED_RENDERED_REVIEW",
|
||||
"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",
|
||||
"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.",
|
||||
"functionalCriteria": "Original preservation register retained; no capability acceptance promotion",
|
||||
"evidence": "DISCOVERY_SEARCH_FIRST.md; evidence/discovery-search-first/BROWSER.json; earlier DASHBOARD_DISCOVERY.md and DISCOVERY_TRACK_REVIEW.md"
|
||||
"evidence": "DISCOVERY_MOBILE_FILTERS.md; evidence/discovery-mobile-filters/BROWSER.json; earlier DISCOVERY_SEARCH_FIRST.md and DISCOVERY_TRACK_REVIEW.md"
|
||||
},
|
||||
{
|
||||
"route": "/jobs",
|
||||
@@ -69,7 +69,7 @@
|
||||
"JobTable"
|
||||
],
|
||||
"visualStatus": "FLAT_ROWS_CORRECTED_PENDING_FINAL_VISUAL_REVIEW",
|
||||
"afterStatus": "PASSED:36 configurations /72 title and explicit selection states at 1246994c. Earlier workspace, count, focus and Add Job evidence retained.",
|
||||
"afterStatus": "PASSED:36 configurations /108 ordinary, selection and row-menu states at bfbfaeb9. Earlier workspace, count, focus and Add Job evidence retained. Final visual and native acceptance remain open.",
|
||||
"functionalCriteria": "Original preservation register retained; no capability acceptance promotion",
|
||||
"evidence": "APPLICATION_ACTIONS_REVIEW.md; evidence/application-actions/BROWSER.json; earlier APPLICATION_SELECTION_REVIEW.md and APPLICATION_FLAT.md"
|
||||
},
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
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
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
[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)
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
[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
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
|
||||
> 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.
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"failedTests": []
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
[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)
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
[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
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user