Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DateTimeInput does not include timezone #6401

Merged
merged 6 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/simple/src/data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ export default {
published_at: new Date('2012-12-01'),
tags: [3, 5],
category: 'lifestyle',
backlinks: [],
notifications: [],
},
],
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"build-crm": "cd examples/crm && yarn -s build"
},
"jest": {
"globalSetup": "./test-global-setup.js",
"setupFilesAfterEnv": [
"./test-setup.js"
],
Expand Down
7 changes: 4 additions & 3 deletions packages/ra-ui-materialui/src/input/DateInput.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ describe('<DateInput />', () => {
render={() => <DateInput {...defaultProps} />}
/>
);
expect(getByLabelText('resources.posts.fields.publishedAt').type).toBe(
'date'
);
const input = getByLabelText(
'resources.posts.fields.publishedAt'
) as HTMLInputElement;
expect(input.type).toBe('date');
});

it('should not make the form dirty on initialization', () => {
Expand Down
11 changes: 2 additions & 9 deletions packages/ra-ui-materialui/src/input/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,11 @@ const DateInput = ({
variant = 'filled',
...rest
}: DateInputProps) => {
const sanitizedDefaultValue = defaultValue
? format(new Date(defaultValue))
: undefined;
const sanitizedInitialValue = initialValue
? format(new Date(initialValue))
: undefined;

const { id, input, isRequired, meta } = useInput({
defaultValue: sanitizedDefaultValue,
defaultValue,
format,
formatOnBlur: true,
initialValue: sanitizedInitialValue,
initialValue,
name,
onBlur,
onChange,
Expand Down
190 changes: 190 additions & 0 deletions packages/ra-ui-materialui/src/input/DateTimeInput.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import * as React from 'react';
import expect from 'expect';
import { render, fireEvent } from '@testing-library/react';
import { Form } from 'react-final-form';
import { required, FormWithRedirect } from 'ra-core';
import { renderWithRedux } from 'ra-test';
import format from 'date-fns/format';

import DateTimeInput from './DateTimeInput';
import ArrayInput from './ArrayInput';
import SimpleFormIterator from '../form/SimpleFormIterator';
import { FormApi } from 'final-form';

describe('<DateTimeInput />', () => {
const defaultProps = {
resource: 'posts',
source: 'publishedAt',
};

it('should render a date time input', () => {
const { getByLabelText } = render(
<Form
onSubmit={jest.fn}
render={() => <DateTimeInput {...defaultProps} />}
/>
);
const input = getByLabelText(
'resources.posts.fields.publishedAt'
) as HTMLInputElement;
expect(input.type).toBe('datetime-local');
});

it('should not make the form dirty on initialization', () => {
const publishedAt = new Date().toISOString();
let formApi: FormApi;
const { getByDisplayValue } = renderWithRedux(
<FormWithRedirect
onSubmit={jest.fn}
record={{ id: 1, publishedAt }}
render={({ form }) => {
formApi = form;
return <DateTimeInput {...defaultProps} />;
}}
/>
);
expect(getByDisplayValue(format(publishedAt, 'YYYY-MM-DDTHH:mm')));
expect(formApi.getState().dirty).toEqual(false);
});

it('should display a default value inside an ArrayInput', () => {
const date = new Date('Wed Oct 05 2011 16:48:00 GMT+0200');
const backlinksDefaultValue = [
{
date,
},
];
let formApi: FormApi;
const { getByDisplayValue } = renderWithRedux(
<FormWithRedirect
onSubmit={jest.fn}
render={({ form }) => {
formApi = form;
return (
<ArrayInput
defaultValue={backlinksDefaultValue}
source="backlinks"
>
<SimpleFormIterator>
<DateTimeInput source="date" />
</SimpleFormIterator>
</ArrayInput>
);
}}
/>
);

expect(getByDisplayValue(format(date, 'YYYY-MM-DDTHH:mm')));
expect(formApi.getState().values.backlinks[0].date).toEqual(
new Date('2011-10-05T14:48:00.000Z')
);
});

it('should submit initial value with its timezone', () => {
let formApi;
const publishedAt = new Date('Wed Oct 05 2011 16:48:00 GMT+0200');
const onSubmit = jest.fn();
const { queryByDisplayValue } = renderWithRedux(
<Form
onSubmit={onSubmit}
initialValues={{ publishedAt }}
render={({ form }) => {
formApi = form;

return <DateTimeInput {...defaultProps} />;
}}
/>
);
expect(
queryByDisplayValue(format(publishedAt, 'YYYY-MM-DDTHH:mm'))
).not.toBeNull();
expect(formApi.getState().values.publishedAt).toEqual(
new Date('2011-10-05T14:48:00.000Z')
);
});

it('should submit default value on input with its timezone', () => {
let formApi;
const publishedAt = new Date('Wed Oct 05 2011 16:48:00 GMT+0200');
const onSubmit = jest.fn();
const { queryByDisplayValue } = renderWithRedux(
<Form
onSubmit={onSubmit}
render={({ form }) => {
formApi = form;

return (
<DateTimeInput
{...defaultProps}
defaultValue={publishedAt}
/>
);
}}
/>
);
expect(
queryByDisplayValue(format(publishedAt, 'YYYY-MM-DDTHH:mm'))
).not.toBeNull();
expect(formApi.getState().values.publishedAt).toEqual(
new Date('2011-10-05T14:48:00.000Z')
);
});

it('should call `input.onChange` method when changed', () => {
let formApi;
const { getByLabelText } = render(
<Form
onSubmit={jest.fn()}
render={({ form }) => {
formApi = form;
return <DateTimeInput {...defaultProps} />;
}}
/>
);
const input = getByLabelText('resources.posts.fields.publishedAt');
fireEvent.change(input, {
target: { value: '2010-01-04T10:20' },
});
expect(formApi.getState().values.publishedAt).toEqual(
new Date('2010-01-04T09:20:00.000Z')
);
});

describe('error message', () => {
it('should not be displayed if field is pristine', () => {
const { queryByText } = render(
<Form
onSubmit={jest.fn}
render={() => (
<DateTimeInput
{...defaultProps}
validate={required()}
/>
)}
/>
);
expect(queryByText('ra.validation.required')).toBeNull();
});

it('should be displayed if field has been touched and is invalid', () => {
const { getByLabelText, queryByText } = render(
<Form
onSubmit={jest.fn}
validateOnBlur
render={() => (
<DateTimeInput
{...defaultProps}
validate={required()}
/>
)}
/>
);
const input = getByLabelText(
'resources.posts.fields.publishedAt *'
);
input.focus();
input.blur();
expect(queryByText('ra.validation.required')).not.toBeNull();
});
});
});
11 changes: 2 additions & 9 deletions packages/ra-ui-materialui/src/input/DateTimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,10 @@ const DateTimeInput = ({
variant = 'filled',
...rest
}: DateTimeInputProps) => {
const sanitizedDefaultValue = defaultValue
? format(new Date(defaultValue))
: undefined;
const sanitizedInitialValue = initialValue
? format(new Date(initialValue))
: undefined;

const { id, input, isRequired, meta } = useInput({
defaultValue: sanitizedDefaultValue,
defaultValue,
format,
initialValue: sanitizedInitialValue,
initialValue,
onBlur,
onChange,
onFocus,
Expand Down
3 changes: 3 additions & 0 deletions test-global-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = async () => {
process.env.TZ = 'Europe/Paris';
};