Updating date-fns library from 1.x to 2.x (#10848)

* first round of fixes and setup

* test fixes

* fix dumb options on new method

* test fix

* clean up

* fixes

* clean up

* handle utc time

* add changelog
This commit is contained in:
Angel Garbarino 2021-02-08 13:13:00 -07:00 committed by GitHub
parent d0994340fb
commit 5ce35d1c52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 103 additions and 64 deletions

3
changelog/10848.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
ui: Upgrade date-fns from 1.3.0 to 2.16.1.
```

View File

@ -1,8 +1,8 @@
/** /**
* @module PricingMetricsDates * @module PricingMetricsDates
* PricingMetricsDates components are used on the Pricing Metrics page to handle queries related to pricing metrics. * PricingMetricsDates components are used on the Pricing Metrics page to handle queries related to pricing metrics.
* This component assumes that query parameters (as in, from route params) are being passed in with the format MM-YYYY, * This component assumes that query parameters (as in, from route params) are being passed in with the format MM-yyyy,
* while the inputs expect a format of MM/YYYY. * while the inputs expect a format of MM/yyyy.
* *
* @example * @example
* ```js * ```js
@ -10,8 +10,8 @@
* ``` * ```
* @param {object} resultStart - resultStart is the start date of the metrics returned. Should be a valid date string that the built-in Date() fn can parse * @param {object} resultStart - resultStart is the start date of the metrics returned. Should be a valid date string that the built-in Date() fn can parse
* @param {object} resultEnd - resultEnd is the end date of the metrics returned. Should be a valid date string that the built-in Date() fn can parse * @param {object} resultEnd - resultEnd is the end date of the metrics returned. Should be a valid date string that the built-in Date() fn can parse
* @param {string} [queryStart] - queryStart is the route param (formatted MM-YYYY) that the result will be measured against for showing discrepancy warning * @param {string} [queryStart] - queryStart is the route param (formatted MM-yyyy) that the result will be measured against for showing discrepancy warning
* @param {string} [queryEnd] - queryEnd is the route param (formatted MM-YYYY) that the result will be measured against for showing discrepancy warning * @param {string} [queryEnd] - queryEnd is the route param (formatted MM-yyyy) that the result will be measured against for showing discrepancy warning
* @param {number} [defaultSpan=12] - setting for default time between start and end input dates * @param {number} [defaultSpan=12] - setting for default time between start and end input dates
* @param {number} [retentionMonths=24] - setting for the retention months, which informs valid dates to query by * @param {number} [retentionMonths=24] - setting for the retention months, which informs valid dates to query by
*/ */
@ -100,10 +100,10 @@ export default Component.extend({
error: computed('end', 'endDate', 'retentionMonths', 'start', 'startDate', function() { error: computed('end', 'endDate', 'retentionMonths', 'start', 'startDate', function() {
if (!this.startDate) { if (!this.startDate) {
return 'Start date is invalid. Please use format MM/YYYY'; return 'Start date is invalid. Please use format MM/yyyy';
} }
if (!this.endDate) { if (!this.endDate) {
return 'End date is invalid. Please use format MM/YYYY'; return 'End date is invalid. Please use format MM/yyyy';
} }
if (isBefore(this.endDate, this.startDate)) { if (isBefore(this.endDate, this.startDate)) {
return 'Start date is after end date'; return 'Start date is after end date';
@ -114,7 +114,7 @@ export default Component.extend({
} }
const earliestRetained = startOfMonth(subMonths(lastMonthAvailable, this.retentionMonths)); const earliestRetained = startOfMonth(subMonths(lastMonthAvailable, this.retentionMonths));
if (isBefore(this.startDate, earliestRetained)) { if (isBefore(this.startDate, earliestRetained)) {
return `No data retained before ${format(earliestRetained, 'MM/YYYY')} due to your settings`; return `No data retained before ${format(earliestRetained, 'MM/yyyy')} due to your settings`;
} }
return null; return null;
@ -130,24 +130,24 @@ export default Component.extend({
initialEnd = parseDateString(this.queryEnd, '-'); initialEnd = parseDateString(this.queryEnd, '-');
} else { } else {
// if query isn't passed in, set it so that showResultsWarning works // if query isn't passed in, set it so that showResultsWarning works
this.queryEnd = format(initialEnd, 'MM-YYYY'); this.queryEnd = format(initialEnd, 'MM-yyyy');
} }
initialStart = subMonths(initialEnd, this.defaultSpan); initialStart = subMonths(initialEnd, this.defaultSpan);
if (this.queryStart) { if (this.queryStart) {
initialStart = parseDateString(this.queryStart, '-'); initialStart = parseDateString(this.queryStart, '-');
} else { } else {
// if query isn't passed in, set it so that showResultsWarning works // if query isn't passed in, set it so that showResultsWarning works
this.queryStart = format(initialStart, 'MM-YYYY'); this.queryStart = format(initialStart, 'MM-yyyy');
} }
this.start = format(initialStart, 'MM/YYYY'); this.start = format(initialStart, 'MM/yyyy');
this.end = format(initialEnd, 'MM/YYYY'); this.end = format(initialEnd, 'MM/yyyy');
}, },
actions: { actions: {
handleQuery() { handleQuery() {
const start = format(this.startDate, 'MM-YYYY'); const start = format(this.startDate, 'MM-yyyy');
const end = format(this.endDate, 'MM-YYYY'); const end = format(this.endDate, 'MM-yyyy');
this.router.transitionTo('vault.cluster.metrics', { this.router.transitionTo('vault.cluster.metrics', {
queryParams: { queryParams: {
start, start,

View File

@ -3,7 +3,7 @@ import { assign } from '@ember/polyfills';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import Component from '@ember/component'; import Component from '@ember/component';
import { setProperties, computed, set } from '@ember/object'; import { setProperties, computed, set } from '@ember/object';
import { addSeconds } from 'date-fns'; import { addSeconds, parseISO } from 'date-fns';
const DEFAULTS = { const DEFAULTS = {
token: null, token: null,
@ -67,8 +67,8 @@ export default Component.extend(DEFAULTS, {
if (!(creation_time && creation_ttl)) { if (!(creation_time && creation_ttl)) {
return null; return null;
} }
// returns new Date with seconds added.
return addSeconds(creation_time, creation_ttl); return addSeconds(parseISO(creation_time), creation_ttl);
}), }),
handleError(e) { handleError(e) {

View File

@ -1,8 +1,11 @@
import { helper } from '@ember/component/helper'; import { helper } from '@ember/component/helper';
import { distanceInWordsToNow } from 'date-fns'; import { formatDistanceToNow } from 'date-fns';
export function dateFromNow([date], options = {}) { export function dateFromNow([date], options = {}) {
return distanceInWordsToNow(date, options); // check first if string. If it is, it could be ISO format or UTC, either way create a new date object
// otherwise it's a number or object and just return
let newDate = typeof date === 'string' ? new Date(date) : date;
return formatDistanceToNow(newDate, { ...options });
} }
export default helper(dateFromNow); export default helper(dateFromNow);

View File

@ -2,7 +2,7 @@ import { helper } from '@ember/component/helper';
import { isValid } from 'date-fns'; import { isValid } from 'date-fns';
export function parseDateString(date, separator = '-') { export function parseDateString(date, separator = '-') {
// Expects format MM-YYYY by default: no dates // Expects format MM-yyyy by default: no dates
let datePieces = date.split(separator); let datePieces = date.split(separator);
if (datePieces.length === 2) { if (datePieces.length === 2) {
if (datePieces[0] < 1 || datePieces[0] > 12) { if (datePieces[0] < 1 || datePieces[0] > 12) {
@ -14,7 +14,7 @@ export function parseDateString(date, separator = '-') {
} }
} }
// what to return if not valid? // what to return if not valid?
throw new Error(`Please use format MM${separator}YYYY`); throw new Error(`Please use format MM${separator}yyyy`);
} }
export default helper(parseDateString); export default helper(parseDateString);

View File

@ -1,25 +1,26 @@
import Route from '@ember/routing/route'; import Route from '@ember/routing/route';
import ClusterRoute from 'vault/mixins/cluster-route'; import ClusterRoute from 'vault/mixins/cluster-route';
import { hash } from 'rsvp'; import { hash } from 'rsvp';
import { format, addDays } from 'date-fns'; import { getTime } from 'date-fns';
import { parseDateString } from 'vault/helpers/parse-date-string'; import { parseDateString } from 'vault/helpers/parse-date-string';
const getActivityParams = ({ start, end }) => { const getActivityParams = ({ start, end }) => {
// Expects MM-YYYY format // Expects MM-yyyy format
// TODO: minStart, maxEnd // TODO: minStart, maxEnd
let params = {}; let params = {};
if (start) { if (start) {
let startDate = parseDateString(start); let startDate = parseDateString(start);
if (startDate) { if (startDate) {
// TODO: Replace with formatRFC3339 when date-fns is updated // TODO: Replace with formatRFC3339 when date-fns is updated
params.start_time = format(addDays(startDate, 1), 'X'); // converts to milliseconds, divide by 1000 to get epoch
params.start_time = getTime(startDate) / 1000;
} }
} }
if (end) { if (end) {
let endDate = parseDateString(end); let endDate = parseDateString(end);
if (endDate) { if (endDate) {
// TODO: Replace with formatRFC3339 when date-fns is updated // TODO: Replace with formatRFC3339 when date-fns is updated
params.end_time = format(addDays(endDate, 10), 'X'); params.end_time = getTime(endDate) / 1000;
} }
} }
return params; return params;

View File

@ -10,7 +10,7 @@
<li class="action"> <li class="action">
<AlertBanner @type="warning" @message="We've stopped auto-renewing your token due to inactivity. <AlertBanner @type="warning" @message="We've stopped auto-renewing your token due to inactivity.
It will expire in {{date-from-now auth.tokenExpirationDate interval=1000 hideSuffix=true}}. It will expire in {{date-from-now auth.tokenExpirationDate interval=1000 hideSuffix=true}}.
on {{date-format auth.tokenExpirationDate 'MMMM Do YYYY, h:mm:ss a'}}" /> On {{date-format auth.tokenExpirationDate 'MMMM Do yyyy, h:mm:ss a'}}" />
</li> </li>
{{/if}} {{/if}}
<li class="action"> <li class="action">

View File

@ -25,7 +25,7 @@
</div> </div>
{{#if this.fileName}} {{#if this.fileName}}
<p class="help has-text-grey"> <p class="help has-text-grey">
This file is {{this.fileSize}} and was created on {{date-format this.fileLastModified 'MMM DD, YYYY hh:mm:ss A'}}. This file is {{this.fileSize}} and was created on {{date-format this.fileLastModified 'MMM dd, yyyy hh:mm:ss a'}}.
</p> </p>
{{/if}} {{/if}}
{{#if @fileHelpText}} {{#if @fileHelpText}}

View File

@ -17,11 +17,11 @@
</InfoTableRow> </InfoTableRow>
<InfoTableRow @label="Created" @value={{@model.creationTime}}> <InfoTableRow @label="Created" @value={{@model.creationTime}}>
<time datetime={{@model.creationTime}} title={{@model.creationTime}}> <time datetime={{@model.creationTime}} title={{@model.creationTime}}>
{{date-format @model.creationTime 'MMM DD, YYYY [at] h:mm a'}} {{date-format @model.creationTime 'MMM dd, yyyy [at] h:mm a'}}
</time> </time>
</InfoTableRow> </InfoTableRow>
<InfoTableRow @label="Last Updated" @value={{@model.lastUpdateTime}}> <InfoTableRow @label="Last Updated" @value={{@model.lastUpdateTime}}>
<time datetime={{@model.lastUpdateTime}} title={{@model.lastUpdateTime}}> <time datetime={{@model.lastUpdateTime}} title={{@model.lastUpdateTime}}>
{{date-format @model.lastUpdateTime 'MMM DD, YYYY [at] h:mm a'}} {{date-format @model.lastUpdateTime 'MMM dd, yyyy [at] h:mm a'}}
</time> </time>
</InfoTableRow> </InfoTableRow>

View File

@ -26,12 +26,12 @@
</InfoTableRow> </InfoTableRow>
<InfoTableRow @label="Created" @value={{model.creationTime}}> <InfoTableRow @label="Created" @value={{model.creationTime}}>
<time datetime={{model.creationTime}} title={{model.creationTime}}> <time datetime={{model.creationTime}} title={{model.creationTime}}>
{{date-format model.creationTime 'MMM DD, YYYY [at] h:mm a'}} {{date-format model.creationTime 'MMM dd, yyyy [at] h:mm a'}}
</time> </time>
</InfoTableRow> </InfoTableRow>
<InfoTableRow @label="Last Updated" @value={{model.lastUpdateTime}}> <InfoTableRow @label="Last Updated" @value={{model.lastUpdateTime}}>
<time datetime={{model.lastUpdateTime}} title={{model.lastUpdateTime}}> <time datetime={{model.lastUpdateTime}} title={{model.lastUpdateTime}}>
{{date-format model.lastUpdateTime 'MMM DD, YYYY [at] h:mm a'}} {{date-format model.lastUpdateTime 'MMM dd, yyyy [at] h:mm a'}}
</time> </time>
</InfoTableRow> </InfoTableRow>
</div> </div>

View File

@ -54,7 +54,7 @@
<div class="field box is-fullwidth is-shadowless is-paddingless is-marginless"> <div class="field box is-fullwidth is-shadowless is-paddingless is-marginless">
<InfoTableRow @label="License ID" @value={{licenseId}} /> <InfoTableRow @label="License ID" @value={{licenseId}} />
<InfoTableRow @label="Valid from" @value={{startTime}}> <InfoTableRow @label="Valid from" @value={{startTime}}>
{{date-format model.startTime 'MMM DD, YYYY hh:mm:ss A'}} to {{date-format expirationTime 'MMM DD, YYYY hh:mm:ss A'}} {{date-format startTime 'MMM dd, yyyy hh:mm:ss a'}} to {{date-format expirationTime 'MMM dd, yyyy hh:mm:ss a'}}
</InfoTableRow> </InfoTableRow>
</div> </div>
<div class="field box is-fullwidth is-shadowless is-paddingless is-marginless"> <div class="field box is-fullwidth is-shadowless is-paddingless is-marginless">

View File

@ -38,7 +38,7 @@
> >
<section class="modal-card-body"> <section class="modal-card-body">
{{#if (eq model.enabled "On")}} {{#if (eq model.enabled "On")}}
<p class="has-bottom-margin-s">Vault will start tracking data starting from todays date, {{date-format (now) "D MMMM YYYY"}}. You will not be able to see or query usage until the end of the month.</p> <p class="has-bottom-margin-s">Vault will start tracking data starting from todays date, {{date-format (now) "d MMMM yyyy"}}. You will not be able to see or query usage until the end of the month.</p>
<p>If youve previously enabled usage tracking, that historical data will still be available to you.</p> <p>If youve previously enabled usage tracking, that historical data will still be available to you.</p>
{{else}} {{else}}
<p class="has-bottom-margin-s">Turning usage tracking off means that all data for the current month will be deleted. You will still be able to query previous months.</p> <p class="has-bottom-margin-s">Turning usage tracking off means that all data for the current month will be deleted. You will still be able to query previous months.</p>

View File

@ -38,7 +38,7 @@
<div class="box is-fullwidth is-shadowless"> <div class="box is-fullwidth is-shadowless">
{{#if (and resultStart resultEnd)}} {{#if (and resultStart resultEnd)}}
<h2 class="title is-4" data-test-pricing-result-dates> <h2 class="title is-4" data-test-pricing-result-dates>
{{date-format resultStart "MMM DD, YYYY"}} through {{date-format resultEnd "MMM DD, YYYY"}} {{date-format resultStart "MMM dd, yyyy"}} through {{date-format resultEnd "MMM dd, yyyy"}}
</h2> </h2>
{{/if}} {{/if}}
{{#if showResultsWarning}} {{#if showResultsWarning}}

View File

@ -3,7 +3,7 @@
<AlertBanner <AlertBanner
@type="danger" @type="danger"
@message="Your auth token expired on @message="Your auth token expired on
{{date-format expirationDate "MMMM Do YYYY, h:mm:ss a"}} {{date-format expirationDate "MMMM Do yyyy, h:mm:ss a"}}
. You will need to re-authenticate." . You will need to re-authenticate."
> >
<LinkTo @route="vault.cluster.logout" class="button link"> <LinkTo @route="vault.cluster.logout" class="button link">

View File

@ -7,7 +7,7 @@
@size="l" @size="l"
aria-hidden="true" aria-hidden="true"
class="has-text-grey-light" /> class="has-text-grey-light" />
&copy; {{date-format (now) "YYYY"}} HashiCorp &copy; {{date-format (now) "yyyy"}} HashiCorp
</span> </span>
<span> <span>
<a href={{changelog-url-for activeCluster.leaderNode.version}} <a href={{changelog-url-for activeCluster.leaderNode.version}}

View File

@ -30,7 +30,7 @@
<div class="field box is-fullwidth is-sideless is-paddingless is-marginless"> <div class="field box is-fullwidth is-sideless is-paddingless is-marginless">
<InfoTableRow @label="Issue time" @value={{model.issueTime}}> <InfoTableRow @label="Issue time" @value={{model.issueTime}}>
{{date-format model.issueTime 'MMM DD, YYYY hh:mm:ss A'}} {{date-format model.issueTime 'MMM dd, yyyy hh:mm:ss a'}}
<br/> <br/>
<code> <code>
{{model.issueTime}} {{model.issueTime}}
@ -38,7 +38,7 @@
</InfoTableRow> </InfoTableRow>
<InfoTableRow @label="Renewable" @value={{model.renewable}} /> <InfoTableRow @label="Renewable" @value={{model.renewable}} />
<InfoTableRow @label="Last renewal" @value={{model.lastRenewal}}> <InfoTableRow @label="Last renewal" @value={{model.lastRenewal}}>
{{date-format model.lastRenewal 'MMM DD, YYYY hh:mm:ss A'}} {{date-format model.lastRenewal 'MMM dd, yyyy hh:mm:ss a'}}
<br/> <br/>
<code> <code>
{{model.lastRenewal}} {{model.lastRenewal}}
@ -46,7 +46,7 @@
</InfoTableRow> </InfoTableRow>
{{#if model.expireTime}} {{#if model.expireTime}}
<InfoTableRow @label="Expiration time" @value={{model.expireTime}}> <InfoTableRow @label="Expiration time" @value={{model.expireTime}}>
{{date-format model.expireTime 'MMM DD, YYYY hh:mm:ss A'}} {{date-format model.expireTime 'MMM dd, yyyy hh:mm:ss a'}}
<br/> <br/>
<code> <code>
{{model.expireTime}} {{model.expireTime}}

View File

@ -5,7 +5,7 @@ This helper returns a url to the changelog for the specified version.
It assumes that Changelog headers for Vault versions >= 1.4.3 are structured as: It assumes that Changelog headers for Vault versions >= 1.4.3 are structured as:
## 1.5.0 ## 1.5.0
### Month, DD, YYYY ### Month, DD, yyyy
## 1.4.5 ## 1.4.5
### Month, DD, YYY ### Month, DD, YYY

View File

@ -1,8 +1,10 @@
import { helper } from '@ember/component/helper'; import { helper } from '@ember/component/helper';
import formatDate from 'date-fns/format'; import { format, parseISO } from 'date-fns';
export function dateFormat([date, format]) { export function dateFormat([date, style]) {
return formatDate(date, format); // see format breaking in upgrade to date-fns 2.x https://github.com/date-fns/date-fns/blob/master/CHANGELOG.md#changed-5
let number = typeof date === 'string' ? parseISO(date) : date;
return format(number, style);
} }
export default helper(dateFormat); export default helper(dateFormat);

View File

@ -69,7 +69,7 @@
value=ttl}} value=ttl}}
{{info-table-row {{info-table-row
label="Expires" label="Expires"
value=(date-format expirationDate 'MMM DD, YYYY hh:mm:ss A')}} value=(date-format expirationDate 'MMM dd, yyyy hh:mm:ss a')}}
</div> </div>
</div> </div>
</section> </section>

View File

@ -64,7 +64,7 @@
"d3-time-format": "^2.1.1", "d3-time-format": "^2.1.1",
"d3-tip": "^0.9.1", "d3-tip": "^0.9.1",
"d3-transition": "^1.2.0", "d3-transition": "^1.2.0",
"date-fns": "^1.30.0", "date-fns": "^2.16.1",
"deepmerge": "^4.0.0", "deepmerge": "^4.0.0",
"doctoc": "^1.4.0", "doctoc": "^1.4.0",
"ember-api-actions": "^0.2.8", "ember-api-actions": "^0.2.8",

View File

@ -13,10 +13,10 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
await render(hbs` await render(hbs`
<PricingMetricsDates /> <PricingMetricsDates />
`); `);
assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/YYYY'), 'End input is last month'); assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/yyyy'), 'End input is last month');
assert assert
.dom('[data-test-start-input]') .dom('[data-test-start-input]')
.hasValue(format(expectedStart, 'MM/YYYY'), 'Start input is 12 months before last month'); .hasValue(format(expectedStart, 'MM/yyyy'), 'Start input is 12 months before last month');
}); });
test('On init if end date passed, start is calculated', async function(assert) { test('On init if end date passed, start is calculated', async function(assert) {
@ -28,7 +28,7 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
assert.dom('[data-test-end-input]').hasValue('09/2020', 'End input matches query'); assert.dom('[data-test-end-input]').hasValue('09/2020', 'End input matches query');
assert assert
.dom('[data-test-start-input]') .dom('[data-test-start-input]')
.hasValue(format(expectedStart, 'MM/YYYY'), 'Start input is 12 months before end input'); .hasValue(format(expectedStart, 'MM/yyyy'), 'Start input is 12 months before end input');
}); });
test('On init if query start date passed, end is default', async function(assert) { test('On init if query start date passed, end is default', async function(assert) {
@ -37,7 +37,7 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
await render(hbs` await render(hbs`
<PricingMetricsDates @queryStart={{queryStart}} /> <PricingMetricsDates @queryStart={{queryStart}} />
`); `);
assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/YYYY'), 'End input is last month'); assert.dom('[data-test-end-input]').hasValue(format(expectedEnd, 'MM/yyyy'), 'End input is last month');
assert.dom('[data-test-start-input]').hasValue('01/2020', 'Start input matches query'); assert.dom('[data-test-start-input]').hasValue('01/2020', 'Start input matches query');
}); });
@ -91,15 +91,15 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
`); `);
assert.dom('[data-test-form-error]').doesNotExist('No form error shows by default'); assert.dom('[data-test-form-error]').doesNotExist('No form error shows by default');
await fillIn('[data-test-start-input]', format(subMonths(firstAvailable, 1), 'MM/YYYY')); await fillIn('[data-test-start-input]', format(subMonths(firstAvailable, 1), 'MM/yyyy'));
assert assert
.dom('[data-test-form-error]') .dom('[data-test-form-error]')
.includesText( .includesText(
`No data retained before ${format(firstAvailable, 'MM/YYYY')}`, `No data retained before ${format(firstAvailable, 'MM/yyyy')}`,
'shows the correct error message for starting before the configured retainment period' 'shows the correct error message for starting before the configured retainment period'
); );
await fillIn('[data-test-end-input]', format(subMonths(lastAvailable, -1), 'MM/YYYY')); await fillIn('[data-test-end-input]', format(subMonths(lastAvailable, -1), 'MM/yyyy'));
assert assert
.dom('[data-test-form-error]') .dom('[data-test-form-error]')
.includesText( .includesText(
@ -111,15 +111,15 @@ module('Integration | Component | pricing-metrics-dates', function(hooks) {
assert assert
.dom('[data-test-form-error]') .dom('[data-test-form-error]')
.includesText( .includesText(
'End date is invalid. Please use format MM/YYYY', 'End date is invalid. Please use format MM/yyyy',
'shows the correct error message for non-date input' 'shows the correct error message for non-date input'
); );
await fillIn('[data-test-start-input]', `13/${format(lastAvailable, 'YYYY')}`); await fillIn('[data-test-start-input]', `13/${format(lastAvailable, 'yyyy')}`);
assert assert
.dom('[data-test-form-error]') .dom('[data-test-form-error]')
.includesText( .includesText(
'Start date is invalid. Please use format MM/YYYY', 'Start date is invalid. Please use format MM/yyyy',
'shows the correct error message for an invalid month' 'shows the correct error message for an invalid month'
); );
}); });

View File

@ -10,7 +10,7 @@ module('Integration | Helper | date-format', function(hooks) {
let today = new Date(); let today = new Date();
this.set('today', today); this.set('today', today);
await render(hbs`<p data-test-date-format>Date: {{date-format today "YYYY"}}</p>`); await render(hbs`<p data-test-date-format>Date: {{date-format today "yyyy"}}</p>`);
assert assert
.dom('[data-test-date-format]') .dom('[data-test-date-format]')
.includesText(today.getFullYear(), 'it renders the date in the year format'); .includesText(today.getFullYear(), 'it renders the date in the year format');
@ -29,7 +29,7 @@ module('Integration | Helper | date-format', function(hooks) {
let todayString = new Date().getFullYear().toString(); let todayString = new Date().getFullYear().toString();
this.set('todayString', todayString); this.set('todayString', todayString);
await render(hbs`<p data-test-date-format>Date: {{date-format todayString}}</p>`); await render(hbs`<p data-test-date-format>Date: {{date-format todayString "yyyy"}}</p>`);
assert assert
.dom('[data-test-date-format]') .dom('[data-test-date-format]')
.includesText(todayString, 'it renders the a date if passed in as a string'); .includesText(todayString, 'it renders the a date if passed in as a string');

View File

@ -1,6 +1,9 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { subMinutes } from 'date-fns';
import { setupRenderingTest } from 'ember-qunit'; import { setupRenderingTest } from 'ember-qunit';
import { dateFromNow } from '../../../helpers/date-from-now'; import { dateFromNow } from '../../../helpers/date-from-now';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Helper | date-from-now', function(hooks) { module('Integration | Helper | date-from-now', function(hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@ -14,4 +17,31 @@ module('Integration | Helper | date-from-now', function(hooks) {
let result = dateFromNow([1481022124443], { addSuffix: true }); let result = dateFromNow([1481022124443], { addSuffix: true });
assert.ok(result.includes(' ago')); assert.ok(result.includes(' ago'));
}); });
test('you can pass in UTC timestamp', function(assert) {
let result = dateFromNow(['Fri, 11 Oct 2019 18:56:08 GMT'], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can pass in ISO timestamp', function(assert) {
let result = dateFromNow(['2019-10-11T18:56:08.984Z'], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can include a suffix using date class', function(assert) {
let now = Date.now();
let pastDate = subMinutes(now, 30);
let result = dateFromNow([pastDate], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can include a suffix using ISO 8601 format', function(assert) {
let result = dateFromNow(['2021-02-05T20:43:09+00:00'], { addSuffix: true });
assert.ok(result.includes(' ago'));
});
test('you can include a suffix in the helper', async function(assert) {
await render(hbs`<p data-test-date-from-now>Date: {{date-from-now 1481022124443 addSuffix=true}}</p>`);
assert.dom('[data-test-date-from-now]').includesText(' years ago');
});
}); });

View File

@ -3,13 +3,13 @@ import { module, test } from 'qunit';
import { compareAsc } from 'date-fns'; import { compareAsc } from 'date-fns';
module('Unit | Helpers | parse-date-string', function() { module('Unit | Helpers | parse-date-string', function() {
test('it returns the first of the month when date like MM-YYYY passed in', function(assert) { test('it returns the first of the month when date like MM-yyyy passed in', function(assert) {
let expected = new Date(2020, 3, 1); let expected = new Date(2020, 3, 1);
let result = parseDateString('04-2020'); let result = parseDateString('04-2020');
assert.equal(compareAsc(expected, result), 0); assert.equal(compareAsc(expected, result), 0);
}); });
test('it can handle a date format like MM/YYYY', function(assert) { test('it can handle a date format like MM/yyyy', function(assert) {
let expected = new Date(2020, 11, 1); let expected = new Date(2020, 11, 1);
let result = parseDateString('12/2020', '/'); let result = parseDateString('12/2020', '/');
assert.equal(compareAsc(expected, result), 0); assert.equal(compareAsc(expected, result), 0);
@ -22,7 +22,7 @@ module('Unit | Helpers | parse-date-string', function() {
} catch (e) { } catch (e) {
result = e.message; result = e.message;
} }
assert.equal('Please use format MM-YYYY', result); assert.equal('Please use format MM-yyyy', result);
}); });
test('it throws an error with wrong separator', function(assert) { test('it throws an error with wrong separator', function(assert) {
@ -32,7 +32,7 @@ module('Unit | Helpers | parse-date-string', function() {
} catch (e) { } catch (e) {
result = e.message; result = e.message;
} }
assert.equal('Please use format MM.YYYY', result); assert.equal('Please use format MM.yyyy', result);
}); });
test('it throws an error if month is invalid', function(assert) { test('it throws an error if month is invalid', function(assert) {

View File

@ -7278,10 +7278,10 @@ data-urls@^1.0.1:
whatwg-mimetype "^2.2.0" whatwg-mimetype "^2.2.0"
whatwg-url "^7.0.0" whatwg-url "^7.0.0"
date-fns@^1.30.0: date-fns@^2.16.1:
version "1.30.1" version "2.16.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==
date-time@^2.1.0: date-time@^2.1.0:
version "2.1.0" version "2.1.0"