diff --git a/banners/english/C24_WMDE_Desktop_EN_04/components/BannerVar.vue b/banners/english/C24_WMDE_Desktop_EN_04/components/BannerVar.vue index 043ceec16..d5f616146 100644 --- a/banners/english/C24_WMDE_Desktop_EN_04/components/BannerVar.vue +++ b/banners/english/C24_WMDE_Desktop_EN_04/components/BannerVar.vue @@ -89,10 +89,10 @@ import MainBanner from './MainBanner.vue'; import FundsModal from '@src/components/UseOfFunds/FundsModal.vue'; import { UseOfFundsContent as useOfFundsContentInterface } from '@src/domain/UseOfFunds/UseOfFundsContent'; import UpgradeToYearlyButtonForm from '@src/components/DonationForm/Forms/UpgradeToYearlyButtonForm.vue'; -import BannerSlides from '../content/BannerSlidesVar.vue'; +import BannerSlides from '../content/BannerSlides.vue'; import MainDonationForm from '@src/components/DonationForm/Forms/MainDonationForm.vue'; import MultiStepDonation from '@src/components/DonationForm/MultiStepDonation.vue'; -import BannerText from '../content/BannerTextVar.vue'; +import BannerText from '../content/BannerText.vue'; import KeenSlider from '@src/components/Slider/KeenSlider.vue'; import FooterAlreadyDonated from '@src/components/Footer/FooterAlreadyDonated.vue'; import { useFormModel } from '@src/components/composables/useFormModel'; diff --git a/banners/english/C24_WMDE_Desktop_EN_04/content/BannerTextVar.vue b/banners/english/C24_WMDE_Desktop_EN_04/content/BannerTextVar.vue deleted file mode 100644 index 62b22623b..000000000 --- a/banners/english/C24_WMDE_Desktop_EN_04/content/BannerTextVar.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - diff --git a/banners/english/C24_WMDE_Desktop_EN_05/banner_ctrl.ts b/banners/english/C24_WMDE_Desktop_EN_05/banner_ctrl.ts new file mode 100644 index 000000000..5ac47a488 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/banner_ctrl.ts @@ -0,0 +1,71 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles.scss'; + +import BannerConductor from '@src/components/BannerConductor/FallbackBannerConductor.vue'; +import Banner from './components/BannerCtrl.vue'; +import FallbackBanner from './components/FallbackBanner.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import { Locales } from '@src/domain/Locales'; +import messages from './messages'; +import { LocaleFactoryEn } from '@src/utils/LocaleFactory/LocaleFactoryEn'; +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import eventMappings from './event_map'; +import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; +import { WindowTimer } from '@src/utils/Timer'; + +const localeFactory = new LocaleFactoryEn(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker( 400 ) ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'english' ) ), + donationLink: createFallbackDonationURL( page.getTracking(), impressionCount, { locale: Locales.EN } ) + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + fallbackBanner: FallbackBanner, + minWidthForMainBanner: 800, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new Date(), + formatters: localeFactory.getFormatters(), + impressionCount, + translator +} ); + +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +app.provide( 'currencyFormatter', currencyFormatter ); +app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { locale: Locales.EN } ) ); +app.provide( 'tracker', tracker ); +app.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/english/C24_WMDE_Desktop_EN_05/banner_var.ts b/banners/english/C24_WMDE_Desktop_EN_05/banner_var.ts new file mode 100644 index 000000000..9883c3e6d --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/banner_var.ts @@ -0,0 +1,71 @@ +import { createVueApp } from '@src/createVueApp'; + +import './styles/styles_var.scss'; + +import BannerConductor from '@src/components/BannerConductor/FallbackBannerConductor.vue'; +import Banner from './components/BannerVar.vue'; +import FallbackBanner from './components/FallbackBanner.vue'; +import { UrlRuntimeEnvironment } from '@src/utils/RuntimeEnvironment'; +import { WindowResizeHandler } from '@src/utils/ResizeHandler'; +import PageWPORG from '@src/page/PageWPORG'; +import { WindowMediaWiki } from '@src/page/MediaWiki/WindowMediaWiki'; +import { SkinFactory } from '@src/page/skin/SkinFactory'; +import { WindowSizeIssueChecker } from '@src/utils/SizeIssueChecker/WindowSizeIssueChecker'; +import TranslationPlugin from '@src/TranslationPlugin'; +import { Translator } from '@src/Translator'; +import DynamicTextPlugin from '@src/DynamicTextPlugin'; +import { LocalImpressionCount } from '@src/utils/LocalImpressionCount'; +import { LegacyTrackerWPORG } from '@src/tracking/LegacyTrackerWPORG'; +import { Locales } from '@src/domain/Locales'; +import messages from './messages_var'; +import { LocaleFactoryEn } from '@src/utils/LocaleFactory/LocaleFactoryEn'; +import { createFormItems } from './form_items'; +import { createFormActions } from '@src/createFormActions'; +import eventMappings from './event_map'; +import { createFallbackDonationURL } from '@src/createFallbackDonationURL'; +import { WindowTimer } from '@src/utils/Timer'; + +const localeFactory = new LocaleFactoryEn(); +const translator = new Translator( messages ); +const mediaWiki = new WindowMediaWiki(); +const page = new PageWPORG( mediaWiki, ( new SkinFactory( mediaWiki ) ).getSkin(), new WindowSizeIssueChecker( 400 ) ); +const runtimeEnvironment = new UrlRuntimeEnvironment( window.location ); +const impressionCount = new LocalImpressionCount( page.getTracking().keyword, runtimeEnvironment ); +const tracker = new LegacyTrackerWPORG( mediaWiki, page.getTracking().keyword, eventMappings, runtimeEnvironment ); + +const app = createVueApp( BannerConductor, { + page, + bannerConfig: { + delay: runtimeEnvironment.getBannerDelay( 7500 ), + transitionDuration: 1000 + }, + bannerProps: { + useOfFundsContent: localeFactory.getUseOfFundsLoader().getContent(), + remainingImpressions: impressionCount.getRemainingImpressions( page.getMaxBannerImpressions( 'english' ) ), + donationLink: createFallbackDonationURL( page.getTracking(), impressionCount, { locale: Locales.EN } ) + }, + resizeHandler: new WindowResizeHandler(), + banner: Banner, + fallbackBanner: FallbackBanner, + minWidthForMainBanner: 800, + impressionCount +} ); + +app.use( TranslationPlugin, translator ); +app.use( DynamicTextPlugin, { + campaignParameters: page.getCampaignParameters(), + date: new Date(), + formatters: localeFactory.getFormatters(), + impressionCount, + translator +} ); + +const currencyFormatter = localeFactory.getCurrencyFormatter(); + +app.provide( 'currencyFormatter', currencyFormatter ); +app.provide( 'formItems', createFormItems( translator, currencyFormatter.euroAmount.bind( currencyFormatter ) ) ); +app.provide( 'formActions', createFormActions( page.getTracking(), impressionCount, { locale: Locales.EN } ) ); +app.provide( 'tracker', tracker ); +app.provide( 'timer', new WindowTimer() ); + +app.mount( page.getBannerContainer() ); diff --git a/banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.vue b/banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.vue new file mode 100644 index 000000000..d5f616146 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.vue @@ -0,0 +1,160 @@ + + + diff --git a/banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.vue b/banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.vue new file mode 100644 index 000000000..c9a62e3be --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.vue @@ -0,0 +1,161 @@ + + + diff --git a/banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.vue b/banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.vue new file mode 100644 index 000000000..75e469475 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.vue @@ -0,0 +1,106 @@ + + + diff --git a/banners/english/C24_WMDE_Desktop_EN_05/components/MainBanner.vue b/banners/english/C24_WMDE_Desktop_EN_05/components/MainBanner.vue new file mode 100644 index 000000000..9f9ebe572 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/components/MainBanner.vue @@ -0,0 +1,50 @@ + + + diff --git a/banners/english/C24_WMDE_Desktop_EN_04/content/BannerSlidesVar.vue b/banners/english/C24_WMDE_Desktop_EN_05/content/BannerSlides.vue similarity index 50% rename from banners/english/C24_WMDE_Desktop_EN_04/content/BannerSlidesVar.vue rename to banners/english/C24_WMDE_Desktop_EN_05/content/BannerSlides.vue index e24663cf5..ac14de304 100644 --- a/banners/english/C24_WMDE_Desktop_EN_04/content/BannerSlidesVar.vue +++ b/banners/english/C24_WMDE_Desktop_EN_05/content/BannerSlides.vue @@ -2,30 +2,29 @@

