|
2 | 2 | // Use of this source code is governed by a BSD-style license that can be |
3 | 3 | // found in the LICENSE file. |
4 | 4 |
|
| 5 | +import * as Common from '../../../core/common/common.js'; |
5 | 6 | import * as Trace from '../../../models/trace/trace.js'; |
6 | 7 | import {dispatchClickEvent} from '../../../testing/DOMHelpers.js'; |
7 | 8 | import {describeWithEnvironment, updateHostConfig} from '../../../testing/EnvironmentHelpers.js'; |
@@ -315,6 +316,46 @@ describeWithEnvironment('Overlays', () => { |
315 | 316 | return {overlays, container, charts}; |
316 | 317 | } |
317 | 318 |
|
| 319 | + async function createAnnotationsLabelElement( |
| 320 | + context: Mocha.Suite|Mocha.Context|null, file: string, entryIndex: number, label?: string): Promise<{ |
| 321 | + elementsWrapper: HTMLElement, |
| 322 | + inputField: HTMLElement, |
| 323 | + overlays: Overlays.Overlays.Overlays, |
| 324 | + event: Trace.Types.Events.Event, |
| 325 | + }> { |
| 326 | + updateHostConfig({ |
| 327 | + devToolsAiGeneratedTimelineLabels: { |
| 328 | + enabled: true, |
| 329 | + } |
| 330 | + }); |
| 331 | + |
| 332 | + const {parsedTrace} = await TraceLoader.traceEngine(context, file); |
| 333 | + const {overlays, container, charts} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
| 334 | + const event = charts.mainProvider.eventByIndex?.(entryIndex); |
| 335 | + assert.isOk(event); |
| 336 | + |
| 337 | + // Create an entry label overlay |
| 338 | + Timeline.ModificationsManager.ModificationsManager.activeManager()?.createAnnotation({ |
| 339 | + type: 'ENTRY_LABEL', |
| 340 | + entry: event, |
| 341 | + label: label ?? '', |
| 342 | + }); |
| 343 | + await overlays.update(); |
| 344 | + |
| 345 | + // Ensure that the overlay was created. |
| 346 | + const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
| 347 | + assert.isOk(overlayDOM); |
| 348 | + const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
| 349 | + assert.isOk(component?.shadowRoot); |
| 350 | + component.connectedCallback(); |
| 351 | + const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
| 352 | + assert.isOk(elementsWrapper); |
| 353 | + const inputField = elementsWrapper.querySelector<HTMLElement>('.input-field'); |
| 354 | + assert.isOk(inputField); |
| 355 | + |
| 356 | + return {elementsWrapper, inputField, overlays, event}; |
| 357 | + } |
| 358 | + |
318 | 359 | it('can render an entry selected overlay', async function() { |
319 | 360 | const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
320 | 361 | const {overlays, container, charts} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
@@ -435,53 +476,47 @@ describeWithEnvironment('Overlays', () => { |
435 | 476 | }); |
436 | 477 | }); |
437 | 478 |
|
438 | | - // TODO: update to check if the fre is completed and make the dialog visible dependant on that |
439 | | - it('should show FRE dialog on the ai suggestion button click', async function() { |
440 | | - updateHostConfig({ |
441 | | - devToolsAiGeneratedTimelineLabels: { |
442 | | - enabled: true, |
443 | | - } |
444 | | - }); |
| 479 | + it('should show FRE dialog on the ai suggestion button click if the `ai-annotations-enabled` setting is off', |
| 480 | + async function() { |
| 481 | + Common.Settings.moduleSetting('ai-annotations-enabled').set(false); |
| 482 | + const {elementsWrapper, inputField} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50); |
445 | 483 |
|
446 | | - const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
447 | | - const {overlays, container} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
448 | | - const charts = createCharts(parsedTrace); |
449 | | - const event = charts.mainProvider.eventByIndex?.(50); |
450 | | - assert.isOk(event); |
| 484 | + // Double click on the label box to make it editable and focus on it |
| 485 | + inputField.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
451 | 486 |
|
452 | | - // Since ENTRY_LABEL is AnnotationOverlay, create it through ModificationsManager |
453 | | - Timeline.ModificationsManager.ModificationsManager.activeManager()?.createAnnotation({ |
454 | | - type: 'ENTRY_LABEL', |
455 | | - label: '', |
456 | | - entry: event, |
457 | | - }); |
| 487 | + const aiLabelButtonWrapper = |
| 488 | + elementsWrapper.querySelector<HTMLElement>('.ai-label-button-wrapper') as HTMLSpanElement; |
| 489 | + assert.isOk(aiLabelButtonWrapper); |
| 490 | + const aiButton = aiLabelButtonWrapper.querySelector<HTMLElement>('.ai-label-button') as HTMLSpanElement; |
| 491 | + assert.isOk(aiButton); |
458 | 492 |
|
459 | | - await overlays.update(); |
460 | | - const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
461 | | - assert.isOk(overlayDOM); |
462 | | - const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
463 | | - assert.isOk(component?.shadowRoot); |
464 | | - const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
465 | | - assert.isOk(elementsWrapper); |
466 | | - const inputField = elementsWrapper.querySelector<HTMLElement>('.input-field'); |
467 | | - assert.isOk(inputField); |
| 493 | + // This dialog should not be visible unless the `generate annotation` button is clicked |
| 494 | + assert.isFalse(showFreDialogStub.called, 'Expected FreDialog to be not shown but it\'s shown'); |
| 495 | + aiButton.dispatchEvent(new FocusEvent('click', {bubbles: true})); |
468 | 496 |
|
469 | | - // Double click on the label box to make it editable and focus on it |
470 | | - inputField.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
| 497 | + // This dialog should be visible |
| 498 | + assert.isTrue(showFreDialogStub.called, 'Expected FreDialog to be shown but it\'s not shown'); |
| 499 | + }); |
471 | 500 |
|
472 | | - const aiLabelButtonWrapper = |
473 | | - elementsWrapper.querySelector<HTMLElement>('.ai-label-button-wrapper') as HTMLSpanElement; |
474 | | - assert.isOk(aiLabelButtonWrapper); |
475 | | - const aiButton = aiLabelButtonWrapper.querySelector<HTMLElement>('.ai-label-button') as HTMLSpanElement; |
476 | | - assert.isOk(aiButton); |
| 501 | + it('should not show FRE dialog on the ai suggestion button click if the `ai-annotations-enabled` setting is on', |
| 502 | + async function() { |
| 503 | + Common.Settings.moduleSetting('ai-annotations-enabled').set(true); |
| 504 | + const {elementsWrapper, inputField} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50); |
477 | 505 |
|
478 | | - // This dialog should not be visible unless the `generate annotation` button is clicked |
479 | | - assert.isFalse(showFreDialogStub.called, 'Expected FreDialog to be not shown but it\'s shown'); |
480 | | - aiButton.dispatchEvent(new FocusEvent('click', {bubbles: true})); |
| 506 | + // Double click on the label box to make it editable and focus on it |
| 507 | + inputField.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
481 | 508 |
|
482 | | - // This dialog should be visible |
483 | | - assert.isTrue(showFreDialogStub.called, 'Expected FreDialog to be shown but it\'s not shown'); |
484 | | - }); |
| 509 | + const aiLabelButtonWrapper = |
| 510 | + elementsWrapper.querySelector<HTMLElement>('.ai-label-button-wrapper') as HTMLSpanElement; |
| 511 | + |
| 512 | + assert.isOk(aiLabelButtonWrapper); |
| 513 | + const aiButton = aiLabelButtonWrapper.querySelector<HTMLElement>('.ai-label-button') as HTMLSpanElement; |
| 514 | + assert.isOk(aiButton); |
| 515 | + |
| 516 | + aiButton.dispatchEvent(new FocusEvent('click', {bubbles: true})); |
| 517 | + // This dialog should not be visible on the `generate label` button click since the setting is already on |
| 518 | + assert.isFalse(showFreDialogStub.called, 'Expected FreDialog to be shown but it\'s not shown'); |
| 519 | + }); |
485 | 520 |
|
486 | 521 | it('toggles overlays container display', async function() { |
487 | 522 | const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
@@ -518,59 +553,13 @@ describeWithEnvironment('Overlays', () => { |
518 | 553 | assert.lengthOf(container.children, 1); |
519 | 554 | }); |
520 | 555 |
|
521 | | - it('can render the label for entry label overlay', async function() { |
522 | | - const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
523 | | - const {overlays, container, charts} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
524 | | - const event = charts.mainProvider.eventByIndex?.(50); |
525 | | - assert.isOk(event); |
526 | | - |
527 | | - overlays.add({ |
528 | | - type: 'ENTRY_LABEL', |
529 | | - entry: event, |
530 | | - label: 'entry label', |
531 | | - }); |
532 | | - await overlays.update(); |
533 | | - |
534 | | - const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
535 | | - assert.isOk(overlayDOM); |
536 | | - const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
537 | | - assert.isOk(component?.shadowRoot); |
538 | | - |
539 | | - const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
540 | | - assert.isOk(elementsWrapper); |
541 | | - |
542 | | - const inputField = elementsWrapper.querySelector<HTMLElement>('.input-field'); |
543 | | - assert.isOk(inputField); |
544 | | - |
| 556 | + it('can render provided label for entry label overlay', async function() { |
| 557 | + const {inputField} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50, 'entry label'); |
545 | 558 | assert.strictEqual(inputField?.innerText, 'entry label'); |
546 | 559 | }); |
547 | 560 |
|
548 | 561 | it('Inputting `Enter`into label overlay makes it non-editable', async function() { |
549 | | - const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
550 | | - const {overlays, container, charts} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
551 | | - const event = charts.mainProvider.eventByIndex?.(50); |
552 | | - assert.isOk(event); |
553 | | - |
554 | | - // Create an entry label overlay |
555 | | - overlays.add({ |
556 | | - type: 'ENTRY_LABEL', |
557 | | - entry: event, |
558 | | - label: 'label', |
559 | | - }); |
560 | | - await overlays.update(); |
561 | | - |
562 | | - // Ensure that the overlay was created. |
563 | | - const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
564 | | - assert.isOk(overlayDOM); |
565 | | - |
566 | | - const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
567 | | - assert.isOk(component?.shadowRoot); |
568 | | - component.connectedCallback(); |
569 | | - const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
570 | | - assert.isOk(elementsWrapper); |
571 | | - |
572 | | - const inputField = elementsWrapper.querySelector<HTMLElement>('.input-field'); |
573 | | - assert.isOk(inputField); |
| 562 | + const {inputField} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50, 'label'); |
574 | 563 |
|
575 | 564 | // Double click on the label box to make it editable and focus on it |
576 | 565 | inputField.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
@@ -687,31 +676,7 @@ describeWithEnvironment('Overlays', () => { |
687 | 676 | }); |
688 | 677 |
|
689 | 678 | it('Removes empty label if it is empty when navigated away from (removed focused from)', async function() { |
690 | | - const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
691 | | - const {overlays, container, charts} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
692 | | - const event = charts.mainProvider.eventByIndex?.(50); |
693 | | - assert.isOk(event); |
694 | | - |
695 | | - // Create an entry label overlay |
696 | | - Timeline.ModificationsManager.ModificationsManager.activeManager()?.createAnnotation({ |
697 | | - type: 'ENTRY_LABEL', |
698 | | - entry: event, |
699 | | - label: '', |
700 | | - }); |
701 | | - await overlays.update(); |
702 | | - |
703 | | - // Ensure that the overlay was created. |
704 | | - const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
705 | | - assert.isOk(overlayDOM); |
706 | | - const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
707 | | - assert.isOk(component?.shadowRoot); |
708 | | - |
709 | | - component.connectedCallback(); |
710 | | - const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
711 | | - assert.isOk(elementsWrapper); |
712 | | - |
713 | | - const inputField = elementsWrapper.querySelector<HTMLElement>('.input-field'); |
714 | | - assert.isOk(inputField); |
| 679 | + const {inputField, overlays, event} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50); |
715 | 680 |
|
716 | 681 | // Double click on the label box to make it editable and focus on it |
717 | 682 | inputField.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
@@ -927,70 +892,25 @@ describeWithEnvironment('Overlays', () => { |
927 | 892 | assert.lengthOf(container.children, 0); |
928 | 893 | }); |
929 | 894 |
|
930 | | - it('the label entry field is editable when created', async function() { |
931 | | - const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
932 | | - const {overlays, container} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
933 | | - const charts = createCharts(parsedTrace); |
934 | | - const event = charts.mainProvider.eventByIndex?.(50); |
935 | | - assert.isOk(event); |
936 | | - |
937 | | - // Since ENTRY_LABEL is AnnotationOverlay, create it through ModificationsManager |
938 | | - Timeline.ModificationsManager.ModificationsManager.activeManager()?.createAnnotation({ |
939 | | - type: 'ENTRY_LABEL', |
940 | | - label: '', |
941 | | - entry: event, |
942 | | - }); |
943 | | - |
944 | | - await overlays.update(); |
945 | | - const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
946 | | - assert.isOk(overlayDOM); |
947 | | - const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
948 | | - assert.isOk(component?.shadowRoot); |
949 | | - |
950 | | - const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
951 | | - const inputField = elementsWrapper?.querySelector<HTMLElement>('.input-field') as HTMLSpanElement; |
952 | | - assert.isOk(inputField); |
| 895 | + it('the label entry field is editable when created without initial label', async function() { |
| 896 | + const {inputField} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50); |
953 | 897 | // The label input box should be editable after it is created and before anything else happened |
954 | 898 | assert.isTrue(inputField.isContentEditable); |
955 | 899 | }); |
956 | 900 |
|
957 | 901 | it('the label entry field is in focus after being double clicked on', async function() { |
958 | | - const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); |
959 | | - const {overlays, container} = setupChartWithDimensionsAndAnnotationOverlayListeners(parsedTrace); |
960 | | - const charts = createCharts(parsedTrace); |
961 | | - const event = charts.mainProvider.eventByIndex?.(50); |
962 | | - assert.isOk(event); |
963 | | - |
964 | | - // Since ENTRY_LABEL is AnnotationOverlay, create it through ModificationsManager |
965 | | - Timeline.ModificationsManager.ModificationsManager.activeManager()?.createAnnotation({ |
966 | | - type: 'ENTRY_LABEL', |
967 | | - label: '', |
968 | | - entry: event, |
969 | | - }); |
970 | | - |
971 | | - await overlays.update(); |
972 | | - const overlayDOM = container.querySelector<HTMLElement>('.overlay-type-ENTRY_LABEL'); |
973 | | - assert.isOk(overlayDOM); |
974 | | - const component = overlayDOM?.querySelector('devtools-entry-label-overlay'); |
975 | | - assert.isOk(component?.shadowRoot); |
976 | | - |
977 | | - const elementsWrapper = component.shadowRoot.querySelector<HTMLElement>('.label-parts-wrapper'); |
978 | | - assert.isOk(elementsWrapper); |
979 | | - const labelBox = elementsWrapper.querySelector<HTMLElement>('.input-field') as HTMLSpanElement; |
980 | | - |
981 | | - assert.isOk(labelBox); |
982 | | - |
| 902 | + const {inputField} = await createAnnotationsLabelElement(this, 'web-dev.json.gz', 50); |
983 | 903 | // The label input box should be editable after it is created and before anything else happened |
984 | | - assert.isTrue(labelBox.isContentEditable); |
| 904 | + assert.isTrue(inputField.isContentEditable); |
985 | 905 |
|
986 | 906 | // Make the content to editable by changing the element blur like when clicking outside of it. |
987 | 907 | // When that happens, the content should be set to not editable. |
988 | | - labelBox.dispatchEvent(new FocusEvent('blur', {bubbles: true})); |
989 | | - assert.isFalse(labelBox.isContentEditable); |
| 908 | + inputField.dispatchEvent(new FocusEvent('blur', {bubbles: true})); |
| 909 | + assert.isFalse(inputField.isContentEditable); |
990 | 910 |
|
991 | 911 | // Double click on the label to make it editable again |
992 | | - labelBox.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
993 | | - assert.isTrue(labelBox.isContentEditable); |
| 912 | + inputField.dispatchEvent(new FocusEvent('dblclick', {bubbles: true})); |
| 913 | + assert.isTrue(inputField.isContentEditable); |
994 | 914 | }); |
995 | 915 | }); |
996 | 916 |
|
|
0 commit comments