import sortBy from 'lodash/sortBy'; import {mountWithTheme} from 'sentry-test/enzyme'; import {openModal} from 'sentry/actionCreators/modal'; import GlobalModal from 'sentry/components/globalModal'; import convertRelayPiiConfig from 'sentry/views/settings/components/dataScrubbing/convertRelayPiiConfig'; import Add from 'sentry/views/settings/components/dataScrubbing/modals/add'; import {MethodType, RuleType} from 'sentry/views/settings/components/dataScrubbing/types'; import { getMethodLabel, getRuleLabel, } from 'sentry/views/settings/components/dataScrubbing/utils'; const relayPiiConfig = TestStubs.DataScrubbingRelayPiiConfig(); const stringRelayPiiConfig = JSON.stringify(relayPiiConfig); const organizationSlug = 'sentry'; const convertedRules = convertRelayPiiConfig(stringRelayPiiConfig); const rules = convertedRules; const successfullySaved = jest.fn(); const projectId = 'foo'; const endpoint = `/projects/${organizationSlug}/${projectId}/`; const api = new MockApiClient(); async function renderComponent() { const wrapper = mountWithTheme(); openModal(modalProps => ( )); await tick(); wrapper.update(); return wrapper; } describe('Add Modal', () => { it('open Add Rule Modal', async () => { const wrapper = await renderComponent(); expect(wrapper.find('Header').text()).toEqual('Add an advanced data scrubbing rule'); const fieldGroup = wrapper.find('FieldGroup'); expect(fieldGroup).toHaveLength(2); // Method Field const methodGroup = fieldGroup.at(0).find('Field'); expect(methodGroup.find('FieldLabel').text()).toEqual('Method'); const methodFieldHelp = 'What to do'; expect(methodGroup.find('QuestionTooltip').prop('title')).toEqual(methodFieldHelp); expect(methodGroup.find('Tooltip').prop('title')).toEqual(methodFieldHelp); const methodField = methodGroup.find('SelectField'); expect(methodField.exists()).toBe(true); const methodFieldProps = methodField.props(); expect(methodFieldProps.value).toEqual(MethodType.MASK); const methodFieldOptions = sortBy(Object.values(MethodType)).map(value => ({ ...getMethodLabel(value), value, })); expect(methodFieldProps.options).toEqual(methodFieldOptions); // Type Field const typeGroup = fieldGroup.at(1).find('Field'); expect(typeGroup.find('FieldLabel').text()).toEqual('Data Type'); const typeFieldHelp = 'What to look for. Use an existing pattern or define your own using regular expressions.'; expect(typeGroup.find('QuestionTooltip').prop('title')).toEqual(typeFieldHelp); expect(typeGroup.find('Tooltip').prop('title')).toEqual(typeFieldHelp); const typeField = typeGroup.find('SelectField'); expect(typeField.exists()).toBe(true); const typeFieldProps = typeField.props(); expect(typeFieldProps.value).toEqual(RuleType.CREDITCARD); const typeFieldOptions = sortBy(Object.values(RuleType)).map(value => ({ label: getRuleLabel(value), value, })); expect(typeFieldProps.options).toEqual(typeFieldOptions); // Event ID expect(wrapper.find('Toggle').text()).toEqual('Use event ID for auto-completion'); // Source Field const sourceGroup = wrapper.find('SourceGroup'); expect(sourceGroup.exists()).toBe(true); expect(sourceGroup.find('EventIdField')).toHaveLength(0); const sourceField = sourceGroup.find('Field'); expect(sourceField.find('FieldLabel').text()).toEqual('Source'); const sourceFieldHelp = 'Where to look. In the simplest case this can be an attribute name.'; expect(sourceField.find('QuestionTooltip').prop('title')).toEqual(sourceFieldHelp); expect(sourceField.find('Tooltip').prop('title')).toEqual(sourceFieldHelp); // Close Modal const cancelButton = wrapper.find('[aria-label="Cancel"]').hostNodes(); expect(cancelButton.exists()).toBe(true); cancelButton.simulate('click'); await tick(); wrapper.update(); expect(wrapper.find('GlobalModal[visible=true]').exists()).toBe(false); }); it('Display placeholder field', async () => { const wrapper = await renderComponent(); const fieldGroup = wrapper.find('FieldGroup'); expect(fieldGroup).toHaveLength(2); // Method Field const methodGroup = fieldGroup.at(0).find('Field'); expect(methodGroup).toHaveLength(1); const methodField = methodGroup.find('[data-test-id="method-field"]'); const methodFieldInput = methodField.find('input').at(1); methodFieldInput.simulate('keyDown', {key: 'ArrowDown'}); const methodFieldMenuOptions = wrapper.find( '[data-test-id="method-field"] MenuList Option' ); expect(methodFieldMenuOptions).toHaveLength(4); const replaceOption = methodFieldMenuOptions.at(3); expect(replaceOption.find('Label').text()).toEqual('Replace'); expect(replaceOption.find('Details').text()).toEqual('(Replace with Placeholder)'); // After the click the placeholder field MUST be in the DOM replaceOption.simulate('click'); wrapper.update(); expect( wrapper.find('[data-test-id="method-field"] input').at(1).prop('value') ).toEqual(MethodType.REPLACE); const updatedMethodGroup = wrapper.find('FieldGroup').at(0).find('Field'); expect(updatedMethodGroup).toHaveLength(2); const placeholderField = updatedMethodGroup.at(1); expect(placeholderField.find('FieldLabel').text()).toEqual( 'Custom Placeholder (Optional)' ); const placeholderFieldHelp = 'It will replace the default placeholder [Filtered]'; expect(placeholderField.find('QuestionTooltip').prop('title')).toEqual( placeholderFieldHelp ); expect(placeholderField.find('Tooltip').prop('title')).toEqual(placeholderFieldHelp); // After the click, the placeholder field MUST NOT be in the DOM wrapper .find('[data-test-id="method-field"]') .find('input') .at(1) .simulate('keyDown', {key: 'ArrowDown'}); const hashOption = wrapper .find('[data-test-id="method-field"] MenuList Option') .at(0); hashOption.simulate('click'); expect(wrapper.find('[data-test-id="method-field"] input').at(1).prop('value')).toBe( MethodType.HASH ); expect(wrapper.find('FieldGroup').at(0).find('Field')).toHaveLength(1); }); it('Display regex field', async () => { const wrapper = await renderComponent(); const fieldGroup = wrapper.find('FieldGroup'); expect(fieldGroup).toHaveLength(2); // Type Field const typeGroup = fieldGroup.at(1).find('Field'); expect(typeGroup).toHaveLength(1); const typeField = typeGroup.find('[data-test-id="type-field"]'); const typeFieldInput = typeField.find('input').at(1); typeFieldInput.simulate('keyDown', {key: 'ArrowDown'}); const typeFieldMenuOptions = wrapper.find( '[data-test-id="type-field"] MenuList Option' ); expect(typeFieldMenuOptions).toHaveLength(13); const regexOption = typeFieldMenuOptions.at(7); expect(regexOption.find('Label').text()).toEqual('Regex matches'); // After the click, the regex matches field MUST be in the DOM regexOption.simulate('click'); wrapper.update(); expect(wrapper.find('[data-test-id="type-field"] input').at(1).prop('value')).toEqual( RuleType.PATTERN ); const updatedTypeGroup = wrapper.find('FieldGroup').at(1).find('Field'); expect(updatedTypeGroup).toHaveLength(2); const regexField = updatedTypeGroup.at(1); expect(regexField.find('FieldLabel').text()).toEqual('Regex matches'); const regexFieldHelp = 'Custom regular expression (see documentation)'; expect(regexField.find('QuestionTooltip').prop('title')).toEqual(regexFieldHelp); expect(regexField.find('Tooltip').prop('title')).toEqual(regexFieldHelp); // After the click, the regex matches field MUST NOT be in the DOM wrapper .find('[data-test-id="type-field"]') .find('input') .at(1) .simulate('keyDown', {key: 'ArrowDown'}); const creditCardOption = wrapper .find('[data-test-id="type-field"] MenuList Option') .at(1); creditCardOption.simulate('click'); expect(wrapper.find('[data-test-id="type-field"] input').at(1).prop('value')).toBe( RuleType.CREDITCARD ); expect(wrapper.find('FieldGroup').at(1).find('Field')).toHaveLength(1); }); it('Display Event Id', async () => { const eventId = '12345678901234567890123456789012'; MockApiClient.addMockResponse({ url: `/organizations/${organizationSlug}/data-scrubbing-selector-suggestions/`, body: { suggestions: [ {type: 'value', examples: ['34359738368'], value: "extra.'system.cpu.memory'"}, {type: 'value', value: '$frame.abs_path'}, ], }, }); const wrapper = await renderComponent(); const eventIdToggle = wrapper.find('Toggle'); eventIdToggle.simulate('click'); const eventIdFieldInput = wrapper.find('[data-test-id="event-id-field"] input'); eventIdFieldInput.simulate('change', { target: {value: eventId}, }); eventIdFieldInput.simulate('blur'); await tick(); // Loading expect(wrapper.find('[data-test-id="event-id-field"] FormSpinner')).toHaveLength(1); wrapper.update(); // Fetched new suggestions successfully through the informed event ID expect(wrapper.find('[data-test-id="event-id-field"] IconCheckmark')).toHaveLength(1); }); });