- - {{ liveDateAndTime.currentDate }}, {{ liveDateAndTime.currentTime }}: “The internet we were promised“ - - An important update for readers in Germany. + + {{ liveDateAndTime.currentDate }}, {{ liveDateAndTime.currentTime }}: “Wikipedia still can't be + sold.” - An important update for readers in Germany.

- You deserve an explanation, so please don't skip this 1-minute read. It's {{ currentDayName }}, - {{ currentDate }}, and this message will be up only briefly. Please reflect on how often you've visited - Wikipedia this year and if you're able to give €5 back. - + Today is the day. We're sorry to interrupt, but it's {{ currentDayName }}, {{ currentDate }}, and this + message will be up for only a few hours.

- The internet we were promised—a place of free, collaborative, and accessible knowledge—is under constant - threat. On Wikipedia, volunteers work together to create and verify the pages you rely on, supported by - tools that undo vandalism within minutes, ensuring the information you seek is trustworthy. + We ask you to reflect on the number of times you visited Wikipedia in the past year and if you're able to give €5 back. + + In the age of AI, access to verifiable facts is crucial. Wikipedia is at the heart of online information, + powering everything from your personal searches to emerging AI technologies.

- Just 1% of our readers donate, so if you have given in the past and Wikipedia still provides you with €5 - worth of knowledge, donate today. If you are undecided, remember any contribution helps, whether it's €5 or - €25. Thank you. + Your gift strengthens the knowledge of today and tomorrow. Just 1% of our readers donate, so if + you have given in the past and Wikipedia still provides you with €5 worth of knowledge, kindly donate + today. If you are undecided, remember that any contribution helps, whether it's €5 or €25. Thank you.

@@ -33,10 +32,10 @@ diff --git a/banners/english/C24_WMDE_Desktop_EN_05/content/FallbackSlides.vue b/banners/english/C24_WMDE_Desktop_EN_05/content/FallbackSlides.vue new file mode 100644 index 000000000..a50a81082 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/content/FallbackSlides.vue @@ -0,0 +1,27 @@ + + + diff --git a/banners/english/C24_WMDE_Desktop_EN_05/content/FallbackText.vue b/banners/english/C24_WMDE_Desktop_EN_05/content/FallbackText.vue new file mode 100644 index 000000000..60a58e80d --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/content/FallbackText.vue @@ -0,0 +1,32 @@ + + + diff --git a/banners/english/C24_WMDE_Desktop_EN_05/event_map.ts b/banners/english/C24_WMDE_Desktop_EN_05/event_map.ts new file mode 100644 index 000000000..612f999a8 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/event_map.ts @@ -0,0 +1,38 @@ +import { TrackingEventConverterFactory } from '@src/tracking/LegacyTrackerWPORG'; +import { WMDELegacyBannerEvent } from '@src/tracking/WPORG/WMDELegacyBannerEvent'; +import { FormStepShownEvent } from '@src/tracking/events/FormStepShownEvent'; +import { mapFormStepShownEvent } from '@src/tracking/LegacyEventTracking/mapFormStepShownEvent'; +import { CustomAmountChangedEvent } from '@src/tracking/events/CustomAmountChangedEvent'; +import { CloseEvent } from '@src/tracking/events/CloseEvent'; +import { mapCloseEvent } from '@src/tracking/LegacyEventTracking/mapCloseEvent'; +import { NotShownEvent } from '@src/tracking/events/NotShownEvent'; +import { mapNotShownEvent } from '@src/tracking/LegacyEventTracking/mapNotShownEvent'; +import { BannerSubmitEvent } from '@src/tracking/events/BannerSubmitEvent'; +import { WMDESizeIssueEvent } from '@src/tracking/WPORG/WMDEBannerSizeIssue'; +import { createViewportInfo } from '@src/tracking/LegacyEventTracking/createViewportInfo'; +import { FallbackBannerSubmitEvent } from '@src/tracking/events/FallbackBannerSubmitEvent'; +import { ShownEvent } from '@src/tracking/events/ShownEvent'; +import { mapShownEvent } from '@src/tracking/LegacyEventTracking/mapShownEvent'; + +export default new Map( [ + [ ShownEvent.EVENT_NAME, mapShownEvent ], + [ CloseEvent.EVENT_NAME, mapCloseEvent ], + + [ FormStepShownEvent.EVENT_NAME, mapFormStepShownEvent ], + [ CustomAmountChangedEvent.EVENT_NAME, + ( e: CustomAmountChangedEvent ): WMDELegacyBannerEvent => + new WMDELegacyBannerEvent( e.userChoice + '-amount', 1 ) + ], + [ NotShownEvent.EVENT_NAME, mapNotShownEvent ], + [ BannerSubmitEvent.EVENT_NAME, ( e: BannerSubmitEvent ): WMDESizeIssueEvent => { + switch ( e.feature ) { + case 'UpgradeToYearlyForm': + return new WMDESizeIssueEvent( `submit-${e.userChoice}`, createViewportInfo(), 1 ); + case 'CustomAmountForm': + return new WMDESizeIssueEvent( `submit-different-amount`, createViewportInfo(), 1 ); + default: + return new WMDESizeIssueEvent( `submit`, createViewportInfo(), 1 ); + } + } ], + [ FallbackBannerSubmitEvent.EVENT_NAME, ( e: FallbackBannerSubmitEvent ): WMDESizeIssueEvent => new WMDESizeIssueEvent( e.eventName, createViewportInfo(), 1 ) ] +] ); diff --git a/banners/english/C24_WMDE_Desktop_EN_05/form_items.ts b/banners/english/C24_WMDE_Desktop_EN_05/form_items.ts new file mode 100644 index 000000000..95a254ccb --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/form_items.ts @@ -0,0 +1,21 @@ +import FormItemsBuilder from '@src/utils/FormItemsBuilder/FormItemsBuilder'; +import { Translator } from '@src/Translator'; +import { DonationFormItems } from '@src/utils/FormItemsBuilder/DonationFormItems'; +import { Intervals } from '@src/utils/FormItemsBuilder/fields/Intervals'; +import { PaymentMethods } from '@src/utils/FormItemsBuilder/fields/PaymentMethods'; +import { NumberFormatter } from '@src/utils/DynamicContent/formatters/NumberFormatter'; + +export function createFormItems( translations: Translator, amountFormatter: NumberFormatter ): DonationFormItems { + return new FormItemsBuilder( translations, amountFormatter ) + .setIntervals( + Intervals.ONCE, + Intervals.MONTHLY, + Intervals.QUARTERLY, + Intervals.YEARLY + ) + .setAmounts( 5, 10, 20, 25, 50, 100 ) + .setPaymentMethods( + PaymentMethods.PAYPAL, + PaymentMethods.CREDIT_CARD + ).getItems(); +} diff --git a/banners/english/C24_WMDE_Desktop_EN_05/messages.ts b/banners/english/C24_WMDE_Desktop_EN_05/messages.ts new file mode 100644 index 000000000..24d57a42d --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/messages.ts @@ -0,0 +1,27 @@ +import CustomAmountFormEn from '@src/components/DonationForm/Forms/messages/CustomAmountForm.en'; +import DynamicCampaignTextEn from '@src/utils/DynamicContent/messages/DynamicCampaignText.en'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyEn from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.en'; +import SoftCloseEn from '@src/components/SoftClose/messages/SoftClose.en'; +import AddressFormEn from '@src/components/DonationForm/Forms/messages/AddressForm.en'; +import FooterEn from '@src/components/Footer/messages/Footer.en'; +import MainDonationFormEn from '@src/components/DonationForm/Forms/messages/MainDonationForm.en'; +import AlreadyDonatedModalEn from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.en'; +import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.en'; + +const messages: TranslationMessages = { + ...CustomAmountFormEn, + ...DynamicCampaignTextEn, + ...UpgradeToYearlyEn, + ...SoftCloseEn, + ...AddressFormEn, + ...FooterEn, + ...MainDonationFormEn, + ...AlreadyDonatedModalEn, + ...FallbackBanner, + 'upgrade-to-yearly-copy': '

