Dirt/pm 33474/setup data testids (#19807)

This commit is contained in:
Vijay Oommen 2026-03-30 12:05:15 -05:00 committed by GitHub
parent 9b859bbdaf
commit 0d2e295ca1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 83 additions and 76 deletions

View File

@ -1,33 +1,33 @@
<div class="tw-flex-col">
<span bitTypography="h6" class="tw-flex tw-text-main">{{ title }}</span>
<div class="tw-flex tw-flex-col" [attr.data-testid]="testId()">
<span bitTypography="h6" class="tw-flex tw-text-main">{{ title() }}</span>
<div class="tw-flex tw-items-baseline tw-gap-2">
@if (iconClass) {
<i class="bwi {{ iconClass }} {{ iconColorClass }}" aria-hidden="true"></i>
@if (iconClass()) {
<i class="bwi {{ iconClass() }} {{ iconColorClass() }}" aria-hidden="true"></i>
}
<span bitTypography="h3">{{ cardMetrics }}</span>
<span bitTypography="h3">{{ cardMetrics() }}</span>
</div>
<div class="tw-flex tw-items-baseline tw-mt-4 tw-gap-2">
<span bitTypography="body2">{{ metricDescription }}</span>
<span bitTypography="body2">{{ metricDescription() }}</span>
</div>
@if (buttonClick.observed && buttonText) {
@if (buttonText()) {
<div class="tw-flex tw-items-baseline tw-mt-4 tw-gap-2">
<button
type="button"
bitButton
size="small"
[buttonType]="buttonType"
[attr.aria-label]="buttonText"
[buttonType]="buttonType()"
[attr.aria-label]="buttonText()"
(click)="onButtonClick()"
>
{{ buttonText }}
{{ buttonText() }}
</button>
</div>
}
@if (showActionLink && !buttonText) {
@if (showActionLink() && !buttonText()) {
<div class="tw-flex tw-items-baseline tw-mt-4 tw-gap-2">
<p bitTypography="body1">
<a bitLink href="#" (click)="onActionClick(); $event.preventDefault()" rel="noreferrer">
{{ actionText }}
{{ actionText() }}
</a>
</p>
</div>

View File

@ -1,15 +1,12 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { Router } from "@angular/router";
import { ChangeDetectionStrategy, Component, input, output } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ButtonModule, ButtonType, LinkModule, TypographyModule } from "@bitwarden/components";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "dirt-activity-card",
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: "./activity-card.component.html",
imports: [TypographyModule, JslibModule, LinkModule, ButtonModule],
imports: [TypographyModule, LinkModule, ButtonModule],
host: {
class:
"tw-box-border tw-bg-background tw-block tw-text-main tw-border-solid tw-border-secondary-100 tw-border [&:not(bit-layout_*)]:tw-rounded-lg tw-rounded-lg tw-p-6 tw-min-h-56 tw-overflow-hidden",
@ -19,87 +16,72 @@ export class ActivityCardComponent {
/**
* The title of the card goes here
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() title: string = "";
readonly title = input.required<string>();
/**
* The card metrics text to display next to the value
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() cardMetrics: string = "";
readonly cardMetrics = input.required<string>();
/**
* The description text to display below the value and metrics
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() metricDescription: string = "";
readonly metricDescription = input.required<string>();
/**
* The text to display for the action link
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() actionText: string = "";
readonly actionText = input<string>("");
/**
* Show action link
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() showActionLink: boolean = false;
readonly showActionLink = input<boolean>(false);
/**
* Icon class to display next to metrics (e.g., "bwi-exclamation-triangle").
* If null, no icon is displayed.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() iconClass: string | null = null;
readonly iconClass = input<string | null>(null);
/**
* CSS class for icon color (e.g., "tw-text-success", "tw-text-muted").
* Defaults to "tw-text-muted" if not provided.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() iconColorClass: string = "tw-text-muted";
readonly iconColorClass = input<string>("tw-text-muted");
/**
* Button text. If provided, a button will be displayed instead of a navigation link.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() buttonText: string = "";
readonly buttonText = input<string>("");
/**
* Button type (e.g., "primary", "secondary")
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() buttonType: ButtonType = "primary";
readonly buttonType = input<ButtonType>("primary");
/**
* Event emitted when button is clicked
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() buttonClick = new EventEmitter<void>();
readonly buttonClick = output<void>();
/*
* To facilitate automated testing, provide a testId that will be
* added as a data attribute to the root element of the card
* (e.g., <dirt-activity-card [testId]="'my-card'">).
* This allows tests to easily select the card using
* the data attribute (e.g., [data-test-id="my-card"].
*/
readonly testId = input.required<string>();
/**
* Event emitted when action link is clicked
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() actionClick = new EventEmitter<void>();
readonly actionClick = output<void>();
constructor(private router: Router) {}
onButtonClick = () => {
readonly onButtonClick = () => {
this.buttonClick.emit();
};
onActionClick = () => {
readonly onActionClick = () => {
this.actionClick.emit();
};
}

View File

@ -1,5 +1,6 @@
<div
class="tw-box-border tw-bg-background tw-block tw-text-main tw-border-solid tw-border tw-border-secondary-100 [&:not(bit-layout_*)]:tw-rounded-lg tw-rounded-lg tw-p-6 tw-min-h-56 tw-overflow-hidden"
data-testid="password-change-metric-card"
>
<div bitTypography="h6" class="tw-mb-2">
{{ "passwordChangeProgress" | i18n }}
@ -7,7 +8,7 @@
@switch (currentView()) {
@case (PasswordChangeViewEnum.EMPTY) {
<div class="tw-items-start tw-mb-2">
<div class="tw-items-start tw-mb-2" data-testid="assign-members-to-tasks-empty">
<span bitTypography="h3">{{ "assignMembersTasksToMonitorProgress" | i18n }}</span>
</div>
@ -17,7 +18,7 @@
}
@case (PasswordChangeViewEnum.NO_TASKS_ASSIGNED) {
<div class="tw-items-start tw-mb-2">
<div class="tw-items-start tw-mb-2" data-testid="assign-members-to-tasks-no-tasks-assigned">
<span bitTypography="h3">{{ "assignMembersTasksToMonitorProgress" | i18n }}</span>
</div>
@ -38,7 +39,7 @@
}
@case (PasswordChangeViewEnum.NEW_TASKS_AVAILABLE) {
<div class="tw-items-start tw-mb-2">
<div class="tw-items-start tw-mb-2" data-testid="assign-members-to-tasks-new-tasks-available">
<span bitTypography="h3">{{ "assignMembersTasksToMonitorProgress" | i18n }}</span>
</div>
@ -55,7 +56,7 @@
}
@case (PasswordChangeViewEnum.PROGRESS) {
<div class="tw-items-start tw-mb-2">
<div class="tw-items-start tw-mb-2" data-testid="assign-members-to-tasks-progress">
<span bitTypography="h3">{{ "percentageCompleted" | i18n: completedTasksPercent() }}</span>
</div>
@ -66,12 +67,13 @@
</div>
<div class="tw-mt-4">
<div class="tw-flex tw-justify-between">
<div class="tw-flex tw-justify-between" data-testid="number-of-tasks-completed">
<div bitTypography="body2">{{ completedTasksCount() }}</div>
<div bitTypography="body2">{{ tasksCount() }}</div>
</div>
</div>
<bit-progress
data-testid="progress-bar"
[showText]="false"
size="small"
bgColor="primary"

View File

@ -23,6 +23,7 @@
actionText="{{ 'viewAtRiskMembers' | i18n }}"
[showActionLink]="totalCriticalAppsAtRiskMemberCount > 0"
(actionClick)="onViewAtRiskMembers()"
[testId]="'at-risk-members-card'"
>
</dirt-activity-card>
<dirt-password-change-metric
@ -47,6 +48,7 @@
actionText="{{ 'viewAtRiskMembers' | i18n }}"
[showActionLink]="totalCriticalAppsAtRiskMemberCount > 0"
(actionClick)="onViewAtRiskMembers()"
[testId]="'at-risk-members-card'"
>
</dirt-activity-card>
</li>
@ -70,6 +72,7 @@
actionText="{{ 'viewAtRiskApplications' | i18n }}"
[showActionLink]="totalCriticalAppsAtRiskCount > 0"
(actionClick)="onViewAtRiskApplications()"
[testId]="'critical-applications-card'"
>
</dirt-activity-card>
</li>
@ -86,6 +89,7 @@
[buttonText]="''"
[buttonType]="'primary'"
(buttonClick)="onReviewNewApplications()"
[testId]="'allCaughtUp'"
>
</dirt-activity-card>
</li>
@ -102,6 +106,7 @@
[buttonText]="'reviewApplications' | i18n"
[buttonType]="'primary'"
(buttonClick)="onReviewNewApplications()"
[testId]="'needs-review-card'"
>
</dirt-activity-card>
</li>
@ -118,6 +123,7 @@
[buttonText]="'reviewNow' | i18n"
[buttonType]="'primary'"
(buttonClick)="onReviewNewApplications()"
[testId]="'review-new-applications-card'"
>
</dirt-activity-card>
</li>

View File

@ -1,4 +1,4 @@
<div class="tw-flex tw-flex-col tw-gap-6">
<div class="tw-flex tw-flex-col tw-gap-6" data-testid="assign-task-dialog">
<!-- Two-column layout: Left panel (stats) and Right panel (browser extension mockup) -->
<div class="tw-flex tw-flex-col md:tw-flex-row tw-gap-6">
<!-- Left Panel -->
@ -13,7 +13,7 @@
</bit-callout>
<!-- Stat Box: Members with At-Risk Passwords -->
<div class="tw-flex tw-items-start tw-gap-3">
<div class="tw-flex tw-items-start tw-gap-3" data-testid="members-with-at-risk-passwords">
<bit-icon-tile
icon="bwi-users"
variant="primary"
@ -32,7 +32,7 @@
</div>
<!-- Stat Box: Critical Applications At-Risk -->
<div class="tw-flex tw-items-start tw-gap-3">
<div class="tw-flex tw-items-start tw-gap-3" data-testid="critical-applications-at-risk">
<bit-icon-tile
icon="bwi-desktop"
variant="warning"
@ -57,7 +57,7 @@
</div>
<!-- Right Panel: Browser Extension Video -->
<div class="tw-flex tw-flex-col tw-gap-4 tw-flex-1">
<div class="tw-flex tw-flex-col tw-gap-4 tw-flex-1" data-testid="browser-extension-video">
<video
class="tw-w-full tw-rounded-lg"
autoplay

View File

@ -1,4 +1,4 @@
<bit-dialog [dialogSize]="'large'">
<bit-dialog [dialogSize]="'large'" data-testid="new-applications-dialog">
<span bitDialogTitle>
{{
currentView() === DialogView.SelectApplications
@ -47,7 +47,7 @@
</div>
@if (currentView() === DialogView.SelectApplications) {
<ng-container bitDialogFooter>
<ng-container bitDialogFooter data-testid="select-applications-footer">
<button
type="button"
bitButton
@ -74,7 +74,7 @@
}
@if (currentView() == DialogView.AssignTasks) {
<!-- Footer: Action Buttons -->
<ng-container bitDialogFooter>
<ng-container bitDialogFooter data-testid="assign-tasks-footer">
<button
type="button"
bitButton

View File

@ -1,4 +1,4 @@
<div class="tw-space-y-3">
<div class="tw-space-y-3" data-testid="review-applications-view">
<bit-search
[placeholder]="'searchApps' | i18n"
[(ngModel)]="searchText"

View File

@ -1,5 +1,6 @@
<div
class="tw-flex tw-flex-col tw-gap-4 tw-border tw-rounded-xl tw-border-solid tw-border-secondary-100 tw-p-6"
data-testid="trend-widget-card"
>
<div class="tw-flex tw-justify-between tw-items-center">
<h2>{{ "riskOverTime" | i18n }}</h2>

View File

@ -1,5 +1,6 @@
<div
class="tw-w-full tw-max-w-4xl tw-p-6 sm:tw-p-8 tw-bg-background tw-rounded-xl tw-border tw-border-solid tw-border-secondary-300 tw-flex tw-flex-col lg:tw-flex-row tw-gap-6 tw-items-center"
data-testid="empty-state-card"
>
<div class="tw-flex-1 tw-flex tw-flex-col tw-gap-4 sm:tw-gap-5 tw-w-full lg:tw-w-auto">
<div class="tw-text-main tw-text-lg sm:tw-text-xl tw-font-medium tw-leading-6 sm:tw-leading-7">
@ -12,7 +13,7 @@
</div>
}
@if (benefits().length > 0) {
<div class="tw-flex tw-flex-col tw-gap-4 sm:tw-gap-5">
<div class="tw-flex tw-flex-col tw-gap-4 sm:tw-gap-5" data-testid="benefits-list">
@for (benefit of benefits(); track $index) {
<div class="tw-flex tw-items-start tw-gap-3">
<div
@ -56,7 +57,7 @@
</div>
@if (videoSrc() || icon()) {
<div class="tw-hidden lg:tw-block tw-flex-shrink-0">
<div class="tw-hidden lg:tw-block tw-flex-shrink-0" data-testid="media-container-desktop">
<div class="tw-size-64 xl:tw-size-80 tw-relative">
@if (videoSrc()) {
<video
@ -81,7 +82,10 @@
}
</div>
</div>
<div class="tw-flex lg:tw-hidden tw-w-full tw-justify-center">
<div
class="tw-flex lg:tw-hidden tw-w-full tw-justify-center"
data-testid="media-container-mobile"
>
<div class="tw-size-48 sm:tw-size-64 tw-relative">
@if (videoSrc()) {
<video

View File

@ -24,7 +24,10 @@
{{ "downloadCSV" | i18n }}
</button>
<ng-container>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div
class="tw-flex tw-justify-between tw-mt-2 tw-text-muted"
data-testid="at-risk-header"
>
<div bitTypography="body2" class="tw-text-sm tw-font-bold">
{{ "email" | i18n }}
</div>
@ -33,7 +36,10 @@
</div>
</div>
@for (member of drawerDetails.atRiskMemberDetails; track member.email) {
<div class="tw-flex tw-justify-between tw-mt-2">
<div
class="tw-flex tw-justify-between tw-mt-2"
[attr.data-testid]="'at-risk-row-' + $index"
>
<div>{{ member.email }}</div>
<div>{{ member.atRiskPasswordCount }}</div>
</div>
@ -63,7 +69,7 @@
</div>
<div class="tw-mt-1">
@for (member of drawerDetails.appAtRiskMembers?.members; track $index) {
<div>{{ member.email }}</div>
<div [attr.data-testid]="'at-risk-row-' + $index">{{ member.email }}</div>
}
</div>
</ng-container>
@ -95,7 +101,10 @@
<i class="bwi bwi-download tw-mr-1"></i>
{{ "downloadCSV" | i18n }}
</button>
<div class="tw-flex tw-justify-between tw-mt-2 tw-text-muted">
<div
class="tw-flex tw-justify-between tw-mt-2 tw-text-muted"
data-testid="at-risk-header"
>
<div bitTypography="body2" class="tw-text-sm tw-font-bold">
{{ "application" | i18n }}
</div>
@ -104,7 +113,10 @@
</div>
</div>
@for (app of drawerDetails.atRiskAppDetails; track app.applicationName) {
<div class="tw-flex tw-justify-between tw-mt-2">
<div
class="tw-flex tw-justify-between tw-mt-2"
[attr.data-testid]="'at-risk-row-' + $index"
>
<div>{{ app.applicationName }}</div>
<div>{{ app.atRiskPasswordCount }}</div>
</div>