From 40982ec4cab8bcbd6dd04c112cee6a30f8ef33c1 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Fri, 21 Jun 2024 08:33:39 +1000 Subject: [PATCH] Added Molecules tests. --- .../button/__snapshots__/button.test.js.snap | 22 +- components/01-atoms/button/button.test.js | 2 +- .../__snapshots__/accordion.test.js.snap | 676 +++++++++++++ .../02-molecules/accordion/accordion.test.js | 82 ++ .../__snapshots__/attachment.test.js.snap | 661 +++++++++++++ .../attachment/attachment.test.js | 69 ++ .../__snapshots__/back-to-top.test.js.snap | 190 ++++ .../back-to-top/back-to-top.test.js | 31 + .../__snapshots__/basic-content.test.js.snap | 117 +++ .../basic-content/basic-content.test.js | 57 ++ .../__snapshots__/breadcrumb.test.js.snap | 754 ++++++++++++++ .../breadcrumb/breadcrumb.test.js | 75 ++ .../__snapshots__/callout.test.js.snap | 421 ++++++++ .../02-molecules/callout/callout.test.js | 71 ++ .../__snapshots__/event-card.test.js.snap | 466 +++++++++ .../event-card/event-card.test.js | 71 ++ .../02-molecules/event-card/event-card.twig | 5 +- .../figure/__snapshots__/figure.test.js.snap | 111 +++ components/02-molecules/figure/figure.test.js | 58 ++ .../logo/__snapshots__/logo.test.js.snap | 196 ++++ components/02-molecules/logo/logo.test.js | 109 +++ .../map/__snapshots__/map.test.js.snap | 319 ++++++ components/02-molecules/map/map.test.js | 76 ++ .../navigation-card.test.js.snap | 568 +++++++++++ .../navigation-card/navigation-card.test.js | 144 +++ .../__snapshots__/next-step.test.js.snap | 369 +++++++ .../02-molecules/next-step/next-step.test.js | 72 ++ .../02-molecules/next-step/next-step.twig | 2 +- .../__snapshots__/pagination.test.js.snap | 923 ++++++++++++++++++ .../pagination/pagination.test.js | 119 +++ .../__snapshots__/promo-card.test.js.snap | 528 ++++++++++ .../promo-card/promo-card.test.js | 95 ++ .../publication-card.test.js.snap | 422 ++++++++ .../publication-card/publication-card.test.js | 111 +++ .../publication-card/publication-card.twig | 2 +- .../search/__snapshots__/search.test.js.snap | 182 ++++ components/02-molecules/search/search.test.js | 56 ++ .../__snapshots__/service-card.test.js.snap | 388 ++++++++ .../service-card/service-card.test.js | 89 ++ .../__snapshots__/single-filter.test.js.snap | 683 +++++++++++++ .../single-filter/single-filter.test.js | 100 ++ .../__snapshots__/snippet.test.js.snap | 460 +++++++++ .../02-molecules/snippet/snippet.test.js | 106 ++ .../__snapshots__/social-links.test.js.snap | 386 ++++++++ .../social-links/social-links.test.js | 90 ++ .../__snapshots__/subject-card.test.js.snap | 264 +++++ .../subject-card/subject-card.test.js | 100 ++ .../tabs/__snapshots__/tabs.test.js.snap | 401 ++++++++ components/02-molecules/tabs/tabs.test.js | 73 ++ .../__snapshots__/tag-list.test.js.snap | 312 ++++++ .../02-molecules/tag-list/tag-list.test.js | 62 ++ .../__snapshots__/tooltip.test.js.snap | 384 ++++++++ .../02-molecules/tooltip/tooltip.test.js | 57 ++ .../__snapshots__/video-player.test.js.snap | 280 ++++++ .../video-player/video-player.test.js | 81 ++ 55 files changed, 12542 insertions(+), 6 deletions(-) create mode 100644 components/02-molecules/accordion/__snapshots__/accordion.test.js.snap create mode 100644 components/02-molecules/accordion/accordion.test.js create mode 100644 components/02-molecules/attachment/__snapshots__/attachment.test.js.snap create mode 100644 components/02-molecules/attachment/attachment.test.js create mode 100644 components/02-molecules/back-to-top/__snapshots__/back-to-top.test.js.snap create mode 100644 components/02-molecules/back-to-top/back-to-top.test.js create mode 100644 components/02-molecules/basic-content/__snapshots__/basic-content.test.js.snap create mode 100644 components/02-molecules/basic-content/basic-content.test.js create mode 100644 components/02-molecules/breadcrumb/__snapshots__/breadcrumb.test.js.snap create mode 100644 components/02-molecules/breadcrumb/breadcrumb.test.js create mode 100644 components/02-molecules/callout/__snapshots__/callout.test.js.snap create mode 100644 components/02-molecules/callout/callout.test.js create mode 100644 components/02-molecules/event-card/__snapshots__/event-card.test.js.snap create mode 100644 components/02-molecules/event-card/event-card.test.js create mode 100644 components/02-molecules/figure/__snapshots__/figure.test.js.snap create mode 100644 components/02-molecules/figure/figure.test.js create mode 100644 components/02-molecules/logo/__snapshots__/logo.test.js.snap create mode 100644 components/02-molecules/logo/logo.test.js create mode 100644 components/02-molecules/map/__snapshots__/map.test.js.snap create mode 100644 components/02-molecules/map/map.test.js create mode 100644 components/02-molecules/navigation-card/__snapshots__/navigation-card.test.js.snap create mode 100644 components/02-molecules/navigation-card/navigation-card.test.js create mode 100644 components/02-molecules/next-step/__snapshots__/next-step.test.js.snap create mode 100644 components/02-molecules/next-step/next-step.test.js create mode 100644 components/02-molecules/pagination/__snapshots__/pagination.test.js.snap create mode 100644 components/02-molecules/pagination/pagination.test.js create mode 100644 components/02-molecules/promo-card/__snapshots__/promo-card.test.js.snap create mode 100644 components/02-molecules/promo-card/promo-card.test.js create mode 100644 components/02-molecules/publication-card/__snapshots__/publication-card.test.js.snap create mode 100644 components/02-molecules/publication-card/publication-card.test.js create mode 100644 components/02-molecules/search/__snapshots__/search.test.js.snap create mode 100644 components/02-molecules/search/search.test.js create mode 100644 components/02-molecules/service-card/__snapshots__/service-card.test.js.snap create mode 100644 components/02-molecules/service-card/service-card.test.js create mode 100644 components/02-molecules/single-filter/__snapshots__/single-filter.test.js.snap create mode 100644 components/02-molecules/single-filter/single-filter.test.js create mode 100644 components/02-molecules/snippet/__snapshots__/snippet.test.js.snap create mode 100644 components/02-molecules/snippet/snippet.test.js create mode 100644 components/02-molecules/social-links/__snapshots__/social-links.test.js.snap create mode 100644 components/02-molecules/social-links/social-links.test.js create mode 100644 components/02-molecules/subject-card/__snapshots__/subject-card.test.js.snap create mode 100644 components/02-molecules/subject-card/subject-card.test.js create mode 100644 components/02-molecules/tabs/__snapshots__/tabs.test.js.snap create mode 100644 components/02-molecules/tabs/tabs.test.js create mode 100644 components/02-molecules/tag-list/__snapshots__/tag-list.test.js.snap create mode 100644 components/02-molecules/tag-list/tag-list.test.js create mode 100644 components/02-molecules/tooltip/__snapshots__/tooltip.test.js.snap create mode 100644 components/02-molecules/tooltip/tooltip.test.js create mode 100644 components/02-molecules/video-player/__snapshots__/video-player.test.js.snap create mode 100644 components/02-molecules/video-player/video-player.test.js diff --git a/components/01-atoms/button/__snapshots__/button.test.js.snap b/components/01-atoms/button/__snapshots__/button.test.js.snap index a3609c17..23fdd2a9 100644 --- a/components/01-atoms/button/__snapshots__/button.test.js.snap +++ b/components/01-atoms/button/__snapshots__/button.test.js.snap @@ -83,7 +83,27 @@ exports[`Button Component renders as a link with optional attributes, is externa - Click me + + + + + Click me { attributes: 'data-test="true"', modifier_class: 'custom-class', theme: 'dark', - icon: 'sample-icon', + icon: 'call', icon_placement: 'before', }); diff --git a/components/02-molecules/accordion/__snapshots__/accordion.test.js.snap b/components/02-molecules/accordion/__snapshots__/accordion.test.js.snap new file mode 100644 index 00000000..4b2a7214 --- /dev/null +++ b/components/02-molecules/accordion/__snapshots__/accordion.test.js.snap @@ -0,0 +1,676 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Accordion Component does not render when panels are empty 1`] = ` +
+ + + + +
+`; + +exports[`Accordion Component expands all panels when expand_all is true 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + + +
+ + +
    + + +
  • + + +
    + + + + + +
    + + + +
    + + + + +
    + + Content 1 + +
    + +
    + + +
  • + + +
  • + + +
    + + + + + +
    + + + +
    + + + + +
    + + Content 2 + +
    + +
    + + +
  • + + +
+ + +
+ + + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Accordion Component renders individual panels with expanded state 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + + +
+ + +
    + + +
  • + + +
    + + + + + +
    + + + +
    + + + + +
    + + Content 1 + +
    + +
    + + +
  • + + +
  • + + +
    + + + + + +
    + + + + + + +
  • + + +
+ + +
+ + + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Accordion Component renders with optional attributes 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + +
+ + Top content + +
+ + + +
+ + +
    + + +
  • + + +
    + + + + + +
    + + + +
    + + + + +
    + + Content 1 + +
    + +
    + + +
  • + + +
  • + + +
    + + + + + +
    + + + +
    + + + + +
    + + Content 2 + +
    + +
    + + +
  • + + +
+ + +
+ + + +
+ + Bottom content + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Accordion Component renders with required attributes 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + + +
+ + +
    + + +
  • + + +
    + + + + + +
    + + + + + + +
  • + + +
  • + + +
    + + + + + +
    + + + + + + +
  • + + +
+ + +
+ + + +
+ + +
+ + +
+ + +
+ + +
+`; diff --git a/components/02-molecules/accordion/accordion.test.js b/components/02-molecules/accordion/accordion.test.js new file mode 100644 index 00000000..99282f34 --- /dev/null +++ b/components/02-molecules/accordion/accordion.test.js @@ -0,0 +1,82 @@ +const template = 'components/02-molecules/accordion/accordion.twig'; + +describe('Accordion Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + panels: [ + { title: 'Panel 1', content: 'Content 1' }, + { title: 'Panel 2', content: 'Content 2' }, + ], + }); + + expect(c.querySelectorAll('.ct-accordion')).toHaveLength(1); + expect(c.querySelectorAll('.ct-accordion__panels__panel')).toHaveLength(2); + expect(c.querySelector('.ct-accordion__panels__panel__header__button').textContent.trim()).toEqual('Panel 1'); + expect(c.querySelector('.ct-accordion__panels__panel__content').textContent.trim()).toContain('Content 1'); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + content_top: 'Top content', + expand_all: true, + panels: [ + { title: 'Panel 1', content: 'Content 1' }, + { title: 'Panel 2', content: 'Content 2', expanded: true }, + ], + content_bottom: 'Bottom content', + theme: 'dark', + with_background: true, + vertical_spacing: 'both', + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + expect(c.querySelectorAll('.ct-accordion.custom-class.ct-theme-dark.ct-accordion--with-background.ct-vertical-spacing-inset--both')).toHaveLength(1); + expect(c.querySelector('.ct-accordion__content-top').textContent.trim()).toEqual('Top content'); + expect(c.querySelector('.ct-accordion__content-bottom').textContent.trim()).toEqual('Bottom content'); + expect(c.querySelectorAll('.ct-accordion__panels__panel')).toHaveLength(2); + expect(c.querySelector('.ct-accordion__panels__panel__header__button').textContent.trim()).toEqual('Panel 1'); + expect(c.querySelector('.ct-accordion__panels__panel__content').textContent.trim()).toContain('Content 1'); + expect(c.querySelector('.ct-accordion').getAttribute('data-test')).toEqual('true'); + expect(c.querySelector('.ct-accordion__panels__panel__header__button').getAttribute('aria-expanded')).toEqual('true'); + + assertUniqueCssClasses(c); + }); + + test('does not render when panels are empty', async () => { + const c = await dom(template, { + panels: [], + }); + + expect(c.querySelectorAll('.ct-accordion')).toHaveLength(0); + }); + + test('expands all panels when expand_all is true', async () => { + const c = await dom(template, { + expand_all: true, + panels: [ + { title: 'Panel 1', content: 'Content 1' }, + { title: 'Panel 2', content: 'Content 2' }, + ], + }); + + expect(c.querySelectorAll('.ct-accordion__panels__panel')).toHaveLength(2); + c.querySelectorAll('.ct-accordion__panels__panel__header__button').forEach((button) => { + expect(button.getAttribute('aria-expanded')).toEqual('true'); + }); + }); + + test('renders individual panels with expanded state', async () => { + const c = await dom(template, { + panels: [ + { title: 'Panel 1', content: 'Content 1', expanded: true }, + { title: 'Panel 2', content: 'Content 2' }, + ], + }); + + expect(c.querySelector('.ct-accordion__panels__panel__header__button').getAttribute('aria-expanded')).toEqual('true'); + expect(c.querySelectorAll('.ct-accordion__panels__panel__header__button')[1].getAttribute('aria-expanded')).toEqual('false'); + }); +}); diff --git a/components/02-molecules/attachment/__snapshots__/attachment.test.js.snap b/components/02-molecules/attachment/__snapshots__/attachment.test.js.snap new file mode 100644 index 00000000..e1424aee --- /dev/null +++ b/components/02-molecules/attachment/__snapshots__/attachment.test.js.snap @@ -0,0 +1,661 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Attachment Component does not render when files are empty 1`] = ` +
+ + + +
+`; + +exports[`Attachment Component renders with multiple files and attributes 1`] = ` +
+ + + +
+ + +
+ + +
+ + +
+ + +
+ + + + + + + + + + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Attachment Component renders with optional attributes 1`] = ` +
+ + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + Top content + +
+ + + +
+ + + + + +

+ Attachment Title +

+ + + + + +
+ + Attachment content + +
+ +
+ + + + + + + + + + + +
+ + Bottom content + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Attachment Component renders with required attributes 1`] = ` +
+ + + +
+ + +
+ + +
+ + +
+ + +
+ + + + + + + + + + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; diff --git a/components/02-molecules/attachment/attachment.test.js b/components/02-molecules/attachment/attachment.test.js new file mode 100644 index 00000000..f76969c9 --- /dev/null +++ b/components/02-molecules/attachment/attachment.test.js @@ -0,0 +1,69 @@ +const template = 'components/02-molecules/attachment/attachment.twig'; + +describe('Attachment Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + files: [ + { name: 'File 1', ext: 'pdf', url: 'https://example.com/file1.pdf', size: '1MB', created: '2023-01-01', changed: '2023-01-02', icon: 'pdf-file' }, + { name: 'File 2', ext: 'docx', url: 'https://example.com/file2.docx', size: '2MB', created: '2023-01-03', changed: '2023-01-04', icon: 'word-file' }, + ], + }); + + expect(c.querySelectorAll('.ct-attachment')).toHaveLength(1); + expect(c.querySelectorAll('.ct-attachment__links__link')).toHaveLength(2); + expect(c.querySelector('.ct-attachment__links__link').textContent.trim()).toContain('File 1'); + expect(c.querySelector('.ct-attachment__links__link__changed').textContent.trim()).toContain('LAST UPDATED: 2023-01-02'); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + content_top: 'Top content', + title: 'Attachment Title', + content: 'Attachment content', + files: [ + { name: 'File 1', ext: 'pdf', url: 'https://example.com/file1.pdf', size: '1MB', created: '2023-01-01', changed: '2023-01-02', icon: 'pdf-file' }, + ], + content_bottom: 'Bottom content', + theme: 'dark', + vertical_spacing: 'both', + with_background: true, + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + expect(c.querySelectorAll('.ct-attachment.custom-class.ct-theme-dark.ct-attachment--with-background.ct-vertical-spacing-inset--both')).toHaveLength(1); + expect(c.querySelector('.ct-attachment__content-top').textContent.trim()).toEqual('Top content'); + expect(c.querySelector('.ct-attachment__title').textContent.trim()).toEqual('Attachment Title'); + expect(c.querySelector('.ct-attachment__content').textContent.trim()).toEqual('Attachment content'); + expect(c.querySelector('.ct-attachment__content-bottom').textContent.trim()).toEqual('Bottom content'); + expect(c.querySelector('.ct-attachment').getAttribute('data-test')).toEqual('true'); + expect(c.querySelector('.ct-attachment__links__link').textContent.trim()).toContain('File 1'); + + assertUniqueCssClasses(c); + }); + + test('does not render when files are empty', async () => { + const c = await dom(template, { + files: [], + }); + + expect(c.querySelectorAll('.ct-attachment')).toHaveLength(0); + }); + + test('renders with multiple files and attributes', async () => { + const c = await dom(template, { + files: [ + { name: 'File 1', ext: 'pdf', url: 'https://example.com/file1.pdf', size: '1MB', created: '2023-01-01', changed: '2023-01-02', icon: 'pdf-file' }, + { name: 'File 2', ext: 'docx', url: 'https://example.com/file2.docx', size: '2MB', created: '2023-01-03', changed: '2023-01-04', icon: 'word-file' }, + ], + }); + + expect(c.querySelectorAll('.ct-attachment__links__link')).toHaveLength(2); + expect(c.querySelectorAll('.ct-attachment__links__link')[0].textContent.trim()).toContain('File 1'); + expect(c.querySelectorAll('.ct-attachment__links__link')[1].textContent.trim()).toContain('File 2'); + expect(c.querySelectorAll('.ct-attachment__links__link__changed')[0].textContent.trim()).toContain('LAST UPDATED: 2023-01-02'); + expect(c.querySelectorAll('.ct-attachment__links__link__changed')[1].textContent.trim()).toContain('LAST UPDATED: 2023-01-04'); + }); +}); diff --git a/components/02-molecules/back-to-top/__snapshots__/back-to-top.test.js.snap b/components/02-molecules/back-to-top/__snapshots__/back-to-top.test.js.snap new file mode 100644 index 00000000..09f3a03b --- /dev/null +++ b/components/02-molecules/back-to-top/__snapshots__/back-to-top.test.js.snap @@ -0,0 +1,190 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Back to Top Component button contains correct icon 1`] = ` +
+ + + + + + +
+`; + +exports[`Back to Top Component renders button with correct attributes 1`] = ` +
+ + + + + + +
+`; + +exports[`Back to Top Component renders correctly 1`] = ` +
+ + + + + + +
+`; diff --git a/components/02-molecules/back-to-top/back-to-top.test.js b/components/02-molecules/back-to-top/back-to-top.test.js new file mode 100644 index 00000000..8f80808c --- /dev/null +++ b/components/02-molecules/back-to-top/back-to-top.test.js @@ -0,0 +1,31 @@ +const template = 'components/02-molecules/back-to-top/back-to-top.twig'; + +describe('Back to Top Component', () => { + test('renders correctly', async () => { + const c = await dom(template); + + expect(c.querySelectorAll('.ct-back-to-top')).toHaveLength(1); + expect(c.querySelector('.ct-back-to-top').getAttribute('data-component-name')).toEqual('back-to-top'); + expect(c.querySelector('.ct-back-to-top').getAttribute('data-scrollspy')).not.toBeNull(); + expect(c.querySelector('.ct-back-to-top').getAttribute('data-scrollspy-offset')).toEqual('400'); + + assertUniqueCssClasses(c); + }); + + test('renders button with correct attributes', async () => { + const c = await dom(template); + + const button = c.querySelector('.ct-back-to-top__button'); + expect(button.classList.contains('ct-button--link')).toBe(true); + expect(button.classList.contains('ct-button--primary')).toBe(true); + expect(button.querySelector('.ct-button__icon')).not.toBeNull(); + expect(button.getAttribute('href')).toEqual('#top'); + }); + + test('button contains correct icon', async () => { + const c = await dom(template); + + const icon = c.querySelector('.ct-button__icon'); + expect(icon).not.toBeNull(); + }); +}); diff --git a/components/02-molecules/basic-content/__snapshots__/basic-content.test.js.snap b/components/02-molecules/basic-content/__snapshots__/basic-content.test.js.snap new file mode 100644 index 00000000..d981603a --- /dev/null +++ b/components/02-molecules/basic-content/__snapshots__/basic-content.test.js.snap @@ -0,0 +1,117 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Basic Content Component does not render when content is empty 1`] = ` +
+ + + + + +
+`; + +exports[`Basic Content Component renders with optional attributes 1`] = ` +
+ + + + + +
+ + +
+ + +
+ + +
+ + This is basic content with options. + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Basic Content Component renders with required attributes 1`] = ` +
+ + + + + +
+ + +
+ + +
+ + +
+ + This is basic content. + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Basic Content Component renders without containment 1`] = ` +
+ + + + + +
+ + This content is not contained. + +
+ + +
+`; diff --git a/components/02-molecules/basic-content/basic-content.test.js b/components/02-molecules/basic-content/basic-content.test.js new file mode 100644 index 00000000..13e95aa2 --- /dev/null +++ b/components/02-molecules/basic-content/basic-content.test.js @@ -0,0 +1,57 @@ +const template = 'components/02-molecules/basic-content/basic-content.twig'; + +describe('Basic Content Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + content: 'This is basic content.', + }); + + expect(c.querySelectorAll('.ct-basic-content')).toHaveLength(1); + expect(c.querySelector('.ct-basic-content').textContent.trim()).toEqual('This is basic content.'); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + content: 'This is basic content with options.', + theme: 'dark', + is_contained: true, + vertical_spacing: 'both', + with_background: true, + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + const element = c.querySelector('.ct-basic-content'); + expect(element).not.toBeNull(); + expect(element.classList.contains('ct-theme-dark')).toBe(true); + expect(element.classList.contains('ct-vertical-spacing-inset--both')).toBe(true); + expect(element.classList.contains('ct-basic-content--with-background')).toBe(true); + expect(element.classList.contains('custom-class')).toBe(true); + expect(element.getAttribute('data-test')).toEqual('true'); + expect(element.textContent.trim()).toEqual('This is basic content with options.'); + + assertUniqueCssClasses(c); + }); + + test('renders without containment', async () => { + const c = await dom(template, { + content: 'This content is not contained.', + is_contained: false, + }); + + expect(c.querySelector('.ct-basic-content .container')).toBeNull(); + expect(c.querySelector('.ct-basic-content').textContent.trim()).toEqual('This content is not contained.'); + + assertUniqueCssClasses(c); + }); + + test('does not render when content is empty', async () => { + const c = await dom(template, { + content: '', + }); + + expect(c.querySelectorAll('.ct-basic-content')).toHaveLength(0); + }); +}); diff --git a/components/02-molecules/breadcrumb/__snapshots__/breadcrumb.test.js.snap b/components/02-molecules/breadcrumb/__snapshots__/breadcrumb.test.js.snap new file mode 100644 index 00000000..c0ad0726 --- /dev/null +++ b/components/02-molecules/breadcrumb/__snapshots__/breadcrumb.test.js.snap @@ -0,0 +1,754 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Breadcrumb Component renders active element as span when active_is_link is false 1`] = ` +
+ + + + + + + + +
+`; + +exports[`Breadcrumb Component renders with optional attributes 1`] = ` +
+ + + + + + + + +
+`; + +exports[`Breadcrumb Component renders with required attributes 1`] = ` +
+ + + + + + + + +
+`; + +exports[`Breadcrumb Component renders without links 1`] = ` +
+ + + + +
+`; diff --git a/components/02-molecules/breadcrumb/breadcrumb.test.js b/components/02-molecules/breadcrumb/breadcrumb.test.js new file mode 100644 index 00000000..89cffd2a --- /dev/null +++ b/components/02-molecules/breadcrumb/breadcrumb.test.js @@ -0,0 +1,75 @@ +const template = 'components/02-molecules/breadcrumb/breadcrumb.twig'; + +describe('Breadcrumb Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + links: [ + { text: 'Home', url: '/' }, + { text: 'Category', url: '/category' }, + { text: 'Subcategory', url: '/category/subcategory' }, + ], + }); + + expect(c.querySelectorAll('.ct-breadcrumb')).toHaveLength(1); + expect(c.querySelector('.ct-breadcrumb__links__link--active').textContent.trim()).toEqual('Subcategory'); + + const links = c.querySelectorAll('.ct-breadcrumb__links__link'); + expect(links).toHaveLength(3); + expect(links[0].textContent.trim()).toEqual('Home'); + expect(links[1].textContent.trim()).toEqual('Category'); + expect(links[2].textContent.trim()).toEqual('Subcategory'); + + const separators = c.querySelectorAll('.ct-breadcrumb__links__separator'); + expect(separators).toHaveLength(2); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + links: [ + { text: 'Home', url: '/' }, + { text: 'Category', url: '/category' }, + { text: 'Subcategory', url: '/category/subcategory' }, + ], + theme: 'dark', + active_is_link: true, + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + expect(c.querySelectorAll('.ct-breadcrumb.custom-class.ct-theme-dark')).toHaveLength(1); + expect(c.querySelector('.ct-breadcrumb').getAttribute('data-test')).toEqual('true'); + + const activeLink = c.querySelector('.ct-breadcrumb__links__link--active'); + expect(activeLink.tagName).toEqual('A'); + expect(activeLink.getAttribute('href')).toEqual('/category/subcategory'); + + assertUniqueCssClasses(c); + }); + + test('renders without links', async () => { + const c = await dom(template, { + links: [], + }); + + expect(c.querySelectorAll('.ct-breadcrumb')).toHaveLength(0); + }); + + test('renders active element as span when active_is_link is false', async () => { + const c = await dom(template, { + links: [ + { text: 'Home', url: '/' }, + { text: 'Category', url: '/category' }, + { text: 'Subcategory', url: '/category/subcategory' }, + ], + active_is_link: false, + }); + + const activeElement = c.querySelector('.ct-breadcrumb__links__link--active'); + expect(activeElement.tagName).toEqual('SPAN'); + expect(activeElement.getAttribute('aria-current')).toEqual('location'); + + assertUniqueCssClasses(c); + }); +}); diff --git a/components/02-molecules/callout/__snapshots__/callout.test.js.snap b/components/02-molecules/callout/__snapshots__/callout.test.js.snap new file mode 100644 index 00000000..9a85d15e --- /dev/null +++ b/components/02-molecules/callout/__snapshots__/callout.test.js.snap @@ -0,0 +1,421 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Callout Component renders with multiple links 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + +
+ + + + + + + + + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Callout Component renders with optional attributes 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + Top content + +
+ + + +
+ + + + + +

+ Callout Title +

+ + + + + +
+ + This is the main content of the callout. + +
+ +
+ + + + + + + + + + +
+ + Bottom content + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; + +exports[`Callout Component renders with required attributes 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + +
+ + This is the main content of the callout. + +
+ +
+ + + + + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+`; diff --git a/components/02-molecules/callout/callout.test.js b/components/02-molecules/callout/callout.test.js new file mode 100644 index 00000000..3bea866e --- /dev/null +++ b/components/02-molecules/callout/callout.test.js @@ -0,0 +1,71 @@ +const template = 'components/02-molecules/callout/callout.twig'; + +describe('Callout Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + content: 'This is the main content of the callout.', + }); + + expect(c.querySelectorAll('.ct-callout')).toHaveLength(1); + expect(c.querySelector('.ct-callout__content').textContent.trim()).toEqual('This is the main content of the callout.'); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + content_top: 'Top content', + title: 'Callout Title', + content: 'This is the main content of the callout.', + links: [ + { text: 'Link 1', url: 'https://example.com', is_new_window: true, is_external: true }, + { text: 'Link 2', url: 'https://example.com' }, + ], + content_bottom: 'Bottom content', + theme: 'dark', + vertical_spacing: 'both', + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + const element = c.querySelector('.ct-callout'); + expect(element).not.toBeNull(); + expect(element.classList.contains('ct-theme-dark')).toBe(true); + expect(element.classList.contains('ct-vertical-spacing-inset--both')).toBe(true); + expect(element.classList.contains('custom-class')).toBe(true); + expect(element.getAttribute('data-test')).toEqual('true'); + + expect(c.querySelector('.ct-callout__content-top').textContent.trim()).toEqual('Top content'); + expect(c.querySelector('.ct-callout__title').textContent.trim()).toEqual('Callout Title'); + expect(c.querySelector('.ct-callout__content').textContent.trim()).toEqual('This is the main content of the callout.'); + expect(c.querySelector('.ct-callout__content-bottom').textContent.trim()).toEqual('Bottom content'); + + const links = c.querySelectorAll('.ct-callout__links .ct-button'); + expect(links).toHaveLength(2); + expect(links[0].textContent.trim()).toContain('Link 1'); + expect(links[0].getAttribute('href')).toEqual('https://example.com'); + expect(links[0].getAttribute('target')).toEqual('_blank'); + expect(links[1].textContent.trim()).toContain('Link 2'); + expect(links[1].getAttribute('href')).toEqual('https://example.com'); + + assertUniqueCssClasses(c); + }); + + test('renders with multiple links', async () => { + const c = await dom(template, { + links: [ + { text: 'Link 1', url: 'https://example.com' }, + { text: 'Link 2', url: 'https://example.com' }, + { text: 'Link 3', url: 'https://example.com' }, + ], + }); + + const links = c.querySelectorAll('.ct-callout__links .ct-button'); + expect(links).toHaveLength(3); + expect(links[0].textContent.trim()).toEqual('Link 1'); + expect(links[1].textContent.trim()).toEqual('Link 2'); + expect(links[2].textContent.trim()).toEqual('Link 3'); + + assertUniqueCssClasses(c); + }); +}); diff --git a/components/02-molecules/event-card/__snapshots__/event-card.test.js.snap b/components/02-molecules/event-card/__snapshots__/event-card.test.js.snap new file mode 100644 index 00000000..739a9eb1 --- /dev/null +++ b/components/02-molecules/event-card/__snapshots__/event-card.test.js.snap @@ -0,0 +1,466 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Event Card Component renders with optional attributes 1`] = ` +
+ + + + +
+ + +
+ + + + + + Image description + + + +
+ + Image over content + +
+ + +
+ + + +
+ + +
+ + Top content + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +

+ + + + + + + + + + + Event Title + + + + + +

+ + + +
+ + Middle content + +
+ + + + + +
+ + Event Location + +
+ + + + +
+ + This is a summary of the event. + +
+ + +
+ + + + + +
+ + + + + + +
    + + +
  • + + + + + + + + + + + Tag 1 + + + + + + +
  • + + +
  • + + + + + + + + + + + Tag 2 + + + + + + +
  • + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + Bottom content + +
+ + +
+ + +
+ + +
+`; + +exports[`Event Card Component renders with required attributes 1`] = ` +
+ + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +

+ Event Title + +

+ + + + + + +
+ + Event Location + +
+ + + + +
+ + This is a summary of the event. + +
+ + + +
+ + +
+ + +
+`; diff --git a/components/02-molecules/event-card/event-card.test.js b/components/02-molecules/event-card/event-card.test.js new file mode 100644 index 00000000..4a0e6c48 --- /dev/null +++ b/components/02-molecules/event-card/event-card.test.js @@ -0,0 +1,71 @@ +const template = 'components/02-molecules/event-card/event-card.twig'; + +describe('Event Card Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + title: 'Event Title', + summary: 'This is a summary of the event.', + date: '2023-01-01 12:00', + date_iso: '2023-01-01T12:00:00Z', + location: 'Event Location', + }); + + expect(c.querySelectorAll('.ct-event-card')).toHaveLength(1); + expect(c.querySelector('.ct-event-card__title').textContent.trim()).toEqual('Event Title'); + expect(c.querySelector('.ct-event-card__summary').textContent.trim()).toEqual('This is a summary of the event.'); + expect(c.querySelector('.ct-event-card__location').textContent.trim()).toEqual('Event Location'); + expect(c.querySelector('.ct-event-card__date')).toBeTruthy(); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + content_top: 'Top content', + image_over: 'Image over content', + content_middle: 'Middle content', + content_bottom: 'Bottom content', + image: { url: 'https://example.com/image.jpg', alt: 'Image description' }, + title: 'Event Title', + summary: 'This is a summary of the event.', + date: '2023-01-01 12:00', + date_iso: '2023-01-01T12:00:00Z', + location: 'Event Location', + link: { url: 'https://example.com' }, + tags: ['Tag 1', 'Tag 2'], + theme: 'dark', + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + const element = c.querySelector('.ct-event-card'); + expect(element).not.toBeNull(); + expect(element.classList.contains('ct-theme-dark')).toBe(true); + expect(element.classList.contains('custom-class')).toBe(true); + expect(element.getAttribute('data-test')).toEqual('true'); + + expect(c.querySelector('.ct-event-card__content-top').textContent.trim()).toEqual('Top content'); + expect(c.querySelector('.ct-event-card__image__over').textContent.trim()).toEqual('Image over content'); + expect(c.querySelector('.ct-event-card__middle').textContent.trim()).toEqual('Middle content'); + expect(c.querySelector('.ct-event-card__content-bottom').textContent.trim()).toEqual('Bottom content'); + expect(c.querySelector('.ct-event-card__title').textContent.trim()).toEqual('Event Title'); + expect(c.querySelector('.ct-event-card__summary').textContent.trim()).toEqual('This is a summary of the event.'); + expect(c.querySelector('.ct-event-card__location').textContent.trim()).toEqual('Event Location'); + + const tags = c.querySelectorAll('.ct-event-card__tags .ct-tag'); + expect(tags).toHaveLength(2); + expect(tags[0].textContent.trim()).toEqual('Tag 1'); + expect(tags[1].textContent.trim()).toEqual('Tag 2'); + + const image = c.querySelector('.ct-event-card__image img'); + expect(image).toBeTruthy(); + expect(image.getAttribute('src')).toEqual('https://example.com/image.jpg'); + expect(image.getAttribute('alt')).toEqual('Image description'); + + const titleLink = c.querySelector('.ct-event-card__title__link'); + expect(titleLink).toBeTruthy(); + expect(titleLink.getAttribute('href')).toEqual('https://example.com'); + + assertUniqueCssClasses(c); + }); +}); diff --git a/components/02-molecules/event-card/event-card.twig b/components/02-molecules/event-card/event-card.twig index 5cb2e8ef..f808d191 100644 --- a/components/02-molecules/event-card/event-card.twig +++ b/components/02-molecules/event-card/event-card.twig @@ -18,7 +18,8 @@ * - date_end: [string] Optional end date and time. * - date_end_iso: [string] Optional end date and time in ISO format. * - location: [string] Location. - * - url: [string] Optional URL. + * - link: [object] Optional link. + * - url: [string] URL. * - tags: [array] Array of tags. * - theme: [string] Theme: light, dark. * - attributes: [string] Additional attributes. @@ -94,7 +95,7 @@ {% include '@atoms/link/link.twig' with { theme: theme, text: title, - url: url, + url: link.url, modifier_class: 'ct-event-card__title__link', } only %} {% else %} diff --git a/components/02-molecules/figure/__snapshots__/figure.test.js.snap b/components/02-molecules/figure/__snapshots__/figure.test.js.snap new file mode 100644 index 00000000..7f62a50e --- /dev/null +++ b/components/02-molecules/figure/__snapshots__/figure.test.js.snap @@ -0,0 +1,111 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Figure Component does not render when URL is empty 1`] = ` +
+ + + + +
+`; + +exports[`Figure Component renders with optional attributes 1`] = ` +
+ + + + +
+ + + + + + Image description + + + +
+ + + + + + + + + This is the image caption. + +
+ + +
+ + +
+`; + +exports[`Figure Component renders with required attributes 1`] = ` +
+ + + + +
+ + + + + + Image description + + + +
+ + +
+`; diff --git a/components/02-molecules/figure/figure.test.js b/components/02-molecules/figure/figure.test.js new file mode 100644 index 00000000..e5ca4f29 --- /dev/null +++ b/components/02-molecules/figure/figure.test.js @@ -0,0 +1,58 @@ +const template = 'components/02-molecules/figure/figure.twig'; + +describe('Figure Component', () => { + test('renders with required attributes', async () => { + const c = await dom(template, { + url: 'https://example.com/image.jpg', + alt: 'Image description', + }); + + expect(c.querySelectorAll('.ct-figure')).toHaveLength(1); + const image = c.querySelector('.ct-figure__image'); + expect(image).toBeTruthy(); + expect(image.getAttribute('src')).toEqual('https://example.com/image.jpg'); + expect(image.getAttribute('alt')).toEqual('Image description'); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + url: 'https://example.com/image.jpg', + alt: 'Image description', + width: '500', + height: '300', + caption: 'This is the image caption.', + theme: 'dark', + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + const element = c.querySelector('.ct-figure'); + expect(element).not.toBeNull(); + expect(element.classList.contains('ct-theme-dark')).toBe(true); + expect(element.classList.contains('custom-class')).toBe(true); + expect(element.getAttribute('data-test')).toEqual('true'); + + const image = c.querySelector('.ct-figure__image'); + expect(image).toBeTruthy(); + expect(image.getAttribute('src')).toEqual('https://example.com/image.jpg'); + expect(image.getAttribute('alt')).toEqual('Image description'); + expect(image.getAttribute('width')).toEqual('500'); + expect(image.getAttribute('height')).toEqual('300'); + + const caption = c.querySelector('.ct-figure__caption'); + expect(caption).toBeTruthy(); + expect(caption.textContent.trim()).toEqual('This is the image caption.'); + + assertUniqueCssClasses(c); + }); + + test('does not render when URL is empty', async () => { + const c = await dom(template, { + url: '', + }); + + expect(c.querySelectorAll('.ct-figure')).toHaveLength(0); + }); +}); diff --git a/components/02-molecules/logo/__snapshots__/logo.test.js.snap b/components/02-molecules/logo/__snapshots__/logo.test.js.snap new file mode 100644 index 00000000..df81c5ba --- /dev/null +++ b/components/02-molecules/logo/__snapshots__/logo.test.js.snap @@ -0,0 +1,196 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Logo Component does not render when logos are empty 1`] = ` +
+ + + + +
+`; + +exports[`Logo Component renders as div when URL is not provided 1`] = ` +
+ + + + + + + +
+`; + +exports[`Logo Component renders as link when URL is provided 1`] = ` +
+ + + + + + + +
+`; + +exports[`Logo Component renders primary logo only for default type 1`] = ` +
+ + + + + + + +
+`; + +exports[`Logo Component renders with optional attributes 1`] = ` +
+ + + + + + + +
+`; diff --git a/components/02-molecules/logo/logo.test.js b/components/02-molecules/logo/logo.test.js new file mode 100644 index 00000000..46ed2c4e --- /dev/null +++ b/components/02-molecules/logo/logo.test.js @@ -0,0 +1,109 @@ +const template = 'components/02-molecules/logo/logo.twig'; + +describe('Logo Component', () => { + test('renders primary logo only for default type', async () => { + const c = await dom(template, { + theme: 'light', + type: 'default', + logos: { + primary: { + mobile: { url: 'https://example.com/logo-mobile.png', alt: 'Logo Mobile' }, + desktop: { url: 'https://example.com/logo-desktop.png', alt: 'Logo Desktop' }, + }, + }, + }); + + expect(c.querySelectorAll('.ct-logo')).toHaveLength(1); + const logoImages = c.querySelectorAll('.ct-logo__image'); + expect(logoImages).toHaveLength(2); + expect(logoImages[0].getAttribute('src')).toEqual('https://example.com/logo-mobile.png'); + expect(logoImages[1].getAttribute('src')).toEqual('https://example.com/logo-desktop.png'); + + assertUniqueCssClasses(c); + }); + + test('renders with optional attributes', async () => { + const c = await dom(template, { + theme: 'dark', + type: 'stacked', + logos: { + primary: { + mobile: { url: 'https://example.com/logo-mobile.png', alt: 'Logo Mobile' }, + desktop: { url: 'https://example.com/logo-desktop.png', alt: 'Logo Desktop' }, + }, + secondary: { + mobile: { url: 'https://example.com/secondary-logo-mobile.png', alt: 'Secondary Logo Mobile' }, + desktop: { url: 'https://example.com/secondary-logo-desktop.png', alt: 'Secondary Logo Desktop' }, + }, + }, + url: 'https://example.com', + title: 'Go to homepage', + attributes: 'data-test="true"', + modifier_class: 'custom-class', + }); + + const element = c.querySelector('.ct-logo'); + expect(element).not.toBeNull(); + expect(element.classList.contains('ct-theme-dark')).toBe(true); + expect(element.classList.contains('ct-logo--stacked')).toBe(true); + expect(element.classList.contains('custom-class')).toBe(true); + expect(element.getAttribute('data-test')).toEqual('true'); + expect(element.getAttribute('href')).toEqual('https://example.com'); + expect(element.getAttribute('title')).toEqual('Go to homepage'); + + const logoImages = c.querySelectorAll('.ct-logo__image'); + expect(logoImages).toHaveLength(4); + expect(logoImages[0].getAttribute('src')).toEqual('https://example.com/logo-mobile.png'); + expect(logoImages[1].getAttribute('src')).toEqual('https://example.com/logo-desktop.png'); + expect(logoImages[2].getAttribute('src')).toEqual('https://example.com/secondary-logo-mobile.png'); + expect(logoImages[3].getAttribute('src')).toEqual('https://example.com/secondary-logo-desktop.png'); + + assertUniqueCssClasses(c); + }); + + test('does not render when logos are empty', async () => { + const c = await dom(template, { + logos: {}, + }); + + expect(c.querySelectorAll('.ct-logo')).toHaveLength(0); + }); + + test('renders as div when URL is not provided', async () => { + const c = await dom(template, { + theme: 'light', + type: 'default', + logos: { + primary: { + mobile: { url: 'https://example.com/logo-mobile.png', alt: 'Logo Mobile' }, + desktop: { url: 'https://example.com/logo-desktop.png', alt: 'Logo Desktop' }, + }, + }, + }); + + const element = c.querySelector('.ct-logo'); + expect(element).not.toBeNull(); + expect(element.tagName).toEqual('DIV'); + }); + + test('renders as link when URL is provided', async () => { + const c = await dom(template, { + theme: 'light', + type: 'default', + logos: { + primary: { + mobile: { url: 'https://example.com/logo-mobile.png', alt: 'Logo Mobile' }, + desktop: { url: 'https://example.com/logo-desktop.png', alt: 'Logo Desktop' }, + }, + }, + url: 'https://example.com', + title: 'Go to homepage', + }); + + const element = c.querySelector('.ct-logo'); + expect(element).not.toBeNull(); + expect(element.tagName).toEqual('A'); + expect(element.getAttribute('href')).toEqual('https://example.com'); + expect(element.getAttribute('title')).toEqual('Go to homepage'); + }); +}); diff --git a/components/02-molecules/map/__snapshots__/map.test.js.snap b/components/02-molecules/map/__snapshots__/map.test.js.snap new file mode 100644 index 00000000..eecab134 --- /dev/null +++ b/components/02-molecules/map/__snapshots__/map.test.js.snap @@ -0,0 +1,319 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Map Component does not render when URL is empty 1`] = ` +
+ + + + +
+`; + +exports[`Map Component renders with default view text 1`] = ` +
+ + + + +
+ + +
+ + +
+ + +
+ + + +
+ + + + + + ', + }); + + expect(c.querySelectorAll('.ct-video-player')).toHaveLength(1); + const iframe = c.querySelector('iframe'); + expect(iframe).not.toBeNull(); + expect(iframe.getAttribute('src')).toEqual('https://www.example.com'); + expect(iframe.getAttribute('width')).toEqual('560'); + expect(iframe.getAttribute('height')).toEqual('315'); + + assertUniqueCssClasses(c); + }); + + test('renders with transcript link', async () => { + const c = await dom(template, { + sources: [ + { url: 'video.mp4', type: 'video/mp4' }, + ], + transcript_link: { + url: 'transcript.html', + text: 'View Transcript', + title: 'Transcript', + is_new_window: true, + is_external: false, + }, + }); + + expect(c.querySelectorAll('.ct-video-player')).toHaveLength(1); + const transcriptLink = c.querySelector('.ct-video-player__links__transcript a'); + expect(transcriptLink).not.toBeNull(); + expect(transcriptLink.getAttribute('href')).toEqual('transcript.html'); + expect(transcriptLink.textContent.trim()).toContain('View Transcript'); + + assertUniqueCssClasses(c); + }); + + test('does not render when sources, embedded_source, and raw_source are all empty', async () => { + const c = await dom(template, {}); + + expect(c.querySelectorAll('.ct-video-player')).toHaveLength(0); + }); +});