Browse Source

test(flags): add tests for component and drawer (#77863)

add some tests for the `EventFeatureFlagList` and `FeatureFlagDrawer`
components.
Michelle Zhang 5 months ago
parent
commit
a3b94bec4a

+ 120 - 0
static/app/components/events/featureFlags/eventFeatureFlagList.spec.tsx

@@ -0,0 +1,120 @@
+import {
+  render,
+  screen,
+  userEvent,
+  waitForDrawerToHide,
+} from 'sentry-test/reactTestingLibrary';
+
+import {EventFeatureFlagList} from 'sentry/components/events/featureFlags/eventFeatureFlagList';
+import {
+  MOCK_DATA_SECTION_PROPS,
+  MOCK_FLAGS,
+} from 'sentry/components/events/featureFlags/testUtils';
+
+// Needed to mock useVirtualizer lists.
+jest.spyOn(window.Element.prototype, 'getBoundingClientRect').mockImplementation(() => ({
+  x: 0,
+  y: 0,
+  width: 0,
+  height: 30,
+  left: 0,
+  top: 0,
+  right: 0,
+  bottom: 0,
+  toJSON: jest.fn(),
+}));
+
+describe('EventFeatureFlagList', function () {
+  it('renders a list of feature flags with a button to view all', async function () {
+    render(<EventFeatureFlagList {...MOCK_DATA_SECTION_PROPS} />);
+
+    for (const {flag, result} of MOCK_FLAGS) {
+      if (result) {
+        expect(screen.getByText(flag)).toBeInTheDocument();
+      }
+    }
+
+    // When expanded, all should be visible
+    const viewAllButton = screen.getByRole('button', {name: 'View All'});
+    await userEvent.click(viewAllButton);
+    const drawer = screen.getByRole('complementary', {name: 'Feature flags drawer'});
+    expect(drawer).toBeInTheDocument();
+    for (const {flag, result} of MOCK_FLAGS) {
+      if (result) {
+        expect(screen.getAllByText(flag)[0]).toBeInTheDocument();
+      }
+    }
+  });
+
+  it('toggles the drawer when view all is clicked', async function () {
+    render(<EventFeatureFlagList {...MOCK_DATA_SECTION_PROPS} />);
+    const viewAllButton = screen.getByRole('button', {name: 'View All'});
+    await userEvent.click(viewAllButton);
+    const drawer = screen.getByRole('complementary', {name: 'Feature flags drawer'});
+    expect(drawer).toBeInTheDocument();
+    await userEvent.click(viewAllButton);
+    await waitForDrawerToHide('Feature flags drawer');
+    expect(drawer).not.toBeInTheDocument();
+  });
+
+  it('opens the drawer and focuses search when the search button is pressed', async function () {
+    render(<EventFeatureFlagList {...MOCK_DATA_SECTION_PROPS} />);
+
+    const control = screen.getByRole('button', {name: 'Open Feature Flag Search'});
+    expect(control).toBeInTheDocument();
+    await userEvent.click(control);
+    expect(
+      screen.getByRole('complementary', {name: 'Feature flags drawer'})
+    ).toBeInTheDocument();
+    const drawerControl = screen.getByRole('textbox', {
+      name: 'Search Flags',
+    });
+    expect(drawerControl).toBeInTheDocument();
+    expect(drawerControl).toHaveFocus();
+  });
+
+  it('renders a sorting dropdown with Newest First as the default', async function () {
+    render(<EventFeatureFlagList {...MOCK_DATA_SECTION_PROPS} />);
+
+    const control = screen.getByRole('button', {name: 'Newest First'});
+    expect(control).toBeInTheDocument();
+    await userEvent.click(control);
+    expect(screen.getByRole('option', {name: 'Alphabetical'})).toBeInTheDocument();
+    expect(screen.getByRole('option', {name: 'Oldest First'})).toBeInTheDocument();
+  });
+
+  it('allows sort dropdown to affect displayed flags', async function () {
+    render(<EventFeatureFlagList {...MOCK_DATA_SECTION_PROPS} />);
+
+    const [webVitalsFlag, enableReplay] = MOCK_FLAGS.filter(f => f.result === true);
+
+    // the flags are reversed by default, so webVitalsFlag should be below enableReplay
+    expect(
+      screen
+        .getByText(webVitalsFlag.flag)
+        .compareDocumentPosition(screen.getByText(enableReplay.flag))
+    ).toBe(document.DOCUMENT_POSITION_FOLLOWING);
+
+    // the sort should be reversed
+    const sortControl = screen.getByRole('button', {
+      name: 'Newest First',
+    });
+    await userEvent.click(sortControl);
+    await userEvent.click(screen.getByRole('option', {name: 'Oldest First'}));
+
+    expect(
+      screen
+        .getByText(webVitalsFlag.flag)
+        .compareDocumentPosition(screen.getByText(enableReplay.flag))
+    ).toBe(document.DOCUMENT_POSITION_PRECEDING);
+
+    await userEvent.click(sortControl);
+    await userEvent.click(screen.getByRole('option', {name: 'Alphabetical'}));
+
+    expect(
+      screen
+        .getByText(webVitalsFlag.flag)
+        .compareDocumentPosition(screen.getByText(enableReplay.flag))
+    ).toBe(document.DOCUMENT_POSITION_FOLLOWING);
+  });
+});

+ 104 - 0
static/app/components/events/featureFlags/featureFlagDrawer.spec.tsx

@@ -0,0 +1,104 @@
+import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary';
+
+import {EventFeatureFlagList} from 'sentry/components/events/featureFlags/eventFeatureFlagList';
+import {
+  MOCK_DATA_SECTION_PROPS,
+  MOCK_FLAGS,
+} from 'sentry/components/events/featureFlags/testUtils';
+
+async function renderFlagDrawer() {
+  // Needed to mock useVirtualizer lists.
+  jest
+    .spyOn(window.Element.prototype, 'getBoundingClientRect')
+    .mockImplementation(() => ({
+      x: 0,
+      y: 0,
+      width: 0,
+      height: 30,
+      left: 0,
+      top: 0,
+      right: 0,
+      bottom: 0,
+      toJSON: jest.fn(),
+    }));
+  render(<EventFeatureFlagList {...MOCK_DATA_SECTION_PROPS} />);
+  await userEvent.click(screen.getByRole('button', {name: 'View All'}));
+  return within(screen.getByRole('complementary', {name: 'Feature flags drawer'}));
+}
+
+describe('FeatureFlagDrawer', function () {
+  it('renders the drawer as expected', async function () {
+    const drawerScreen = await renderFlagDrawer();
+    expect(drawerScreen.getByRole('button', {name: 'Close Drawer'})).toBeInTheDocument();
+
+    // Inner drawer flags
+    const {event, group} = MOCK_DATA_SECTION_PROPS;
+    expect(drawerScreen.getByText(group.shortId)).toBeInTheDocument();
+    expect(drawerScreen.getByText(event.id.slice(0, 8))).toBeInTheDocument();
+    expect(
+      drawerScreen.getByText('Feature Flags', {selector: 'span'})
+    ).toBeInTheDocument();
+
+    // Header & Controls
+    expect(drawerScreen.getByText('Feature Flags', {selector: 'h3'})).toBeInTheDocument();
+    expect(drawerScreen.getByRole('textbox', {name: 'Search Flags'})).toBeInTheDocument();
+    expect(drawerScreen.getByRole('button', {name: 'Newest First'})).toBeInTheDocument();
+
+    // Contents
+    for (const {flag, result} of MOCK_FLAGS) {
+      expect(drawerScreen.getByText(flag)).toBeInTheDocument();
+      expect(drawerScreen.getAllByText(result.toString())[0]).toBeInTheDocument();
+    }
+  });
+
+  it('allows search to affect displayed flags', async function () {
+    const drawerScreen = await renderFlagDrawer();
+
+    const [webVitalsFlag, enableReplay] = MOCK_FLAGS.filter(f => f.result === true);
+    expect(drawerScreen.getByText(webVitalsFlag.flag)).toBeInTheDocument();
+    expect(drawerScreen.getByText(enableReplay.flag)).toBeInTheDocument();
+
+    const searchInput = drawerScreen.getByRole('textbox', {
+      name: 'Search Flags',
+    });
+    await userEvent.type(searchInput, webVitalsFlag.flag);
+
+    expect(drawerScreen.getByText(webVitalsFlag.flag)).toBeInTheDocument();
+    expect(drawerScreen.queryByText(enableReplay.flag)).not.toBeInTheDocument();
+  });
+
+  it('allows sort dropdown to affect displayed flags', async function () {
+    const drawerScreen = await renderFlagDrawer();
+
+    const [webVitalsFlag, enableReplay] = MOCK_FLAGS.filter(f => f.result === true);
+
+    // the flags are reversed by default, so webVitalsFlag should be below enableReplay
+    expect(
+      drawerScreen
+        .getByText(webVitalsFlag.flag)
+        .compareDocumentPosition(drawerScreen.getByText(enableReplay.flag))
+    ).toBe(document.DOCUMENT_POSITION_FOLLOWING);
+
+    // the sort should be reversed
+    const sortControl = drawerScreen.getByRole('button', {
+      name: 'Newest First',
+    });
+    await userEvent.click(sortControl);
+    await userEvent.click(drawerScreen.getByRole('option', {name: 'Oldest First'}));
+
+    expect(
+      drawerScreen
+        .getByText(webVitalsFlag.flag)
+        .compareDocumentPosition(drawerScreen.getByText(enableReplay.flag))
+    ).toBe(document.DOCUMENT_POSITION_PRECEDING);
+
+    await userEvent.click(sortControl);
+    await userEvent.click(drawerScreen.getByRole('option', {name: 'Alphabetical'}));
+
+    expect(
+      drawerScreen
+        .getByText(webVitalsFlag.flag)
+        .compareDocumentPosition(drawerScreen.getByText(enableReplay.flag))
+    ).toBe(document.DOCUMENT_POSITION_FOLLOWING);
+  });
+});

+ 33 - 0
static/app/components/events/featureFlags/testUtils.tsx

@@ -0,0 +1,33 @@
+import {EventFixture} from 'sentry-fixture/event';
+import {GroupFixture} from 'sentry-fixture/group';
+import {ProjectFixture} from 'sentry-fixture/project';
+
+import type {FeatureFlag} from 'sentry/types/event';
+
+export const MOCK_FLAGS: FeatureFlag[] = [
+  {
+    flag: 'mobile-replay-ui',
+    result: false,
+  },
+  {
+    flag: 'web-vitals-ui',
+    result: true,
+  },
+  {
+    flag: 'enable-replay',
+    result: true,
+  },
+  {
+    flag: 'secret-feature',
+    result: false,
+  },
+];
+
+export const MOCK_DATA_SECTION_PROPS = {
+  event: EventFixture({
+    id: 'abc123def456ghi789jkl',
+    contexts: {flags: {values: MOCK_FLAGS}},
+  }),
+  project: ProjectFixture(),
+  group: GroupFixture(),
+};