1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-31 01:16:01 +02:00

E2E test - batch updates (#3392)

This commit is contained in:
Tymoteusz Czech 2023-03-29 13:47:12 +02:00 committed by GitHub
parent 5c27153e50
commit f124997485
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 199 additions and 8 deletions

View File

@ -10,6 +10,9 @@ jobs:
- feature/feature.spec.ts
- groups/groups.spec.ts
- projects/access.spec.ts
- projects/overview.spec.ts
# - projects/settings.spec.ts
- projects/notifications.spec.ts
- segments/segments.spec.ts
- import/import.spec.ts
steps:

View File

@ -113,7 +113,6 @@ describe('notifications', () => {
//then
cy.get("[data-testid='NOTIFICATIONS_MODAL']").should('exist');
cy.get("[data-testid='UNREAD_NOTIFICATIONS']").should('not.exist');
const credentials = userCredentials[0];

View File

@ -0,0 +1,171 @@
/// <reference types="cypress" />
import {
BATCH_ACTIONS_BAR,
BATCH_SELECT,
BATCH_SELECTED_COUNT,
MORE_BATCH_ACTIONS,
SEARCH_INPUT,
} from '../../../src/utils/testIds';
const randomId = String(Math.random()).split('.')[1];
const featureTogglePrefix = 'unleash-e2e-project-overview';
const featureToggleName = `${featureTogglePrefix}-${randomId}`;
const baseUrl = Cypress.config().baseUrl;
const selectAll = '[title="Toggle All Rows Selected"] input[type="checkbox"]';
// Disable the prod guard modal by marking it as seen.
const disableFeatureStrategiesProdGuard = () => {
localStorage.setItem(
'useFeatureStrategyProdGuardSettings:v2',
JSON.stringify({ hide: true })
);
};
// Disable all active splash pages by visiting them.
const disableActiveSplashScreens = () => {
cy.visit(`/splash/operators`);
};
describe('project overview', () => {
before(() => {
disableFeatureStrategiesProdGuard();
disableActiveSplashScreens();
cy.login();
cy.request({
url: '/api/admin/projects/default/features',
method: 'POST',
body: {
name: `${featureToggleName}-A`,
description: 'hello-world',
type: 'release',
impressionData: false,
},
});
cy.request({
url: '/api/admin/projects/default/features',
method: 'POST',
body: {
name: `${featureToggleName}-B`,
description: 'hello-world',
type: 'release',
impressionData: false,
},
});
});
beforeEach(() => {
cy.login();
if (document.querySelector("[data-testid='CLOSE_SPLASH']")) {
cy.get("[data-testid='CLOSE_SPLASH']").click();
}
});
after(() => {
cy.request({
method: 'DELETE',
url: `${baseUrl}/api/admin/features/${featureToggleName}-A`,
failOnStatusCode: false,
});
cy.request({
method: 'DELETE',
url: `${baseUrl}/api/admin/features/${featureToggleName}-B`,
failOnStatusCode: false,
});
cy.request({
method: 'DELETE',
url: `${baseUrl}/api/admin/archive/${featureToggleName}-A`,
});
cy.request({
method: 'DELETE',
url: `${baseUrl}/api/admin/archive/${featureToggleName}-B`,
});
});
it('loads the table', () => {
cy.visit('/projects/default');
// Use search to filter feature toggles and check that the feature toggle is listed in the table.
cy.get("[data-testid='SEARCH_INPUT']").click().type(featureToggleName);
cy.get('table').contains('td', `${featureToggleName}-A`);
cy.get('table tbody tr').should('have.length', 2);
});
it('can select and deselect feature toggles', () => {
cy.visit('/projects/default');
cy.viewport(1920, 1080);
cy.get("[data-testid='SEARCH_INPUT']").click().type(featureToggleName);
cy.get('table tbody tr').should('have.length', 2);
const counter = `[data-testid="${BATCH_SELECTED_COUNT}"]`;
cy.get(counter).should('not.exist');
cy.get(selectAll).click();
cy.get(counter).contains('2');
cy.get(selectAll).click();
cy.get(counter).should('not.exist');
cy.get('table td')
.contains(`${featureToggleName}-A`)
.closest('tr')
.find(`[data-testid="${BATCH_SELECT}"] input[type="checkbox"]`)
.click();
cy.get(counter).contains('1');
cy.get('table td')
.contains(`${featureToggleName}-A`)
.closest('tr')
.find(`[data-testid="${BATCH_SELECT}"] input[type="checkbox"]`)
.click();
cy.get(counter).should('not.exist');
cy.get('table td')
.contains(`${featureToggleName}-B`)
.closest('tr')
.find(`[data-testid="${BATCH_SELECT}"] input[type="checkbox"]`)
.click();
cy.get(counter).contains('1');
cy.get('table td')
.contains(`${featureToggleName}-A`)
.closest('tr')
.find(`[data-testid="${BATCH_SELECT}"] input[type="checkbox"]`)
.click();
cy.get(counter).contains('2');
cy.get('table td')
.contains(`${featureToggleName}-B`)
.closest('tr')
.find(`[data-testid="${BATCH_SELECT}"] input[type="checkbox"]`)
.click();
cy.get(counter).contains('1');
});
it('can mark selected togggles as stale', () => {
cy.visit('/projects/default');
cy.viewport(1920, 1080);
cy.get(`[data-testid='${SEARCH_INPUT}']`).click().type(featureToggleName);
cy.get('table tbody tr').should('have.length', 2);
cy.get(selectAll).click();
cy.get(`[data-testid="${MORE_BATCH_ACTIONS}"]`).click();
cy.get('[role="menuitem"]').contains('Mark as stale').click();
cy.visit(`/projects/default/features/${featureToggleName}-A`);
cy.get('[title="Feature toggle is deprecated."]').should('exist');
});
it('can archive selected togggles', () => {
cy.visit('/projects/default');
cy.viewport(1920, 1080);
cy.get(`[data-testid='${SEARCH_INPUT}']`).click().type(featureToggleName);
cy.get('table tbody tr').should('have.length', 2);
cy.get(selectAll).click();
cy.get(`[data-testid=${BATCH_ACTIONS_BAR}] button`)
.contains('Archive')
.click();
cy.get('p')
.contains('Are you sure you want to archive 2 feature toggles?')
.should('exist');
cy.get('button').contains('Archive toggles').click();
cy.get('table tbody tr').should('have.length', 0);
});
});

View File

@ -1,5 +1,6 @@
import { FC } from 'react';
import { Box, Paper, styled, Typography } from '@mui/material';
import { BATCH_ACTIONS_BAR, BATCH_SELECTED_COUNT } from 'utils/testIds';
interface IBatchSelectionActionsBarProps {
count: number;
@ -56,11 +57,13 @@ export const BatchSelectionActionsBar: FC<IBatchSelectionActionsBarProps> = ({
}
return (
<StyledStickyContainer>
<StyledStickyContainer data-testid={BATCH_ACTIONS_BAR}>
<StyledContainer>
<StyledBar elevation={4}>
<StyledText>
<StyledCount>{count}</StyledCount>
<StyledCount data-testid={BATCH_SELECTED_COUNT}>
{count}
</StyledCount>
&ensp;selected
</StyledText>
{children}

View File

@ -6,6 +6,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { SearchSuggestions } from './SearchSuggestions/SearchSuggestions';
import { IGetSearchContextOutput } from 'hooks/useSearch';
import { useKeyboardShortcut } from 'hooks/useKeyboardShortcut';
import { SEARCH_INPUT } from 'utils/testIds';
interface ISearchProps {
initialValue?: string;
@ -108,7 +109,10 @@ export const Search = ({
<StyledInputBase
inputRef={ref}
placeholder={placeholder}
inputProps={{ 'aria-label': placeholder }}
inputProps={{
'aria-label': placeholder,
'data-testid': SEARCH_INPUT,
}}
value={value}
onChange={e => onSearchChange(e.target.value)}
onFocus={() => setShowSuggestions(true)}

View File

@ -19,6 +19,7 @@ import useProject from 'hooks/api/getters/useProject/useProject';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { MORE_BATCH_ACTIONS } from 'utils/testIds';
interface IMoreActionsProps {
projectId: string;
@ -89,7 +90,7 @@ export const MoreActions: VFC<IMoreActionsProps> = ({ projectId, data }) => {
return (
<>
<Tooltip title="Feature toggle actions" arrow describeChild>
<Tooltip title="More bulk actions" arrow describeChild>
<IconButton
id={menuId}
aria-controls={open ? menuId : undefined}
@ -97,6 +98,7 @@ export const MoreActions: VFC<IMoreActionsProps> = ({ projectId, data }) => {
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
type="button"
data-testid={MORE_BATCH_ACTIONS}
>
<MoreVert />
</IconButton>

View File

@ -1,5 +1,6 @@
import { Box, Checkbox, styled } from '@mui/material';
import { FC } from 'react';
import { BATCH_SELECT } from 'utils/testIds';
interface IRowSelectCellProps {
onChange: () => void;
@ -18,7 +19,7 @@ export const RowSelectCell: FC<IRowSelectCellProps> = ({
checked,
title,
}) => (
<StyledBoxCell>
<StyledBoxCell data-testid={BATCH_SELECT}>
<Checkbox onChange={onChange} title={title} checked={checked} />
</StyledBoxCell>
);

View File

@ -55,6 +55,7 @@ exports[`renders an empty list correctly 1`] = `
<input
aria-label="Search (Ctrl+K)"
className="MuiInputBase-input css-mfsqjb-MuiInputBase-input"
data-testid="SEARCH_INPUT"
onAnimationStart={[Function]}
onBlur={[Function]}
onChange={[Function]}

View File

@ -77,7 +77,6 @@ export const TOAST_TEXT = 'TOAST_TEXT';
export const LARGE_NUMBER_PRETTIFIED = 'LARGE_NUMBER_PRETTIFIED';
/* EXPORT/IMPORT FEATURES */
export const IMPORT_BUTTON = 'IMPORT_BUTTON';
export const CODE_EDITOR_TAB = 'CODE_EDITOR_TAB';
export const IMPORT_ENVIRONMENT = 'IMPORT_ENVIRONMENT';
@ -86,5 +85,13 @@ export const VALIDATE_BUTTON = 'VALIDATE_BUTTON';
export const IMPORT_CONFIGURATION_BUTTON = 'IMPORT_CONFIGURATION_BUTTON';
/* NOTIFICATIONS FEATURES */
export const NOTIFICATIONS_BUTTON = 'NOTIFICATIONS_BUTTON';
/* TABLE */
export const SEARCH_INPUT = 'SEARCH_INPUT';
/* BATCH UPDATES */
export const BATCH_ACTIONS_BAR = 'BATCH_ACTIONS_BAR';
export const BATCH_SELECTED_COUNT = 'BATCH_SELECTED_COUNT';
export const BATCH_SELECT = 'BATCH_SELECT';
export const MORE_BATCH_ACTIONS = 'MORE_BATCH_ACTIONS';