Every year we are dependent on the support of people like you. Yearly donations ' + + 'help sustainably and enable long term development.

' + + '

No risks attached, you can tell us to stop at any time.

' +}; + +export default messages; diff --git a/banners/english/C24_WMDE_Desktop_EN_05/messages_var.ts b/banners/english/C24_WMDE_Desktop_EN_05/messages_var.ts new file mode 100644 index 000000000..4b3e5c0e9 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/messages_var.ts @@ -0,0 +1,28 @@ +import CustomAmountFormEn from '@src/components/DonationForm/Forms/messages/CustomAmountForm.en'; +import DynamicCampaignTextEn from '@src/utils/DynamicContent/messages/DynamicCampaignText.en'; +import { TranslationMessages } from '@src/Translator'; +import UpgradeToYearlyEn from '@src/components/DonationForm/Forms/messages/UpgradeToYearly.en'; +import SoftCloseEn from '@src/components/SoftClose/messages/SoftClose.en'; +import AddressFormEn from '@src/components/DonationForm/Forms/messages/AddressForm.en'; +import FooterEn from '@src/components/Footer/messages/Footer.en'; +import MainDonationFormEn from '@src/components/DonationForm/Forms/messages/MainDonationForm.en'; +import AlreadyDonatedModalEn from '@src/components/AlreadyDonatedModal/translations/AlreadyDonatedModal.en'; +import FallbackBanner from '@src/components/FallbackBanner/messages/FallbackBanner.en'; + +const messages: TranslationMessages = { + ...CustomAmountFormEn, + ...DynamicCampaignTextEn, + ...UpgradeToYearlyEn, + ...SoftCloseEn, + ...AddressFormEn, + ...FooterEn, + ...MainDonationFormEn, + ...AlreadyDonatedModalEn, + ...FallbackBanner, + 'upgrade-to-yearly-copy': '

Every year we are dependent on the support of people like you. Yearly donations ' + + 'help sustainably and enable long term development.

' + + '

No risks attached, you can tell us to stop at any time.

