diff --git a/static/app/components/codecov/datePicker/datePicker.spec.tsx b/static/app/components/codecov/datePicker/datePicker.spec.tsx
new file mode 100644
index 00000000000000..c032d38ce5b6b0
--- /dev/null
+++ b/static/app/components/codecov/datePicker/datePicker.spec.tsx
@@ -0,0 +1,145 @@
+import {initializeOrg} from 'sentry-test/initializeOrg';
+import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
+
+import {initializeUrlState} from 'sentry/actionCreators/pageFilters';
+import {DatePicker} from 'sentry/components/codecov/datePicker/datePicker';
+import OrganizationStore from 'sentry/stores/organizationStore';
+import PageFiltersStore from 'sentry/stores/pageFiltersStore';
+
+const {organization, router} = initializeOrg({
+ router: {
+ location: {
+ query: {},
+ pathname: '/codecov/tests',
+ },
+ params: {},
+ },
+});
+
+describe('DatePicker', function () {
+ beforeEach(() => {
+ PageFiltersStore.init();
+ OrganizationStore.init();
+
+ OrganizationStore.onUpdate(organization, {replace: true});
+ PageFiltersStore.onInitializeUrlState(
+ {
+ projects: [],
+ environments: [],
+ datetime: {
+ period: '7d',
+ start: null,
+ end: null,
+ utc: false,
+ },
+ },
+ new Set(['datetime'])
+ );
+ });
+
+ it('can change period', async function () {
+ render(, {router});
+
+ await userEvent.click(screen.getByRole('button', {name: '7D', expanded: false}));
+ await userEvent.click(screen.getByRole('option', {name: 'Last 30 days'}));
+
+ expect(
+ screen.getByRole('button', {name: '30D', expanded: false})
+ ).toBeInTheDocument();
+ expect(router.push).toHaveBeenCalledWith(
+ expect.objectContaining({query: {statsPeriod: '30d'}})
+ );
+ expect(PageFiltersStore.getState()).toEqual({
+ isReady: true,
+ shouldPersist: true,
+ desyncedFilters: new Set(),
+ pinnedFilters: new Set(['datetime']),
+ selection: {
+ datetime: {
+ period: '30d',
+ end: null,
+ start: null,
+ utc: false,
+ },
+ environments: [],
+ projects: [],
+ },
+ });
+ });
+
+ it('adjusts period if invalid', async function () {
+ PageFiltersStore.reset();
+ PageFiltersStore.onInitializeUrlState(
+ {
+ projects: [],
+ environments: [],
+ datetime: {
+ period: '123d',
+ start: null,
+ end: null,
+ utc: false,
+ },
+ },
+ new Set(['datetime'])
+ );
+
+ render(, {router});
+
+ // Confirm selection changed to default Codecov period
+ const button = await screen.findByRole('button', {name: '24H', expanded: false});
+ expect(button).toBeInTheDocument();
+ expect(router.push).toHaveBeenCalledWith(
+ expect.objectContaining({query: {statsPeriod: '24h'}})
+ );
+ expect(PageFiltersStore.getState()).toEqual({
+ isReady: true,
+ shouldPersist: true,
+ desyncedFilters: new Set(),
+ pinnedFilters: new Set(['datetime']),
+ selection: {
+ datetime: {
+ period: '24h',
+ end: null,
+ start: null,
+ utc: false,
+ },
+ environments: [],
+ projects: [],
+ },
+ });
+ });
+
+ it('displays a desynced state message', async function () {
+ const {organization: desyncOrganization, router: desyncRouter} = initializeOrg({
+ router: {
+ location: {
+ query: {statsPeriod: '7d'},
+ pathname: '/codecov/test',
+ },
+ params: {},
+ },
+ });
+
+ PageFiltersStore.reset();
+ initializeUrlState({
+ memberProjects: [],
+ nonMemberProjects: [],
+ organization: desyncOrganization,
+ queryParams: {statsPeriod: '30d'},
+ router: desyncRouter,
+ shouldEnforceSingleProject: false,
+ });
+
+ render(, {
+ router: desyncRouter,
+ organization: desyncOrganization,
+ });
+
+ await userEvent.click(screen.getByRole('button', {name: '30D', expanded: false}));
+ expect(screen.getByText('Filters Updated')).toBeInTheDocument();
+ expect(
+ screen.getByRole('button', {name: 'Restore Previous Values'})
+ ).toBeInTheDocument();
+ expect(screen.getByRole('button', {name: 'Got It'})).toBeInTheDocument();
+ });
+});
diff --git a/static/app/components/codecov/datePicker.tsx b/static/app/components/codecov/datePicker/datePicker.tsx
similarity index 85%
rename from static/app/components/codecov/datePicker.tsx
rename to static/app/components/codecov/datePicker/datePicker.tsx
index 226701ec6e76d2..dc6f35fc9a807a 100644
--- a/static/app/components/codecov/datePicker.tsx
+++ b/static/app/components/codecov/datePicker/datePicker.tsx
@@ -1,14 +1,14 @@
import {useEffect} from 'react';
import {updateDateTime} from 'sentry/actionCreators/pageFilters';
-import type {DateSelectorProps} from 'sentry/components/codecov/dateSelector';
-import {DateSelector} from 'sentry/components/codecov/dateSelector';
+import type {DateSelectorProps} from 'sentry/components/codecov/datePicker/dateSelector';
+import {DateSelector} from 'sentry/components/codecov/datePicker/dateSelector';
import {DesyncedFilterMessage} from 'sentry/components/organizations/pageFilters/desyncedFilter';
import {t} from 'sentry/locale';
import usePageFilters from 'sentry/utils/usePageFilters';
import useRouter from 'sentry/utils/useRouter';
-import {isValidCodecovRelativePeriod} from './utils';
+import {isValidCodecovRelativePeriod} from '../utils';
const CODECOV_DEFAULT_RELATIVE_PERIOD = '24h';
export const CODECOV_DEFAULT_RELATIVE_PERIODS = {
@@ -32,7 +32,7 @@ export function DatePicker({
const desynced = desyncedFilters.has('datetime');
const period = selection.datetime?.period;
- // Adjusts to valid Codecov relative period
+ // Adjusts to valid Codecov relative period since Codecov only accepts a subset of dates other components accept, defined in CODECOV_DEFAULT_RELATIVE_PERIODS
useEffect(() => {
if (!isValidCodecovRelativePeriod(period)) {
const newTimePeriod = {period: CODECOV_DEFAULT_RELATIVE_PERIOD};
diff --git a/static/app/components/codecov/datePicker/dateSelector.spec.tsx b/static/app/components/codecov/datePicker/dateSelector.spec.tsx
new file mode 100644
index 00000000000000..f2a0be2fa9b87a
--- /dev/null
+++ b/static/app/components/codecov/datePicker/dateSelector.spec.tsx
@@ -0,0 +1,17 @@
+import {render, screen} from 'sentry-test/reactTestingLibrary';
+
+import {DateSelector} from 'sentry/components/codecov/datePicker/dateSelector';
+
+describe('DateSelector', function () {
+ it('renders when given relative period', async function () {
+ render();
+ expect(await screen.findByRole('button', {name: '7D'})).toBeInTheDocument();
+ });
+
+ it('renders when given an invalid relative period', async function () {
+ render();
+ expect(
+ await screen.findByRole('button', {name: 'Invalid Period'})
+ ).toBeInTheDocument();
+ });
+});
diff --git a/static/app/components/codecov/dateSelector.tsx b/static/app/components/codecov/datePicker/dateSelector.tsx
similarity index 100%
rename from static/app/components/codecov/dateSelector.tsx
rename to static/app/components/codecov/datePicker/dateSelector.tsx
diff --git a/static/app/components/codecov/utils.spec.tsx b/static/app/components/codecov/utils.spec.tsx
new file mode 100644
index 00000000000000..187470d6f4bf1e
--- /dev/null
+++ b/static/app/components/codecov/utils.spec.tsx
@@ -0,0 +1,16 @@
+import {isValidCodecovRelativePeriod} from 'sentry/components/codecov/utils';
+
+describe('isValidCodecovRelativePeriod', function () {
+ it('returns false for null relative periods', function () {
+ const period = null;
+ expect(isValidCodecovRelativePeriod(period)).toBe(false);
+ });
+ it('returns false for periods not belonging to the Codecov default relative periods', function () {
+ const period = '123d';
+ expect(isValidCodecovRelativePeriod(period)).toBe(false);
+ });
+ it('returns true for a valid relative period', function () {
+ const period = '7d';
+ expect(isValidCodecovRelativePeriod(period)).toBe(true);
+ });
+});
diff --git a/static/app/components/codecov/utils.tsx b/static/app/components/codecov/utils.tsx
index f6d28e18531fe2..9c82455c27c47d 100644
--- a/static/app/components/codecov/utils.tsx
+++ b/static/app/components/codecov/utils.tsx
@@ -1,4 +1,6 @@
-import {CODECOV_DEFAULT_RELATIVE_PERIODS} from './datePicker';
+import {CODECOV_DEFAULT_RELATIVE_PERIODS} from './datePicker/datePicker';
+
+// Date Picker Utils Start
/**
* Determines if a period is valid for a Codecov DatePicker component. A period is invalid if
@@ -15,3 +17,5 @@ export function isValidCodecovRelativePeriod(period: string | null): boolean {
return true;
}
+
+// Date Picker Utils End
diff --git a/static/app/views/codecov/tests/tests.tsx b/static/app/views/codecov/tests/tests.tsx
index 6d6e2e317a2d65..e104058370f27c 100644
--- a/static/app/views/codecov/tests/tests.tsx
+++ b/static/app/views/codecov/tests/tests.tsx
@@ -1,6 +1,6 @@
import styled from '@emotion/styled';
-import {DatePicker} from 'sentry/components/codecov/datePicker';
+import {DatePicker} from 'sentry/components/codecov/datePicker/datePicker';
import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
import {space} from 'sentry/styles/space';