From 2a3e1b83512da39130266ba90a918ea7aa22b4ff Mon Sep 17 00:00:00 2001 From: splincode Date: Thu, 26 Sep 2024 19:02:58 +0300 Subject: [PATCH] feat(addon-doc): render page tabs as soon as possible --- projects/addon-doc/components/demo/index.html | 2 +- projects/addon-doc/components/demo/index.ts | 24 ++++++++++----- .../components/page/page.template.html | 9 +++--- .../tests/core/dialogs/dialogs.spec.ts | 30 +++++++++++++++---- .../demo-playwright/tests/demo/demo.spec.ts | 17 +++++++++-- .../tests/kit/routable/routable.spec.ts | 2 +- .../page-objects/documentation-api-page.po.ts | 2 +- .../utils/wait-stable-state.ts | 10 +++++-- .../src/modules/components/tabs/index.html | 2 +- .../demo/src/modules/components/tabs/index.ts | 5 +++- 10 files changed, 76 insertions(+), 27 deletions(-) diff --git a/projects/addon-doc/components/demo/index.html b/projects/addon-doc/components/demo/index.html index 8c4b82f8e970..2bb9f3d0ef90 100644 --- a/projects/addon-doc/components/demo/index.html +++ b/projects/addon-doc/components/demo/index.html @@ -25,6 +25,7 @@ class="t-wrapper" [attr.tuiTheme]="theme()" [class.t-wrapper_transparent]="!opaque" + [style.visibility]="rendered() ? 'visible' : 'hidden'" >
diff --git a/projects/addon-doc/components/demo/index.ts b/projects/addon-doc/components/demo/index.ts index 2469774c71fc..d6499014c967 100644 --- a/projects/addon-doc/components/demo/index.ts +++ b/projects/addon-doc/components/demo/index.ts @@ -1,10 +1,11 @@ -import {JsonPipe, Location, NgIf, NgTemplateOutlet} from '@angular/common'; +import {JsonPipe, Location, NgTemplateOutlet} from '@angular/common'; import type {ElementRef, OnInit} from '@angular/core'; import { ChangeDetectionStrategy, Component, computed, ContentChild, + DestroyRef, inject, Input, signal, @@ -13,7 +14,7 @@ import { } from '@angular/core'; import {takeUntilDestroyed, toObservable} from '@angular/core/rxjs-interop'; import type {AbstractControl} from '@angular/forms'; -import {FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {FormControl, FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms'; import type {Params, UrlTree} from '@angular/router'; import {UrlSerializer} from '@angular/router'; import {TUI_DOC_DEMO_TEXTS, TUI_DOC_URL_STATE_HANDLER} from '@taiga-ui/addon-doc/tokens'; @@ -32,7 +33,7 @@ import {TuiSwitch} from '@taiga-ui/kit/components/switch'; import {TuiChevron} from '@taiga-ui/kit/directives/chevron'; import {TuiSelectModule} from '@taiga-ui/legacy/components/select'; import {TuiTextfieldControllerModule} from '@taiga-ui/legacy/directives/textfield-controller'; -import {skip} from 'rxjs'; +import {skip, timer} from 'rxjs'; const MIN_WIDTH = 160; @@ -42,7 +43,6 @@ const MIN_WIDTH = 160; imports: [ FormsModule, JsonPipe, - NgIf, NgTemplateOutlet, ReactiveFormsModule, TuiButton, @@ -76,6 +76,7 @@ export class TuiDocDemo implements OnInit { private readonly resizer?: ElementRef; private readonly el = tuiInjectElement(); + private readonly destroyRef = inject(DestroyRef); private readonly locationRef = inject(Location); private readonly urlSerializer = inject(UrlSerializer); private readonly urlStateHandler = inject(TUI_DOC_URL_STATE_HANDLER); @@ -84,6 +85,8 @@ export class TuiDocDemo implements OnInit { @ContentChild(TemplateRef) protected readonly template: TemplateRef> | null = null; + protected readonly rendered = signal(false); + protected theme = computed(() => (this.dark() ? 'dark' : 'light')); protected dark = signal( @@ -94,7 +97,9 @@ export class TuiDocDemo implements OnInit { .pipe(skip(1), takeUntilDestroyed()) .subscribe((mode) => this.onModeChange(mode)); - protected testForm?: FormGroup; + protected testForm = new FormGroup<{testValue: AbstractControl}>({ + testValue: new FormControl(null), + }); protected readonly updateOnVariants = ['change', 'blur', 'submit'] as const; @@ -113,8 +118,13 @@ export class TuiDocDemo implements OnInit { public sticky = true; public ngOnInit(): void { - this.createForm(); - this.updateWidth(this.sandboxWidth + this.delta); + timer(0) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.createForm(); + this.updateWidth(this.sandboxWidth + this.delta); + this.rendered.set(true); + }); } protected onResize(): void { diff --git a/projects/addon-doc/components/page/page.template.html b/projects/addon-doc/components/page/page.template.html index f95c94cd9506..6ba0cdbae0cf 100644 --- a/projects/addon-doc/components/page/page.template.html +++ b/projects/addon-doc/components/page/page.template.html @@ -70,10 +70,9 @@

class="t-see-also" [seeAlso]="seeAlso" /> - - + +
+ +

diff --git a/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts b/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts index 769f773b6b0b..c5be5a7ceaaf 100644 --- a/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts +++ b/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts @@ -150,7 +150,11 @@ test.describe('Dialogs', () => { `${DemoRoute.Dialog}/API?closeable=true&dismissible=false`, ); - await page.locator('tui-doc-page button[data-appearance="primary"]').click(); + await page + .locator('button[data-appearance="primary"]:visible') + .getByText('Show') + .click(); + await page.mouse.click(100, 100); await expect(page.locator('tui-dialog')).toHaveCount(1); @@ -162,7 +166,11 @@ test.describe('Dialogs', () => { `${DemoRoute.Dialog}/API?closeable=false&dismissible=true`, ); - await page.locator('tui-doc-page button[data-appearance="primary"]').click(); + await page + .locator('button[data-appearance="primary"]:visible') + .getByText('Show') + .click(); + await page.mouse.click(100, 100); await expect(page.locator('tui-dialog')).toHaveCount(0); @@ -174,7 +182,11 @@ test.describe('Dialogs', () => { `${DemoRoute.Dialog}/API?closeable=true&dismissible=false`, ); - await page.locator('tui-doc-page button[data-appearance="primary"]').click(); + await page + .locator('button[data-appearance="primary"]:visible') + .getByText('Show') + .click(); + await page.mouse.click(100, 100); await expect(page.locator('tui-dialog')).toHaveCount(1); @@ -190,7 +202,11 @@ test.describe('Dialogs', () => { `${DemoRoute.Dialog}/API?size=fullscreen&dismissible=true`, ); - await page.locator('tui-doc-page button[data-appearance="primary"]').click(); + await page + .locator('button[data-appearance="primary"]:visible') + .getByText('Show') + .click(); + await page.mouse.click(100, 100); await expect(page.locator('tui-dialog')).toHaveCount(1); @@ -205,7 +221,11 @@ test.describe('Dialogs', () => { `${DemoRoute.Dialog}/API?size=fullscreen&dismissible=true`, ); - await page.locator('tui-doc-page button[data-appearance="primary"]').click(); + await page + .locator('button[data-appearance="primary"]:visible') + .getByText('Show') + .click(); + await page.mouse.click(100, 100); await expect(page.locator('tui-dialog')).toHaveCount(1); diff --git a/projects/demo-playwright/tests/demo/demo.spec.ts b/projects/demo-playwright/tests/demo/demo.spec.ts index 83159721eb5c..729f050a1837 100644 --- a/projects/demo-playwright/tests/demo/demo.spec.ts +++ b/projects/demo-playwright/tests/demo/demo.spec.ts @@ -1,4 +1,10 @@ -import {TuiDocumentationPagePO, tuiGoto, tuiMockImages} from '@demo-playwright/utils'; +import { + TuiDocumentationPagePO, + tuiGoto, + tuiMockImages, + waitStableState, +} from '@demo-playwright/utils'; +import type {Locator} from '@playwright/test'; import {expect, test} from '@playwright/test'; import {tuiIsFlakyExample} from './is-flaky-examples'; @@ -24,9 +30,16 @@ test.describe('Demo', () => { } }).toPass(); + const visibleExamples: Locator[] = []; const examples = await page.getByTestId('tui-doc-example').all(); - for (const [i, example] of examples.entries()) { + for (const example of examples) { + if (await waitStableState(example)) { + visibleExamples.push(example); + } + } + + for (const [i, example] of visibleExamples.entries()) { if (tuiIsFlakyExample(path, i)) { continue; } diff --git a/projects/demo-playwright/tests/kit/routable/routable.spec.ts b/projects/demo-playwright/tests/kit/routable/routable.spec.ts index 2aae3f21e36e..f4c380b0c775 100644 --- a/projects/demo-playwright/tests/kit/routable/routable.spec.ts +++ b/projects/demo-playwright/tests/kit/routable/routable.spec.ts @@ -27,7 +27,7 @@ test.describe('Routable', () => { await expect(page).toHaveURL(/\/dialog\/lazy-routable\/path\/to\/dialog$/); - await page.locator('[automation-id="tui-dialog__close"]').click(); + await page.locator('[automation-id="tui-dialog__close"]').nth(1).click(); await expect(page).toHaveURL(/\/dialog\/lazy-routable$/); }); diff --git a/projects/demo-playwright/utils/page-objects/documentation-api-page.po.ts b/projects/demo-playwright/utils/page-objects/documentation-api-page.po.ts index 1f5eb51a4e47..9ce48dd09833 100644 --- a/projects/demo-playwright/utils/page-objects/documentation-api-page.po.ts +++ b/projects/demo-playwright/utils/page-objects/documentation-api-page.po.ts @@ -6,7 +6,7 @@ import {waitStableState} from '../wait-stable-state'; export class TuiDocumentationApiPagePO { public readonly pageExamples: Locator = this.page.locator('tui-doc-example'); - public readonly apiPageExample: Locator = this.page.locator('#demo-content'); + public readonly apiPageExample: Locator = this.page.locator('#demo-content:visible'); constructor(protected readonly page: Page) {} diff --git a/projects/demo-playwright/utils/wait-stable-state.ts b/projects/demo-playwright/utils/wait-stable-state.ts index 67392805ee17..6be28b71819b 100644 --- a/projects/demo-playwright/utils/wait-stable-state.ts +++ b/projects/demo-playwright/utils/wait-stable-state.ts @@ -1,6 +1,6 @@ import type {Locator} from '@playwright/test'; -export async function waitStableState(locator: Locator): Promise { +export async function waitStableState(locator: Locator): Promise { try { const handle = await locator.elementHandle(); @@ -12,6 +12,10 @@ export async function waitStableState(locator: Locator): Promise { // https://playwright.dev/docs/actionability#visible // Element is considered visible when it has non-empty bounding box - await handle?.waitForElementState('visible'); - } catch {} + await handle?.waitForElementState('visible', {timeout: 1000}); + + return true; + } catch { + return false; + } } diff --git a/projects/demo/src/modules/components/tabs/index.html b/projects/demo/src/modules/components/tabs/index.html index d3fa0e0a9a68..06346642f35d 100644 --- a/projects/demo/src/modules/components/tabs/index.html +++ b/projects/demo/src/modules/components/tabs/index.html @@ -158,7 +158,7 @@ - + diff --git a/projects/demo/src/modules/components/tabs/index.ts b/projects/demo/src/modules/components/tabs/index.ts index 33ea604f68c2..788124bf9b5e 100644 --- a/projects/demo/src/modules/components/tabs/index.ts +++ b/projects/demo/src/modules/components/tabs/index.ts @@ -1,4 +1,5 @@ -import {Component} from '@angular/core'; +import {Component, inject} from '@angular/core'; +import {Router} from '@angular/router'; import {changeDetection} from '@demo/emulate/change-detection'; import {TuiDemo} from '@demo/utils'; import {tuiDocExampleOptionsProvider} from '@taiga-ui/addon-doc'; @@ -14,6 +15,8 @@ import {TuiTabs} from '@taiga-ui/kit'; providers: [tuiDocExampleOptionsProvider({fullsize: true})], }) export default class Page { + protected readonly path = inject(Router); + protected buttons = ['Button 1', 'Button 2', 'Button 3', 'Button 4']; protected readonly moreContentVariants = ['', 'And more'];