-
-
-
diff --git a/examples/vic-gov-au/tide/modules/event/formdata.js b/examples/vic-gov-au/tide/modules/event/formdata.js
new file mode 100644
index 000000000..cbb595012
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/formdata.js
@@ -0,0 +1,115 @@
+export default {
+ getFormData: async setFilterOptions => {
+ const eventCategoryValues = await setFilterOptions({
+ fieldName: 'field_event_category_name'
+ })
+ const eventNameValues = await setFilterOptions({
+ fieldName: 'field_event_details_event_requirements_name'
+ })
+ return {
+ title: "What's on in Victoria",
+ searchPlaceholder: 'Search by keyword or location',
+ theme: 'light',
+ allowBlank: true,
+ filterForm: {
+ tideId: 'tide_search_form',
+ tag: 'rpl-fieldset',
+ model: {
+ // Multi-value fields should always be an array.
+ field_event_category_name: [],
+ field_event_date_end_value: '',
+ location: '',
+ field_event_details_event_requirements_name: []
+ },
+ schema: {
+ groups: [
+ {
+ fields: [
+ {
+ type: 'rplchecklist',
+ styleClasses: ['form-group--col-two'],
+ label: 'Select an event category',
+ model: 'field_event_category_name',
+ values: eventCategoryValues,
+ placeholder: 'Select a topic',
+ // TODO: Update 'filter' key to 'query' to make purpose clearer.
+ filter: {
+ type: 'term',
+ operator: ''
+ }
+ },
+ {
+ type: 'input',
+ inputType: 'text',
+ maxlength: 50,
+ styleClasses: ['form-group--col-two'],
+ label: 'Location',
+ model: 'location',
+ placeholder: 'Start typing suburb or postcode...',
+ filter: {
+ type: 'multiMatch',
+ operator: '',
+ fields: [
+ 'field_event_details_event_locality',
+ 'field_event_details_event_postal_code'
+ ]
+ }
+ }
+ ]
+ },
+ {
+ fields: [
+ {
+ type: 'rpldatepicker',
+ ranged: false,
+ styleClasses: ['form-group--col-two'],
+ label: 'Select an event date',
+ model: 'field_event_date_end_value',
+ placeholder: 'DD/MM/YYYY',
+ filter: {
+ type: 'date',
+ operator: 'lte'
+ }
+ },
+ {
+ type: 'rplchecklist',
+ label: 'Event requirements',
+ styleClasses: ['form-group--col-two'],
+ model: 'field_event_details_event_requirements_name',
+ // TODO: There are no values for this field how can we programmactically hide a field in this instance.
+ values: eventNameValues,
+ placeholder: 'Please select',
+ filter: {
+ type: 'term',
+ operator: ''
+ }
+ }
+ ]
+ },
+ {
+ fields: [
+ {
+ type: 'rplsubmitloader',
+ buttonText: 'Apply change',
+ loading: false,
+ autoUpdate: true,
+ styleClasses: ['form-group--inline']
+ },
+ {
+ type: 'rplclearform',
+ buttonText: 'Clear search filters',
+ styleClasses: ['form-group--inline']
+ }
+ ]
+ }
+ ]
+ },
+ formOptions: {
+ validateAfterLoad: false,
+ validateAfterChanged: false
+ },
+ formState: {}
+ }
+ }
+ }
+}
diff --git a/examples/vic-gov-au/tide/modules/event/helpers.js b/examples/vic-gov-au/tide/modules/event/helpers.js
new file mode 100644
index 000000000..4058ab1c8
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/helpers.js
@@ -0,0 +1,18 @@
+import { latestEvents } from './mapping-fetchers'
+
+export const getCardCarouselEvents = async (mapping) => {
+ // A little hack here to change latst event query limit to 9 for card carousel.
+ latestEvents.args[3] = {
+ offset: 0,
+ limit: 9
+ }
+ return mapping.filter(mapping.fetch(latestEvents), ['eventLatestEvents']).then(cards => {
+ // Reassemble the data with a component name data structure so we can render them by vue dynamic components.
+ return cards.map(card => {
+ return {
+ name: 'rpl-card-event',
+ data: card
+ }
+ })
+ })
+}
diff --git a/examples/vic-gov-au/tide/modules/event/mapping-fetchers.js b/examples/vic-gov-au/tide/modules/event/mapping-fetchers.js
new file mode 100644
index 000000000..56429d0d3
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/mapping-fetchers.js
@@ -0,0 +1,41 @@
+// This file provides fetcher objects for our mapping to fetch data from Tide API.
+// const moment = require('moment-timezone')
+
+module.exports = {
+ latestEvents: {
+ method: 'getContentList',
+ args: [
+ 'event',
+ {
+ // TODO: https://digital-engagement.atlassian.net/browse/SDPA-1938
+ // 'date-filter': {
+ // condition: {
+ // path: 'field_event_details.0.field_paragraph_date_range.end_value',
+ // operator: '>',
+ // value: moment().tz('Australia/Melbourne').format()
+ // }
+ // }
+ },
+ [
+ 'field_event_details',
+ 'field_featured_image',
+ 'field_featured_image.field_media_image'
+ ],
+ {
+ offset: 0,
+ limit: 6
+ },
+ {
+ 'sort-end': {
+ path: 'field_event_details.0.field_paragraph_date_range.end_value'
+ },
+ 'sort-start': {
+ path: 'field_event_details.0.field_paragraph_date_range.value'
+ }
+ },
+ {
+ allPages: false
+ }
+ ]
+ }
+}
diff --git a/examples/vic-gov-au/tide/modules/event/mapping-filters.js b/examples/vic-gov-au/tide/modules/event/mapping-filters.js
new file mode 100644
index 000000000..6b5f6fd8f
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/mapping-filters.js
@@ -0,0 +1,48 @@
+// Filters for adding extra process on a mapping value
+
+// Create more filters if need.
+module.exports = {
+ eventLatestEvents: async (list, { mapping }) => {
+ try {
+ const latestEvents = await list
+ return latestEvents.map(item => {
+ const location = mapping.parseField(['field_event_details', 0, 'field_paragraph_location'], item)
+ return {
+ image: mapping.parseField(['field_featured_image', 'field_media_image', 'url'], item),
+ dateStart: mapping.parseField(['field_event_details', 0, 'field_paragraph_date_range', 'value'], item),
+ dateEnd: mapping.parseField(['field_event_details', 0, 'field_paragraph_date_range', 'end_value'], item),
+ location: mapping.filter(location, ['paragraphLocation']),
+ title: item.title,
+ summary: item.field_landing_page_summary,
+ link: { text: 'See event details', url: item.path.url }
+ }
+ })
+ } catch (err) {
+ // TODO: log error to log system when ops got it.
+ // console.log(err)
+ return []
+ }
+ },
+
+ eventCtaCard: (fieldParagraphCtaCardEvent, { mapping }) => {
+ if (!fieldParagraphCtaCardEvent.field_paragraph_cta) {
+ return null
+ }
+
+ let image = ''
+ if (fieldParagraphCtaCardEvent.field_paragraph_media) {
+ const media = fieldParagraphCtaCardEvent.field_paragraph_media
+ if (media.field_media_image) {
+ image = media.field_media_image.url || media.field_media_image.uri
+ }
+ }
+
+ const link = mapping.parseField('field_paragraph_cta', fieldParagraphCtaCardEvent)
+ return {
+ image: image,
+ title: fieldParagraphCtaCardEvent.field_paragraph_title,
+ summary: mapping.parseField(['field_paragraph_body', 'processed'], fieldParagraphCtaCardEvent),
+ link: mapping.filter(link, ['paragraphCta'])
+ }
+ }
+}
diff --git a/examples/vic-gov-au/tide/modules/event/module.js b/examples/vic-gov-au/tide/modules/event/module.js
new file mode 100644
index 000000000..b18bb19eb
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/module.js
@@ -0,0 +1,9 @@
+module.exports = function () {
+ this.extendRoutes((routes, resolve) => {
+ routes.push({
+ name: 'tidewhatson',
+ path: '/whatson',
+ component: '~/tide/modules/event/pages/search.vue'
+ })
+ })
+}
diff --git a/examples/vic-gov-au/tide/modules/event/pages/index.vue b/examples/vic-gov-au/tide/modules/event/pages/index.vue
new file mode 100644
index 000000000..acc3a319c
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/pages/index.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{cta.text}}
+
+
+
+
+
+
diff --git a/examples/vic-gov-au/tide/modules/event/pages/search.vue b/examples/vic-gov-au/tide/modules/event/pages/search.vue
new file mode 100644
index 000000000..4f8954aed
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/pages/search.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/vic-gov-au/tide/modules/event/tide.config.js b/examples/vic-gov-au/tide/modules/event/tide.config.js
new file mode 100644
index 000000000..591f6d008
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/tide.config.js
@@ -0,0 +1,88 @@
+const fetchers = require('./mapping-fetchers')
+
+// Grid columns setting for cards.
+// TODO: make this is a core setting so we don't have a duplicated setting here.
+const cardColsSetting = {
+ wide: {
+ m: 6,
+ l: 4,
+ xxxl: 3
+ },
+ narrow: {
+ m: 6,
+ xxxl: 4
+ }
+}
+
+module.exports = {
+ include: {
+ event: [
+ 'field_landing_page_contact',
+ 'field_landing_page_contact.field_paragraph_phones',
+ 'field_landing_page_contact.field_paragraph_social_media',
+ 'field_event_category',
+ 'field_event_details',
+ 'field_event_details.field_event_requirements',
+ 'field_audience'
+ ],
+
+ landingPage: [
+ 'field_landing_page_component.field_paragraph_reference.field_event_details',
+ 'field_landing_page_component.field_paragraph_cta_card_event',
+ 'field_landing_page_component.field_paragraph_cta_card_event.field_paragraph_media',
+ 'field_landing_page_component.field_paragraph_cta_card_event.field_paragraph_media.field_media_image'
+ ],
+ publicationPage: [
+ 'field_landing_page_component.field_paragraph_reference.field_event_details',
+ 'field_landing_page_component.field_paragraph_cta_card_event',
+ 'field_landing_page_component.field_paragraph_cta_card_event.field_paragraph_media',
+ 'field_landing_page_component.field_paragraph_cta_card_event.field_paragraph_media.field_media_image'
+ ]
+ },
+
+ mapping: {
+ landingPageComponents: {
+ 'paragraph--card_event_auto': {
+ component: 'rpl-card-event',
+ props: {
+ 'image': [
+ ['field_paragraph_reference', 'field_featured_image', 'field_media_image', 'url'],
+ ['field_paragraph_reference', 'field_media_image', 'url']
+ ],
+ 'dateStart': ['field_paragraph_reference', 'field_event_details', 0, 'field_paragraph_date_range', 'value'],
+ 'dateEnd': ['field_paragraph_reference', 'field_event_details', 0, 'field_paragraph_date_range', 'end_value'],
+ 'location': ['field_paragraph_reference', 'field_event_details', 0, 'field_paragraph_location', 'locality'],
+ 'title': ['field_paragraph_reference', 'title'],
+ 'summary': [
+ ['field_paragraph_reference', 'field_landing_page_summary']
+ ],
+ 'link': {
+ filters: ['autoCardLink']
+ }
+ },
+ cols: cardColsSetting
+ },
+
+ 'paragraph--latest_events': {
+ component: 'rpl-latest-events',
+ props: {
+ 'title': 'field_paragraph_title',
+ 'events': {
+ fetcher: fetchers.latestEvents,
+ filters: ['eventLatestEvents']
+ },
+ 'cta': {
+ field: 'field_paragraph_cta_card_event',
+ filters: ['eventCtaCard']
+ },
+ 'link': {
+ value: {
+ text: 'See all events',
+ url: '/whatson'
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/vic-gov-au/tide/modules/event/tide.load-components.js b/examples/vic-gov-au/tide/modules/event/tide.load-components.js
new file mode 100644
index 000000000..de5cdcb31
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/tide.load-components.js
@@ -0,0 +1,14 @@
+// This custom component load config is for user want to add a custom component in the dynamic component mapping.
+//
+// An example:
+// You added a custom component named `YourCustomComponent.vue` in nuxt 'components/' dir.
+// And you added the custom map config in `tide.config.js` because it will be dynamically mapped and added into landing page.
+// Then you need to add load config like below.
+//
+// export default {
+// 'your-custom-component': () => import(/* webackChunkName: 'your-custom-component' */ '~/components/YourCustomComponent')
+// }
+
+export default {
+ 'rpl-card-event': () => import(/* webpackChunkName: 'rpl-card-event' */ '@dpc-sdp/ripple-card').then(m => m.RplCardEvent)
+}
diff --git a/examples/vic-gov-au/tide/modules/event/tide.page-types.js b/examples/vic-gov-au/tide/modules/event/tide.page-types.js
new file mode 100644
index 000000000..2a82be906
--- /dev/null
+++ b/examples/vic-gov-au/tide/modules/event/tide.page-types.js
@@ -0,0 +1,5 @@
+export default {
+ pageTemplates: {
+ 'node--event': () => import('~/tide/modules/event/pages/index.vue')
+ }
+}
diff --git a/examples/vic-gov-au/tide/tide.config.js b/examples/vic-gov-au/tide/tide.config.js
index 358dea91f..ae665b8d9 100644
--- a/examples/vic-gov-au/tide/tide.config.js
+++ b/examples/vic-gov-au/tide/tide.config.js
@@ -1,6 +1,12 @@
// You can add site specific custom config for tide.
const tideConfig = {
+ // middleware: true,
+ // mappingFilters: true,
+ // pageTypes: true,
+ // loadComponents: true,
+ // markupPlugins: true,
+
// Include config is used for Tide API query relationship.
include: {
// Add custom content type config here.
@@ -11,7 +17,11 @@ const tideConfig = {
mapping: {
// landingPageComponents: {}
- }
+ },
+
+ modules: [
+ 'event'
+ ]
}
module.exports = tideConfig
diff --git a/examples/vic-gov-au/tide/tide.load-components.js b/examples/vic-gov-au/tide/tide.load-components.js
index 3447f5806..f852cdde7 100644
--- a/examples/vic-gov-au/tide/tide.load-components.js
+++ b/examples/vic-gov-au/tide/tide.load-components.js
@@ -8,3 +8,7 @@
// export default {
// 'your-custom-component': () => import(/* webackChunkName: 'your-custom-component' */ '~/components/YourCustomComponent')
// }
+
+export default {
+ 'example-message': () => import(/* webackChunkName: 'example-message' */ '~/components/examples/Message')
+}
diff --git a/examples/vic-gov-au/tide/tide.middleware.js b/examples/vic-gov-au/tide/tide.middleware.js
new file mode 100644
index 000000000..841874304
--- /dev/null
+++ b/examples/vic-gov-au/tide/tide.middleware.js
@@ -0,0 +1,31 @@
+// This custom middleware allows you to override the data passed to the Tide page
+// This should always return a object of functions which take the current context as a param
+// The results param can be modified for variables used on the page.
+// See nuxt-tide/lib/pages/Tide.vue asyncData for execution order
+// export default {
+// nameOfMiddlewareA: (context, results) => {
+// results.test = 'foo'
+// },
+// nameOfMiddlewareB: (context, results) => {
+// results.test = 'bar'
+// },
+// }
+
+export default {
+ // Example for adding a custom component into the landing page without backend changes.
+ exampleAddComponent: (context, pageData) => {
+ if (!pageData.tidePage) {
+ return
+ }
+
+ if (context.route.path === '/demo-landing-page') {
+ const message = {
+ name: 'example-message', // You need load this custom component in your project root "/tide/tide.load-components.js"
+ data: {
+ text: 'This is an example component added by custom middleware.'
+ }
+ }
+ pageData.tidePage.appDComponents.push(message)
+ }
+ }
+}
diff --git a/examples/vic-gov-au/tide/tide.page-types.js b/examples/vic-gov-au/tide/tide.page-types.js
new file mode 100644
index 000000000..a208b6da5
--- /dev/null
+++ b/examples/vic-gov-au/tide/tide.page-types.js
@@ -0,0 +1,6 @@
+export default {
+ // Load your custom page type template here.
+ pageTemplates: {
+ // 'node--my--page-type': () => import('~/pages/MyPageType.vue')
+ }
+}
diff --git a/jest.config.js b/jest.config.js
index ff2de368c..19abefc41 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -15,6 +15,7 @@ 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/packages/components/Organisms/ImageGallery/no-ssr/ImageGallery.vue b/packages/components/Organisms/ImageGallery/no-ssr/ImageGallery.vue
index 9109b49b1..dbad29250 100644
--- a/packages/components/Organisms/ImageGallery/no-ssr/ImageGallery.vue
+++ b/packages/components/Organisms/ImageGallery/no-ssr/ImageGallery.vue
@@ -62,6 +62,7 @@
diff --git a/packages/ripple-nuxt-tide/modules/landing-page/tide.page-types.js b/packages/ripple-nuxt-tide/modules/landing-page/tide.page-types.js
new file mode 100644
index 000000000..9c9f9c4a4
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/landing-page/tide.page-types.js
@@ -0,0 +1,5 @@
+export default {
+ pageTemplates: {
+ 'node--landing_page': () => import('./pages/index.vue')
+ }
+}
diff --git a/packages/ripple-nuxt-tide/modules/media/tide.page-types.js b/packages/ripple-nuxt-tide/modules/media/tide.page-types.js
new file mode 100644
index 000000000..85b8e72f6
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/media/tide.page-types.js
@@ -0,0 +1,5 @@
+export default {
+ pageTemplates: {
+ 'media--embedded_video': () => import('./components/EmbeddedVideo.vue')
+ }
+}
diff --git a/packages/ripple-nuxt-tide/modules/news/tide.page-types.js b/packages/ripple-nuxt-tide/modules/news/tide.page-types.js
new file mode 100644
index 000000000..00fbfc377
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/news/tide.page-types.js
@@ -0,0 +1,5 @@
+export default {
+ pageTemplates: {
+ 'node--news': () => import('./pages/index.vue')
+ }
+}
diff --git a/packages/ripple-nuxt-tide/modules/page/tide.page-types.js b/packages/ripple-nuxt-tide/modules/page/tide.page-types.js
new file mode 100644
index 000000000..e32244ebd
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/page/tide.page-types.js
@@ -0,0 +1,5 @@
+export default {
+ pageTemplates: {
+ 'node--page': () => import('./pages/index.vue')
+ }
+}
diff --git a/packages/ripple-nuxt-tide/modules/profile/tide.page-types.js b/packages/ripple-nuxt-tide/modules/profile/tide.page-types.js
new file mode 100644
index 000000000..098ad1fdb
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/profile/tide.page-types.js
@@ -0,0 +1,5 @@
+export default {
+ pageTemplates: {
+ 'node--profile': () => import('./pages/index.vue')
+ }
+}
diff --git a/packages/ripple-nuxt-tide/modules/publication/pages/index.vue b/packages/ripple-nuxt-tide/modules/publication/pages/index.vue
index 2bdd999fb..ec41705b8 100644
--- a/packages/ripple-nuxt-tide/modules/publication/pages/index.vue
+++ b/packages/ripple-nuxt-tide/modules/publication/pages/index.vue
@@ -32,7 +32,6 @@ import RplAnchorLinks from '@dpc-sdp/ripple-anchor-links'
import RplMarkup from '@dpc-sdp/ripple-markup'
import { RplPublicationPagination, RplPublicationAuthorInformation } from '@dpc-sdp/ripple-publication'
import { RplRow, RplCol } from '@dpc-sdp/ripple-grid'
-import { dComponentsLoader } from '@dpc-sdp/ripple-nuxt-tide/lib/core/componentLoader'
import { truncateText } from '@dpc-sdp/ripple-nuxt-tide/lib/core/tide-helper'
import { RplCardNavigation } from '@dpc-sdp/ripple-card'
@@ -52,7 +51,7 @@ export default {
sidebar: Boolean
},
created () {
- this.dynamicComponents = dComponentsLoader(this.page.appDComponents, this.sidebar)
+ this.dynamicComponents = this.$tide.getDynamicComponents(this.page.appDComponents, this.sidebar)
},
computed: {
publishingInfo () {
diff --git a/packages/ripple-nuxt-tide/modules/publication/tide.page-types.js b/packages/ripple-nuxt-tide/modules/publication/tide.page-types.js
new file mode 100644
index 000000000..e3dc925fe
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/publication/tide.page-types.js
@@ -0,0 +1,6 @@
+export default {
+ pageTemplates: {
+ 'node--publication': () => import('./pages/index.vue'),
+ 'node--publication_page': () => import('./pages/index.vue')
+ }
+}
diff --git a/packages/ripple-nuxt-tide/modules/search/tide.load-components.js b/packages/ripple-nuxt-tide/modules/search/tide.load-components.js
new file mode 100644
index 000000000..1fbe20073
--- /dev/null
+++ b/packages/ripple-nuxt-tide/modules/search/tide.load-components.js
@@ -0,0 +1,14 @@
+// This custom component load config is for user want to add a custom component in the dynamic component mapping.
+//
+// An example:
+// You added a custom component named `YourCustomComponent.vue` in nuxt 'components/' dir.
+// And you added the custom map config in `tide.config.js` because it will be dynamically mapped and added into landing page.
+// Then you need to add load config like below.
+//
+// export default {
+// 'your-custom-component': () => import(/* webackChunkName: 'your-custom-component' */ '~/components/YourCustomComponent')
+// }
+
+export default {
+ 'rpl-search-form': () => import(/* webpackChunkName: 'rpl-search-form' */ '@dpc-sdp/ripple-search').then(m => m.RplSearchForm)
+}
diff --git a/packages/ripple-nuxt-tide/test/unit/markup-transpiler.test.js b/packages/ripple-nuxt-tide/test/unit/markup-transpiler.test.js
index 3aa8fafa6..4666e8954 100644
--- a/packages/ripple-nuxt-tide/test/unit/markup-transpiler.test.js
+++ b/packages/ripple-nuxt-tide/test/unit/markup-transpiler.test.js
@@ -1,5 +1,5 @@
import markupTranspiler from '@dpc-sdp/ripple-markup/markup-transpiler.js'
-import markupPlugins from '../../lib/core/markup-plugins-loader.js'
+import markupPluginsLoader from '../../lib/core/markup-plugins-loader.js'
describe('Markup transpiler', () => {
test('should able transpile html into vue template', () => {
@@ -220,8 +220,9 @@ describe('Markup transpiler', () => {
`
-
- const result = markupTranspiler(html, markupPlugins)
+ // TODO: update this tests to include core module markup plugins when we add them.
+ const plugins = markupPluginsLoader()
+ const result = markupTranspiler(html, plugins)
expect(result).toMatchSnapshot()
})
})
diff --git a/test/e2e/integration/LandingPage/DemoLandingPage.feature b/test/e2e/integration/LandingPage/DemoLandingPage.feature
index 558abcd92..a3a59450f 100644
--- a/test/e2e/integration/LandingPage/DemoLandingPage.feature
+++ b/test/e2e/integration/LandingPage/DemoLandingPage.feature
@@ -23,7 +23,6 @@ Feature: Demo Page
And the featured news list component should exist
And the featured card navigation component should exist
And the card event component should exist
- And the card event component should exist
And the card CTA component should exist
And the card keydates component should exist
And the card promotion component should exist