mirror of https://github.com/Unleash/unleash
test: move import test from cypress to RTL to make it less flaky (#6982)
parent
d698eccb4a
commit
d01100fbf0
5 changed files with 158 additions and 139 deletions
@ -1,136 +0,0 @@ |
||||
///<reference path="../../global.d.ts" />
|
||||
|
||||
describe('imports', () => { |
||||
const baseUrl = Cypress.config().baseUrl; |
||||
const randomSeed = String(Math.random()).split('.')[1]; |
||||
const randomFeatureName = `cypress-features${randomSeed}`; |
||||
const userIds: any[] = []; |
||||
|
||||
before(() => { |
||||
cy.runBefore(); |
||||
cy.login_UI(); |
||||
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_UI(); |
||||
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({ force: true }); |
||||
|
||||
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'); |
||||
|
||||
cy.intercept('POST', '/api/admin/features-batch/import').as( |
||||
'featureImported', |
||||
); |
||||
|
||||
// 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.wait('@featureImported'); |
||||
cy.contains('Import completed'); |
||||
|
||||
cy.request({ |
||||
url: `/api/admin/projects/default/features/${randomFeatureName}`, |
||||
headers: { 'Content-Type': 'application/json' }, |
||||
}).then((response) => { |
||||
expect(response.body.name).to.equal(randomFeatureName); |
||||
const devEnv = response.body.environments.find( |
||||
(env: any) => env.name === 'development', |
||||
); |
||||
|
||||
expect(devEnv.name).to.equal('development'); |
||||
expect(devEnv.strategies[0].parameters.rollout).to.equal('50'); |
||||
expect(devEnv.enabled).to.equal(true); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,151 @@ |
||||
import { render } from 'utils/testRenderer'; |
||||
import { screen, waitFor } from '@testing-library/react'; |
||||
import { ImportModal } from './ImportModal'; |
||||
import { testServerRoute, testServerSetup } from 'utils/testServer'; |
||||
import userEvent from '@testing-library/user-event'; |
||||
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions'; |
||||
|
||||
const server = testServerSetup(); |
||||
|
||||
const setupApi = () => { |
||||
testServerRoute(server, '/api/admin/ui-config', { |
||||
versionInfo: { |
||||
current: { enterprise: 'present' }, |
||||
}, |
||||
}); |
||||
testServerRoute(server, '/api/admin/projects/default', { |
||||
environments: [ |
||||
{ environment: 'development' }, |
||||
{ environment: 'production' }, |
||||
], |
||||
}); |
||||
testServerRoute( |
||||
server, |
||||
'/api/admin/features-batch/validate', |
||||
{ errors: [], permissions: [], warnings: [] }, |
||||
'post', |
||||
); |
||||
testServerRoute(server, '/api/admin/features-batch/import', {}, 'post'); |
||||
}; |
||||
|
||||
const importFile = async (content: string) => { |
||||
const selectFileInput = screen.getByTestId('import-file'); |
||||
const importFile = new File([content], 'import.json', { |
||||
type: 'application/json', |
||||
}); |
||||
userEvent.upload(selectFileInput, importFile); |
||||
}; |
||||
|
||||
test('Import happy path', async () => { |
||||
setupApi(); |
||||
let closed = false; |
||||
const setOpen = (open: boolean) => { |
||||
closed = !open; |
||||
}; |
||||
render(<ImportModal open={true} setOpen={setOpen} project='default' />, { |
||||
permissions: [{ permission: CREATE_FEATURE }], |
||||
}); |
||||
|
||||
// configure stage
|
||||
screen.getByText('Import options'); |
||||
screen.getByText('Drop your file here'); |
||||
const validateButton = screen.getByText('Validate'); |
||||
expect(validateButton).toBeDisabled(); |
||||
|
||||
await importFile('{}'); |
||||
await waitFor(() => { |
||||
expect(screen.getByText('Validate')).toBeEnabled(); |
||||
}); |
||||
|
||||
const codeEditorLabel = screen.getByText('Code editor'); |
||||
codeEditorLabel.click(); |
||||
const editor = screen.getByLabelText('Exported toggles'); |
||||
expect(editor.textContent).toBe('{}'); |
||||
|
||||
screen.getByText('Validate').click(); |
||||
|
||||
// validate stage
|
||||
screen.getByText('You are importing this configuration in:'); |
||||
screen.getByText('development'); |
||||
screen.getByText('default'); |
||||
const importButton = screen.getByText('Import configuration'); |
||||
expect(importButton).toBeEnabled(); |
||||
importButton.click(); |
||||
|
||||
// import stage
|
||||
await screen.findByText('Importing...'); |
||||
await screen.findByText('Import completed'); |
||||
|
||||
expect(closed).toBe(false); |
||||
const closeButton = screen.getByText('Close'); |
||||
closeButton.click(); |
||||
expect(closed).toBe(true); |
||||
}); |
||||
|
||||
test('Block when importing non json content', async () => { |
||||
setupApi(); |
||||
const setOpen = () => {}; |
||||
render(<ImportModal open={true} setOpen={setOpen} project='default' />, { |
||||
permissions: [{ permission: CREATE_FEATURE }], |
||||
}); |
||||
|
||||
const codeEditorLabel = screen.getByText('Code editor'); |
||||
codeEditorLabel.click(); |
||||
const editor = screen.getByLabelText('Exported toggles'); |
||||
userEvent.type(editor, 'invalid non json'); |
||||
|
||||
const validateButton = screen.getByText('Validate'); |
||||
expect(validateButton).toBeDisabled(); |
||||
}); |
||||
|
||||
test('Show validation errors', async () => { |
||||
setupApi(); |
||||
testServerRoute( |
||||
server, |
||||
'/api/admin/features-batch/validate', |
||||
{ |
||||
errors: [ |
||||
{ message: 'error message', affectedItems: ['itemC', 'itemD'] }, |
||||
], |
||||
permissions: [ |
||||
{ |
||||
message: 'permission message', |
||||
affectedItems: ['itemE', 'itemF'], |
||||
}, |
||||
], |
||||
warnings: [ |
||||
{ |
||||
message: 'warning message', |
||||
affectedItems: ['itemA', 'itemB'], |
||||
}, |
||||
], |
||||
}, |
||||
'post', |
||||
); |
||||
const setOpen = () => {}; |
||||
render(<ImportModal open={true} setOpen={setOpen} project='default' />, { |
||||
permissions: [{ permission: CREATE_FEATURE }], |
||||
}); |
||||
|
||||
await importFile('{}'); |
||||
await waitFor(() => { |
||||
expect(screen.getByText('Validate')).toBeEnabled(); |
||||
}); |
||||
|
||||
screen.getByText('Validate').click(); |
||||
|
||||
await screen.findByText('warning message'); |
||||
await screen.findByText('itemA'); |
||||
await screen.findByText('itemB'); |
||||
|
||||
await screen.findByText('error message'); |
||||
await screen.findByText('itemC'); |
||||
await screen.findByText('itemD'); |
||||
|
||||
await screen.findByText('permission message'); |
||||
await screen.findByText('itemE'); |
||||
await screen.findByText('itemF'); |
||||
|
||||
const importButton = screen.getByText('Import configuration'); |
||||
expect(importButton).toBeDisabled(); |
||||
}); |
Loading…
Reference in new issue