Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@types/urijs": "^1.19.26",
"@typescript-eslint/eslint-plugin": "8.69.0",
"@typescript-eslint/parser": "8.69.0",
"@vitest/browser-playwright": "^4.1.10",
"@vitest/browser-playwright": "^4.1.11",
"@vitest/coverage-v8": "^4.1.11",
"@vitest/eslint-plugin": "^1.6.27",
"angular-eslint": "^22.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,13 @@ describe('autocompleter', () => {
});

it('should recover and keep loading results after a lookup fails', () => {
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);
const lookupError = new Error('backend rejected the query');
vi.useFakeTimers();
try {
getOptionsFnSpy.mockImplementation((searchTerm:string) => {
if (searchTerm === 'bad') {
return throwError(() => new Error('backend rejected the query'));
return throwError(() => lookupError);
}

return of(workPackagesStub).pipe(map((wps) => wps.filter((wp) => searchTerm !== '' && wp.subject.includes(searchTerm))));
Expand All @@ -279,6 +281,7 @@ describe('autocompleter', () => {
fixture.detectChanges();

expect(getOptionsFnSpy).toHaveBeenCalledWith('bad');
expect(consoleError).toHaveBeenCalledWith(lookupError);
expect(select.itemsList.items.length).toEqual(0);

inputElement.value = 'Wor';
Expand Down Expand Up @@ -438,6 +441,7 @@ describe('autocompleter', () => {
});

it('should load items with debounce', async () => {
silenceDestroyedOutputWarning();
fixture.detectChanges();

// Wait for ngAfterViewInit's internal setTimeout(25ms) and debounce to fire.
Expand Down Expand Up @@ -478,13 +482,12 @@ describe('autocompleter', () => {
});
});

// NG0953 ("Unexpected emit for destroyed OutputRef") is emitted when ng-select
// emits on an OutputRef during fixture teardown under fake timers. It is a real
// lifecycle smell, not pure noise — silencing it here is a pragmatic stopgap so
// these specs stay readable, not a fix. The proper fix is to stop the
// emit-after-destroy in the component teardown path; until then this is
// scoped to the two affected specs and passes every other warning through so it
// does not hide unrelated regressions. Do not promote this to a global filter.
// NG0953 ("Unexpected emit for destroyed OutputRef") comes from ng-select's
// dropdown panel: `_measureDimensions` retries through a Promise and
// requestAnimationFrame chain with no destroyed guard, so it emits after the
// panel is torn down (https://github.com/ng-select/ng-select/issues/2869).
// Silencing is a stopgap until ng-select guards that chain; it passes every
// other warning through. Do not promote this to a global filter.
function silenceDestroyedOutputWarning():void {
const originalWarn = console.warn.bind(console);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ describe('GlobalEditFormChangesTrackerService', () => {
beforeEach(() => {
originalOpenProject = window.OpenProject;
window.OpenProject = new OpenProject();
vi.spyOn(window, 'confirm').mockReturnValue(false);
TestBed.configureTestingModule({});
service = TestBed.inject(GlobalEditFormChangesTrackerService);
});
Expand All @@ -61,6 +62,7 @@ describe('GlobalEditFormChangesTrackerService', () => {
// eslint-disable-next-line @typescript-eslint/dot-notation
service['abortController'].abort();
window.OpenProject = originalOpenProject;
vi.restoreAllMocks();
});

it('should be created', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ describe('sortable-lists directive group behavior', () => {

describe('root teardown', () => {
@Component({
selector: 'op-sortable-lists-teardown-host',
imports: [OpSortableListsDirective, OpSortableListsListDirective, OpSortableListsItemDirective],
template: `
<div class="root" opSortableLists opSortableListsList>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,16 @@ describe('Activities tab polling controller', () => {
});

it('keeps polling after an error without an HTTP status', async () => {
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);
const networkError = new Error('network hiccup');
await renderPolling();
request.mockRejectedValue(new Error('network hiccup'));
request.mockRejectedValue(networkError);

resolveContext(pluginContext());
await vi.advanceTimersByTimeAsync(20000);

expect(request).toHaveBeenCalledTimes(2);
expect(consoleError).toHaveBeenCalledWith('Error updating activities list:', networkError);
});
});
});
9 changes: 9 additions & 0 deletions frontend/src/test-browser-polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ const globalWithProcess = globalThis as unknown as { process?:{ env:Record<strin
if (typeof globalWithProcess.process === 'undefined') {
globalWithProcess.process = { env: {} };
}

// Lit announces dev mode once per realm unless the warning is already recorded.
// lit-html dedupes by code, @lit/reactive-element by the full message.
const globalWithLitWarnings = globalThis as unknown as { litIssuedWarnings?:Set<string> };

globalWithLitWarnings.litIssuedWarnings ??= new Set([
'dev-mode',
'Lit is in dev mode. Not recommended for production! See https://lit.dev/msg/dev-mode for more information.',
]);
Loading