mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs(docs-infra): replace wait with debounce for search
Replaces custom search debounce with `debounced`
This commit is contained in:
committed by
Pawel Kozlowski
parent
7234432715
commit
ff2ba7c864
@@ -14,7 +14,7 @@ import {Router, provideRouter} from '@angular/router';
|
||||
import {SearchDialog} from './search-dialog.component';
|
||||
import {ENVIRONMENT, WINDOW} from '../../providers';
|
||||
import {ALGOLIA_CLIENT, Search} from '../../services';
|
||||
import {FakeEventTarget} from '../../testing/index';
|
||||
import {FakeEventTarget, timeout, useAutoTick} from '../../testing/index';
|
||||
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
|
||||
import {SearchResult} from '../../interfaces';
|
||||
|
||||
@@ -27,8 +27,10 @@ describe('SearchDialog', () => {
|
||||
|
||||
let search: Search;
|
||||
|
||||
useAutoTick();
|
||||
|
||||
beforeEach(async () => {
|
||||
searchResults.and.returnValue([]);
|
||||
searchResults.and.returnValue(Promise.resolve({results: [{hits: []}]}));
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [SearchDialog],
|
||||
@@ -55,6 +57,9 @@ describe('SearchDialog', () => {
|
||||
// Fire the request
|
||||
TestBed.inject(ApplicationRef).tick();
|
||||
|
||||
// The delay from debounced (200ms)
|
||||
await timeout(300);
|
||||
|
||||
// Wait for the resource to resolve
|
||||
await TestBed.inject(ApplicationRef).whenStable();
|
||||
|
||||
@@ -85,6 +90,9 @@ describe('SearchDialog', () => {
|
||||
// Fire the request
|
||||
TestBed.inject(ApplicationRef).tick();
|
||||
|
||||
// The delay from debounced (200ms)
|
||||
await timeout(300);
|
||||
|
||||
// Wait for the resource to resolve
|
||||
await TestBed.inject(ApplicationRef).whenStable();
|
||||
|
||||
@@ -96,7 +104,7 @@ describe('SearchDialog', () => {
|
||||
});
|
||||
|
||||
it('should display `Start typing to see results` message when there are no provided query', () => {
|
||||
searchResults.and.returnValue(undefined);
|
||||
searchResults.and.returnValue(Promise.resolve(undefined));
|
||||
|
||||
const startTypingContainer = fixture.debugElement.query(
|
||||
By.css('.docs-search-results__start-typing'),
|
||||
@@ -112,6 +120,9 @@ describe('SearchDialog', () => {
|
||||
// Fire the request
|
||||
TestBed.inject(ApplicationRef).tick();
|
||||
|
||||
// The delay from debounced (200ms)
|
||||
await timeout(300);
|
||||
|
||||
// Wait for the resource to resolve
|
||||
await TestBed.inject(ApplicationRef).whenStable();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Injectable,
|
||||
InjectionToken,
|
||||
Provider,
|
||||
debounced,
|
||||
inject,
|
||||
linkedSignal,
|
||||
resource,
|
||||
@@ -48,13 +49,11 @@ export class Search {
|
||||
private readonly config = inject(ENVIRONMENT);
|
||||
private readonly client = inject(ALGOLIA_CLIENT);
|
||||
|
||||
debounceParams = debounced(this.searchQuery, SEARCH_DELAY);
|
||||
|
||||
readonly resultsResource = resource({
|
||||
params: () => this.searchQuery() || undefined, // coerces empty string to undefined
|
||||
loader: async ({params: query, abortSignal}) => {
|
||||
// Until we have a better alternative we debounce by awaiting for a short delay.
|
||||
await wait(SEARCH_DELAY, abortSignal);
|
||||
return this.searchWithQuery(query);
|
||||
},
|
||||
params: () => this.debounceParams.value() || undefined, // coerces empty string to undefined
|
||||
loader: async ({params}) => this.searchWithQuery(params),
|
||||
});
|
||||
|
||||
readonly searchResults = linkedSignal<SearchResultItem[] | undefined, SearchResultItem[]>({
|
||||
@@ -223,27 +222,6 @@ function matched(snippet: SnippetResult | undefined): boolean {
|
||||
return snippet?.matchLevel !== undefined && snippet.matchLevel !== 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary helper to implement the debounce functionality on the search resource
|
||||
*/
|
||||
function wait(ms: number, signal: AbortSignal): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
const onAbort = () => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error('Operation aborted'));
|
||||
};
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
signal.removeEventListener('abort', onAbort);
|
||||
resolve();
|
||||
}, ms);
|
||||
|
||||
signal.addEventListener('abort', onAbort, {once: true});
|
||||
});
|
||||
}
|
||||
|
||||
function extractPackageNameFromUrl(url: string): string | null {
|
||||
const extractedSegment = url.match(/\/api\/(.*)\/.*#?/);
|
||||
if (extractedSegment == null) {
|
||||
|
||||
@@ -21,8 +21,10 @@ ts_project(
|
||||
"index.ts",
|
||||
],
|
||||
),
|
||||
tsconfig = "//adev/shared-docs:tsconfig_test",
|
||||
deps = [
|
||||
"//adev:node_modules/@angular/core",
|
||||
"//adev:node_modules/@types/jasmine",
|
||||
"//adev:node_modules/@webcontainer/api",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -181,3 +181,46 @@ export class FakeWebContainerProcess implements WebContainerProcess {
|
||||
kill(): void {}
|
||||
resize(dimensions: {cols: number; rows: number}): void {}
|
||||
}
|
||||
|
||||
// Copy from utils in packages/private/testing
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves after the specified time.
|
||||
*
|
||||
* @param ms - Time to wait in milliseconds. Defaults to 0.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* await timeout(100); // Wait 100ms
|
||||
* ```
|
||||
*/
|
||||
export async function timeout(ms?: number): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs Jasmine's fake clock with auto-tick enabled for all tests in the describe block.
|
||||
* Call at the top level of a describe block to automatically advance time for async operations.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* describe('MyComponent', () => {
|
||||
* useAutoTick();
|
||||
*
|
||||
* it('should handle timers', () => {
|
||||
* // setTimeout, setInterval, etc. will execute synchronously
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function useAutoTick() {
|
||||
beforeEach(() => {
|
||||
jasmine.clock().install();
|
||||
jasmine.clock().autoTick();
|
||||
});
|
||||
afterEach(() => {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user