mirror of
https://github.com/Unleash/unleash.git
synced 2025-12-09 20:04:11 +01:00
**Upgrade to React v18 for Unleash v6. Here's why I think it's a good time to do it:** - Command Bar project: We've begun work on the command bar project, and there's a fantastic library we want to use. However, it requires React v18 support. - Straightforward Upgrade: I took a look at the upgrade guide https://react.dev/blog/2022/03/08/react-18-upgrade-guide and it seems fairly straightforward. In fact, I was able to get React v18 running with minimal changes in just 10 minutes! - Dropping IE Support: React v18 no longer supports Internet Explorer (IE), which is no longer supported by Microsoft as of June 15, 2022. Upgrading to v18 in v6 would be a good way to align with this change. TS updates: * FC children has to be explicit: https://stackoverflow.com/questions/71788254/react-18-typescript-children-fc * forcing version 18 types in resolutions: https://sentry.io/answers/type-is-not-assignable-to-type-reactnode/ Test updates: * fixing SWR issue that we have always had but it manifests more in new React (https://github.com/vercel/swr/issues/2373) --------- Co-authored-by: kwasniew <kwasniewski.mateusz@gmail.com>
449 lines
15 KiB
TypeScript
449 lines
15 KiB
TypeScript
import { formatAddStrategyApiCode } from 'component/feature/FeatureStrategy/FeatureStrategyCreate/FeatureStrategyCreate';
|
|
import { screen, fireEvent, waitFor } from '@testing-library/react';
|
|
import { render } from 'utils/testRenderer';
|
|
import { Route, Routes } from 'react-router-dom';
|
|
|
|
import {
|
|
CREATE_FEATURE_STRATEGY,
|
|
UPDATE_FEATURE_ENVIRONMENT_VARIANTS,
|
|
UPDATE_FEATURE_STRATEGY,
|
|
} from 'component/providers/AccessProvider/permissions';
|
|
import { FeatureStrategyCreate } from './FeatureStrategyCreate';
|
|
import {
|
|
setupProjectEndpoint,
|
|
setupSegmentsEndpoint,
|
|
setupStrategyEndpoint,
|
|
setupFeaturesEndpoint,
|
|
setupUiConfigEndpoint,
|
|
setupContextEndpoint,
|
|
} from './featureStrategyFormTestSetup';
|
|
|
|
const featureName = 'my-new-feature';
|
|
|
|
const setupComponent = () => {
|
|
return {
|
|
wrapper: render(
|
|
<Routes>
|
|
<Route
|
|
path={
|
|
'/projects/:projectId/features/:featureId/strategies/create'
|
|
}
|
|
element={<FeatureStrategyCreate />}
|
|
/>
|
|
</Routes>,
|
|
{
|
|
route: `/projects/default/features/${featureName}/strategies/create?environmentId=development&strategyName=flexibleRollout&defaultStrategy=true`,
|
|
permissions: [
|
|
{
|
|
permission: CREATE_FEATURE_STRATEGY,
|
|
project: 'default',
|
|
environment: 'development',
|
|
},
|
|
{
|
|
permission: UPDATE_FEATURE_STRATEGY,
|
|
project: 'default',
|
|
environment: 'development',
|
|
},
|
|
{
|
|
permission: UPDATE_FEATURE_ENVIRONMENT_VARIANTS,
|
|
project: 'default',
|
|
environment: 'development',
|
|
},
|
|
],
|
|
},
|
|
),
|
|
expectedSegmentName: 'test',
|
|
expectedGroupId: 'newGroupId',
|
|
expectedVariantName: 'Blue',
|
|
expectedSliderValue: '50',
|
|
expectedConstraintValue: 'new value',
|
|
expectedMultipleValues: '1234,4141,51515',
|
|
};
|
|
};
|
|
|
|
beforeEach(() => {
|
|
setupProjectEndpoint();
|
|
setupSegmentsEndpoint();
|
|
setupStrategyEndpoint();
|
|
setupFeaturesEndpoint(featureName);
|
|
setupUiConfigEndpoint();
|
|
setupContextEndpoint();
|
|
});
|
|
|
|
describe('NewFeatureStrategyCreate', () => {
|
|
test('formatAddStrategyApiCode', () => {
|
|
expect(
|
|
formatAddStrategyApiCode(
|
|
'projectId',
|
|
'featureId',
|
|
'environmentId',
|
|
{ id: 'strategyId' },
|
|
'unleashUrl',
|
|
),
|
|
).toMatchInlineSnapshot(`
|
|
"curl --location --request POST 'unleashUrl/api/admin/projects/projectId/features/featureId/environments/environmentId/strategies' \\
|
|
--header 'Authorization: INSERT_API_KEY' \\
|
|
--header 'Content-Type: application/json' \\
|
|
--data-raw '{
|
|
"id": "strategyId"
|
|
}'"
|
|
`);
|
|
});
|
|
|
|
test('should navigate tabs', async () => {
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const slider = await screen.findByRole('slider', { name: /rollout/i });
|
|
expect(slider).toHaveValue('100');
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const segmentsEl = await screen.findByText('Segments');
|
|
expect(segmentsEl).toBeInTheDocument();
|
|
|
|
const variantEl = screen.getByText('Variants');
|
|
fireEvent.click(variantEl);
|
|
|
|
const addVariantEl = await screen.findByText('Add variant');
|
|
expect(addVariantEl).toBeInTheDocument();
|
|
});
|
|
|
|
test('should change general settings', async () => {
|
|
const { expectedGroupId, expectedSliderValue } = setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const slider = await screen.findByRole('slider', { name: /rollout/i });
|
|
const groupIdInput = await screen.findByLabelText('groupId');
|
|
|
|
expect(slider).toHaveValue('100');
|
|
expect(groupIdInput).toHaveValue(featureName);
|
|
|
|
fireEvent.change(slider, { target: { value: expectedSliderValue } });
|
|
fireEvent.change(groupIdInput, { target: { value: expectedGroupId } });
|
|
|
|
expect(slider).toHaveValue(expectedSliderValue);
|
|
expect(groupIdInput).toHaveValue(expectedGroupId);
|
|
});
|
|
|
|
test('should change targeting settings', async () => {
|
|
const { expectedConstraintValue, expectedSegmentName } =
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
fireEvent.click(addConstraintEl);
|
|
|
|
const inputElement = screen.getByPlaceholderText(
|
|
'value1, value2, value3...',
|
|
);
|
|
fireEvent.change(inputElement, {
|
|
target: { value: expectedConstraintValue },
|
|
});
|
|
|
|
const addValueEl = screen.getByText('Add values');
|
|
fireEvent.click(addValueEl);
|
|
|
|
const doneEl = screen.getByText('Done');
|
|
fireEvent.click(doneEl);
|
|
|
|
const selectElement = screen.getByPlaceholderText('Select segments');
|
|
fireEvent.mouseDown(selectElement);
|
|
|
|
const optionElement = await screen.findByText(expectedSegmentName);
|
|
fireEvent.click(optionElement);
|
|
|
|
expect(screen.getByText(expectedSegmentName)).toBeInTheDocument();
|
|
expect(screen.getByText(expectedConstraintValue)).toBeInTheDocument();
|
|
});
|
|
|
|
test('should change variants settings', async () => {
|
|
const { expectedVariantName } = setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const variantsEl = screen.getByText('Variants');
|
|
fireEvent.click(variantsEl);
|
|
|
|
const addVariantEl = await screen.findByText('Add variant');
|
|
fireEvent.click(addVariantEl);
|
|
|
|
const inputElement = screen.getAllByRole('textbox')[0];
|
|
fireEvent.change(inputElement, {
|
|
target: { value: expectedVariantName },
|
|
});
|
|
|
|
expect(screen.getByText(expectedVariantName)).toBeInTheDocument();
|
|
|
|
const generalSettingsEl = screen.getByText('General');
|
|
fireEvent.click(generalSettingsEl);
|
|
|
|
await waitFor(() => {
|
|
const codeSnippet = document.querySelector('pre')?.innerHTML;
|
|
const variantNameMatches = (
|
|
codeSnippet!.match(new RegExp(expectedVariantName, 'g')) || []
|
|
).length;
|
|
const metaDataMatches = (codeSnippet!.match(/isValid/g) || [])
|
|
.length;
|
|
expect(variantNameMatches).toBe(1);
|
|
expect(metaDataMatches).toBe(0);
|
|
});
|
|
});
|
|
|
|
test('should change variant name after changing tab', async () => {
|
|
const { expectedVariantName } = setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const variantsEl = screen.getByText('Variants');
|
|
fireEvent.click(variantsEl);
|
|
|
|
const addVariantEl = await screen.findByText('Add variant');
|
|
fireEvent.click(addVariantEl);
|
|
|
|
const inputElement = screen.getAllByRole('textbox')[0];
|
|
fireEvent.change(inputElement, {
|
|
target: { value: expectedVariantName },
|
|
});
|
|
|
|
const targetingEl = await screen.findByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
expect(addConstraintEl).toBeInTheDocument();
|
|
|
|
fireEvent.click(variantsEl);
|
|
const inputElement2 = screen.getAllByRole('textbox')[0];
|
|
|
|
expect(inputElement2).not.toBeDisabled();
|
|
});
|
|
|
|
test('should remove empty variants when changing tabs', async () => {
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const variantsEl = screen.getByText('Variants');
|
|
fireEvent.click(variantsEl);
|
|
|
|
const addVariantEl = await screen.findByText('Add variant');
|
|
fireEvent.click(addVariantEl);
|
|
|
|
const variants = screen.queryAllByTestId('VARIANT');
|
|
expect(variants.length).toBe(1);
|
|
|
|
const targetingEl = await screen.findByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
expect(addConstraintEl).toBeInTheDocument();
|
|
|
|
fireEvent.click(variantsEl);
|
|
|
|
const variants2 = screen.queryAllByTestId('VARIANT');
|
|
expect(variants2.length).toBe(0);
|
|
});
|
|
|
|
test('Should autosave constraint settings when navigating between tabs', async () => {
|
|
const { expectedMultipleValues } = setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
fireEvent.click(addConstraintEl);
|
|
|
|
const inputElement = screen.getByPlaceholderText(
|
|
'value1, value2, value3...',
|
|
);
|
|
fireEvent.change(inputElement, {
|
|
target: { value: expectedMultipleValues },
|
|
});
|
|
|
|
const addValueEl = await screen.findByText('Add values');
|
|
fireEvent.click(addValueEl);
|
|
|
|
const variantsEl = screen.getByText('Variants');
|
|
fireEvent.click(variantsEl);
|
|
|
|
fireEvent.click(targetingEl);
|
|
|
|
const values = expectedMultipleValues.split(',');
|
|
|
|
expect(screen.getByText(values[0])).toBeInTheDocument();
|
|
expect(screen.getByText(values[1])).toBeInTheDocument();
|
|
expect(screen.getByText(values[2])).toBeInTheDocument();
|
|
});
|
|
|
|
test('Should update multiple constraints correctly', async () => {
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
fireEvent.click(addConstraintEl);
|
|
fireEvent.click(addConstraintEl);
|
|
fireEvent.click(addConstraintEl);
|
|
|
|
const inputElements = screen.getAllByPlaceholderText(
|
|
'value1, value2, value3...',
|
|
);
|
|
|
|
fireEvent.change(inputElements[0], {
|
|
target: { value: '123' },
|
|
});
|
|
fireEvent.change(inputElements[1], {
|
|
target: { value: '456' },
|
|
});
|
|
fireEvent.change(inputElements[2], {
|
|
target: { value: '789' },
|
|
});
|
|
|
|
const addValueEls = await screen.findAllByText('Add values');
|
|
fireEvent.click(addValueEls[0]);
|
|
fireEvent.click(addValueEls[1]);
|
|
fireEvent.click(addValueEls[2]);
|
|
|
|
expect(screen.queryByText('123')).toBeInTheDocument();
|
|
const deleteBtns = await screen.findAllByTestId('CancelIcon');
|
|
fireEvent.click(deleteBtns[0]);
|
|
|
|
expect(screen.queryByText('123')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('456')).toBeInTheDocument();
|
|
expect(screen.queryByText('789')).toBeInTheDocument();
|
|
});
|
|
|
|
test('Should update multiple constraints with the correct react key', async () => {
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
fireEvent.click(addConstraintEl);
|
|
fireEvent.click(addConstraintEl);
|
|
fireEvent.click(addConstraintEl);
|
|
|
|
const inputElements = screen.getAllByPlaceholderText(
|
|
'value1, value2, value3...',
|
|
);
|
|
|
|
fireEvent.change(inputElements[0], {
|
|
target: { value: '123' },
|
|
});
|
|
fireEvent.change(inputElements[1], {
|
|
target: { value: '456' },
|
|
});
|
|
fireEvent.change(inputElements[2], {
|
|
target: { value: '789' },
|
|
});
|
|
|
|
const addValueEls = await screen.findAllByText('Add values');
|
|
fireEvent.click(addValueEls[0]);
|
|
fireEvent.click(addValueEls[1]);
|
|
fireEvent.click(addValueEls[2]);
|
|
|
|
expect(screen.queryByText('123')).toBeInTheDocument();
|
|
|
|
const deleteBtns = screen.getAllByTestId('DELETE_CONSTRAINT_BUTTON');
|
|
fireEvent.click(deleteBtns[0]);
|
|
|
|
const inputElements2 = screen.getAllByPlaceholderText(
|
|
'value1, value2, value3...',
|
|
);
|
|
|
|
fireEvent.change(inputElements2[0], {
|
|
target: { value: '666' },
|
|
});
|
|
const addValueEls2 = screen.getAllByText('Add values');
|
|
fireEvent.click(addValueEls2[0]);
|
|
|
|
expect(screen.queryByText('123')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('456')).toBeInTheDocument();
|
|
expect(screen.queryByText('789')).toBeInTheDocument();
|
|
});
|
|
|
|
test('Should undo changes made to constraints', async () => {
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
fireEvent.click(addConstraintEl);
|
|
|
|
const inputEl = screen.getByPlaceholderText(
|
|
'value1, value2, value3...',
|
|
);
|
|
|
|
fireEvent.change(inputEl, {
|
|
target: { value: '6, 7, 8' },
|
|
});
|
|
|
|
const addBtn = await screen.findByText('Add values');
|
|
fireEvent.click(addBtn);
|
|
|
|
expect(screen.queryByText('6')).toBeInTheDocument();
|
|
expect(screen.queryByText('7')).toBeInTheDocument();
|
|
expect(screen.queryByText('8')).toBeInTheDocument();
|
|
|
|
const undoBtn = await screen.findByTestId(
|
|
'UNDO_CONSTRAINT_CHANGE_BUTTON',
|
|
);
|
|
|
|
fireEvent.click(undoBtn);
|
|
|
|
expect(screen.queryByText('6')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('7')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('8')).not.toBeInTheDocument();
|
|
});
|
|
|
|
test('Should remove constraint when no valid values are set and moving between tabs', async () => {
|
|
setupComponent();
|
|
|
|
const titleEl = await screen.findByText('Gradual rollout');
|
|
expect(titleEl).toBeInTheDocument();
|
|
|
|
const targetingEl = screen.getByText('Targeting');
|
|
fireEvent.click(targetingEl);
|
|
|
|
const addConstraintEl = await screen.findByText('Add constraint');
|
|
fireEvent.click(addConstraintEl);
|
|
|
|
const variantsEl = screen.getByText('Variants');
|
|
fireEvent.click(variantsEl);
|
|
fireEvent.click(targetingEl);
|
|
|
|
const seconAddConstraintEl = await screen.findByText('Add constraint');
|
|
|
|
expect(seconAddConstraintEl).toBeInTheDocument();
|
|
expect(screen.queryByText('appName')).not.toBeInTheDocument();
|
|
});
|
|
});
|