diff --git a/jest.config.js b/jest.config.js index 19abefc41..ff2de368c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -15,7 +15,6 @@ module.exports = { 'node_modules/(?!(@dpc-sdp*|ol|ol-ext|storybook-addon-vue-info|@storybook*)/)' ], moduleNameMapper: { - '~(.*)$': '/examples/vic-gov-au/$1', // Add nuxt root alias in jest '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|svg)$': '/__mocks__/fileMock.js', '\\.(css|scss)$': '/__mocks__/styleMock.js' diff --git a/package.json b/package.json index 951a2db37..c2bef2618 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,9 @@ "markdown-loader-jest": "^0.1.1", "sass-lint": "^1.12.1", "start-server-and-test": "^1.7.11", - "vue-jest": "^3.0.4" + "vue-jest": "^3.0.4", + "mockdate": "^2.0.3", + "vuex-mock-store": "^0.0.7" }, "cypress-cucumber-preprocessor": { "nonGlobalStepDefinitions": true diff --git a/packages/components/Molecules/List/index.vue b/packages/components/Molecules/List/index.vue index 723f53683..e3f765873 100644 --- a/packages/components/Molecules/List/index.vue +++ b/packages/components/Molecules/List/index.vue @@ -12,7 +12,7 @@
-
+
{{ item.text }} @@ -46,6 +46,9 @@ export default { iconSize (item) { const size = (item.size ? item.size : 1) * this.iconScale return size.toString() + }, + testId (item) { + return item.id ? item.id : null } } } diff --git a/packages/components/Organisms/Grants/GrantsOverview.vue b/packages/components/Organisms/Grants/GrantsOverview.vue index 49f6a9f45..f1189e190 100644 --- a/packages/components/Organisms/Grants/GrantsOverview.vue +++ b/packages/components/Organisms/Grants/GrantsOverview.vue @@ -12,6 +12,7 @@ import RplButton from '@dpc-sdp/ripple-button' import RplMarkup from '@dpc-sdp/ripple-markup' import RplList from '@dpc-sdp/ripple-list' import { formatMoney } from '@dpc-sdp/ripple-global/utils/helpers.js' +import formatdate from '@dpc-sdp/ripple-global/mixins/formatdate' export default { name: 'RplGrantsOverview', @@ -20,6 +21,7 @@ export default { RplMarkup, RplList }, + mixins: [formatdate], props: { title: { type: String, default: '' }, funding: { type: Object }, @@ -36,84 +38,113 @@ export default { open: 'Open', closed: 'Closed', ongoing: 'Ongoing', - openingsoon: 'Opening soon' + openingSoon: (startdate) => `Opening on ${startdate}`, + closingSoon: (end, now) => { + const daysRemaining = parseInt(end.diff(now, 'days')) + if (daysRemaining > 1) { + return `Open, closing in ${daysRemaining} days` + } else if (daysRemaining === 1) { + return `Open, closing in ${daysRemaining} day` + } + return `Open, closing today` + } } } } }, - computed: { - list () { - let list = [] - if (this.funding) { - const calcFunding = (funding) => { - if (funding.from > 0 && funding.to > 0) { - if (funding.from === funding.to) { - return formatMoney(funding.from) - } else { - return `${formatMoney(funding.from)} - ${formatMoney(funding.to)}` - } - } else if (funding.from === 0 && funding.to > 0) { - return `$0 - ${formatMoney(funding.to)}` - } else if (funding.from > 0 && funding.to === 0) { - return formatMoney(funding.from) - } else { - return null - } - } - const fundingLevel = calcFunding(this.funding) - - if (fundingLevel) { - list.push({ - symbol: 'dollar_negative', - size: '1.666', - text: fundingLevel - }) + methods: { + calcFunding (from, to) { + if (from > 0 && to > 0) { + if (from === to) { + return formatMoney(from) + } else { + return `${formatMoney(from)} - ${formatMoney(to)}` } + } else if (from === 0 && to > 0) { + return `$0 - ${formatMoney(to)}` + } else if (from > 0 && to === 0) { + return formatMoney(from) + } else { + return null } - if (this.audience) { - list.push({ - symbol: 'user', - size: '1.666', - text: this.audience - }) - } - - let status = this.statusTerms.ongoing - if (this.startdate || this.enddate) { + }, + calcStatus (startDate, endDate, terms = this.statusTerms) { + if (startDate || endDate) { const now = moment() - const start = this.startdate ? moment(this.startdate) : null - const end = this.enddate ? moment(this.enddate) : null + const start = startDate ? moment(startDate) : null + const end = endDate ? moment(endDate) : null + if (start) { if (now.isAfter(start)) { if (end) { if (now.isBefore(end)) { - status = this.statusTerms.open + // displays status as "Open, closing in x days" when current date is more start date and less than end date + return terms.closingSoon(end, now) } else { - status = this.statusTerms.closed + // displays status as "closed" when current date is after start date and after end date + return terms.closed } } else { - status = this.statusTerms.ongoing + // displays status as "Ongoing" if there is no end date and the current date is after the start date + return terms.ongoing } - } else { - status = this.statusTerms.openingsoon } + // displays status as "Opening on startdate" when current date is within one month of startdate + if (now.isBetween(moment(start).subtract(1, 'months'), start)) { + return terms.openingSoon(this.formatDate(startDate)) + } + // displays status as "Closed" when current date is more than one month of startdate + return terms.closed } else { if (end) { if (now.isBefore(end)) { - status = this.statusTerms.open + // displays status as "Open, closing in x days" when current date is more start date and less than end date + return terms.closingSoon(end, now) } else { - status = this.statusTerms.closed + return terms.closed } } else { - status = this.statusTerms.ongoing + // displays status as "Ongoing" if there is no start or end date + return terms.ongoing } } } + // displays status as "Ongoing" if there is no start or end date + return terms.ongoing + } + }, + computed: { + list () { + let list = [] + if (this.funding) { + const fundingLevel = this.calcFunding(this.funding.from, this.funding.to) + + if (fundingLevel) { + list.push({ + symbol: 'dollar_negative', + size: '1.666', + text: fundingLevel, + id: 'grants-funding' + }) + } + } + if (this.audience) { + list.push({ + symbol: 'user', + size: '1.666', + text: this.audience, + id: 'grants-audience' + }) + } + + const status = this.calcStatus(this.startdate, this.enddate, this.statusTerms) + list.push({ symbol: status === 'Closed' ? 'cross_circle' : 'success', color: status === 'Closed' ? 'danger' : 'success', size: '0.8333', - text: status + text: status, + id: 'grants-status' }) return list.length > 0 ? list : null diff --git a/packages/components/Organisms/Grants/__tests__/grantsoverview.test.js b/packages/components/Organisms/Grants/__tests__/grantsoverview.test.js new file mode 100644 index 000000000..bcd14e3d1 --- /dev/null +++ b/packages/components/Organisms/Grants/__tests__/grantsoverview.test.js @@ -0,0 +1,142 @@ +import { mount } from '@vue/test-utils' +import { RplGrantsOverview } from './../index' +const MockDate = require('mockdate') + +describe('RplGrantsOverview', () => { + const defaultProps = { + title: '', + funding: { + from: '', + to: '' + }, + audience: '', + startdate: '', + enddate: '', + description: '', + link: { + url: '', + text: '' + }, + listing: false + } + afterEach(() => { + MockDate.reset() + }) + + it('displays status as "closed" when current date is after start date and after end date', () => { + MockDate.set('2019-04-13T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-04-10T06:19:17+00:00', + enddate: '2019-04-12T06:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Closed') + }) + + it('displays status as "closed" when current date is after end date and there is no start date', () => { + MockDate.set('2019-04-13T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '', + enddate: '2019-04-12T06:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Closed') + }) + + it('displays status as "Opening on startdate" when current date is within one month of startdate', () => { + MockDate.set('2019-03-11T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-04-10T06:19:17+00:00', + enddate: '2019-05-10T06:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Opening on 10 April') + }) + + it('displays status as "Closed" when current date is more than one month of startdate', () => { + MockDate.set('2019-01-10T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-02-10T06:19:17+00:00', + enddate: '2019-05-10T06:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Closed') + }) + + it('displays status as "Open, closing in x days" when current date is more start date and less than end date', () => { + MockDate.set('2019-04-11T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-04-09T06:19:17+00:00', + enddate: '2019-05-10T06:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Open, closing in 29 days') + }) + + it('displays status as "Open, closing in 1 day" when current date is after start date and 1 day from end date', () => { + MockDate.set('2019-04-11T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-04-10T06:19:17+00:00', + enddate: '2019-04-12T06:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Open, closing in 1 day') + }) + + it('displays status as "Open, closes today" when current date is after start date and the same as end date', () => { + MockDate.set('2019-04-12T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-04-10T06:19:17+00:00', + enddate: '2019-04-12T07:19:17+00:00' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Open, closing today') + }) + + it('displays status as "Ongoing" if there is no end date and the current date is after the start date', () => { + MockDate.set('2019-04-12T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '2019-04-11T06:19:17+00:00', + enddate: '' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Ongoing') + }) + + it('displays status as "Ongoing" if there is no start or end date', () => { + MockDate.set('2019-04-12T06:19:17+00:00') + + const wrapper = mount(RplGrantsOverview, { + propsData: { + ...defaultProps, + startdate: '', + enddate: '' + } + }) + expect(wrapper.find('[data-tid="grants-status"]').text()).toEqual('Ongoing') + }) +}) diff --git a/packages/components/Organisms/Grants/stories.js b/packages/components/Organisms/Grants/stories.js index 9b779d896..d5590d168 100644 --- a/packages/components/Organisms/Grants/stories.js +++ b/packages/components/Organisms/Grants/stories.js @@ -10,7 +10,40 @@ import { storiesOf('Organisms/Grants', module) .addDecorator(withKnobs) - .add('Grants Overview', () => ({ + .add('Default', () => ({ + components: { RplGrantsOverview }, + template: ``, + props: { + title: { + default: text('Title', 'Program Overview') + }, + funding: { + default: () => object('Funding', { + from: 10000, + to: 30000 + }) + }, + audience: { + default: text('Audience', 'individuals, organisations, local council') + }, + startdate: { + default: text('Start Date', '2018-10-10T09:00:00.000+10:00') + }, + enddate: { + default: text('End Date', '2018-12-10T09:00:00.000+10:00') + }, + description: { + default: text('Description', '

This is a description of the grant. Omnis facilis omnis. Quia cumque eius mollitia iusto corporis suscipit aliquid qui et. Ut cumque molestiae qui aperiam totam. Vel consequatur ut at aut ipsum. Quia qui corporis totam ut. Veniam beatae praesentium recusandae.Dolorem praesentium quo molestiae beatae. Eaque natus animi omnis aliquam voluptatibus vel odit voluptatum. Sint et omnis est porro corrupti recusandae. Rem doloribus nam quia est iste. Temporibus velit qui odio et molestiae iure nam magnam. Sit et possimus neque quasi et. Quae necessitatibus debitis cumque libero natus quidem. Architecto nulla est doloremque. Ut excepturi voluptatem. Doloribus dolorem voluptates aut eos vitae ut tenetur enim suscipit.

A paragraph of text with a link.

') + }, + link: { + default: () => object('Call to action', { text: 'Apply Now', url: '#' }) + }, + listing: { + default: boolean('Listing', false) + } + } + })) + .add('Open - Countdown displayed', () => ({ components: { RplGrantsOverview }, template: ``, props: { diff --git a/src/test/__snapshots__/storyshots.test.js.snap b/src/test/__snapshots__/storyshots.test.js.snap index 976b245ca..cd40a20c3 100644 --- a/src/test/__snapshots__/storyshots.test.js.snap +++ b/src/test/__snapshots__/storyshots.test.js.snap @@ -9424,7 +9424,7 @@ exports[`RippleStoryshots Organisms/Event Latest Events 1`] = `
`; -exports[`RippleStoryshots Organisms/Grants Grants Overview 1`] = ` +exports[`RippleStoryshots Organisms/Grants Default 1`] = `
@@ -9446,6 +9446,7 @@ exports[`RippleStoryshots Organisms/Grants Grants Overview 1`] = ` >
+ + + + + + Closed + +
+
+ +
+ +
+
+

+ This is a description of the grant. Omnis facilis omnis. Quia cumque eius mollitia iusto corporis suscipit aliquid qui et. Ut cumque molestiae qui aperiam totam. Vel consequatur ut at aut ipsum. Quia qui corporis totam ut. Veniam beatae praesentium recusandae.Dolorem praesentium quo molestiae beatae. Eaque natus animi omnis aliquam voluptatibus vel odit voluptatum. Sint et omnis est porro corrupti recusandae. Rem doloribus nam quia est iste. Temporibus velit qui odio et molestiae iure nam magnam. Sit et possimus neque quasi et. Quae necessitatibus debitis cumque libero natus quidem. Architecto nulla est doloremque. Ut excepturi voluptatem. Doloribus dolorem voluptates aut eos vitae ut tenetur enim suscipit. +

+ + +

+ A paragraph of + + text + + with a + + link + + . +

+
+
+ + + + Apply Now + + +
+`; + +exports[`RippleStoryshots Organisms/Grants Open - Countdown displayed 1`] = ` +
+
+

+ + Program Overview + +

+ +
+
+ + + + + + $10,000 - $30,000 + +
+
+ + + + + + individuals, organisations, local council + +
+