diff --git a/package.serve.json b/package.serve.json index ff9bf5879..02b2db208 100644 --- a/package.serve.json +++ b/package.serve.json @@ -90,7 +90,8 @@ "react-native-web": "^0.19.7", "react-native-web-webview": "^1.0.2", "react-qr-code": "^2.0.11", - "shelljs": "^0.8.5" + "shelljs": "^0.8.5", + "setimmediate": "^1.0.5" }, "cordova": { "platforms": [ diff --git a/www/__tests__/Carousel.test.tsx b/www/__tests__/Carousel.test.tsx index 7b8601109..d523f3afc 100644 --- a/www/__tests__/Carousel.test.tsx +++ b/www/__tests__/Carousel.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render } from '@testing-library/react-native'; +import { render, fireEvent } from '@testing-library/react-native'; import { View } from 'react-native'; import Carousel from '../js/components/Carousel'; @@ -23,4 +23,32 @@ describe('Carousel component', () => { expect(renderedChild1).toBeTruthy(); expect(renderedChild2).toBeTruthy(); }); + + it('scrolls correctly to the next card', () => { + const { getByTestId } = render( + + {child1} + {child2} + , + ); + + const scrollView = getByTestId('carousel'); + fireEvent.scroll(scrollView, { + // Scroll to the second card + nativeEvent: { + contentOffset: { + x: cardWidth + cardMargin, + }, + contentSize: { + width: (cardWidth + cardMargin) * 2, + }, + layoutMeasurement: { + width: cardWidth + cardMargin, + }, + }, + }); + + expect(scrollView.props.horizontal).toBe(true); + expect(scrollView.props.snapToInterval).toBe(cardWidth + cardMargin); + }); }); diff --git a/www/__tests__/DateSelect.test.tsx b/www/__tests__/DateSelect.test.tsx index 79fdc1997..e66424f17 100644 --- a/www/__tests__/DateSelect.test.tsx +++ b/www/__tests__/DateSelect.test.tsx @@ -1,19 +1,81 @@ import React from 'react'; -import { render, screen } from '@testing-library/react-native'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react-native'; import DateSelect from '../js/diary/list/DateSelect'; +import { DateTime } from 'luxon'; +import TimelineContext from '../js/TimelineContext'; +import initializedI18next from '../js/i18nextInit'; +window['i18next'] = initializedI18next; jest.mock('react-native-safe-area-context', () => ({ useSafeAreaInsets: () => ({ bottom: 30, left: 0, right: 0, top: 30 }), })); -jest.spyOn(React, 'useState').mockImplementation((initialValue) => [initialValue, jest.fn()]); -jest.spyOn(React, 'useEffect').mockImplementation((effect: () => void) => effect()); + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useMemo: (fn) => fn(), + useCallback: (fn) => fn, +})); describe('DateSelect', () => { - it('renders correctly', () => { + const pipelineRangeMock = { + start_ts: DateTime.local().set({ month: 5, day: 20 }).startOf('day').toSeconds(), + end_ts: DateTime.local() + .set({ month: 5, day: 30 }) + .endOf('day') + .set({ millisecond: 0 }) + .toSeconds(), + }; + + const queriedDateRangeMock = [ + DateTime.local().set({ month: 5, day: 20 }).startOf('day').toISO(), + DateTime.local().set({ month: 5, day: 30 }).endOf('day').set({ millisecond: 0 }).toISO(), + ]; + + const contextValue = { + pipelineRange: pipelineRangeMock, + queriedDateRange: queriedDateRangeMock, + }; + + it('renders correctly DatePickerModal after clicking the button and save date correctly', async () => { const onChooseMock = jest.fn(); - const { getByText } = render(); + render( + + + , + ); + // check if DateSelect rendered correctly expect(screen.getByTestId('button-container')).toBeTruthy(); expect(screen.getByTestId('button')).toBeTruthy(); + expect(screen.getByText('5/20/2024')).toBeTruthy(); + + fireEvent.press(screen.getByTestId('button')); + await waitFor(() => { + // 'save' and 'close' buttons should pop up correctly after DateSelect Modal Opens + expect(screen.getByTestId('react-native-paper-dates-close')).toBeTruthy(); + expect(screen.getByTestId('react-native-paper-dates-save-text')).toBeTruthy(); + }); + + // check if date changes corretly + // Start Date : 05/20/24 -> 05/25/2024 + fireEvent.changeText(screen.getAllByTestId('text-input-flat')[0], '05/25/2024'); + expect(screen.queryByDisplayValue('May 20')).toBeNull(); + expect(screen.getByText('May 25')).toBeTruthy(); + // End Date : 05/30/24 -> 05/28/2024 + fireEvent.changeText(screen.getAllByTestId('text-input-flat')[1], '05/28/2024'); + expect(screen.queryByDisplayValue('May 30')).toBeNull(); + expect(screen.getByText('May 28')).toBeTruthy(); + + // check if onChoose function gets called with changed dates after clicking 'save' button. + fireEvent.press(screen.getByTestId('react-native-paper-dates-save-text')); + const expectedParams = { + startDate: DateTime.local().set({ month: 5, day: 25 }).startOf('day').toJSDate(), + endDate: DateTime.local() + .set({ month: 5, day: 28 }) + .endOf('day') + .set({ millisecond: 0 }) + .toJSDate(), + }; + expect(onChooseMock).toHaveBeenCalledWith(expectedParams); }); }); diff --git a/www/__tests__/metricsHelper.test.ts b/www/__tests__/metricsHelper.test.ts index c914c5782..dbbf32c35 100644 --- a/www/__tests__/metricsHelper.test.ts +++ b/www/__tests__/metricsHelper.test.ts @@ -23,14 +23,23 @@ window['i18next'] = initializedI18next; describe('metricsHelper', () => { describe('getUniqueLabelsForDays', () => { - const days1 = [ - { mode_confirm_a: 1, mode_confirm_b: 2 }, - { mode_confirm_b: 1, mode_confirm_c: 3 }, - { mode_confirm_c: 1, mode_confirm_d: 3 }, - ] as any as DayOfMetricData[]; it("should return unique labels for days with 'mode_confirm_*'", () => { + const days1 = [ + { mode_confirm_a: 1, mode_confirm_b: 2 }, + { mode_confirm_b: 1, mode_confirm_c: 3 }, + { mode_confirm_c: 1, mode_confirm_d: 3 }, + ] as any as DayOfMetricData[]; expect(getUniqueLabelsForDays(days1)).toEqual(['a', 'b', 'c', 'd']); }); + + it('should return unique labels for days with duplicated labels', () => { + const days2 = [ + { mode_confirm_a: 1, mode_confirm_b: 2 }, + { mode_confirm_a: 1, mode_confirm_b: 2 }, + { mode_confirm_a: 1, mode_confirm_b: 2 }, + ] as any as DayOfMetricData[]; + expect(getUniqueLabelsForDays(days2)).toEqual(['a', 'b']); + }); }); describe('getLabelsForDay', () => { @@ -229,17 +238,17 @@ describe('metricsHelper', () => { expect(result).toBe(true); }); - it('returns true for all sensed labels', () => { + it('returns false for all sensed labels', () => { const modeMap = [ { - key: 'label_mode1', + key: 'SENSED_MODE_1', values: [ ['value1', 10], ['value2', 20], ], }, { - key: 'label_mode2', + key: 'SENSED_MODE_2', values: [ ['value3', 30], ['value4', 40], @@ -247,7 +256,7 @@ describe('metricsHelper', () => { }, ]; const result = isCustomLabels(modeMap); - expect(result).toBe(true); + expect(result).toBe(false); }); it('returns false for mixed custom and sensed labels', () => { diff --git a/www/js/components/Carousel.tsx b/www/js/components/Carousel.tsx index 8afe6624a..81740fc8b 100644 --- a/www/js/components/Carousel.tsx +++ b/www/js/components/Carousel.tsx @@ -10,6 +10,7 @@ const Carousel = ({ children, cardWidth, cardMargin }: Props) => { const numCards = React.Children.count(children); return ( & { mode: 'single' | 'range'; @@ -72,6 +74,7 @@ const DateSelect = ({ mode, onChoose, ...rest }: Props) => { return ( <>