Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(addon-doc): render page tabs as soon as possible #9223

Closed
wants to merge 1 commit into from
Closed
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 projects/addon-doc/components/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
class="t-wrapper"
[attr.tuiTheme]="theme()"
[class.t-wrapper_transparent]="!opaque"
[style.visibility]="rendered() ? 'visible' : 'hidden'"
>
<div class="t-content">
<div
#content
id="demo-content"
>
<form
*ngIf="testForm"
class="t-form"
[formGroup]="testForm"
>
Expand Down
24 changes: 17 additions & 7 deletions projects/addon-doc/components/demo/index.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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';
Expand All @@ -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;

Expand All @@ -42,7 +43,6 @@ const MIN_WIDTH = 160;
imports: [
FormsModule,
JsonPipe,
NgIf,
NgTemplateOutlet,
ReactiveFormsModule,
TuiButton,
Expand Down Expand Up @@ -76,6 +76,7 @@ export class TuiDocDemo implements OnInit {
private readonly resizer?: ElementRef<HTMLElement>;

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);
Expand All @@ -84,6 +85,8 @@ export class TuiDocDemo implements OnInit {
@ContentChild(TemplateRef)
protected readonly template: TemplateRef<Record<string, unknown>> | null = null;

protected readonly rendered = signal(false);

protected theme = computed(() => (this.dark() ? 'dark' : 'light'));

protected dark = signal(
Expand All @@ -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;

Expand All @@ -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 {
Expand Down
9 changes: 4 additions & 5 deletions projects/addon-doc/components/page/page.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ <h1 class="t-title">
class="t-see-also"
[seeAlso]="seeAlso"
/>
<ng-container *ngFor="let tab of tabConnectors; index as index">
<ng-container
*ngIf="index === activeItemIndex"
[ngTemplateOutlet]="tab.template"
/>
<ng-container *ngFor="let tab of tabConnectors; let index = index">
<div [style.display]="index === activeItemIndex ? 'block' : 'none'">
<ng-container [ngTemplateOutlet]="tab.template" />
</div>
</ng-container>
</div>
30 changes: 25 additions & 5 deletions projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

const documentationPagePO = new TuiDocumentationPagePO(page);

await documentationPagePO.apiPageExample.locator('button').click();

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 320x480

2) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 320x480 ──────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 320x480

2) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 320x480 ──────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 320x480

2) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 320x480 ──────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 720x900

3) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 720x900 ──────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 720x900

3) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 720x900 ──────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 720x900

3) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 720x900 ──────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72

Check failure on line 21 in projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts

View workflow job for this annotation

GitHub Actions / playwright / (1 of 9)

[chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 1024x900

4) [chromium] › tests/core/dialogs/dialogs.spec.ts:12:13 › Dialogs › Prompt - 1024x900 ─────────── Error: locator.click: Error: strict mode violation: locator('#demo-content:visible').locator('button') resolved to 2 elements: 1) <button size="s" tuiicons="" tuibutton="" tuichevron="" type="button" data-size="s" tuiappearance="" class="t-button" data-appearance="primary" _ngcontent-ng-c2329576148="" automation-id="tui-demo-button__toggle-details"> Form value </button> aka getByTestId('tui-demo-button__toggle-details') 2) <button class="" tuiicons="" tuibutton="" type="button" data-size="l" tuiappearance="" data-appearance="primary"> Show </button> aka getByRole('button', { name: 'Show' }) Call log: - waiting for locator('#demo-content:visible').locator('button') 19 | const documentationPagePO = new TuiDocumentationPagePO(page); 20 | > 21 | await documentationPagePO.apiPageExample.locator('button').click(); | ^ 22 | await documentationPagePO.prepareBeforeScreenshot(); 23 | 24 | await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`); at /home/runner/work/taiga-ui/taiga-ui/projects/demo-playwright/tests/core/dialogs/dialogs.spec.ts:21:72
await documentationPagePO.prepareBeforeScreenshot();

await expect(page).toHaveScreenshot(`01-prompt_${width}x${height}.png`);
Expand Down Expand Up @@ -150,7 +150,11 @@
`${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);
Expand All @@ -162,7 +166,11 @@
`${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);
Expand All @@ -174,7 +182,11 @@
`${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);
Expand All @@ -190,7 +202,11 @@
`${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);
Expand All @@ -205,7 +221,11 @@
`${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);
Expand Down
17 changes: 15 additions & 2 deletions projects/demo-playwright/tests/demo/demo.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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$/);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}

Expand Down
10 changes: 7 additions & 3 deletions projects/demo-playwright/utils/wait-stable-state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {Locator} from '@playwright/test';

export async function waitStableState(locator: Locator): Promise<void> {
export async function waitStableState(locator: Locator): Promise<boolean> {
try {
const handle = await locator.elementHandle();

Expand All @@ -12,6 +12,10 @@ export async function waitStableState(locator: Locator): Promise<void> {

// 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;
}
}
2 changes: 1 addition & 1 deletion projects/demo/src/modules/components/tabs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@

<ng-template pageTab="Routing">
<tui-doc-example [content]="8 | tuiExample: 'html,ts'">
<router-outlet />
<router-outlet *ngIf="path.url.endsWith('Routing')" />
</tui-doc-example>
</ng-template>
</tui-doc-page>
5 changes: 4 additions & 1 deletion projects/demo/src/modules/components/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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'];
Expand Down
Loading