mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
Cypress test for importing (#3058)
This commit is contained in:
parent
a2ce8455de
commit
9f93f78fcc
1
.github/workflows/e2e.frontend.yaml
vendored
1
.github/workflows/e2e.frontend.yaml
vendored
@ -11,6 +11,7 @@ jobs:
|
|||||||
- groups/groups.spec.ts
|
- groups/groups.spec.ts
|
||||||
- projects/access.spec.ts
|
- projects/access.spec.ts
|
||||||
- segments/segments.spec.ts
|
- segments/segments.spec.ts
|
||||||
|
- import/import.spec.ts
|
||||||
steps:
|
steps:
|
||||||
- name: Dump GitHub context
|
- name: Dump GitHub context
|
||||||
env:
|
env:
|
||||||
|
125
frontend/cypress/integration/import/import.spec.ts
Normal file
125
frontend/cypress/integration/import/import.spec.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
const baseUrl = Cypress.config().baseUrl;
|
||||||
|
const randomSeed = String(Math.random()).split('.')[1];
|
||||||
|
const randomFeatureName = `cypress-features${randomSeed}`;
|
||||||
|
const userIds: any[] = [];
|
||||||
|
|
||||||
|
// Disable all active splash pages by visiting them.
|
||||||
|
const disableActiveSplashScreens = () => {
|
||||||
|
cy.visit(`/splash/operators`);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('imports', () => {
|
||||||
|
before(() => {
|
||||||
|
disableActiveSplashScreens();
|
||||||
|
cy.login();
|
||||||
|
for (let i = 1; i <= 2; i++) {
|
||||||
|
cy.request('POST', `${baseUrl}/api/admin/user-admin`, {
|
||||||
|
name: `unleash-e2e-user${i}-${randomFeatureName}`,
|
||||||
|
email: `unleash-e2e-user${i}-${randomFeatureName}@test.com`,
|
||||||
|
sendEmail: false,
|
||||||
|
rootRole: 3,
|
||||||
|
}).then(response => userIds.push(response.body.id));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
userIds.forEach(id =>
|
||||||
|
cy.request('DELETE', `${baseUrl}/api/admin/user-admin/${id}`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login();
|
||||||
|
if (document.querySelector("[data-testid='CLOSE_SPLASH']")) {
|
||||||
|
cy.get("[data-testid='CLOSE_SPLASH']").click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can import data', () => {
|
||||||
|
cy.visit('/projects/default');
|
||||||
|
cy.get("[data-testid='IMPORT_BUTTON']").click();
|
||||||
|
|
||||||
|
const exportText = {
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
name: randomFeatureName,
|
||||||
|
description: '',
|
||||||
|
type: 'release',
|
||||||
|
project: 'default',
|
||||||
|
stale: false,
|
||||||
|
impressionData: false,
|
||||||
|
archived: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
featureStrategies: [
|
||||||
|
{
|
||||||
|
name: 'flexibleRollout',
|
||||||
|
id: '14a0d9dd-2b5d-4a21-98fd-ede72bda0328',
|
||||||
|
featureName: randomFeatureName,
|
||||||
|
parameters: {
|
||||||
|
groupId: randomFeatureName,
|
||||||
|
rollout: '50',
|
||||||
|
stickiness: 'default',
|
||||||
|
},
|
||||||
|
constraints: [],
|
||||||
|
segments: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
featureEnvironments: [
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
featureName: randomFeatureName,
|
||||||
|
environment: 'test',
|
||||||
|
variants: [],
|
||||||
|
name: randomFeatureName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
contextFields: [],
|
||||||
|
featureTags: [
|
||||||
|
{
|
||||||
|
featureName: randomFeatureName,
|
||||||
|
tagType: 'simple',
|
||||||
|
tagValue: 'best-tag',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
featureName: randomFeatureName,
|
||||||
|
tagType: 'simple',
|
||||||
|
tagValue: 'rserw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
featureName: randomFeatureName,
|
||||||
|
tagType: 'simple',
|
||||||
|
tagValue: 'FARO',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
segments: [],
|
||||||
|
tagTypes: [
|
||||||
|
{
|
||||||
|
name: 'simple',
|
||||||
|
description: 'Used to simplify filtering of features',
|
||||||
|
icon: '#',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
cy.get("[data-testid='VALIDATE_BUTTON']").should('be.disabled');
|
||||||
|
|
||||||
|
// cypress can only work with input@file that is visible
|
||||||
|
cy.get('input[type=file]')
|
||||||
|
.invoke('attr', 'style', 'display: block')
|
||||||
|
.selectFile({
|
||||||
|
contents: Cypress.Buffer.from(JSON.stringify(exportText)),
|
||||||
|
fileName: 'upload.json',
|
||||||
|
lastModified: Date.now(),
|
||||||
|
});
|
||||||
|
cy.get("[data-testid='VALIDATE_BUTTON']").click();
|
||||||
|
cy.get("[data-testid='IMPORT_CONFIGURATION_BUTTON']").click();
|
||||||
|
// cy.contains('Import completed');
|
||||||
|
|
||||||
|
cy.visit(`/projects/default/features/${randomFeatureName}`);
|
||||||
|
cy.contains('enabled in development');
|
||||||
|
cy.contains('50%');
|
||||||
|
});
|
||||||
|
});
|
@ -14,6 +14,11 @@ import {
|
|||||||
import { ValidationStage } from './validate/ValidationStage';
|
import { ValidationStage } from './validate/ValidationStage';
|
||||||
import { ImportStage } from './import/ImportStage';
|
import { ImportStage } from './import/ImportStage';
|
||||||
import { ImportOptions } from './configure/ImportOptions';
|
import { ImportOptions } from './configure/ImportOptions';
|
||||||
|
import {
|
||||||
|
IMPORT_BUTTON,
|
||||||
|
IMPORT_CONFIGURATION_BUTTON,
|
||||||
|
VALIDATE_BUTTON,
|
||||||
|
} from '../../../../utils/testIds';
|
||||||
|
|
||||||
const ModalContentContainer = styled('div')(({ theme }) => ({
|
const ModalContentContainer = styled('div')(({ theme }) => ({
|
||||||
minHeight: '100vh',
|
minHeight: '100vh',
|
||||||
|
@ -16,6 +16,11 @@ import React, { FC, ReactNode, useState } from 'react';
|
|||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { ImportLayoutContainer } from '../ImportLayoutContainer';
|
import { ImportLayoutContainer } from '../ImportLayoutContainer';
|
||||||
import { ActionsContainer } from '../ActionsContainer';
|
import { ActionsContainer } from '../ActionsContainer';
|
||||||
|
import {
|
||||||
|
CODE_EDITOR_TAB,
|
||||||
|
CODE_TEXT_FIELD,
|
||||||
|
VALIDATE_BUTTON,
|
||||||
|
} from 'utils/testIds';
|
||||||
|
|
||||||
const StyledTextField = styled(TextField)(({ theme }) => ({
|
const StyledTextField = styled(TextField)(({ theme }) => ({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@ -58,6 +63,7 @@ export const ConfigurationTabs: FC<{
|
|||||||
<Tab
|
<Tab
|
||||||
label="Code editor"
|
label="Code editor"
|
||||||
value="code"
|
value="code"
|
||||||
|
data-testid={CODE_EDITOR_TAB}
|
||||||
onClick={() => setActiveTab('code')}
|
onClick={() => setActiveTab('code')}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
@ -119,6 +125,7 @@ export const ImportArea: FC<{
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={event => setImportPayload(event.target.value)}
|
onChange={event => setImportPayload(event.target.value)}
|
||||||
value={importPayload}
|
value={importPayload}
|
||||||
|
data-testid={CODE_TEXT_FIELD}
|
||||||
multiline
|
multiline
|
||||||
minRows={13}
|
minRows={13}
|
||||||
maxRows={13}
|
maxRows={13}
|
||||||
@ -139,6 +146,7 @@ export const Actions: FC<{
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
|
data-testid={VALIDATE_BUTTON}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
Validate
|
Validate
|
||||||
|
@ -3,6 +3,7 @@ import { KeyboardArrowDownOutlined } from '@mui/icons-material';
|
|||||||
import React, { FC, useEffect } from 'react';
|
import React, { FC, useEffect } from 'react';
|
||||||
import { useProjectEnvironments } from 'hooks/api/getters/useProjectEnvironments/useProjectEnvironments';
|
import { useProjectEnvironments } from 'hooks/api/getters/useProjectEnvironments/useProjectEnvironments';
|
||||||
import { Box, styled, Typography } from '@mui/material';
|
import { Box, styled, Typography } from '@mui/material';
|
||||||
|
import { IMPORT_ENVIRONMENT } from 'utils/testIds';
|
||||||
|
|
||||||
const ImportOptionsContainer = styled(Box)(({ theme }) => ({
|
const ImportOptionsContainer = styled(Box)(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.secondaryContainer,
|
backgroundColor: theme.palette.secondaryContainer,
|
||||||
@ -57,6 +58,7 @@ export const ImportOptions: FC<IImportOptionsProps> = ({
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
label={'Environment'}
|
label={'Environment'}
|
||||||
value={environment}
|
value={environment}
|
||||||
|
data-testid={IMPORT_ENVIRONMENT}
|
||||||
IconComponent={KeyboardArrowDownOutlined}
|
IconComponent={KeyboardArrowDownOutlined}
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
@ -9,6 +9,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
|
|||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { ActionsContainer } from '../ActionsContainer';
|
import { ActionsContainer } from '../ActionsContainer';
|
||||||
|
import { IMPORT_CONFIGURATION_BUTTON } from 'utils/testIds';
|
||||||
|
|
||||||
const ImportInfoContainer = styled(Box)(({ theme }) => ({
|
const ImportInfoContainer = styled(Box)(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.secondaryContainer,
|
backgroundColor: theme.palette.secondaryContainer,
|
||||||
@ -191,6 +192,7 @@ export const ValidationStage: FC<{
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
|
data-testid={IMPORT_CONFIGURATION_BUTTON}
|
||||||
disabled={validationResult.errors.length > 0 || !validJSON}
|
disabled={validationResult.errors.length > 0 || !validJSON}
|
||||||
>
|
>
|
||||||
Import configuration
|
Import configuration
|
||||||
|
@ -41,6 +41,7 @@ import { ProjectChangeRequests } from '../../changeRequest/ProjectChangeRequests
|
|||||||
import { ProjectSettings } from './ProjectSettings/ProjectSettings';
|
import { ProjectSettings } from './ProjectSettings/ProjectSettings';
|
||||||
import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi';
|
import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi';
|
||||||
import { ImportModal } from './Import/ImportModal';
|
import { ImportModal } from './Import/ImportModal';
|
||||||
|
import { IMPORT_BUTTON } from 'utils/testIds';
|
||||||
|
|
||||||
export const Project = () => {
|
export const Project = () => {
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
@ -150,6 +151,7 @@ export const Project = () => {
|
|||||||
}}
|
}}
|
||||||
onClick={() => setModalOpen(true)}
|
onClick={() => setModalOpen(true)}
|
||||||
tooltipProps={{ title: 'Import' }}
|
tooltipProps={{ title: 'Import' }}
|
||||||
|
data-testid={IMPORT_BUTTON}
|
||||||
data-loading
|
data-loading
|
||||||
>
|
>
|
||||||
<FileUpload />
|
<FileUpload />
|
||||||
|
@ -75,3 +75,12 @@ export const ANNOUNCER_ELEMENT_TEST_ID = 'ANNOUNCER_ELEMENT_TEST_ID';
|
|||||||
export const INSTANCE_STATUS_BAR_ID = 'INSTANCE_STATUS_BAR_ID';
|
export const INSTANCE_STATUS_BAR_ID = 'INSTANCE_STATUS_BAR_ID';
|
||||||
export const TOAST_TEXT = 'TOAST_TEXT';
|
export const TOAST_TEXT = 'TOAST_TEXT';
|
||||||
export const LARGE_NUMBER_PRETTIFIED = 'LARGE_NUMBER_PRETTIFIED';
|
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';
|
||||||
|
export const CODE_TEXT_FIELD = 'CODE_TEXT_FIELD';
|
||||||
|
export const VALIDATE_BUTTON = 'VALIDATE_BUTTON';
|
||||||
|
export const IMPORT_CONFIGURATION_BUTTON = 'IMPORT_CONFIGURATION_BUTTON';
|
||||||
|
Loading…
Reference in New Issue
Block a user