', + 'donation-receipt-checkbox-label': 'Please send me a tax deductible donation receipt to my postal address.' +}; + +export default messages; diff --git a/banners/english/C24_WMDE_Desktop_EN_05/styles/Banner.scss b/banners/english/C24_WMDE_Desktop_EN_05/styles/Banner.scss new file mode 100644 index 000000000..f88657686 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/styles/Banner.scss @@ -0,0 +1,17 @@ +@use 'src/themes/Treedip/variables/fonts'; + +.wmde-banner { + &-wrapper { + font-size: 14px; + font-family: fonts.$ui; + box-shadow: var( --main-box-shadow ); + background-color: var( --main-background ); + color: var( --main-color ); + } + + &--closed { + .wmde-banner-wrapper { + display: none; + } + } +} diff --git a/banners/english/C24_WMDE_Desktop_EN_05/styles/FallbackBanner.scss b/banners/english/C24_WMDE_Desktop_EN_05/styles/FallbackBanner.scss new file mode 100644 index 000000000..2361a26cf --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/styles/FallbackBanner.scss @@ -0,0 +1,136 @@ +@use 'src/themes/Treedip/variables/globals'; +@use 'src/themes/Treedip/variables/fonts'; + +$breakpoint: 800px; + +.wmde-banner { + &-fallback { + width: 100%; + height: 150px; + display: flex; + flex-direction: column; + background: var( --fallback-background ); + box-shadow: var( --main-box-shadow ); + + @media ( min-width: $breakpoint ) { + height: auto; + min-height: 250px; + padding: 4px; + } + + &-small, + &-large { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } + + &-small { + align-items: center; + border: 4px solid var( --fallback-border ); + border-radius: 4px; + padding: 8px; + + .wmde-banner-progress-bar { + height: 25px; + line-height: 25px; + } + + .wmde-banner-progress-bar-text, + .wmde-banner-progress-bar-fill-wrapper { + height: 25px; + } + + .wmde-banner-progress-bar-fill { + line-height: 20px; + } + + .wmde-banner-fallback-button { + margin: 0 0 8px; + } + + .wmde-banner-selection-input-text, + .wmde-banner-selection-input-input { + font-family: fonts.$content; + font-size: 14px; + font-weight: normal; + } + } + + &-large { + align-items: stretch; + } + + &-usage-link { + color: var( --fallback-uof-link ); + } + + &-message { + flex: 1 1 auto; + display: flex; + flex-direction: column; + background: var( --fallback-message-background ); + border: 4px solid var( --fallback-message-border ); + border-radius: 4px; + padding: 8px 0; + } + + &-bank-item { + display: block; + + &-label { + font-weight: bold; + } + } + + .wmde-banner-close { + height: 16px; + width: 16px; + top: 8px; + right: 8px; + margin: 0; + padding: 0; + + @media ( min-width: $breakpoint ) { + height: 30px; + width: 30px; + top: 12px; + right: 12px; + } + } + + .wmde-banner-slider-container { + padding: 0 0 8px; + } + + .wmde-banner-slide-content { + font-size: 14px; + p { + margin-bottom: 8px; + } + } + + .wmde-banner-slider-navigation-previous, + .wmde-banner-slider-navigation-next { + align-items: end; + } + + .wmde-banner-slider-pagination-dot { + cursor: default; + } + + .wmde-banner-message { + flex: 1 1 auto; + + p { + margin-bottom: 0; + } + } + } + + &--pending { + .wmde-banner-fallback { + box-shadow: none; + } + } +} diff --git a/banners/english/C24_WMDE_Desktop_EN_05/styles/MainBanner.scss b/banners/english/C24_WMDE_Desktop_EN_05/styles/MainBanner.scss new file mode 100644 index 000000000..518b8c959 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/styles/MainBanner.scss @@ -0,0 +1,44 @@ +$banner-height: 357px !default; +$form-width: 300px !default; + +.wmde-banner { + &-main { + min-height: $banner-height; + display: flex; + flex-direction: column; + padding: 12px 24px 0; + } + + &-content { + display: flex; + flex-direction: row; + flex-grow: 1; + } + + &-message { + padding: 0 15px; + } + + &-column-left { + display: flex; + flex-direction: column; + justify-content: center; + flex: 1 1 auto; + margin-bottom: 0; + overflow-y: hidden; + margin-right: 30px; + padding: 0 0 10px; + background: var( --message-background ); + border: 5px solid var( --message-border ); + border-radius: 9px; + } + + &-column-right { + order: 2; + flex: 0 0 $form-width; + display: flex; + flex-direction: column; + width: $form-width; + padding: 10px 0; + } +} diff --git a/banners/english/C24_WMDE_Desktop_EN_05/styles/styles.scss b/banners/english/C24_WMDE_Desktop_EN_05/styles/styles.scss new file mode 100644 index 000000000..1e0e5a7f3 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/styles/styles.scss @@ -0,0 +1,61 @@ +// This is the file where we import the theme-specific component styles +@use 'src/themes/Treedip/swatches/skin_vector-2022' with ( + $slider: true, + $select-group-bubble: true, + $select-group-image-label: true, + $upgrade-to-yearly: true, + $fallback-banner: true, + $progress-bar: true, + $soft-close: true, +); +@use 'src/themes/Treedip/variables/breakpoints'; +@use 'src/components/BannerConductor/banner-transition'; +@use 'Banner'; +@use 'MainBanner' with ( + $banner-height: 355px, + $form-width: 300px +); +@use 'src/themes/UseOfFunds/swatches/skin_vector-2022' as uof-vector-2022; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Treedip/defaults'; +@use 'src/themes/Treedip/ButtonClose/ButtonClose' with ( + $padding: 4px, + $top: 12px, + $right: 8px, + $margin: -4.5px +); +@use 'src/themes/Treedip/ProgressBar/ProgressBarAlternative' with ( + $progress-bar-margin: 0 15px +); +@use 'src/themes/Treedip/DonationForm/DonationForm'; +@use 'src/themes/Treedip/DonationForm/MultiStepDonation'; +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectGroupBubble'; +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectGroupRadioBubbles' with ( + $height: 34px, + $font-size: 14px +); +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectCustomAmountRadioBubble' with ( + $height: 34px, + $font-size: 14px +); +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectGroupBubbleImageLabel'; +@use 'src/themes/Treedip/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Treedip/DonationForm/Forms/MainDonationForm' with ( + $padding: 14px 0 0 +); +@use 'src/themes/Treedip/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( + $font-size: 14px +); +@use 'src/themes/Treedip/Footer/FooterAlreadyDonated' with ( + $right-column-width: 300px +); +@use 'src/themes/Treedip/Footer/SelectionInput'; +@use 'src/themes/Treedip/Message/Message' with ( + $font-sizes: ( 1400px: 15px, 1600px: 16px, 1800px: 18px ) +); +@use 'src/themes/Treedip/Slider/KeenSlider'; +@use 'src/themes/Treedip/SoftClose/SoftClose'; +@use 'FallbackBanner'; +@use 'src/themes/Fijitiv/FallbackBanner/FallbackButton'; +@use 'src/themes/Fijitiv/FallbackBanner/LargeFooter'; +@use 'src/themes/Fijitiv/FallbackBanner/SmallFooter'; diff --git a/banners/english/C24_WMDE_Desktop_EN_05/styles/styles_var.scss b/banners/english/C24_WMDE_Desktop_EN_05/styles/styles_var.scss new file mode 100644 index 000000000..7a126e0a0 --- /dev/null +++ b/banners/english/C24_WMDE_Desktop_EN_05/styles/styles_var.scss @@ -0,0 +1,61 @@ +// This is the file where we import the theme-specific component styles +@use 'src/themes/Treedip/swatches/skin_vector-2022' with ( + $slider: true, + $select-group-bubble: true, + $select-group-image-label: true, + $upgrade-to-yearly: true, + $fallback-banner: true, + $progress-bar: true, + $soft-close: true, +); +@use 'src/themes/Treedip/variables/breakpoints'; +@use 'src/components/BannerConductor/banner-transition'; +@use 'Banner'; +@use 'MainBanner' with ( + $banner-height: 355px, + $form-width: 300px +); +@use 'src/themes/UseOfFunds/swatches/skin_vector-2022' as uof-vector-2022; +@use 'src/themes/UseOfFunds/UseOfFunds'; +@use 'src/themes/Treedip/defaults'; +@use 'src/themes/Treedip/ButtonClose/ButtonClose' with ( + $padding: 4px, + $top: 12px, + $right: 8px, + $margin: -4.5px +); +@use 'src/themes/Treedip/ProgressBar/ProgressBarAlternative' with ( + $progress-bar-margin: 0 15px +); +@use 'src/themes/Treedip/DonationForm/DonationForm'; +@use 'src/themes/Treedip/DonationForm/MultiStepDonation'; +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectGroupBubble'; +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectGroupRadioBubbles' with ( + $height: 34px, + $font-size: 14px +); +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectCustomAmountRadioBubble' with ( + $height: 34px, + $font-size: 14px +); +@use 'src/themes/Treedip/DonationForm/BubbleForm/SelectGroupBubbleImageLabel'; +@use 'src/themes/Treedip/DonationForm/SubComponents/SmsBox'; +@use 'src/themes/Treedip/DonationForm/Forms/MainDonationFormDonationReceipt' with ( + $padding: 14px 0 0 +); +@use 'src/themes/Treedip/DonationForm/Forms/UpgradeToYearlyButtonForm' with ( + $font-size: 14px +); +@use 'src/themes/Treedip/Footer/FooterAlreadyDonated' with ( + $right-column-width: 300px +); +@use 'src/themes/Treedip/Footer/SelectionInput'; +@use 'src/themes/Treedip/Message/Message' with ( + $font-sizes: ( 1400px: 15px, 1600px: 16px, 1800px: 18px ) +); +@use 'src/themes/Treedip/Slider/KeenSlider'; +@use 'src/themes/Treedip/SoftClose/SoftClose'; +@use 'FallbackBanner'; +@use 'src/themes/Fijitiv/FallbackBanner/FallbackButton'; +@use 'src/themes/Fijitiv/FallbackBanner/LargeFooter'; +@use 'src/themes/Fijitiv/FallbackBanner/SmallFooter'; diff --git a/campaign_info.toml b/campaign_info.toml index 190cb701a..1d201832b 100644 --- a/campaign_info.toml +++ b/campaign_info.toml @@ -139,9 +139,9 @@ tracking = "wpde-mob01-241028-var" [english] name = "English Desktop" icon = "desktop" -campaign = "C24_WMDE_Desktop_EN_04" -description = "Based on CTRL desktop EN 03" -campaign_tracking = "en04-ba-241113" +campaign = "C24_WMDE_Desktop_EN_05" +description = "Based on CTRL desktop EN 04" +campaign_tracking = "en05-ba-241126" preview_link = "/wiki/Main_Page?devbanner={{banner}}&banner=B22_WMDE_local_prototype" preview_link_darkmode = "/wiki/Main_Page?devbanner={{banner}}&banner=B22_WMDE_local_prototype&vectornightmode=1" preview_url = 'https://en.wikipedia.org/wiki/Main_Page?banner={{banner}}&devMode' @@ -149,14 +149,14 @@ wrapper_template = "wikipedia_org" use_of_funds_source = "MediaWiki:WMDE_Fundraising/UseOfFunds_2024_EN" [english.banners.ctrl] -filename = "./banners/english/C24_WMDE_Desktop_EN_04/banner_ctrl.ts" -pagename = "B24_WMDE_Desktop_EN_04_ctrl" -tracking = "org-en04-241113-ctrl" +filename = "./banners/english/C24_WMDE_Desktop_EN_05/banner_ctrl.ts" +pagename = "B24_WMDE_Desktop_EN_05_ctrl" +tracking = "org-en05-241126-ctrl" [english.banners.var] -filename = "./banners/english/C24_WMDE_Desktop_EN_04/banner_var.ts" -pagename = "B24_WMDE_Desktop_EN_04_var" -tracking = "org-en04-241113-var" +filename = "./banners/english/C24_WMDE_Desktop_EN_05/banner_var.ts" +pagename = "B24_WMDE_Desktop_EN_05_var" +tracking = "org-en05-241126-var" [english.test_matrix] platform = ["edge", "firefox_win10", "chrome_win10", "safari", "firefox_macos", "chrome_macos", "firefox_linux", "chrome_linux"] diff --git a/package-lock.json b/package-lock.json index 448496332..3d5f71755 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4499,9 +4499,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -8920,9 +8920,9 @@ "license": "MIT" }, "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/src/components/DonationForm/Forms/MainDonationFormDonationReceipt.scss b/src/components/DonationForm/Forms/MainDonationFormDonationReceipt.scss new file mode 100644 index 000000000..04192c9a6 --- /dev/null +++ b/src/components/DonationForm/Forms/MainDonationFormDonationReceipt.scss @@ -0,0 +1,31 @@ +@mixin layout { + &-sub-form-donation { + .wmde-banner-form-field-group { + border: 0; + margin: 0; + display: block; + + &-legend { + width: 100%; + position: relative; + padding: 0; + } + } + } + + .wmde-banner-form-donation-receipt-checkbox { + display: inline-block; + cursor: pointer; + position: relative; + padding: 0 0 10px 24px; + + input[ type='checkbox' ] { + display: block; + float: left; + height: 16px; + margin: 0 0 0 -24px; + transition: background 0.15s ease-out; + width: 16px; + } + } +} diff --git a/src/components/DonationForm/Forms/MainDonationFormDonationReceipt.vue b/src/components/DonationForm/Forms/MainDonationFormDonationReceipt.vue new file mode 100644 index 000000000..266e8ba63 --- /dev/null +++ b/src/components/DonationForm/Forms/MainDonationFormDonationReceipt.vue @@ -0,0 +1,176 @@ + + + + diff --git a/src/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.vue b/src/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.vue new file mode 100644 index 000000000..a64f6820c --- /dev/null +++ b/src/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/components/UseOfFunds/Infographics/WMDEFundsForwardingEN.vue b/src/components/UseOfFunds/Infographics/WMDEFundsForwardingEN.vue index 2649f47bc..ffe5d9741 100644 --- a/src/components/UseOfFunds/Infographics/WMDEFundsForwardingEN.vue +++ b/src/components/UseOfFunds/Infographics/WMDEFundsForwardingEN.vue @@ -1,551 +1,4 @@ - - diff --git a/src/themes/Treedip/DonationForm/BubbleForm/SelectCustomAmountRadioBubble.scss b/src/themes/Treedip/DonationForm/BubbleForm/SelectCustomAmountRadioBubble.scss index 68dd716bc..a7604bd17 100644 --- a/src/themes/Treedip/DonationForm/BubbleForm/SelectCustomAmountRadioBubble.scss +++ b/src/themes/Treedip/DonationForm/BubbleForm/SelectCustomAmountRadioBubble.scss @@ -71,3 +71,14 @@ $font-size: 0.9em !default; } } } + +html[ lang='en' ] .wmde-banner { + .wmde-banner-select-custom-amount-euro-symbol { + right: auto; + left: 20px; + } + + .wmde-banner-select-custom-amount-input { + padding: 0 10px 0 30px; + } +} diff --git a/src/themes/Treedip/DonationForm/Forms/MainDonationFormDonationReceipt.scss b/src/themes/Treedip/DonationForm/Forms/MainDonationFormDonationReceipt.scss new file mode 100644 index 000000000..279055b90 --- /dev/null +++ b/src/themes/Treedip/DonationForm/Forms/MainDonationFormDonationReceipt.scss @@ -0,0 +1,46 @@ +@use '../../variables/globals'; +@use '../../variables/fonts'; +@use '../../../../components/DonationForm/Forms/MainDonationFormDonationReceipt'; + +$padding: 0 !default; + +.wmde-banner { + @include MainDonationFormDonationReceipt.layout; + + &-sub-form-donation { + padding: $padding; + + .wmde-banner-form-field-group { + padding: 0 0 10px; + + &-legend { + display: none; + visibility: hidden; + font-family: fonts.$ui; + font-size: 12px; + line-height: 13px; + color: var( --main-color ); + } + } + } + + &-form-donation-receipt-checkbox { + input[ type='checkbox' ] { + cursor: pointer; + appearance: none; + background: var( --input-checkbox-background ); + border: 1px solid var( --input-checkbox-border ); + border-radius: 2px; + transition: background 0.15s ease-out; + + &:checked { + background: var( --input-checkbox-background-checked ) url( "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath d='M.04.627.146.52.43.804.323.91zm.177.177L.854.167.96.273.323.91z' style='fill:%23fff'/%3E%3C/svg%3E" ) no-repeat 50%; + border-color: var( --input-checkbox-border-checked ); + } + } + + label { + cursor: pointer; + } + } +} diff --git a/src/themes/Treedip/DonationForm/SubComponents/TransactionFees.scss b/src/themes/Treedip/DonationForm/SubComponents/TransactionFees.scss index ca29ce0da..b71d1ad05 100644 --- a/src/themes/Treedip/DonationForm/SubComponents/TransactionFees.scss +++ b/src/themes/Treedip/DonationForm/SubComponents/TransactionFees.scss @@ -13,8 +13,8 @@ transition: background 0.15s ease-out; &:checked { - background: var( --input-checkbox-checked-background ) url( "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath d='M.04.627.146.52.43.804.323.91zm.177.177L.854.167.96.273.323.91z' style='fill:%23fff'/%3E%3C/svg%3E" ) no-repeat 50%; - border-color: var( --input-checkbox-checked-background ); + background: var( --input-checkbox-background-checked ) url( "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath d='M.04.627.146.52.43.804.323.91zm.177.177L.854.167.96.273.323.91z' style='fill:%23fff'/%3E%3C/svg%3E" ) no-repeat 50%; + border-color: var( --input-checkbox-background-checked ); } } } diff --git a/src/themes/Treedip/swatches/color_dark.scss b/src/themes/Treedip/swatches/color_dark.scss index 3f1cdb2c7..44731ebad 100644 --- a/src/themes/Treedip/swatches/color_dark.scss +++ b/src/themes/Treedip/swatches/color_dark.scss @@ -52,8 +52,11 @@ $blue800: #20303f; --input-selection-color: #{$grey100}; --input-selection-selected-background: #{$red600}; --input-selection-selected-color: #{$white}; - --input-checkbox-border: #{$grey200}; - --input-checkbox-checked-background: #{$blue700}; + + --input-checkbox-background: #{$white}; + --input-checkbox-border: #{$grey500}; + --input-checkbox-background-checked: #{$blue700}; + --input-checkbox-border-checked: #{$white}; --animated-highlight-color: #{$white}; /* stylelint-disable */ diff --git a/src/themes/Treedip/swatches/color_light.scss b/src/themes/Treedip/swatches/color_light.scss index 2dd2d8b19..3061bd40e 100644 --- a/src/themes/Treedip/swatches/color_light.scss +++ b/src/themes/Treedip/swatches/color_light.scss @@ -51,8 +51,11 @@ $blue700: #2a4b8d; --input-selection-color: #{$black}; --input-selection-selected-background: #{$red600}; --input-selection-selected-color: #{$white}; + + --input-checkbox-background: transparent; --input-checkbox-border: #{$grey500}; - --input-checkbox-checked-background: #{$blue600}; + --input-checkbox-background-checked: #{$blue700}; + --input-checkbox-border-checked: #{$blue700}; --animated-highlight-color: #{$grey700}; /* stylelint-disable */ diff --git a/test/banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.spec.ts b/test/banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.spec.ts new file mode 100644 index 000000000..87c1a797b --- /dev/null +++ b/test/banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.spec.ts @@ -0,0 +1,141 @@ +import { beforeEach, describe, test } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/english/C24_WMDE_Desktop_EN_05/components/BannerCtrl.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { formItems } from '@test/banners/formItems'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { useOfFundsFeatures } from '@test/features/UseOfFunds'; +import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures, bannerContentDisplaySwitchFeatures, bannerContentFeatures } from '@test/features/BannerContent'; +import { TrackerStub } from '@test/fixtures/TrackerStub'; +import { donationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { bannerAutoHideFeatures, bannerMainFeatures } from '@test/features/MainBanner'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { alreadyDonatedModalFeatures } from '@test/features/AlreadyDonatedModal'; +import { softCloseFeatures } from '@test/features/SoftCloseDesktop'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +const formModel = useFormModel(); +const translator = ( key: string ): string => key; + +describe( 'BannerCtrl.vue', () => { + + beforeEach( () => { + resetFormModel( formModel ); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + return mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + remainingImpressions: 10 + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com', donateWithoutAddressAction: 'https://example.com' }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker: new TrackerStub(), + timer: timer ?? new TimerStub() + } + } + } ); + }; + + describe( 'Main Banner', () => { + test.each( [ + [ 'expectDoesNotEmitCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await bannerMainFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectClosesBannerWhenWindowBecomesSmall' ] + ] )( '%s', async ( testName: string ) => { + await bannerAutoHideFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Content', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenBecomesVisible' ], + [ 'expectSlideShowStopsOnFormInteraction' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectShowsSlideShowOnSmallSizes' ], + [ 'expectShowsMessageOnLargeSizes' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDisplaySwitchFeatures[ testName ]( getWrapper, 1300 ); + } ); + + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMessage' ], + [ 'expectShowsLiveDateAndTimeInSlideshow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Already Donated', () => { + test.each( [ + [ 'expectFiresMaybeLaterEventOnLinkClick' ] + ] )( '%s', async ( testName: string ) => { + await alreadyDonatedModalFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); diff --git a/test/banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.spec.ts b/test/banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.spec.ts new file mode 100644 index 000000000..3705d2f23 --- /dev/null +++ b/test/banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.spec.ts @@ -0,0 +1,142 @@ +import { beforeEach, describe, test } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import Banner from '@banners/english/C24_WMDE_Desktop_EN_05/components/BannerVar.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { formItems } from '@test/banners/formItems'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { useOfFundsFeatures } from '@test/features/UseOfFunds'; +import { bannerContentAnimatedTextFeatures, bannerContentDateAndTimeFeatures, bannerContentDisplaySwitchFeatures, bannerContentFeatures } from '@test/features/BannerContent'; +import { TrackerStub } from '@test/fixtures/TrackerStub'; +import { donationFormFeatures } from '@test/features/forms/MainDonationDonationReceipt_UpgradeToYearlyButton'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { bannerAutoHideFeatures, bannerMainFeatures } from '@test/features/MainBanner'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { alreadyDonatedModalFeatures } from '@test/features/AlreadyDonatedModal'; +import { softCloseFeatures } from '@test/features/SoftCloseDesktop'; +import { Timer } from '@src/utils/Timer'; +import { TimerStub } from '@test/fixtures/TimerStub'; + +const formModel = useFormModel(); +const translator = ( key: string ): string => key; + +describe( 'BannerVar.vue', () => { + + beforeEach( () => { + resetFormModel( formModel ); + } ); + + const getWrapper = ( dynamicContent: DynamicContent = null, timer: Timer = null ): VueWrapper => { + return mount( Banner, { + attachTo: document.body, + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + remainingImpressions: 10 + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + formActions: { donateWithAddressAction: 'https://example.com', donateWithoutAddressAction: 'https://example.com' }, + currencyFormatter: new CurrencyEn(), + formItems, + tracker: new TrackerStub(), + timer: timer ?? new TimerStub() + } + } + } ); + }; + + describe( 'Main Banner', () => { + test.each( [ + [ 'expectDoesNotEmitCloseEvent' ] + ] )( '%s', async ( testName: string ) => { + await bannerMainFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectClosesBannerWhenWindowBecomesSmall' ] + ] )( '%s', async ( testName: string ) => { + await bannerAutoHideFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Content', () => { + test.each( [ + [ 'expectSlideShowPlaysWhenBecomesVisible' ], + [ 'expectSlideShowStopsOnFormInteraction' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentFeatures[ testName ]( getWrapper() ); + } ); + + test.each( [ + [ 'expectShowsSlideShowOnSmallSizes' ], + [ 'expectShowsMessageOnLargeSizes' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDisplaySwitchFeatures[ testName ]( getWrapper, 1300 ); + } ); + + test.each( [ + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInMessage' ], + [ 'expectShowsAnimatedVisitorsVsDonorsSentenceInSlideShow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentAnimatedTextFeatures[ testName ]( getWrapper ); + } ); + + test.each( [ + [ 'expectShowsLiveDateAndTimeInMessage' ], + [ 'expectShowsLiveDateAndTimeInSlideshow' ] + ] )( '%s', async ( testName: string ) => { + await bannerContentDateAndTimeFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Donation Form Happy Paths', () => { + test.each( [ + [ 'expectMainDonationFormSubmitsWhenSofortIsSelected' ], + [ 'expectMainDonationFormSubmitsWhenYearlyIsSelected' ], + [ 'expectMainDonationFormGoesToUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsUpgrade' ], + [ 'expectUpgradeToYearlyFormSubmitsDontUpgrade' ], + [ 'expectMainDonationFormShowsDonationReceiptCheckbox' ] + ] )( '%s', async ( testName: string ) => { + await donationFormFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Soft Close', () => { + test.each( [ + [ 'expectShowsSoftClose' ], + [ 'expectEmitsSoftCloseCloseEvent' ], + [ 'expectEmitsSoftCloseMaybeLaterEvent' ], + [ 'expectEmitsSoftCloseTimeOutEvent' ], + [ 'expectEmitsBannerContentChangedOnSoftClose' ], + [ 'expectDoesNotShowSoftCloseOnFinalBannerImpression' ] + ] )( '%s', async ( testName: string ) => { + await softCloseFeatures[ testName ]( getWrapper ); + } ); + } ); + + describe( 'Use of Funds', () => { + test.each( [ + [ 'expectShowsUseOfFunds' ], + [ 'expectHidesUseOfFunds' ] + ] )( '%s', async ( testName: string ) => { + await useOfFundsFeatures[ testName ]( getWrapper() ); + } ); + } ); + + describe( 'Already Donated', () => { + test.each( [ + [ 'expectFiresMaybeLaterEventOnLinkClick' ] + ] )( '%s', async ( testName: string ) => { + await alreadyDonatedModalFeatures[ testName ]( getWrapper() ); + } ); + } ); +} ); diff --git a/test/banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.spec.ts b/test/banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.spec.ts new file mode 100644 index 000000000..4a04d7f75 --- /dev/null +++ b/test/banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.spec.ts @@ -0,0 +1,64 @@ +import { describe, test } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import FallbackBanner from '@banners/english/C24_WMDE_Desktop_EN_05/components/FallbackBanner.vue'; +import { BannerStates } from '@src/components/BannerConductor/StateMachine/BannerStates'; +import { useOfFundsContent } from '@test/banners/useOfFundsContent'; +import { newDynamicContent } from '@test/banners/dynamicCampaignContent'; +import { DynamicContent } from '@src/utils/DynamicContent/DynamicContent'; +import { Tracker } from '@src/tracking/Tracker'; +import { TrackerStub } from '@test/fixtures/TrackerStub'; +import { dynamicContentFeatures, fallbackBannerFeatures, submitFeatures } from '@test/features/FallbackBanner'; +import { TimerStub } from '@test/fixtures/TimerStub'; +import { Timer } from '@src/utils/Timer'; + +const translator = ( key: string ): string => key; + +describe( 'FallbackBanner.vue', () => { + const getWrapperAtWidth = ( width: number, dynamicContent: DynamicContent = null, tracker: Tracker = null, timer: Timer = null ): VueWrapper => { + Object.defineProperty( window, 'innerWidth', { writable: true, configurable: true, value: width } ); + return mount( FallbackBanner, { + props: { + bannerState: BannerStates.Pending, + useOfFundsContent, + donationLink: 'https://spenden.wikimedia.de' + }, + global: { + mocks: { + $translate: translator + }, + provide: { + translator: { translate: translator }, + dynamicCampaignText: dynamicContent ?? newDynamicContent(), + tracker: tracker ?? new TrackerStub(), + timer: timer ?? new TimerStub() + } + } + } ); + }; + + test.each( [ + [ 'showsTheSmallBanner' ], + [ 'showsTheLargeBanner' ], + [ 'emitsTheBannerCloseEvent' ], + [ 'playsTheSlideshowWhenBecomesVisible' ], + [ 'showsUseOfFundsFromSmallBanner' ], + [ 'hidesUseOfFundsFromSmallBanner' ], + [ 'showsUseOfFundsFromLargeBanner' ], + [ 'hidesUseOfFundsFromLargeBanner' ] + ] )( '%s', async ( testName: string ) => { + await fallbackBannerFeatures[ testName ]( getWrapperAtWidth ); + } ); + + test.each( [ + [ 'showsLiveTimeInLargeBanner' ] + ] )( '%s', async ( testName: string ) => { + await dynamicContentFeatures[ testName ]( getWrapperAtWidth ); + } ); + + test.each( [ + [ 'submitsFromLargeBanner' ], + [ 'submitsFromSmallBanner' ] + ] )( '%s', async ( testName: string ) => { + await submitFeatures[ testName ]( getWrapperAtWidth ); + } ); +} ); diff --git a/test/components/DonationForm/Forms/MainDonationFormDonationReceipt.spec.ts b/test/components/DonationForm/Forms/MainDonationFormDonationReceipt.spec.ts new file mode 100644 index 000000000..0ce061c99 --- /dev/null +++ b/test/components/DonationForm/Forms/MainDonationFormDonationReceipt.spec.ts @@ -0,0 +1,215 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mount, VueWrapper } from '@vue/test-utils'; +import DonationForm from '@src/components/DonationForm/Forms/MainDonationFormDonationReceipt.vue'; +import { DonationFormItems } from '@src/utils/FormItemsBuilder/DonationFormItems'; +import { Intervals } from '@src/utils/FormItemsBuilder/fields/Intervals'; +import { PaymentMethods } from '@src/utils/FormItemsBuilder/fields/PaymentMethods'; +import { newDonationFormValidator } from '@src/validation/DonationFormValidator'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { resetFormModel } from '@test/resetFormModel'; +import { CurrencyEn } from '@src/utils/DynamicContent/formatters/CurrencyEn'; +import { TrackerSpy } from '@test/fixtures/TrackerSpy'; +import { AddressTypes } from '@src/utils/FormItemsBuilder/fields/AddressTypes'; + +const formItems: DonationFormItems = { + addressType: [], + amounts: [ + { value: '1', label: '€1', className: 'amount-1' }, + { value: '5', label: '€5', className: 'amount-5' } + ], + intervals: [ Intervals.ONCE, Intervals.MONTHLY ], + paymentMethods: [ PaymentMethods.PAYPAL, PaymentMethods.CREDIT_CARD, PaymentMethods.DIRECT_DEBIT ] +}; + +vi.mock( '@src/validation/DonationFormValidator', () => { + return { + newDonationFormValidator: vi.fn() + }; +} ); + +const formModel = useFormModel(); +const translate = ( key: string ): string => key; + +describe( 'MainDonationFormDonationReceipt.vue', () => { + + // The model values are in the global scope, and they need to be reset before each test + beforeEach( () => resetFormModel( formModel ) ); + + const getWrapper = ( showErrorScrollLink: boolean = false ): VueWrapper => { + return mount( DonationForm, { + props: { + showErrorScrollLink + }, + global: { + mocks: { + $translate: translate + }, + provide: { + currencyFormatter: new CurrencyEn(), + formActions: { donateWithAddressAction: 'https://example.com', donateWithoutAddressAction: 'https://example.com' }, + formItems: formItems, + translator: { translate }, + tracker: new TrackerSpy() + } + }, + attachTo: document.body + } ); + }; + + it( 'should clear selected amount when input field is focused', () => { + const input = getWrapper().find( '.wmde-banner-select-custom-amount-input' ); + formModel.selectedAmount.value = '100'; + + input.trigger( 'focus' ); + + expect( formModel.selectedAmount.value ).toBe( '' ); + } ); + + it( 'should format custom amount when custom amount input field is blurred and it has a value', async () => { + const input = getWrapper().find( '.wmde-banner-select-custom-amount-input' ); + + await input.setValue( '3,14' ); + await input.trigger( 'blur' ); + + expect( input.element.value ).toBe( '3.14' ); + } ); + + it( 'should not format custom amount to 0.00 when input field is blurred and is blank', async () => { + const input = getWrapper().find( '.wmde-banner-select-custom-amount-input' ); + + await input.trigger( 'blur' ); + + expect( input.element.value ).toBe( '' ); + } ); + + it( 'shows invalid fields on submit when fields are invalid', async () => { + vi.mocked( newDonationFormValidator ).mockReturnValue( { validate: () => false } ); + const wrapper = getWrapper(); + + await wrapper.trigger( 'submit' ); + + expect( wrapper.find( '.select-interval .wmde-banner-select-group-error-message' ).exists() ).toBeTruthy(); + expect( wrapper.find( '.select-amount .wmde-banner-select-group-error-message' ).exists() ).toBeTruthy(); + expect( wrapper.find( '.select-payment-method .wmde-banner-select-group-error-message' ).exists() ).toBeTruthy(); + } ); + + it( 'shows the error scroll link when form fields are invalid', async () => { + vi.mocked( newDonationFormValidator ).mockReturnValue( { validate: () => false } ); + const wrapper = getWrapper( true ); + + await wrapper.trigger( 'submit' ); + + expect( wrapper.find( '.wmde-banner-form-button-error' ).exists() ).toBeTruthy(); + } ); + + it( 'emits an event on submit when fields are valid', () => { + vi.mocked( newDonationFormValidator ).mockReturnValue( { validate: () => true } ); + const wrapper = getWrapper(); + + wrapper.trigger( 'submit' ); + + expect( wrapper.emitted( 'submit' ).length ).toBe( 1 ); + } ); + + it( 'does not emit our own submit event when form fields are invalid', () => { + vi.mocked( newDonationFormValidator ).mockReturnValue( { validate: () => false } ); + const wrapper = getWrapper(); + + wrapper.trigger( 'submit' ); + + expect( wrapper.emitted( 'submit' ) ).toBeUndefined(); + } ); + + it( 'passes payment label slots dynamically to select group', () => { + const wrapper = mount( DonationForm, { + props: { + showErrorScrollLink: false + }, + slots: { + 'label-payment-ppl': ``, + 'label-payment-mcp': `` + }, + global: { + mocks: { + $translate: translate + }, + provide: { + currencyFormatter: new CurrencyEn(), + formActions: { donateWithAddressAction: 'https://example.com', donateWithoutAddressAction: 'https://example.com' }, + formItems: formItems, + translator: { translate }, + tracker: new TrackerSpy() + } + } + } ); + + expect( wrapper.find( '.custom-label-paypal' ).exists() ).toBeTruthy(); + expect( wrapper.find( '.custom-label-credit-cards' ).exists() ).toBeTruthy(); + } ); + + it( 'sets the address type to anonymous when mounted', async () => { + expect( formModel.addressType.value ).toStrictEqual( '' ); + getWrapper(); + expect( formModel.addressType.value ).toStrictEqual( AddressTypes.ANONYMOUS.value ); + } ); + + it( 'shows the donation receipt checkbox', async () => { + const wrapper = getWrapper(); + + expect( wrapper.find( '.wmde-banner-form-donation-receipt-checkbox' ).exists() ).toBeFalsy(); + + await wrapper.find( '.interval-0 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.amount-5 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.payment-ppl .wmde-banner-select-group-input' ).trigger( 'change' ); + + expect( wrapper.find( '.wmde-banner-form-donation-receipt-checkbox' ).exists() ).toBeTruthy(); + } ); + + it( 'does not show the donation receipt checkbox when address type is direct debit', async () => { + const wrapper = getWrapper(); + + expect( wrapper.find( '.wmde-banner-form-donation-receipt-checkbox' ).exists() ).toBeFalsy(); + + await wrapper.find( '.interval-0 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.amount-5 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.payment-bez .wmde-banner-select-group-input' ).trigger( 'change' ); + + expect( wrapper.find( '.wmde-banner-form-donation-receipt-checkbox' ).exists() ).toBeFalsy(); + } ); + + it( 'updates the address type based on the donation receipt', async () => { + const wrapper = getWrapper(); + + await wrapper.find( '.interval-0 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.amount-5 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.payment-ppl .wmde-banner-select-group-input' ).trigger( 'change' ); + + expect( formModel.addressType.value ).toStrictEqual( AddressTypes.ANONYMOUS.value ); + + await wrapper.find( '#wmde-banner-form-donation-receipt' ).trigger( 'click' ); + + expect( formModel.addressType.value ).toStrictEqual( '' ); + + await wrapper.find( '#wmde-banner-form-donation-receipt' ).trigger( 'click' ); + + expect( formModel.addressType.value ).toStrictEqual( AddressTypes.ANONYMOUS.value ); + } ); + + it( 'clears the address type when radio field becomes hidden', async () => { + const wrapper = getWrapper(); + + await wrapper.find( '.interval-0 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.amount-5 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.payment-ppl .wmde-banner-select-group-input' ).trigger( 'change' ); + + expect( formModel.addressType.value ).toStrictEqual( AddressTypes.ANONYMOUS.value ); + + await wrapper.find( '#wmde-banner-form-donation-receipt' ).trigger( 'click' ); + + expect( formModel.addressType.value ).toStrictEqual( '' ); + + await wrapper.find( '.payment-bez .wmde-banner-select-group-input' ).trigger( 'change' ); + + expect( formModel.addressType.value ).toStrictEqual( AddressTypes.ANONYMOUS.value ); + } ); +} ); diff --git a/test/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.spec.ts b/test/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.spec.ts new file mode 100644 index 000000000..dc4b3afd4 --- /dev/null +++ b/test/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.spec.ts @@ -0,0 +1,79 @@ +import { describe, expect, test } from 'vitest'; +import { useFormModel } from '@src/components/composables/useFormModel'; +import { shallowMount } from '@vue/test-utils'; +import { Intervals } from '@src/utils/FormItemsBuilder/fields/Intervals'; +import { PaymentMethods } from '@src/utils/FormItemsBuilder/fields/PaymentMethods'; +import MainDonationFormPaymentsAndReceiptButton from '@src/components/DonationForm/Forms/MainDonationFormPaymentsAndReceiptButton.vue'; +import { AddressTypes } from '@src/utils/FormItemsBuilder/fields/AddressTypes'; + +const translate = ( key: string ): string => key; + +describe( 'MainDonationFormPaymentsAndReceiptButton.vue', () => { + + test.each( [ + [ Intervals.ONCE.value, 'submit-label-short' ], + [ Intervals.MONTHLY.value, 'submit-label' ], + [ Intervals.BIANNUAL.value, 'submit-label' ], + [ Intervals.YEARLY.value, 'submit-label' ], + [ Intervals.QUARTERLY.value, 'submit-label' ] + ] )( 'shows the correct label for interval %i', ( interval: string, label: string ) => { + const formModel = useFormModel(); + formModel.interval.value = interval; + formModel.addressType.value = interval; + formModel.paymentMethod.value = PaymentMethods.PAYPAL.value; + + const wrapper = shallowMount( MainDonationFormPaymentsAndReceiptButton, { + global: { + provide: { + translator: { translate } + } + } + } ); + + expect( wrapper.text() ).toStrictEqual( label ); + } ); + + test.each( [ + [ AddressTypes.ANONYMOUS.value, 'submit-label-paypal' ], + [ AddressTypes.EMAIL.value, 'submit-label' ], + [ AddressTypes.FULL.value, 'submit-label' ] + ] )( 'shows the correct label for address type %s', ( addressType: string, label: string ) => { + const formModel = useFormModel(); + formModel.addressType.value = addressType; + formModel.paymentMethod.value = PaymentMethods.PAYPAL.value; + + const wrapper = shallowMount( MainDonationFormPaymentsAndReceiptButton, { + global: { + provide: { + translator: { translate } + } + } + } ); + + expect( wrapper.text() ).toStrictEqual( label ); + } ); + + test.each( [ + [ PaymentMethods.PAYPAL.value, 'submit-label-paypal' ], + [ PaymentMethods.BANK_TRANSFER.value, 'submit-label-bank-transfer' ], + [ PaymentMethods.CREDIT_CARD.value, 'submit-label-credit-card' ], + [ PaymentMethods.SOFORT.value, 'submit-label-sofort' ], + [ PaymentMethods.DIRECT_DEBIT.value, 'submit-label' ] + ] )( 'shows the correct label when anonymous for payment method %s', ( paymentMethod: string, label: string ) => { + const formModel = useFormModel(); + formModel.interval.value = Intervals.MONTHLY.value; + formModel.addressType.value = AddressTypes.ANONYMOUS.value; + formModel.paymentMethod.value = paymentMethod; + + const wrapper = shallowMount( MainDonationFormPaymentsAndReceiptButton, { + global: { + provide: { + translator: { translate } + } + } + } ); + + expect( wrapper.text() ).toStrictEqual( label ); + } ); + +} ); diff --git a/test/features/forms/MainDonationDonationReceipt_UpgradeToYearlyButton.ts b/test/features/forms/MainDonationDonationReceipt_UpgradeToYearlyButton.ts new file mode 100644 index 000000000..cb142efb8 --- /dev/null +++ b/test/features/forms/MainDonationDonationReceipt_UpgradeToYearlyButton.ts @@ -0,0 +1,17 @@ +import { VueWrapper } from '@vue/test-utils'; +import { donationFormFeatures as mainDonationFormFeatures } from '@test/features/forms/MainDonation_UpgradeToYearlyButton'; +import { expect } from 'vitest'; + +export const donationFormFeatures: Record ) => Promise> = { + ...mainDonationFormFeatures, + + expectMainDonationFormShowsDonationReceiptCheckbox: async ( wrapper: VueWrapper ) => { + expect( wrapper.find( '.wmde-banner-form-donation-receipt-checkbox' ).exists() ).toBeFalsy(); + + await wrapper.find( '.interval-0 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.amount-5 .wmde-banner-select-group-input' ).trigger( 'change' ); + await wrapper.find( '.payment-ppl .wmde-banner-select-group-input' ).trigger( 'change' ); + + expect( wrapper.find( '.wmde-banner-form-donation-receipt-checkbox' ).exists() ).toBeTruthy(); + } +};